ndk_headers.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. // True if this API is not yet ready to be shipped in the NDK. It will be
  66. // available in the platform for testing, but will be excluded from the
  67. // sysroot provided to the NDK proper.
  68. Draft bool
  69. }
  70. type headerModule struct {
  71. android.ModuleBase
  72. properties headerProperties
  73. installPaths android.Paths
  74. licensePath android.Path
  75. }
  76. func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
  77. to string) android.InstallPath {
  78. // Output path is the sysroot base + "usr/include" + to directory + directory component
  79. // of the file without the leading from directory stripped.
  80. //
  81. // Given:
  82. // sysroot base = "ndk/sysroot"
  83. // from = "include/foo"
  84. // to = "bar"
  85. // header = "include/foo/woodly/doodly.h"
  86. // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
  87. // full/platform/path/to/include/foo
  88. fullFromPath := android.PathForModuleSrc(ctx, from)
  89. // full/platform/path/to/include/foo/woodly
  90. headerDir := filepath.Dir(header.String())
  91. // woodly
  92. strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
  93. if err != nil {
  94. ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
  95. fullFromPath.String(), err)
  96. }
  97. // full/platform/path/to/sysroot/usr/include/bar/woodly
  98. installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
  99. // full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
  100. return installDir
  101. }
  102. func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  103. if String(m.properties.License) == "" {
  104. ctx.PropertyErrorf("license", "field is required")
  105. }
  106. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  107. srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
  108. for _, header := range srcFiles {
  109. installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
  110. String(m.properties.To))
  111. installedPath := ctx.InstallFile(installDir, header.Base(), header)
  112. installPath := installDir.Join(ctx, header.Base())
  113. if installPath != installedPath {
  114. panic(fmt.Sprintf(
  115. "expected header install path (%q) not equal to actual install path %q",
  116. installPath, installedPath))
  117. }
  118. m.installPaths = append(m.installPaths, installPath)
  119. }
  120. if len(m.installPaths) == 0 {
  121. ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
  122. }
  123. }
  124. // ndk_headers installs the sets of ndk headers defined in the srcs property
  125. // to the sysroot base + "usr/include" + to directory + directory component.
  126. // ndk_headers requires the license file to be specified. Example:
  127. //
  128. // Given:
  129. // sysroot base = "ndk/sysroot"
  130. // from = "include/foo"
  131. // to = "bar"
  132. // header = "include/foo/woodly/doodly.h"
  133. // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
  134. func ndkHeadersFactory() android.Module {
  135. module := &headerModule{}
  136. module.AddProperties(&module.properties)
  137. android.InitAndroidModule(module)
  138. return module
  139. }
  140. type versionedHeaderProperties struct {
  141. // Base directory of the headers being installed. As an example:
  142. //
  143. // versioned_ndk_headers {
  144. // name: "foo",
  145. // from: "include",
  146. // to: "",
  147. // }
  148. //
  149. // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
  150. // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
  151. From *string
  152. // Install path within the sysroot. This is relative to usr/include.
  153. To *string
  154. // Path to the NOTICE file associated with the headers.
  155. License *string
  156. // True if this API is not yet ready to be shipped in the NDK. It will be
  157. // available in the platform for testing, but will be excluded from the
  158. // sysroot provided to the NDK proper.
  159. Draft bool
  160. }
  161. // Like ndk_headers, but preprocesses the headers with the bionic versioner:
  162. // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
  163. //
  164. // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
  165. // module does not have the srcs property, and operates on a full directory (the `from` property).
  166. //
  167. // Note that this is really only built to handle bionic/libc/include.
  168. type versionedHeaderModule struct {
  169. android.ModuleBase
  170. properties versionedHeaderProperties
  171. installPaths android.Paths
  172. licensePath android.Path
  173. }
  174. func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  175. if String(m.properties.License) == "" {
  176. ctx.PropertyErrorf("license", "field is required")
  177. }
  178. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  179. fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
  180. toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
  181. srcFiles := ctx.GlobFiles(filepath.Join(fromSrcPath.String(), "**/*.h"), nil)
  182. var installPaths []android.WritablePath
  183. for _, header := range srcFiles {
  184. installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
  185. installPath := installDir.Join(ctx, header.Base())
  186. installPaths = append(installPaths, installPath)
  187. m.installPaths = append(m.installPaths, installPath)
  188. }
  189. if len(m.installPaths) == 0 {
  190. ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
  191. }
  192. processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
  193. }
  194. func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
  195. srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
  196. // The versioner depends on a dependencies directory to simplify determining include paths
  197. // when parsing headers. This directory contains architecture specific directories as well
  198. // as a common directory, each of which contains symlinks to the actually directories to
  199. // be included.
  200. //
  201. // ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
  202. // depend on these headers.
  203. // TODO(http://b/35673191): Update the versioner to use a --sysroot.
  204. depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
  205. depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
  206. for i, path := range depsGlob {
  207. if ctx.IsSymlink(path) {
  208. dest := ctx.Readlink(path)
  209. // Additional .. to account for the symlink itself.
  210. depsGlob[i] = android.PathForSource(
  211. ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
  212. }
  213. }
  214. timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
  215. ctx.Build(pctx, android.BuildParams{
  216. Rule: versionBionicHeaders,
  217. Description: "versioner preprocess " + srcDir.Rel(),
  218. Output: timestampFile,
  219. Implicits: append(srcFiles, depsGlob...),
  220. ImplicitOutputs: installPaths,
  221. Args: map[string]string{
  222. "depsPath": depsPath.String(),
  223. "srcDir": srcDir.String(),
  224. "outDir": outDir.String(),
  225. },
  226. })
  227. return timestampFile
  228. }
  229. // versioned_ndk_headers preprocesses the headers with the bionic versioner:
  230. // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
  231. // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
  232. // directory level specified in `from` property. This is only used to process
  233. // the bionic/libc/include directory.
  234. func versionedNdkHeadersFactory() android.Module {
  235. module := &versionedHeaderModule{}
  236. module.AddProperties(&module.properties)
  237. android.InitAndroidModule(module)
  238. return module
  239. }
  240. // preprocessed_ndk_header {
  241. // name: "foo",
  242. // preprocessor: "foo.sh",
  243. // srcs: [...],
  244. // to: "android",
  245. // }
  246. //
  247. // Will invoke the preprocessor as:
  248. // $preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
  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. // True if this API is not yet ready to be shipped in the NDK. It will be
  263. // available in the platform for testing, but will be excluded from the
  264. // sysroot provided to the NDK proper.
  265. Draft bool
  266. }
  267. type preprocessedHeadersModule struct {
  268. android.ModuleBase
  269. properties preprocessedHeadersProperties
  270. installPaths android.Paths
  271. licensePath android.Path
  272. }
  273. func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  274. if String(m.properties.License) == "" {
  275. ctx.PropertyErrorf("license", "field is required")
  276. }
  277. preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
  278. m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
  279. srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
  280. installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
  281. for _, src := range srcFiles {
  282. installPath := installDir.Join(ctx, src.Base())
  283. m.installPaths = append(m.installPaths, installPath)
  284. ctx.Build(pctx, android.BuildParams{
  285. Rule: preprocessNdkHeader,
  286. Description: "preprocess " + src.Rel(),
  287. Input: src,
  288. Output: installPath,
  289. Args: map[string]string{
  290. "preprocessor": preprocessor.String(),
  291. },
  292. })
  293. }
  294. if len(m.installPaths) == 0 {
  295. ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
  296. }
  297. }
  298. // preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
  299. // property by executing the command defined in the preprocessor property.
  300. func preprocessedNdkHeadersFactory() android.Module {
  301. module := &preprocessedHeadersModule{}
  302. module.AddProperties(&module.properties)
  303. android.InitAndroidModule(module)
  304. return module
  305. }