ndk_headers.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // Copyright 2016 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package cc
  15. import (
  16. "fmt"
  17. "path/filepath"
  18. "github.com/google/blueprint"
  19. "android/soong/android"
  20. )
  21. var (
  22. versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
  23. blueprint.RuleParams{
  24. // The `&& touch $out` isn't really necessary, but Blueprint won't
  25. // let us have only implicit outputs.
  26. Command: "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
  27. CommandDeps: []string{"$versionerCmd"},
  28. },
  29. "depsPath", "srcDir", "outDir")
  30. preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
  31. blueprint.RuleParams{
  32. Command: "$preprocessor -o $out $in",
  33. CommandDeps: []string{"$preprocessor"},
  34. },
  35. "preprocessor")
  36. )
  37. func init() {
  38. pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
  39. }
  40. // Returns the NDK base include path for use with sdk_version current. Usable with -I.
  41. func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath {
  42. return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
  43. }
  44. type headerProperties struct {
  45. // Base directory of the headers being installed. As an example:
  46. //
  47. // ndk_headers {
  48. // name: "foo",
  49. // from: "include",
  50. // to: "",
  51. // srcs: ["include/foo/bar/baz.h"],
  52. // }
  53. //
  54. // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
  55. // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
  56. From *string
  57. // Install path within the sysroot. This is relative to usr/include.
  58. To *string
  59. // List of headers to install. Glob compatible. Common case is "include/**/*.h".
  60. Srcs []string `android:"path"`
  61. // Source paths that should be excluded from the srcs glob.
  62. Exclude_srcs []string `android:"path"`
  63. // Path to the NOTICE file associated with the headers.
  64. License *string `android:"path"`
  65. }
  66. type headerModule struct {
  67. android.ModuleBase
  68. properties headerProperties
  69. installPaths android.Paths
  70. licensePath android.Path
  71. }
  72. func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
  73. to string) android.InstallPath {
  74. // Output path is the sysroot base + "usr/include" + to directory + directory component
  75. // of the file without the leading from directory stripped.
  76. //
  77. // Given:
  78. // sysroot base = "ndk/sysroot"
  79. // from = "include/foo"
  80. // to = "bar"
  81. // header = "include/foo/woodly/doodly.h"
  82. // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
  83. // full/platform/path/to/include/foo
  84. fullFromPath := android.PathForModuleSrc(ctx, from)
  85. // full/platform/path/to/include/foo/woodly
  86. headerDir := filepath.Dir(header.String())
  87. // woodly
  88. strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
  89. if err != nil {
  90. ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
  91. fullFromPath.String(), err)
  92. }
  93. // full/platform/path/to/sysroot/usr/include/bar/woodly
  94. installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
  95. // full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
  96. return installDir
  97. }
  98. func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  99. if String(m.properties.License) == "" {
  100. ctx.PropertyErrorf("license", "field is required")
  101. }
  102. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  103. srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
  104. for _, header := range srcFiles {
  105. installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
  106. String(m.properties.To))
  107. installedPath := ctx.InstallFile(installDir, header.Base(), header)
  108. installPath := installDir.Join(ctx, header.Base())
  109. if installPath != installedPath {
  110. panic(fmt.Sprintf(
  111. "expected header install path (%q) not equal to actual install path %q",
  112. installPath, installedPath))
  113. }
  114. m.installPaths = append(m.installPaths, installPath)
  115. }
  116. if len(m.installPaths) == 0 {
  117. ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
  118. }
  119. }
  120. // ndk_headers installs the sets of ndk headers defined in the srcs property
  121. // to the sysroot base + "usr/include" + to directory + directory component.
  122. // ndk_headers requires the license file to be specified. Example:
  123. //
  124. // Given:
  125. // sysroot base = "ndk/sysroot"
  126. // from = "include/foo"
  127. // to = "bar"
  128. // header = "include/foo/woodly/doodly.h"
  129. // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
  130. func ndkHeadersFactory() android.Module {
  131. module := &headerModule{}
  132. module.AddProperties(&module.properties)
  133. android.InitAndroidModule(module)
  134. return module
  135. }
  136. type versionedHeaderProperties struct {
  137. // Base directory of the headers being installed. As an example:
  138. //
  139. // versioned_ndk_headers {
  140. // name: "foo",
  141. // from: "include",
  142. // to: "",
  143. // }
  144. //
  145. // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
  146. // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
  147. From *string
  148. // Install path within the sysroot. This is relative to usr/include.
  149. To *string
  150. // Path to the NOTICE file associated with the headers.
  151. License *string
  152. }
  153. // Like ndk_headers, but preprocesses the headers with the bionic versioner:
  154. // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
  155. //
  156. // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
  157. // module does not have the srcs property, and operates on a full directory (the `from` property).
  158. //
  159. // Note that this is really only built to handle bionic/libc/include.
  160. type versionedHeaderModule struct {
  161. android.ModuleBase
  162. properties versionedHeaderProperties
  163. installPaths android.Paths
  164. licensePath android.Path
  165. }
  166. // Return the glob pattern to find all .h files beneath `dir`
  167. func headerGlobPattern(dir string) string {
  168. return filepath.Join(dir, "**", "*.h")
  169. }
  170. func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  171. if String(m.properties.License) == "" {
  172. ctx.PropertyErrorf("license", "field is required")
  173. }
  174. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  175. fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
  176. toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
  177. srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
  178. var installPaths []android.WritablePath
  179. for _, header := range srcFiles {
  180. installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
  181. installPath := installDir.Join(ctx, header.Base())
  182. installPaths = append(installPaths, installPath)
  183. m.installPaths = append(m.installPaths, installPath)
  184. }
  185. if len(m.installPaths) == 0 {
  186. ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
  187. }
  188. processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
  189. }
  190. func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
  191. srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
  192. // The versioner depends on a dependencies directory to simplify determining include paths
  193. // when parsing headers. This directory contains architecture specific directories as well
  194. // as a common directory, each of which contains symlinks to the actually directories to
  195. // be included.
  196. //
  197. // ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
  198. // depend on these headers.
  199. // TODO(http://b/35673191): Update the versioner to use a --sysroot.
  200. depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
  201. depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
  202. for i, path := range depsGlob {
  203. if ctx.IsSymlink(path) {
  204. dest := ctx.Readlink(path)
  205. // Additional .. to account for the symlink itself.
  206. depsGlob[i] = android.PathForSource(
  207. ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
  208. }
  209. }
  210. timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
  211. ctx.Build(pctx, android.BuildParams{
  212. Rule: versionBionicHeaders,
  213. Description: "versioner preprocess " + srcDir.Rel(),
  214. Output: timestampFile,
  215. Implicits: append(srcFiles, depsGlob...),
  216. ImplicitOutputs: installPaths,
  217. Args: map[string]string{
  218. "depsPath": depsPath.String(),
  219. "srcDir": srcDir.String(),
  220. "outDir": outDir.String(),
  221. },
  222. })
  223. return timestampFile
  224. }
  225. // versioned_ndk_headers preprocesses the headers with the bionic versioner:
  226. // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
  227. // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
  228. // directory level specified in `from` property. This is only used to process
  229. // the bionic/libc/include directory.
  230. func versionedNdkHeadersFactory() android.Module {
  231. module := &versionedHeaderModule{}
  232. module.AddProperties(&module.properties)
  233. android.InitAndroidModule(module)
  234. return module
  235. }
  236. // preprocessed_ndk_header {
  237. //
  238. // name: "foo",
  239. // preprocessor: "foo.sh",
  240. // srcs: [...],
  241. // to: "android",
  242. //
  243. // }
  244. //
  245. // Will invoke the preprocessor as:
  246. //
  247. // $preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
  248. //
  249. // For each src in srcs.
  250. type preprocessedHeadersProperties struct {
  251. // The preprocessor to run. Must be a program inside the source directory
  252. // with no dependencies.
  253. Preprocessor *string
  254. // Source path to the files to be preprocessed.
  255. Srcs []string
  256. // Source paths that should be excluded from the srcs glob.
  257. Exclude_srcs []string
  258. // Install path within the sysroot. This is relative to usr/include.
  259. To *string
  260. // Path to the NOTICE file associated with the headers.
  261. License *string
  262. }
  263. type preprocessedHeadersModule struct {
  264. android.ModuleBase
  265. properties preprocessedHeadersProperties
  266. installPaths android.Paths
  267. licensePath android.Path
  268. }
  269. func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  270. if String(m.properties.License) == "" {
  271. ctx.PropertyErrorf("license", "field is required")
  272. }
  273. preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
  274. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  275. srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
  276. installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
  277. for _, src := range srcFiles {
  278. installPath := installDir.Join(ctx, src.Base())
  279. m.installPaths = append(m.installPaths, installPath)
  280. ctx.Build(pctx, android.BuildParams{
  281. Rule: preprocessNdkHeader,
  282. Description: "preprocess " + src.Rel(),
  283. Input: src,
  284. Output: installPath,
  285. Args: map[string]string{
  286. "preprocessor": preprocessor.String(),
  287. },
  288. })
  289. }
  290. if len(m.installPaths) == 0 {
  291. ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
  292. }
  293. }
  294. // preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
  295. // property by executing the command defined in the preprocessor property.
  296. func preprocessedNdkHeadersFactory() android.Module {
  297. module := &preprocessedHeadersModule{}
  298. module.AddProperties(&module.properties)
  299. android.InitAndroidModule(module)
  300. return module
  301. }