github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cc/ndk_headers.go (about)

     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  
    15  package cc
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"path/filepath"
    21  	"strings"
    22  
    23  	"github.com/google/blueprint"
    24  
    25  	"android/soong/android"
    26  )
    27  
    28  var (
    29  	preprocessBionicHeaders = pctx.AndroidStaticRule("preprocessBionicHeaders",
    30  		blueprint.RuleParams{
    31  			// The `&& touch $out` isn't really necessary, but Blueprint won't
    32  			// let us have only implicit outputs.
    33  			Command:     "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
    34  			CommandDeps: []string{"$versionerCmd"},
    35  		},
    36  		"depsPath", "srcDir", "outDir")
    37  )
    38  
    39  func init() {
    40  	pctx.HostBinToolVariable("versionerCmd", "versioner")
    41  }
    42  
    43  // Returns the NDK base include path for use with sdk_version current. Usable with -I.
    44  func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath {
    45  	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
    46  }
    47  
    48  type headerProperies struct {
    49  	// Base directory of the headers being installed. As an example:
    50  	//
    51  	// ndk_headers {
    52  	//     name: "foo",
    53  	//     from: "include",
    54  	//     to: "",
    55  	//     srcs: ["include/foo/bar/baz.h"],
    56  	// }
    57  	//
    58  	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
    59  	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
    60  	From *string
    61  
    62  	// Install path within the sysroot. This is relative to usr/include.
    63  	To *string
    64  
    65  	// List of headers to install. Glob compatible. Common case is "include/**/*.h".
    66  	Srcs []string
    67  
    68  	// Path to the NOTICE file associated with the headers.
    69  	License *string
    70  }
    71  
    72  type headerModule struct {
    73  	android.ModuleBase
    74  
    75  	properties headerProperies
    76  
    77  	installPaths android.Paths
    78  	licensePath  android.ModuleSrcPath
    79  }
    80  
    81  func (m *headerModule) DepsMutator(ctx android.BottomUpMutatorContext) {
    82  }
    83  
    84  func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
    85  	to string) android.OutputPath {
    86  	// Output path is the sysroot base + "usr/include" + to directory + directory component
    87  	// of the file without the leading from directory stripped.
    88  	//
    89  	// Given:
    90  	// sysroot base = "ndk/sysroot"
    91  	// from = "include/foo"
    92  	// to = "bar"
    93  	// header = "include/foo/woodly/doodly.h"
    94  	// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
    95  
    96  	// full/platform/path/to/include/foo
    97  	fullFromPath := android.PathForModuleSrc(ctx, from)
    98  
    99  	// full/platform/path/to/include/foo/woodly
   100  	headerDir := filepath.Dir(header.String())
   101  
   102  	// woodly
   103  	strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
   104  	if err != nil {
   105  		ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
   106  			fullFromPath.String(), err)
   107  	}
   108  
   109  	// full/platform/path/to/sysroot/usr/include/bar/woodly
   110  	installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
   111  
   112  	// full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
   113  	return installDir
   114  }
   115  
   116  func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
   117  	if String(m.properties.License) == "" {
   118  		ctx.PropertyErrorf("license", "field is required")
   119  	}
   120  
   121  	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
   122  
   123  	// When generating NDK prebuilts, skip installing MIPS headers,
   124  	// but keep them when doing regular platform build.
   125  	// Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh
   126  	// TODO: Revert this once MIPS is supported in NDK again.
   127  	if Bool(ctx.AConfig().Ndk_abis) && strings.Contains(ctx.ModuleName(), "mips") {
   128  		return
   129  	}
   130  
   131  	srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
   132  	for _, header := range srcFiles {
   133  		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
   134  			String(m.properties.To))
   135  		installedPath := ctx.InstallFile(installDir, header.Base(), header)
   136  		installPath := installDir.Join(ctx, header.Base())
   137  		if installPath != installedPath {
   138  			panic(fmt.Sprintf(
   139  				"expected header install path (%q) not equal to actual install path %q",
   140  				installPath, installedPath))
   141  		}
   142  		m.installPaths = append(m.installPaths, installPath)
   143  	}
   144  
   145  	if len(m.installPaths) == 0 {
   146  		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
   147  	}
   148  }
   149  
   150  func ndkHeadersFactory() android.Module {
   151  	module := &headerModule{}
   152  	module.AddProperties(&module.properties)
   153  	android.InitAndroidModule(module)
   154  	return module
   155  }
   156  
   157  type preprocessedHeaderProperies struct {
   158  	// Base directory of the headers being installed. As an example:
   159  	//
   160  	// preprocessed_ndk_headers {
   161  	//     name: "foo",
   162  	//     from: "include",
   163  	//     to: "",
   164  	// }
   165  	//
   166  	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
   167  	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
   168  	From *string
   169  
   170  	// Install path within the sysroot. This is relative to usr/include.
   171  	To *string
   172  
   173  	// Path to the NOTICE file associated with the headers.
   174  	License *string
   175  }
   176  
   177  // Like ndk_headers, but preprocesses the headers with the bionic versioner:
   178  // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
   179  //
   180  // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
   181  // module does not have the srcs property, and operates on a full directory (the `from` property).
   182  //
   183  // Note that this is really only built to handle bionic/libc/include.
   184  type preprocessedHeaderModule struct {
   185  	android.ModuleBase
   186  
   187  	properties preprocessedHeaderProperies
   188  
   189  	installPaths android.Paths
   190  	licensePath  android.ModuleSrcPath
   191  }
   192  
   193  func (m *preprocessedHeaderModule) DepsMutator(ctx android.BottomUpMutatorContext) {
   194  }
   195  
   196  func (m *preprocessedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
   197  	if String(m.properties.License) == "" {
   198  		ctx.PropertyErrorf("license", "field is required")
   199  	}
   200  
   201  	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
   202  
   203  	fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
   204  	toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
   205  	srcFiles := ctx.GlobFiles(filepath.Join(fromSrcPath.String(), "**/*.h"), nil)
   206  	var installPaths []android.WritablePath
   207  	for _, header := range srcFiles {
   208  		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
   209  		installPath := installDir.Join(ctx, header.Base())
   210  		installPaths = append(installPaths, installPath)
   211  		m.installPaths = append(m.installPaths, installPath)
   212  	}
   213  
   214  	if len(m.installPaths) == 0 {
   215  		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
   216  	}
   217  
   218  	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
   219  }
   220  
   221  func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path, srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
   222  	// The versioner depends on a dependencies directory to simplify determining include paths
   223  	// when parsing headers. This directory contains architecture specific directories as well
   224  	// as a common directory, each of which contains symlinks to the actually directories to
   225  	// be included.
   226  	//
   227  	// ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
   228  	// depend on these headers.
   229  	// TODO(http://b/35673191): Update the versioner to use a --sysroot.
   230  	depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
   231  	depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
   232  	for i, path := range depsGlob {
   233  		fileInfo, err := os.Lstat(path.String())
   234  		if err != nil {
   235  			ctx.ModuleErrorf("os.Lstat(%q) failed: %s", path.String, err)
   236  		}
   237  		if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
   238  			dest, err := os.Readlink(path.String())
   239  			if err != nil {
   240  				ctx.ModuleErrorf("os.Readlink(%q) failed: %s",
   241  					path.String, err)
   242  			}
   243  			// Additional .. to account for the symlink itself.
   244  			depsGlob[i] = android.PathForSource(
   245  				ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
   246  		}
   247  	}
   248  
   249  	timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
   250  	ctx.Build(pctx, android.BuildParams{
   251  		Rule:            preprocessBionicHeaders,
   252  		Description:     "versioner preprocess " + srcDir.Rel(),
   253  		Output:          timestampFile,
   254  		Implicits:       append(srcFiles, depsGlob...),
   255  		ImplicitOutputs: installPaths,
   256  		Args: map[string]string{
   257  			"depsPath": depsPath.String(),
   258  			"srcDir":   srcDir.String(),
   259  			"outDir":   outDir.String(),
   260  		},
   261  	})
   262  
   263  	return timestampFile
   264  }
   265  
   266  func preprocessedNdkHeadersFactory() android.Module {
   267  	module := &preprocessedHeaderModule{}
   268  
   269  	module.AddProperties(&module.properties)
   270  
   271  	// Host module rather than device module because device module install steps
   272  	// do not get run when embedded in make. We're not any of the existing
   273  	// module types that can be exposed via the Android.mk exporter, so just use
   274  	// a host module.
   275  	android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst)
   276  
   277  	return module
   278  }