ndk_headers.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. "github.com/google/blueprint/proptools"
  20. "android/soong/android"
  21. "android/soong/bazel"
  22. )
  23. var (
  24. versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
  25. blueprint.RuleParams{
  26. // The `&& touch $out` isn't really necessary, but Blueprint won't
  27. // let us have only implicit outputs.
  28. Command: "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
  29. CommandDeps: []string{"$versionerCmd"},
  30. },
  31. "depsPath", "srcDir", "outDir")
  32. preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
  33. blueprint.RuleParams{
  34. Command: "$preprocessor -o $out $in",
  35. CommandDeps: []string{"$preprocessor"},
  36. },
  37. "preprocessor")
  38. )
  39. func init() {
  40. pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
  41. }
  42. // Returns the NDK base include path for use with sdk_version current. Usable with -I.
  43. func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath {
  44. return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
  45. }
  46. type headerProperties struct {
  47. // Base directory of the headers being installed. As an example:
  48. //
  49. // ndk_headers {
  50. // name: "foo",
  51. // from: "include",
  52. // to: "",
  53. // srcs: ["include/foo/bar/baz.h"],
  54. // }
  55. //
  56. // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
  57. // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
  58. From *string
  59. // Install path within the sysroot. This is relative to usr/include.
  60. To *string
  61. // List of headers to install. Glob compatible. Common case is "include/**/*.h".
  62. Srcs []string `android:"path"`
  63. // Source paths that should be excluded from the srcs glob.
  64. Exclude_srcs []string `android:"path"`
  65. // Path to the NOTICE file associated with the headers.
  66. License *string `android:"path"`
  67. }
  68. type headerModule struct {
  69. android.ModuleBase
  70. android.BazelModuleBase
  71. properties headerProperties
  72. installPaths android.Paths
  73. licensePath android.Path
  74. }
  75. func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
  76. to string) android.InstallPath {
  77. // Output path is the sysroot base + "usr/include" + to directory + directory component
  78. // of the file without the leading from directory stripped.
  79. //
  80. // Given:
  81. // sysroot base = "ndk/sysroot"
  82. // from = "include/foo"
  83. // to = "bar"
  84. // header = "include/foo/woodly/doodly.h"
  85. // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
  86. // full/platform/path/to/include/foo
  87. fullFromPath := android.PathForModuleSrc(ctx, from)
  88. // full/platform/path/to/include/foo/woodly
  89. headerDir := filepath.Dir(header.String())
  90. // woodly
  91. strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
  92. if err != nil {
  93. ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
  94. fullFromPath.String(), err)
  95. }
  96. // full/platform/path/to/sysroot/usr/include/bar/woodly
  97. installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
  98. // full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
  99. return installDir
  100. }
  101. func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  102. if String(m.properties.License) == "" {
  103. ctx.PropertyErrorf("license", "field is required")
  104. }
  105. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  106. srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
  107. for _, header := range srcFiles {
  108. installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
  109. String(m.properties.To))
  110. installedPath := ctx.InstallFile(installDir, header.Base(), header)
  111. installPath := installDir.Join(ctx, header.Base())
  112. if installPath != installedPath {
  113. panic(fmt.Sprintf(
  114. "expected header install path (%q) not equal to actual install path %q",
  115. installPath, installedPath))
  116. }
  117. m.installPaths = append(m.installPaths, installPath)
  118. }
  119. if len(m.installPaths) == 0 {
  120. ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
  121. }
  122. }
  123. // TODO(b/243196151): Populate `system` and `arch` metadata
  124. type bazelCcApiHeadersAttributes struct {
  125. Hdrs bazel.LabelListAttribute
  126. Include_dir *string
  127. }
  128. func createCcApiHeadersTarget(ctx android.TopDownMutatorContext, includes []string, excludes []string, include_dir *string) {
  129. props := bazel.BazelTargetModuleProperties{
  130. Rule_class: "cc_api_headers",
  131. Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
  132. }
  133. attrs := &bazelCcApiHeadersAttributes{
  134. Hdrs: bazel.MakeLabelListAttribute(
  135. android.BazelLabelForModuleSrcExcludes(
  136. ctx,
  137. includes,
  138. excludes,
  139. ),
  140. ),
  141. Include_dir: include_dir,
  142. }
  143. ctx.CreateBazelTargetModule(props, android.CommonAttributes{
  144. Name: android.ApiContributionTargetName(ctx.ModuleName()),
  145. }, attrs)
  146. }
  147. var _ android.ApiProvider = (*headerModule)(nil)
  148. func (h *headerModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
  149. // Generate `cc_api_headers` target for Multi-tree API export
  150. createCcApiHeadersTarget(ctx, h.properties.Srcs, h.properties.Exclude_srcs, h.properties.From)
  151. }
  152. // ndk_headers installs the sets of ndk headers defined in the srcs property
  153. // to the sysroot base + "usr/include" + to directory + directory component.
  154. // ndk_headers requires the license file to be specified. Example:
  155. //
  156. // Given:
  157. // sysroot base = "ndk/sysroot"
  158. // from = "include/foo"
  159. // to = "bar"
  160. // header = "include/foo/woodly/doodly.h"
  161. // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
  162. func ndkHeadersFactory() android.Module {
  163. module := &headerModule{}
  164. module.AddProperties(&module.properties)
  165. android.InitAndroidModule(module)
  166. return module
  167. }
  168. type versionedHeaderProperties struct {
  169. // Base directory of the headers being installed. As an example:
  170. //
  171. // versioned_ndk_headers {
  172. // name: "foo",
  173. // from: "include",
  174. // to: "",
  175. // }
  176. //
  177. // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
  178. // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
  179. From *string
  180. // Install path within the sysroot. This is relative to usr/include.
  181. To *string
  182. // Path to the NOTICE file associated with the headers.
  183. License *string
  184. }
  185. // Like ndk_headers, but preprocesses the headers with the bionic versioner:
  186. // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
  187. //
  188. // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
  189. // module does not have the srcs property, and operates on a full directory (the `from` property).
  190. //
  191. // Note that this is really only built to handle bionic/libc/include.
  192. type versionedHeaderModule struct {
  193. android.ModuleBase
  194. android.BazelModuleBase
  195. properties versionedHeaderProperties
  196. installPaths android.Paths
  197. licensePath android.Path
  198. }
  199. // Return the glob pattern to find all .h files beneath `dir`
  200. func headerGlobPattern(dir string) string {
  201. return filepath.Join(dir, "**", "*.h")
  202. }
  203. func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  204. if String(m.properties.License) == "" {
  205. ctx.PropertyErrorf("license", "field is required")
  206. }
  207. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  208. fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
  209. toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
  210. srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
  211. var installPaths []android.WritablePath
  212. for _, header := range srcFiles {
  213. installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
  214. installPath := installDir.Join(ctx, header.Base())
  215. installPaths = append(installPaths, installPath)
  216. m.installPaths = append(m.installPaths, installPath)
  217. }
  218. if len(m.installPaths) == 0 {
  219. ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
  220. }
  221. processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
  222. }
  223. var _ android.ApiProvider = (*versionedHeaderModule)(nil)
  224. func (h *versionedHeaderModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
  225. // Glob all .h files under `From`
  226. includePattern := headerGlobPattern(proptools.String(h.properties.From))
  227. // Generate `cc_api_headers` target for Multi-tree API export
  228. createCcApiHeadersTarget(ctx, []string{includePattern}, []string{}, h.properties.From)
  229. }
  230. func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
  231. srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
  232. // The versioner depends on a dependencies directory to simplify determining include paths
  233. // when parsing headers. This directory contains architecture specific directories as well
  234. // as a common directory, each of which contains symlinks to the actually directories to
  235. // be included.
  236. //
  237. // ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
  238. // depend on these headers.
  239. // TODO(http://b/35673191): Update the versioner to use a --sysroot.
  240. depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
  241. depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
  242. for i, path := range depsGlob {
  243. if ctx.IsSymlink(path) {
  244. dest := ctx.Readlink(path)
  245. // Additional .. to account for the symlink itself.
  246. depsGlob[i] = android.PathForSource(
  247. ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
  248. }
  249. }
  250. timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
  251. ctx.Build(pctx, android.BuildParams{
  252. Rule: versionBionicHeaders,
  253. Description: "versioner preprocess " + srcDir.Rel(),
  254. Output: timestampFile,
  255. Implicits: append(srcFiles, depsGlob...),
  256. ImplicitOutputs: installPaths,
  257. Args: map[string]string{
  258. "depsPath": depsPath.String(),
  259. "srcDir": srcDir.String(),
  260. "outDir": outDir.String(),
  261. },
  262. })
  263. return timestampFile
  264. }
  265. // versioned_ndk_headers preprocesses the headers with the bionic versioner:
  266. // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
  267. // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
  268. // directory level specified in `from` property. This is only used to process
  269. // the bionic/libc/include directory.
  270. func versionedNdkHeadersFactory() android.Module {
  271. module := &versionedHeaderModule{}
  272. module.AddProperties(&module.properties)
  273. android.InitAndroidModule(module)
  274. return module
  275. }
  276. // preprocessed_ndk_header {
  277. //
  278. // name: "foo",
  279. // preprocessor: "foo.sh",
  280. // srcs: [...],
  281. // to: "android",
  282. //
  283. // }
  284. //
  285. // Will invoke the preprocessor as:
  286. //
  287. // $preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
  288. //
  289. // For each src in srcs.
  290. type preprocessedHeadersProperties struct {
  291. // The preprocessor to run. Must be a program inside the source directory
  292. // with no dependencies.
  293. Preprocessor *string
  294. // Source path to the files to be preprocessed.
  295. Srcs []string
  296. // Source paths that should be excluded from the srcs glob.
  297. Exclude_srcs []string
  298. // Install path within the sysroot. This is relative to usr/include.
  299. To *string
  300. // Path to the NOTICE file associated with the headers.
  301. License *string
  302. }
  303. type preprocessedHeadersModule struct {
  304. android.ModuleBase
  305. properties preprocessedHeadersProperties
  306. installPaths android.Paths
  307. licensePath android.Path
  308. }
  309. func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  310. if String(m.properties.License) == "" {
  311. ctx.PropertyErrorf("license", "field is required")
  312. }
  313. preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
  314. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  315. srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
  316. installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
  317. for _, src := range srcFiles {
  318. installPath := installDir.Join(ctx, src.Base())
  319. m.installPaths = append(m.installPaths, installPath)
  320. ctx.Build(pctx, android.BuildParams{
  321. Rule: preprocessNdkHeader,
  322. Description: "preprocess " + src.Rel(),
  323. Input: src,
  324. Output: installPath,
  325. Args: map[string]string{
  326. "preprocessor": preprocessor.String(),
  327. },
  328. })
  329. }
  330. if len(m.installPaths) == 0 {
  331. ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
  332. }
  333. }
  334. // preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
  335. // property by executing the command defined in the preprocessor property.
  336. func preprocessedNdkHeadersFactory() android.Module {
  337. module := &preprocessedHeadersModule{}
  338. module.AddProperties(&module.properties)
  339. android.InitAndroidModule(module)
  340. return module
  341. }