123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- // Copyright 2016 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package cc
- import (
- "fmt"
- "path/filepath"
- "github.com/google/blueprint"
- "android/soong/android"
- )
- var (
- versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
- blueprint.RuleParams{
- // The `&& touch $out` isn't really necessary, but Blueprint won't
- // let us have only implicit outputs.
- Command: "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
- CommandDeps: []string{"$versionerCmd"},
- },
- "depsPath", "srcDir", "outDir")
- preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
- blueprint.RuleParams{
- Command: "$preprocessor -o $out $in",
- CommandDeps: []string{"$preprocessor"},
- },
- "preprocessor")
- )
- func init() {
- pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
- }
- // Returns the NDK base include path for use with sdk_version current. Usable with -I.
- func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath {
- return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
- }
- type headerProperties struct {
- // Base directory of the headers being installed. As an example:
- //
- // ndk_headers {
- // name: "foo",
- // from: "include",
- // to: "",
- // srcs: ["include/foo/bar/baz.h"],
- // }
- //
- // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
- // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
- From *string
- // Install path within the sysroot. This is relative to usr/include.
- To *string
- // List of headers to install. Glob compatible. Common case is "include/**/*.h".
- Srcs []string `android:"path"`
- // Source paths that should be excluded from the srcs glob.
- Exclude_srcs []string `android:"path"`
- // Path to the NOTICE file associated with the headers.
- License *string `android:"path"`
- }
- type headerModule struct {
- android.ModuleBase
- properties headerProperties
- installPaths android.Paths
- licensePath android.Path
- }
- func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
- to string) android.InstallPath {
- // Output path is the sysroot base + "usr/include" + to directory + directory component
- // of the file without the leading from directory stripped.
- //
- // Given:
- // sysroot base = "ndk/sysroot"
- // from = "include/foo"
- // to = "bar"
- // header = "include/foo/woodly/doodly.h"
- // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
- // full/platform/path/to/include/foo
- fullFromPath := android.PathForModuleSrc(ctx, from)
- // full/platform/path/to/include/foo/woodly
- headerDir := filepath.Dir(header.String())
- // woodly
- strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
- if err != nil {
- ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
- fullFromPath.String(), err)
- }
- // full/platform/path/to/sysroot/usr/include/bar/woodly
- installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
- // full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
- return installDir
- }
- func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if String(m.properties.License) == "" {
- ctx.PropertyErrorf("license", "field is required")
- }
- m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
- srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
- for _, header := range srcFiles {
- installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
- String(m.properties.To))
- installedPath := ctx.InstallFile(installDir, header.Base(), header)
- installPath := installDir.Join(ctx, header.Base())
- if installPath != installedPath {
- panic(fmt.Sprintf(
- "expected header install path (%q) not equal to actual install path %q",
- installPath, installedPath))
- }
- m.installPaths = append(m.installPaths, installPath)
- }
- if len(m.installPaths) == 0 {
- ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
- }
- }
- // ndk_headers installs the sets of ndk headers defined in the srcs property
- // to the sysroot base + "usr/include" + to directory + directory component.
- // ndk_headers requires the license file to be specified. Example:
- //
- // Given:
- // sysroot base = "ndk/sysroot"
- // from = "include/foo"
- // to = "bar"
- // header = "include/foo/woodly/doodly.h"
- // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
- func ndkHeadersFactory() android.Module {
- module := &headerModule{}
- module.AddProperties(&module.properties)
- android.InitAndroidModule(module)
- return module
- }
- type versionedHeaderProperties struct {
- // Base directory of the headers being installed. As an example:
- //
- // versioned_ndk_headers {
- // name: "foo",
- // from: "include",
- // to: "",
- // }
- //
- // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
- // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
- From *string
- // Install path within the sysroot. This is relative to usr/include.
- To *string
- // Path to the NOTICE file associated with the headers.
- License *string
- }
- // Like ndk_headers, but preprocesses the headers with the bionic versioner:
- // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
- //
- // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
- // module does not have the srcs property, and operates on a full directory (the `from` property).
- //
- // Note that this is really only built to handle bionic/libc/include.
- type versionedHeaderModule struct {
- android.ModuleBase
- properties versionedHeaderProperties
- installPaths android.Paths
- licensePath android.Path
- }
- // Return the glob pattern to find all .h files beneath `dir`
- func headerGlobPattern(dir string) string {
- return filepath.Join(dir, "**", "*.h")
- }
- func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if String(m.properties.License) == "" {
- ctx.PropertyErrorf("license", "field is required")
- }
- m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
- fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
- toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
- srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
- var installPaths []android.WritablePath
- for _, header := range srcFiles {
- installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
- installPath := installDir.Join(ctx, header.Base())
- installPaths = append(installPaths, installPath)
- m.installPaths = append(m.installPaths, installPath)
- }
- if len(m.installPaths) == 0 {
- ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
- }
- processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
- }
- func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
- srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
- // The versioner depends on a dependencies directory to simplify determining include paths
- // when parsing headers. This directory contains architecture specific directories as well
- // as a common directory, each of which contains symlinks to the actually directories to
- // be included.
- //
- // ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
- // depend on these headers.
- // TODO(http://b/35673191): Update the versioner to use a --sysroot.
- depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
- depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
- for i, path := range depsGlob {
- if ctx.IsSymlink(path) {
- dest := ctx.Readlink(path)
- // Additional .. to account for the symlink itself.
- depsGlob[i] = android.PathForSource(
- ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
- }
- }
- timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
- ctx.Build(pctx, android.BuildParams{
- Rule: versionBionicHeaders,
- Description: "versioner preprocess " + srcDir.Rel(),
- Output: timestampFile,
- Implicits: append(srcFiles, depsGlob...),
- ImplicitOutputs: installPaths,
- Args: map[string]string{
- "depsPath": depsPath.String(),
- "srcDir": srcDir.String(),
- "outDir": outDir.String(),
- },
- })
- return timestampFile
- }
- // versioned_ndk_headers preprocesses the headers with the bionic versioner:
- // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
- // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
- // directory level specified in `from` property. This is only used to process
- // the bionic/libc/include directory.
- func versionedNdkHeadersFactory() android.Module {
- module := &versionedHeaderModule{}
- module.AddProperties(&module.properties)
- android.InitAndroidModule(module)
- return module
- }
- // preprocessed_ndk_header {
- //
- // name: "foo",
- // preprocessor: "foo.sh",
- // srcs: [...],
- // to: "android",
- //
- // }
- //
- // Will invoke the preprocessor as:
- //
- // $preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
- //
- // For each src in srcs.
- type preprocessedHeadersProperties struct {
- // The preprocessor to run. Must be a program inside the source directory
- // with no dependencies.
- Preprocessor *string
- // Source path to the files to be preprocessed.
- Srcs []string
- // Source paths that should be excluded from the srcs glob.
- Exclude_srcs []string
- // Install path within the sysroot. This is relative to usr/include.
- To *string
- // Path to the NOTICE file associated with the headers.
- License *string
- }
- type preprocessedHeadersModule struct {
- android.ModuleBase
- properties preprocessedHeadersProperties
- installPaths android.Paths
- licensePath android.Path
- }
- func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if String(m.properties.License) == "" {
- ctx.PropertyErrorf("license", "field is required")
- }
- preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
- m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
- srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
- installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
- for _, src := range srcFiles {
- installPath := installDir.Join(ctx, src.Base())
- m.installPaths = append(m.installPaths, installPath)
- ctx.Build(pctx, android.BuildParams{
- Rule: preprocessNdkHeader,
- Description: "preprocess " + src.Rel(),
- Input: src,
- Output: installPath,
- Args: map[string]string{
- "preprocessor": preprocessor.String(),
- },
- })
- }
- if len(m.installPaths) == 0 {
- ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
- }
- }
- // preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
- // property by executing the command defined in the preprocessor property.
- func preprocessedNdkHeadersFactory() android.Module {
- module := &preprocessedHeadersModule{}
- module.AddProperties(&module.properties)
- android.InitAndroidModule(module)
- return module
- }
|