From 34cc69e4bf36cb65bb181b42ccb0f8c792a32cfb Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Wed, 23 Sep 2015 15:26:20 -0700 Subject: Use `Path` instead of string for file paths This centralizes verification and common operations, like converting the path to a source file to the path for a built object. It also embeds the configuration knowledge into the path, so that we can remove "${SrcDir}/path" from the ninja file. When SrcDir is '.', that leads to paths like './path' instead of just 'path' like make is doing, causing differences in compiled binaries. Change-Id: Ib4e8910a6e867ce1b7b420d927c04f1142a7589e --- Android.bp | 4 + cc/androidmk.go | 11 +- cc/arm64_device.go | 2 +- cc/arm_device.go | 2 +- cc/builder.go | 130 +++++------ cc/cc.go | 274 +++++++++++----------- cc/gen.go | 53 ++--- cc/mips64_device.go | 2 +- cc/mips_device.go | 2 +- cc/util.go | 8 +- cc/x86_64_device.go | 2 +- cc/x86_darwin_host.go | 4 +- cc/x86_device.go | 2 +- cc/x86_linux_host.go | 4 +- cc/x86_windows_host.go | 4 +- common/androidmk.go | 48 ++-- common/config.go | 73 ++---- common/defs.go | 4 +- common/env.go | 11 +- common/module.go | 135 ++++++----- common/package_ctx.go | 127 +++++++++++ common/paths.go | 600 +++++++++++++++++++++++++++++++++++++++++++------ common/paths_test.go | 167 ++++++++++++++ genrule/genrule.go | 43 ++-- java/app.go | 101 +++------ java/app_builder.go | 65 +++--- java/builder.go | 108 +++++---- java/gen.go | 58 ++--- java/java.go | 106 ++++----- java/resources.go | 15 +- 30 files changed, 1416 insertions(+), 749 deletions(-) create mode 100644 common/package_ctx.go create mode 100644 common/paths_test.go diff --git a/Android.bp b/Android.bp index 52bdc7cc..b6f6a639 100644 --- a/Android.bp +++ b/Android.bp @@ -98,10 +98,14 @@ bootstrap_go_package { "common/glob.go", "common/module.go", "common/mutator.go", + "common/package_ctx.go", "common/paths.go", "common/util.go", "common/variable.go", ], + testSrcs: [ + "common/paths_test.go", + ], } bootstrap_go_package { diff --git a/cc/androidmk.go b/cc/androidmk.go index 7554ef47..11d7614b 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -16,7 +16,6 @@ package cc import ( "io" - "path/filepath" "strings" "android/soong/common" @@ -29,7 +28,7 @@ func (c *CCLibrary) AndroidMk() (ret common.AndroidMkData) { ret.Class = "SHARED_LIBRARIES" } ret.OutputFile = c.outputFile() - ret.Extra = func(name, prefix, outputFile string, arch common.Arch) (ret []string) { + ret.Extra = func(name, prefix string, outputFile common.Path, arch common.Arch) (ret []string) { exportedIncludes := c.exportedFlags() for i := range exportedIncludes { exportedIncludes[i] = strings.TrimPrefix(exportedIncludes[i], "-I") @@ -38,7 +37,7 @@ func (c *CCLibrary) AndroidMk() (ret common.AndroidMkData) { ret = append(ret, "LOCAL_EXPORT_C_INCLUDE_DIRS := "+strings.Join(exportedIncludes, " ")) } - ret = append(ret, "LOCAL_MODULE_SUFFIX := "+filepath.Ext(outputFile)) + ret = append(ret, "LOCAL_MODULE_SUFFIX := "+outputFile.Ext()) ret = append(ret, "LOCAL_SHARED_LIBRARIES_"+arch.ArchType.String()+" := "+strings.Join(c.savedDepNames.SharedLibs, " ")) if c.Properties.Relative_install_path != "" { @@ -57,9 +56,9 @@ func (c *CCLibrary) AndroidMk() (ret common.AndroidMkData) { func (c *ccObject) AndroidMk() (ret common.AndroidMkData) { ret.OutputFile = c.outputFile() ret.Custom = func(w io.Writer, name, prefix string) { - out := c.outputFile() + out := c.outputFile().Path() - io.WriteString(w, "$("+prefix+"TARGET_OUT_INTERMEDIATE_LIBRARIES)/"+name+objectExtension+": "+out+" | $(ACP)\n") + io.WriteString(w, "$("+prefix+"TARGET_OUT_INTERMEDIATE_LIBRARIES)/"+name+objectExtension+": "+out.String()+" | $(ACP)\n") io.WriteString(w, "\t$(copy-file-to-target)\n") } return @@ -67,7 +66,7 @@ func (c *ccObject) AndroidMk() (ret common.AndroidMkData) { func (c *CCBinary) AndroidMk() (ret common.AndroidMkData) { ret.Class = "EXECUTABLES" - ret.Extra = func(name, prefix, outputFile string, arch common.Arch) []string { + ret.Extra = func(name, prefix string, outputFile common.Path, arch common.Arch) []string { ret := []string{ "LOCAL_CXX_STL := none", "LOCAL_SYSTEM_SHARED_LIBRARIES :=", diff --git a/cc/arm64_device.go b/cc/arm64_device.go index 055f948e..8d773ed8 100644 --- a/cc/arm64_device.go +++ b/cc/arm64_device.go @@ -78,7 +78,7 @@ const ( func init() { pctx.StaticVariable("arm64GccVersion", arm64GccVersion) - pctx.StaticVariable("arm64GccRoot", + pctx.SourcePathVariable("arm64GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/aarch64/aarch64-linux-android-${arm64GccVersion}") pctx.StaticVariable("arm64GccTriple", "aarch64-linux-android") diff --git a/cc/arm_device.go b/cc/arm_device.go index ccfefba8..5c91a828 100644 --- a/cc/arm_device.go +++ b/cc/arm_device.go @@ -154,7 +154,7 @@ func init() { pctx.StaticVariable("armGccVersion", armGccVersion) - pctx.StaticVariable("armGccRoot", + pctx.SourcePathVariable("armGccRoot", "prebuilts/gcc/${HostPrebuiltTag}/arm/arm-linux-androideabi-${armGccVersion}") pctx.StaticVariable("armGccTriple", "arm-linux-androideabi") diff --git a/cc/builder.go b/cc/builder.go index 64437d28..f5fc9eeb 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -28,7 +28,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" ) const ( @@ -37,7 +36,7 @@ const ( ) var ( - pctx = blueprint.NewPackageContext("android/soong/cc") + pctx = common.NewPackageContext("android/soong/cc") cc = pctx.StaticRule("cc", blueprint.RuleParams{ @@ -102,7 +101,7 @@ var ( }, "objcopyCmd", "prefix") - copyGccLibPath = pctx.StaticVariable("copyGccLibPath", "${SrcDir}/build/soong/copygcclib.sh") + copyGccLibPath = pctx.SourcePathVariable("copyGccLibPath", "build/soong/copygcclib.sh") copyGccLib = pctx.StaticRule("copyGccLib", blueprint.RuleParams{ @@ -141,45 +140,24 @@ type builderFlags struct { } // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files -func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles []string, - flags builderFlags, deps []string) (objFiles []string) { +func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFiles common.Paths, + flags builderFlags, deps common.Paths) (objFiles common.Paths) { - srcRoot := ctx.AConfig().SrcDir() - intermediatesRoot := ctx.AConfig().IntermediatesDir() - - objFiles = make([]string, len(srcFiles)) - objDir := common.ModuleObjDir(ctx) - if subdir != "" { - objDir = filepath.Join(objDir, subdir) - } + objFiles = make(common.Paths, len(srcFiles)) cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags asflags := flags.globalFlags + " " + flags.asFlags for i, srcFile := range srcFiles { - var objFile string - if strings.HasPrefix(srcFile, intermediatesRoot) { - objFile = strings.TrimPrefix(srcFile, intermediatesRoot) - objFile = filepath.Join(objDir, "gen", objFile) - } else if strings.HasPrefix(srcFile, srcRoot) { - srcFile, _ = filepath.Rel(srcRoot, srcFile) - objFile = filepath.Join(objDir, srcFile) - } else if srcRoot == "." && srcFile[0] != '/' { - objFile = filepath.Join(objDir, srcFile) - } else { - ctx.ModuleErrorf("source file %q is not in source directory %q", srcFile, srcRoot) - continue - } - - objFile = pathtools.ReplaceExtension(objFile, "o") + objFile := common.ObjPathWithExt(ctx, srcFile, subdir, "o") objFiles[i] = objFile var moduleCflags string var ccCmd string - switch filepath.Ext(srcFile) { + switch srcFile.Ext() { case ".S", ".s": ccCmd = "gcc" moduleCflags = asflags @@ -204,15 +182,15 @@ func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFil panic("unrecoginzied ccCmd") } - ccCmd = "${clangPath}" + ccCmd + ccCmd = "${clangPath}/" + ccCmd } else { ccCmd = gccCmd(flags.toolchain, ccCmd) } - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: cc, - Outputs: []string{objFile}, - Inputs: []string{srcFile}, + Output: objFile, + Input: srcFile, Implicits: deps, Args: map[string]string{ "cFlags": moduleCflags, @@ -225,16 +203,16 @@ func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFil } // Generate a rule for compiling multiple .o files to a static library (.a) -func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string, - flags builderFlags, outputFile string) { +func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths, + flags builderFlags, outputFile common.ModuleOutPath) { arCmd := gccCmd(flags.toolchain, "ar") arFlags := "crsPD" - ctx.Build(pctx, blueprint.BuildParams{ - Rule: ar, - Outputs: []string{outputFile}, - Inputs: objFiles, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: ar, + Output: outputFile, + Inputs: objFiles, Args: map[string]string{ "arFlags": arFlags, "arCmd": arCmd, @@ -246,18 +224,20 @@ func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string, // darwin. The darwin ar tool doesn't support @file for list files, and has a // very small command line length limit, so we have to split the ar into multiple // steps, each appending to the previous one. -func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string, - flags builderFlags, outputFile string) { +func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles common.Paths, + flags builderFlags, outputPath common.ModuleOutPath) { arCmd := "ar" arFlags := "cqs" // ARG_MAX on darwin is 262144, use half that to be safe - objFilesLists, err := splitListForSize(objFiles, 131072) + objFilesLists, err := splitListForSize(objFiles.Strings(), 131072) if err != nil { ctx.ModuleErrorf("%s", err.Error()) } + outputFile := outputPath.String() + var in, out string for i, l := range objFilesLists { in = out @@ -295,12 +275,12 @@ func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []s // Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries, // and shared libraires, to a shared library (.so) or dynamic executable func TransformObjToDynamicBinary(ctx common.AndroidModuleContext, - objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps []string, - crtBegin, crtEnd string, groupLate bool, flags builderFlags, outputFile string) { + objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps common.Paths, + crtBegin, crtEnd common.OptionalPath, groupLate bool, flags builderFlags, outputFile common.WritablePath) { var ldCmd string if flags.clang { - ldCmd = "${clangPath}clang++" + ldCmd = "${clangPath}/clang++" } else { ldCmd = gccCmd(flags.toolchain, "g++") } @@ -310,31 +290,31 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext, if len(wholeStaticLibs) > 0 { if ctx.Host() && ctx.Darwin() { - libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load ")) + libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load ")) } else { libFlagsList = append(libFlagsList, "-Wl,--whole-archive ") - libFlagsList = append(libFlagsList, wholeStaticLibs...) + libFlagsList = append(libFlagsList, wholeStaticLibs.Strings()...) libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ") } } - libFlagsList = append(libFlagsList, staticLibs...) + libFlagsList = append(libFlagsList, staticLibs.Strings()...) if groupLate && len(lateStaticLibs) > 0 { libFlagsList = append(libFlagsList, "-Wl,--start-group") } - libFlagsList = append(libFlagsList, lateStaticLibs...) + libFlagsList = append(libFlagsList, lateStaticLibs.Strings()...) if groupLate && len(lateStaticLibs) > 0 { libFlagsList = append(libFlagsList, "-Wl,--end-group") } for _, lib := range sharedLibs { - dir, file := filepath.Split(lib) + dir, file := filepath.Split(lib.String()) if !strings.HasPrefix(file, "lib") { - panic("shared library " + lib + " does not start with lib") + panic("shared library " + lib.String() + " does not start with lib") } if !strings.HasSuffix(file, flags.toolchain.ShlibSuffix()) { - panic("shared library " + lib + " does not end with " + flags.toolchain.ShlibSuffix()) + panic("shared library " + lib.String() + " does not end with " + flags.toolchain.ShlibSuffix()) } libFlagsList = append(libFlagsList, "-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), flags.toolchain.ShlibSuffix())) @@ -345,29 +325,29 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext, deps = append(deps, staticLibs...) deps = append(deps, lateStaticLibs...) deps = append(deps, wholeStaticLibs...) - if crtBegin != "" { - deps = append(deps, crtBegin, crtEnd) + if crtBegin.Valid() { + deps = append(deps, crtBegin.Path(), crtEnd.Path()) } - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: ld, - Outputs: []string{outputFile}, + Output: outputFile, Inputs: objFiles, Implicits: deps, Args: map[string]string{ "ldCmd": ldCmd, "ldDirFlags": ldDirsToFlags(ldDirs), - "crtBegin": crtBegin, + "crtBegin": crtBegin.String(), "libFlags": strings.Join(libFlagsList, " "), "ldFlags": flags.ldFlags, - "crtEnd": crtEnd, + "crtEnd": crtEnd.String(), }, }) } // Generate a rule for compiling multiple .o files to a .o using ld partial linking -func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string, - flags builderFlags, outputFile string) { +func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles common.Paths, + flags builderFlags, outputFile common.WritablePath) { var ldCmd string if flags.clang { @@ -376,27 +356,27 @@ func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles []string, ldCmd = gccCmd(flags.toolchain, "g++") } - ctx.Build(pctx, blueprint.BuildParams{ - Rule: partialLd, - Outputs: []string{outputFile}, - Inputs: objFiles, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: partialLd, + Output: outputFile, + Inputs: objFiles, Args: map[string]string{ - "ldCmd": ldCmd, + "ldCmd": ldCmd, "ldFlags": flags.ldFlags, }, }) } // Generate a rule for runing objcopy --prefix-symbols on a binary -func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile string, - flags builderFlags, outputFile string) { +func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string, inputFile common.Path, + flags builderFlags, outputFile common.WritablePath) { objcopyCmd := gccCmd(flags.toolchain, "objcopy") - ctx.Build(pctx, blueprint.BuildParams{ - Rule: prefixSymbols, - Outputs: []string{outputFile}, - Inputs: []string{inputFile}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: prefixSymbols, + Output: outputFile, + Input: inputFile, Args: map[string]string{ "objcopyCmd": objcopyCmd, "prefix": prefix, @@ -405,11 +385,11 @@ func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string } func CopyGccLib(ctx common.AndroidModuleContext, libName string, - flags builderFlags, outputFile string) { + flags builderFlags, outputFile common.WritablePath) { - ctx.Build(pctx, blueprint.BuildParams{ - Rule: copyGccLib, - Outputs: []string{outputFile}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: copyGccLib, + Output: outputFile, Args: map[string]string{ "ccCmd": gccCmd(flags.toolchain, "gcc"), "cFlags": flags.globalFlags, diff --git a/cc/cc.go b/cc/cc.go index 489bffe0..b497d66e 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -24,7 +24,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" "android/soong" @@ -64,10 +63,9 @@ func init() { var ( HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", common.Config.PrebuiltOS) - SrcDir = pctx.VariableConfigMethod("SrcDir", common.Config.SrcDir) - LibcRoot = pctx.StaticVariable("LibcRoot", "bionic/libc") - LibmRoot = pctx.StaticVariable("LibmRoot", "bionic/libm") + LibcRoot = pctx.SourcePathVariable("LibcRoot", "bionic/libc") + LibmRoot = pctx.SourcePathVariable("LibmRoot", "bionic/libm") ) // Flags used by lots of devices. Putting them in package static variables will save bytes in @@ -127,19 +125,20 @@ func init() { // Everything in this list is a crime against abstraction and dependency tracking. // Do not add anything to this list. - pctx.StaticVariable("commonGlobalIncludes", strings.Join([]string{ - "-isystem ${SrcDir}/system/core/include", - "-isystem ${SrcDir}/hardware/libhardware/include", - "-isystem ${SrcDir}/hardware/libhardware_legacy/include", - "-isystem ${SrcDir}/hardware/ril/include", - "-isystem ${SrcDir}/libnativehelper/include", - "-isystem ${SrcDir}/frameworks/native/include", - "-isystem ${SrcDir}/frameworks/native/opengl/include", - "-isystem ${SrcDir}/frameworks/av/include", - "-isystem ${SrcDir}/frameworks/base/include", - }, " ")) + pctx.PrefixedPathsForSourceVariable("commonGlobalIncludes", "-isystem ", + []string{ + "system/core/include", + "hardware/libhardware/include", + "hardware/libhardware_legacy/include", + "hardware/ril/include", + "libnativehelper/include", + "frameworks/native/include", + "frameworks/native/opengl/include", + "frameworks/av/include", + "frameworks/base/include", + }) - pctx.StaticVariable("clangPath", "${SrcDir}/prebuilts/clang/host/${HostPrebuiltTag}/3.8/bin/") + pctx.SourcePathVariable("clangPath", "prebuilts/clang/host/${HostPrebuiltTag}/3.8/bin") } type CCModuleContext common.AndroidBaseContext @@ -162,23 +161,36 @@ type CCModuleType interface { depsMutator(common.AndroidBottomUpMutatorContext) // Compile objects into final module - compileModule(common.AndroidModuleContext, CCFlags, CCDeps, []string) + compileModule(common.AndroidModuleContext, CCFlags, CCPathDeps, common.Paths) // Install the built module. installModule(common.AndroidModuleContext, CCFlags) // Return the output file (.o, .a or .so) for use by other modules - outputFile() string + outputFile() common.OptionalPath } type CCDeps struct { - StaticLibs, SharedLibs, LateStaticLibs, WholeStaticLibs, ObjFiles, Cflags, ReexportedCflags []string + StaticLibs, SharedLibs, LateStaticLibs, WholeStaticLibs []string + + ObjFiles common.Paths - WholeStaticLibObjFiles []string + Cflags, ReexportedCflags []string CrtBegin, CrtEnd string } +type CCPathDeps struct { + StaticLibs, SharedLibs, LateStaticLibs, WholeStaticLibs common.Paths + + ObjFiles common.Paths + WholeStaticLibObjFiles common.Paths + + Cflags, ReexportedCflags []string + + CrtBegin, CrtEnd common.OptionalPath +} + type CCFlags struct { GlobalFlags []string // Flags that apply to C, C++, and assembly source files AsFlags []string // Flags that apply to assembly source files @@ -440,7 +452,7 @@ func (c *CCBase) depsMutator(ctx common.AndroidBottomUpMutatorContext) { ctx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, c.savedDepNames.SharedLibs...) - ctx.AddDependency(ctx.Module(), c.savedDepNames.ObjFiles...) + ctx.AddDependency(ctx.Module(), c.savedDepNames.ObjFiles.Strings()...) if c.savedDepNames.CrtBegin != "" { ctx.AddDependency(ctx.Module(), c.savedDepNames.CrtBegin) } @@ -472,17 +484,14 @@ func (c *CCBase) collectFlags(ctx common.AndroidModuleContext, toolchain Toolcha } // Include dir cflags - common.CheckSrcDirsExist(ctx, c.Properties.Include_dirs, "include_dirs") - common.CheckModuleSrcDirsExist(ctx, c.Properties.Local_include_dirs, "local_include_dirs") - - rootIncludeDirs := pathtools.PrefixPaths(c.Properties.Include_dirs, ctx.AConfig().SrcDir()) - localIncludeDirs := pathtools.PrefixPaths(c.Properties.Local_include_dirs, common.ModuleSrcDir(ctx)) + rootIncludeDirs := common.PathsForSource(ctx, c.Properties.Include_dirs) + localIncludeDirs := common.PathsForModuleSrc(ctx, c.Properties.Local_include_dirs) flags.GlobalFlags = append(flags.GlobalFlags, includeDirsToFlags(localIncludeDirs), includeDirsToFlags(rootIncludeDirs)) - rootIncludeFiles := pathtools.PrefixPaths(c.Properties.Include_files, ctx.AConfig().SrcDir()) - localIncludeFiles := pathtools.PrefixPaths(c.Properties.Local_include_files, common.ModuleSrcDir(ctx)) + rootIncludeFiles := common.PathsForSource(ctx, c.Properties.Include_files) + localIncludeFiles := common.PathsForModuleSrc(ctx, c.Properties.Local_include_files) flags.GlobalFlags = append(flags.GlobalFlags, includeFilesToFlags(rootIncludeFiles), @@ -493,13 +502,13 @@ func (c *CCBase) collectFlags(ctx common.AndroidModuleContext, toolchain Toolcha flags.GlobalFlags = append(flags.GlobalFlags, "${commonGlobalIncludes}", toolchain.IncludeFlags(), - "-I${SrcDir}/libnativehelper/include/nativehelper") + "-I"+common.PathForSource(ctx, "libnativehelper/include/nativehelper").String()) } flags.GlobalFlags = append(flags.GlobalFlags, []string{ - "-I" + common.ModuleSrcDir(ctx), - "-I" + common.ModuleOutDir(ctx), - "-I" + common.ModuleGenDir(ctx), + "-I" + common.PathForModuleSrc(ctx).String(), + "-I" + common.PathForModuleOut(ctx).String(), + "-I" + common.PathForModuleGen(ctx).String(), }...) } @@ -636,18 +645,18 @@ func (c *CCBase) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags { // Compile a list of source files into objects a specified subdirectory func (c *CCBase) customCompileObjs(ctx common.AndroidModuleContext, flags CCFlags, - subdir string, srcFiles, excludes []string) []string { + subdir string, srcFiles, excludes []string) common.Paths { buildFlags := ccFlagsToBuilderFlags(flags) - srcFiles = ctx.ExpandSources(srcFiles, excludes) - srcFiles, deps := genSources(ctx, srcFiles, buildFlags) + inputFiles := ctx.ExpandSources(srcFiles, excludes) + srcPaths, deps := genSources(ctx, inputFiles, buildFlags) - return TransformSourceToObj(ctx, subdir, srcFiles, buildFlags, deps) + return TransformSourceToObj(ctx, subdir, srcPaths, buildFlags, deps) } // Compile files listed in c.Properties.Srcs into objects -func (c *CCBase) compileObjs(ctx common.AndroidModuleContext, flags CCFlags) []string { +func (c *CCBase) compileObjs(ctx common.AndroidModuleContext, flags CCFlags) common.Paths { if c.Properties.SkipCompileObjs { return nil @@ -657,8 +666,8 @@ func (c *CCBase) compileObjs(ctx common.AndroidModuleContext, flags CCFlags) []s } // Compile generated source files from dependencies -func (c *CCBase) compileGeneratedObjs(ctx common.AndroidModuleContext, flags CCFlags) []string { - var srcs []string +func (c *CCBase) compileGeneratedObjs(ctx common.AndroidModuleContext, flags CCFlags) common.Paths { + var srcs common.Paths if c.Properties.SkipCompileObjs { return nil @@ -677,13 +686,13 @@ func (c *CCBase) compileGeneratedObjs(ctx common.AndroidModuleContext, flags CCF return TransformSourceToObj(ctx, "", srcs, ccFlagsToBuilderFlags(flags), nil) } -func (c *CCBase) outputFile() string { - return "" +func (c *CCBase) outputFile() common.OptionalPath { + return common.OptionalPath{} } func (c *CCBase) depsToPathsFromList(ctx common.AndroidModuleContext, names []string) (modules []common.AndroidModule, - outputFiles []string, exportedFlags []string) { + outputFiles common.Paths, exportedFlags []string) { for _, n := range names { found := false @@ -707,12 +716,12 @@ func (c *CCBase) depsToPathsFromList(ctx common.AndroidModuleContext, return } - if outputFile := a.outputFile(); outputFile != "" { + if outputFile := a.outputFile(); outputFile.Valid() { if found { ctx.ModuleErrorf("multiple modules satisified dependency on %q", otherName) return } - outputFiles = append(outputFiles, outputFile) + outputFiles = append(outputFiles, outputFile.Path()) modules = append(modules, a) if i, ok := a.(ccExportedFlagsProducer); ok { exportedFlags = append(exportedFlags, i.exportedFlags()...) @@ -735,10 +744,10 @@ func (c *CCBase) depsToPathsFromList(ctx common.AndroidModuleContext, return modules, outputFiles, exportedFlags } -// Convert depenedency names to paths. Takes a CCDeps containing names and returns a CCDeps +// Convert dependency names to paths. Takes a CCDeps containing names and returns a CCPathDeps // containing paths -func (c *CCBase) depsToPaths(ctx common.AndroidModuleContext, depNames CCDeps) CCDeps { - var depPaths CCDeps +func (c *CCBase) depsToPaths(ctx common.AndroidModuleContext, depNames CCDeps) CCPathDeps { + var depPaths CCPathDeps var newCflags []string var wholeStaticLibModules []common.AndroidModule @@ -778,7 +787,12 @@ func (c *CCBase) depsToPaths(ctx common.AndroidModuleContext, depNames CCDeps) C depPaths.CrtEnd = obj.object().outputFile() } } else { - depPaths.ObjFiles = append(depPaths.ObjFiles, obj.object().outputFile()) + output := obj.object().outputFile() + if output.Valid() { + depPaths.ObjFiles = append(depPaths.ObjFiles, output.Path()) + } else { + ctx.ModuleErrorf("module %s did not provide an output file", otherName) + } } } }) @@ -908,11 +922,11 @@ func (c *CCLinked) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags // tree is in good enough shape to not need it. // Host builds will use GNU libstdc++. if ctx.Device() { - flags.CFlags = append(flags.CFlags, "-I${SrcDir}/bionic/libstdc++/include") + flags.CFlags = append(flags.CFlags, "-I"+common.PathForSource(ctx, "bionic/libstdc++/include").String()) } case "ndk_system": - ndkSrcRoot := ctx.AConfig().SrcDir() + "/prebuilts/ndk/current/sources/" - flags.CFlags = append(flags.CFlags, "-isystem "+ndkSrcRoot+"cxx-stl/system/include") + ndkSrcRoot := common.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include") + flags.CFlags = append(flags.CFlags, "-isystem "+ndkSrcRoot.String()) case "ndk_libc++_shared", "ndk_libc++_static": // TODO(danalbert): This really shouldn't be here... flags.CppFlags = append(flags.CppFlags, "-std=c++11") @@ -1067,23 +1081,23 @@ type CCLibraryProperties struct { } `android:"arch_variant"` // local file name to pass to the linker as --version_script - Version_script string `android:"arch_variant"` + Version_script *string `android:"arch_variant"` // local file name to pass to the linker as -unexported_symbols_list - Unexported_symbols_list string `android:"arch_variant"` + Unexported_symbols_list *string `android:"arch_variant"` // local file name to pass to the linker as -force_symbols_not_weak_list - Force_symbols_not_weak_list string `android:"arch_variant"` + Force_symbols_not_weak_list *string `android:"arch_variant"` // local file name to pass to the linker as -force_symbols_weak_list - Force_symbols_weak_list string `android:"arch_variant"` + Force_symbols_weak_list *string `android:"arch_variant"` } type CCLibrary struct { CCLinked reuseFrom ccLibraryInterface - reuseObjFiles []string - objFiles []string + reuseObjFiles common.Paths + objFiles common.Paths exportFlags []string - out string + out common.Path systemLibs []string LibraryProperties CCLibraryProperties @@ -1102,8 +1116,8 @@ type ccLibraryInterface interface { ccLibrary() *CCLibrary setReuseFrom(ccLibraryInterface) getReuseFrom() ccLibraryInterface - getReuseObjFiles() []string - allObjFiles() []string + getReuseObjFiles() common.Paths + allObjFiles() common.Paths } var _ ccLibraryInterface = (*CCLibrary)(nil) @@ -1154,11 +1168,11 @@ func (c *CCLibrary) depNames(ctx common.AndroidBaseContext, depNames CCDeps) CCD return depNames } -func (c *CCLibrary) outputFile() string { - return c.out +func (c *CCLibrary) outputFile() common.OptionalPath { + return common.OptionalPathForPath(c.out) } -func (c *CCLibrary) getReuseObjFiles() []string { +func (c *CCLibrary) getReuseObjFiles() common.Paths { return c.reuseObjFiles } @@ -1170,7 +1184,7 @@ func (c *CCLibrary) getReuseFrom() ccLibraryInterface { return c.reuseFrom } -func (c *CCLibrary) allObjFiles() []string { +func (c *CCLibrary) allObjFiles() common.Paths { return c.objFiles } @@ -1225,7 +1239,7 @@ func (c *CCLibrary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlag } func (c *CCLibrary) compileStaticLibrary(ctx common.AndroidModuleContext, - flags CCFlags, deps CCDeps, objFiles []string) { + flags CCFlags, deps CCPathDeps, objFiles common.Paths) { staticFlags := flags objFilesStatic := c.customCompileObjs(ctx, staticFlags, common.DeviceStaticLibrary, @@ -1234,7 +1248,7 @@ func (c *CCLibrary) compileStaticLibrary(ctx common.AndroidModuleContext, objFiles = append(objFiles, objFilesStatic...) objFiles = append(objFiles, deps.WholeStaticLibObjFiles...) - outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+staticLibraryExtension) + outputFile := common.PathForModuleOut(ctx, ctx.ModuleName()+staticLibraryExtension) if ctx.Darwin() { TransformDarwinObjToStaticLib(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile) @@ -1245,8 +1259,7 @@ func (c *CCLibrary) compileStaticLibrary(ctx common.AndroidModuleContext, c.objFiles = objFiles c.out = outputFile - common.CheckModuleSrcDirsExist(ctx, c.Properties.Export_include_dirs, "export_include_dirs") - includeDirs := pathtools.PrefixPaths(c.Properties.Export_include_dirs, common.ModuleSrcDir(ctx)) + includeDirs := common.PathsForModuleSrc(ctx, c.Properties.Export_include_dirs) c.exportFlags = []string{includeDirsToFlags(includeDirs)} c.exportFlags = append(c.exportFlags, deps.ReexportedCflags...) @@ -1254,7 +1267,7 @@ func (c *CCLibrary) compileStaticLibrary(ctx common.AndroidModuleContext, } func (c *CCLibrary) compileSharedLibrary(ctx common.AndroidModuleContext, - flags CCFlags, deps CCDeps, objFiles []string) { + flags CCFlags, deps CCPathDeps, objFiles common.Paths) { sharedFlags := flags objFilesShared := c.customCompileObjs(ctx, sharedFlags, common.DeviceSharedLibrary, @@ -1262,43 +1275,43 @@ func (c *CCLibrary) compileSharedLibrary(ctx common.AndroidModuleContext, objFiles = append(objFiles, objFilesShared...) - outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+flags.Toolchain.ShlibSuffix()) + outputFile := common.PathForModuleOut(ctx, ctx.ModuleName()+flags.Toolchain.ShlibSuffix()) - var linkerDeps []string + var linkerDeps common.Paths + versionScript := common.OptionalPathForModuleSrc(ctx, c.LibraryProperties.Version_script) + unexportedSymbols := common.OptionalPathForModuleSrc(ctx, c.LibraryProperties.Unexported_symbols_list) + forceNotWeakSymbols := common.OptionalPathForModuleSrc(ctx, c.LibraryProperties.Force_symbols_not_weak_list) + forceWeakSymbols := common.OptionalPathForModuleSrc(ctx, c.LibraryProperties.Force_symbols_weak_list) if !ctx.Darwin() { - if c.LibraryProperties.Version_script != "" { - versionScript := filepath.Join(common.ModuleSrcDir(ctx), c.LibraryProperties.Version_script) - sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,--version-script,"+versionScript) - linkerDeps = append(linkerDeps, versionScript) + if versionScript.Valid() { + sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,--version-script,"+versionScript.String()) + linkerDeps = append(linkerDeps, versionScript.Path()) } - if c.LibraryProperties.Unexported_symbols_list != "" { + if unexportedSymbols.Valid() { ctx.PropertyErrorf("unexported_symbols_list", "Only supported on Darwin") } - if c.LibraryProperties.Force_symbols_not_weak_list != "" { + if forceNotWeakSymbols.Valid() { ctx.PropertyErrorf("force_symbols_not_weak_list", "Only supported on Darwin") } - if c.LibraryProperties.Force_symbols_weak_list != "" { + if forceWeakSymbols.Valid() { ctx.PropertyErrorf("force_symbols_weak_list", "Only supported on Darwin") } } else { - if c.LibraryProperties.Version_script != "" { + if versionScript.Valid() { ctx.PropertyErrorf("version_script", "Not supported on Darwin") } - if c.LibraryProperties.Unexported_symbols_list != "" { - localFile := filepath.Join(common.ModuleSrcDir(ctx), c.LibraryProperties.Unexported_symbols_list) - sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,-unexported_symbols_list,"+localFile) - linkerDeps = append(linkerDeps, localFile) + if unexportedSymbols.Valid() { + sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,-unexported_symbols_list,"+unexportedSymbols.String()) + linkerDeps = append(linkerDeps, unexportedSymbols.Path()) } - if c.LibraryProperties.Force_symbols_not_weak_list != "" { - localFile := filepath.Join(common.ModuleSrcDir(ctx), c.LibraryProperties.Force_symbols_not_weak_list) - sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,-force_symbols_not_weak_list,"+localFile) - linkerDeps = append(linkerDeps, localFile) + if forceNotWeakSymbols.Valid() { + sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,-force_symbols_not_weak_list,"+forceNotWeakSymbols.String()) + linkerDeps = append(linkerDeps, forceNotWeakSymbols.Path()) } - if c.LibraryProperties.Force_symbols_weak_list != "" { - localFile := filepath.Join(common.ModuleSrcDir(ctx), c.LibraryProperties.Force_symbols_weak_list) - sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,-force_symbols_weak_list,"+localFile) - linkerDeps = append(linkerDeps, localFile) + if forceWeakSymbols.Valid() { + sharedFlags.LdFlags = append(sharedFlags.LdFlags, "-Wl,-force_symbols_weak_list,"+forceWeakSymbols.String()) + linkerDeps = append(linkerDeps, forceWeakSymbols.Path()) } } @@ -1307,13 +1320,13 @@ func (c *CCLibrary) compileSharedLibrary(ctx common.AndroidModuleContext, ccFlagsToBuilderFlags(sharedFlags), outputFile) c.out = outputFile - includeDirs := pathtools.PrefixPaths(c.Properties.Export_include_dirs, common.ModuleSrcDir(ctx)) + includeDirs := common.PathsForModuleSrc(ctx, c.Properties.Export_include_dirs) c.exportFlags = []string{includeDirsToFlags(includeDirs)} c.exportFlags = append(c.exportFlags, deps.ReexportedCflags...) } func (c *CCLibrary) compileModule(ctx common.AndroidModuleContext, - flags CCFlags, deps CCDeps, objFiles []string) { + flags CCFlags, deps CCPathDeps, objFiles common.Paths) { // Reuse the object files from the matching static library if it exists if c.getReuseFrom().ccLibrary() == c { @@ -1321,7 +1334,7 @@ func (c *CCLibrary) compileModule(ctx common.AndroidModuleContext, } else { if c.getReuseFrom().ccLibrary().LibraryProperties.Static.Cflags == nil && c.LibraryProperties.Shared.Cflags == nil { - objFiles = append([]string(nil), c.getReuseFrom().getReuseObjFiles()...) + objFiles = append(common.Paths(nil), c.getReuseFrom().getReuseObjFiles()...) } } @@ -1363,7 +1376,7 @@ type ccObjectProvider interface { type ccObject struct { CCBase - out string + out common.OptionalPath } func (c *ccObject) object() *ccObject { @@ -1382,19 +1395,20 @@ func (*ccObject) depNames(ctx common.AndroidBaseContext, depNames CCDeps) CCDeps } func (c *ccObject) compileModule(ctx common.AndroidModuleContext, - flags CCFlags, deps CCDeps, objFiles []string) { + flags CCFlags, deps CCPathDeps, objFiles common.Paths) { objFiles = append(objFiles, deps.ObjFiles...) - var outputFile string + var outputFile common.Path if len(objFiles) == 1 { outputFile = objFiles[0] } else { - outputFile = filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+objectExtension) - TransformObjsToObj(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile) + output := common.PathForModuleOut(ctx, ctx.ModuleName()+objectExtension) + TransformObjsToObj(ctx, objFiles, ccFlagsToBuilderFlags(flags), output) + outputFile = output } - c.out = outputFile + c.out = common.OptionalPathForPath(outputFile) ctx.CheckbuildFile(outputFile) } @@ -1403,7 +1417,7 @@ func (c *ccObject) installModule(ctx common.AndroidModuleContext, flags CCFlags) // Object files do not get installed. } -func (c *ccObject) outputFile() string { +func (c *ccObject) outputFile() common.OptionalPath { return c.out } @@ -1433,8 +1447,8 @@ type CCBinaryProperties struct { type CCBinary struct { CCLinked - out string - installFile string + out common.Path + installFile common.Path BinaryProperties CCBinaryProperties } @@ -1569,23 +1583,23 @@ func (c *CCBinary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags } func (c *CCBinary) compileModule(ctx common.AndroidModuleContext, - flags CCFlags, deps CCDeps, objFiles []string) { + flags CCFlags, deps CCPathDeps, objFiles common.Paths) { if !Bool(c.BinaryProperties.Static_executable) && inList("libc", c.Properties.Static_libs) { ctx.ModuleErrorf("statically linking libc to dynamic executable, please remove libc\n" + "from static libs or set static_executable: true") } - outputFile := filepath.Join(common.ModuleOutDir(ctx), c.getStem(ctx)+flags.Toolchain.ExecutableSuffix()) + outputFile := common.PathForModuleOut(ctx, c.getStem(ctx)+flags.Toolchain.ExecutableSuffix()) c.out = outputFile if c.BinaryProperties.Prefix_symbols != "" { afterPrefixSymbols := outputFile - outputFile = outputFile + ".intermediate" + outputFile = common.PathForModuleOut(ctx, c.getStem(ctx)+".intermediate") TransformBinaryPrefixSymbols(ctx, c.BinaryProperties.Prefix_symbols, outputFile, ccFlagsToBuilderFlags(flags), afterPrefixSymbols) } - var linkerDeps []string + var linkerDeps common.Paths TransformObjToDynamicBinary(ctx, objFiles, deps.SharedLibs, deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true, @@ -1596,11 +1610,11 @@ func (c *CCBinary) installModule(ctx common.AndroidModuleContext, flags CCFlags) c.installFile = ctx.InstallFile(filepath.Join("bin", c.Properties.Relative_install_path), c.out) } -func (c *CCBinary) HostToolPath() string { +func (c *CCBinary) HostToolPath() common.OptionalPath { if c.HostOrDevice().Host() { - return c.installFile + return common.OptionalPathForPath(c.installFile) } - return "" + return common.OptionalPath{} } func (c *CCBinary) testPerSrc() bool { @@ -1649,7 +1663,7 @@ func (c *CCTest) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags { // TODO(danalbert): Make gtest export its dependencies. flags.CFlags = append(flags.CFlags, - "-I"+filepath.Join(ctx.AConfig().SrcDir(), "external/gtest/include")) + "-I"+common.PathForSource(ctx, "external/gtest/include").String()) return flags } @@ -1832,10 +1846,10 @@ func ToolchainLibraryFactory() (blueprint.Module, []interface{}) { } func (c *toolchainLibrary) compileModule(ctx common.AndroidModuleContext, - flags CCFlags, deps CCDeps, objFiles []string) { + flags CCFlags, deps CCPathDeps, objFiles common.Paths) { libName := ctx.ModuleName() + staticLibraryExtension - outputFile := filepath.Join(common.ModuleOutDir(ctx), libName) + outputFile := common.PathForModuleOut(ctx, libName) CopyGccLib(ctx, libName, ccFlagsToBuilderFlags(flags), outputFile) @@ -1854,19 +1868,19 @@ func (c *toolchainLibrary) installModule(ctx common.AndroidModuleContext, flags // either (with the exception of the shared STLs, which are installed to the app's directory rather // than to the system image). -func getNdkLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, version string) string { - return fmt.Sprintf("%s/prebuilts/ndk/current/platforms/android-%s/arch-%s/usr/lib", - ctx.AConfig().SrcDir(), version, toolchain.Name()) +func getNdkLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, version string) common.SourcePath { + return common.PathForSource(ctx, fmt.Sprintf("prebuilts/ndk/current/platforms/android-%s/arch-%s/usr/lib", + version, toolchain.Name())) } func ndkPrebuiltModuleToPath(ctx common.AndroidModuleContext, toolchain Toolchain, - ext string, version string) string { + ext string, version string) common.Path { // NDK prebuilts are named like: ndk_NAME.EXT.SDK_VERSION. // We want to translate to just NAME.EXT name := strings.Split(strings.TrimPrefix(ctx.ModuleName(), "ndk_"), ".")[0] dir := getNdkLibDir(ctx, toolchain, version) - return filepath.Join(dir, name+ext) + return dir.Join(ctx, name+ext) } type ndkPrebuiltObject struct { @@ -1884,13 +1898,13 @@ func NdkPrebuiltObjectFactory() (blueprint.Module, []interface{}) { } func (c *ndkPrebuiltObject) compileModule(ctx common.AndroidModuleContext, flags CCFlags, - deps CCDeps, objFiles []string) { + deps CCPathDeps, objFiles common.Paths) { // A null build step, but it sets up the output path. if !strings.HasPrefix(ctx.ModuleName(), "ndk_crt") { ctx.ModuleErrorf("NDK prebuilts must have an ndk_crt prefixed name") } - c.out = ndkPrebuiltModuleToPath(ctx, flags.Toolchain, objectExtension, c.Properties.Sdk_version) + c.out = common.OptionalPathForPath(ndkPrebuiltModuleToPath(ctx, flags.Toolchain, objectExtension, c.Properties.Sdk_version)) } func (c *ndkPrebuiltObject) installModule(ctx common.AndroidModuleContext, flags CCFlags) { @@ -1915,14 +1929,14 @@ func NdkPrebuiltLibraryFactory() (blueprint.Module, []interface{}) { } func (c *ndkPrebuiltLibrary) compileModule(ctx common.AndroidModuleContext, flags CCFlags, - deps CCDeps, objFiles []string) { + deps CCPathDeps, objFiles common.Paths) { // A null build step, but it sets up the output path. if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") { ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name") } - includeDirs := pathtools.PrefixPaths(c.Properties.Export_include_dirs, common.ModuleSrcDir(ctx)) - c.exportFlags = []string{common.JoinWithPrefix(includeDirs, "-isystem ")} + includeDirs := common.PathsForModuleSrc(ctx, c.Properties.Export_include_dirs) + c.exportFlags = []string{common.JoinWithPrefix(includeDirs.Strings(), "-isystem ")} c.out = ndkPrebuiltModuleToPath(ctx, flags.Toolchain, flags.Toolchain.ShlibSuffix(), c.Properties.Sdk_version) @@ -1960,7 +1974,7 @@ func NdkPrebuiltStaticStlFactory() (blueprint.Module, []interface{}) { return NewCCLibrary(&module.CCLibrary, module, common.DeviceSupported) } -func getNdkStlLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, stl string) string { +func getNdkStlLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, stl string) common.SourcePath { gccVersion := toolchain.GccVersion() var libDir string switch stl { @@ -1973,22 +1987,22 @@ func getNdkStlLibDir(ctx common.AndroidModuleContext, toolchain Toolchain, stl s } if libDir != "" { - ndkSrcRoot := ctx.AConfig().SrcDir() + "/prebuilts/ndk/current/sources" - return fmt.Sprintf("%s/%s/%s", ndkSrcRoot, libDir, ctx.Arch().Abi) + ndkSrcRoot := "prebuilts/ndk/current/sources" + return common.PathForSource(ctx, ndkSrcRoot).Join(ctx, libDir, ctx.Arch().Abi[0]) } ctx.ModuleErrorf("Unknown NDK STL: %s", stl) - return "" + return common.PathForSource(ctx, "") } func (c *ndkPrebuiltStl) compileModule(ctx common.AndroidModuleContext, flags CCFlags, - deps CCDeps, objFiles []string) { + deps CCPathDeps, objFiles common.Paths) { // A null build step, but it sets up the output path. if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") { ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name") } - includeDirs := pathtools.PrefixPaths(c.Properties.Export_include_dirs, common.ModuleSrcDir(ctx)) + includeDirs := common.PathsForModuleSrc(ctx, c.Properties.Export_include_dirs) c.exportFlags = []string{includeDirsToFlags(includeDirs)} libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_") @@ -2000,7 +2014,7 @@ func (c *ndkPrebuiltStl) compileModule(ctx common.AndroidModuleContext, flags CC stlName := strings.TrimSuffix(libName, "_shared") stlName = strings.TrimSuffix(stlName, "_static") libDir := getNdkStlLibDir(ctx, flags.Toolchain, stlName) - c.out = libDir + "/" + libName + libExt + c.out = libDir.Join(ctx, libName+libExt) } func linkageMutator(mctx common.AndroidBottomUpMutatorContext) { diff --git a/cc/gen.go b/cc/gen.go index be50d757..035f40ed 100644 --- a/cc/gen.go +++ b/cc/gen.go @@ -19,18 +19,15 @@ package cc // functions. import ( - "path/filepath" - "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "android/soong/common" ) func init() { - pctx.StaticVariable("lexCmd", "${SrcDir}/prebuilts/misc/${HostPrebuiltTag}/flex/flex-2.5.39") - pctx.StaticVariable("yaccCmd", "${SrcDir}/prebuilts/misc/${HostPrebuiltTag}/bison/bison") - pctx.StaticVariable("yaccDataDir", "${SrcDir}/external/bison/data") + pctx.SourcePathVariable("lexCmd", "prebuilts/misc/${HostPrebuiltTag}/flex/flex-2.5.39") + pctx.SourcePathVariable("yaccCmd", "prebuilts/misc/${HostPrebuiltTag}/bison/bison") + pctx.SourcePathVariable("yaccDataDir", "external/bison/data") } var ( @@ -51,49 +48,45 @@ var ( }) ) -func genYacc(ctx common.AndroidModuleContext, yaccFile, yaccFlags string) (cppFile, headerFile string) { - cppFile = common.SrcDirRelPath(ctx, yaccFile) - cppFile = filepath.Join(common.ModuleGenDir(ctx), cppFile) - cppFile = pathtools.ReplaceExtension(cppFile, "cpp") - hppFile := pathtools.ReplaceExtension(cppFile, "hpp") - headerFile = pathtools.ReplaceExtension(cppFile, "h") +func genYacc(ctx common.AndroidModuleContext, yaccFile common.Path, yaccFlags string) (cppFile, headerFile common.ModuleGenPath) { + cppFile = common.GenPathWithExt(ctx, yaccFile, "cpp") + hppFile := common.GenPathWithExt(ctx, yaccFile, "hpp") + headerFile = common.GenPathWithExt(ctx, yaccFile, "h") - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: yacc, - Outputs: []string{cppFile, headerFile}, - Inputs: []string{yaccFile}, + Outputs: common.WritablePaths{cppFile, headerFile}, + Input: yaccFile, Args: map[string]string{ "yaccFlags": yaccFlags, - "cppFile": cppFile, - "hppFile": hppFile, - "hFile": headerFile, + "cppFile": cppFile.String(), + "hppFile": hppFile.String(), + "hFile": headerFile.String(), }, }) return cppFile, headerFile } -func genLex(ctx common.AndroidModuleContext, lexFile string) (cppFile string) { - cppFile = common.SrcDirRelPath(ctx, lexFile) - cppFile = filepath.Join(common.ModuleGenDir(ctx), cppFile) - cppFile = pathtools.ReplaceExtension(cppFile, "cpp") +func genLex(ctx common.AndroidModuleContext, lexFile common.Path) (cppFile common.ModuleGenPath) { + cppFile = common.GenPathWithExt(ctx, lexFile, "cpp") - ctx.Build(pctx, blueprint.BuildParams{ - Rule: lex, - Outputs: []string{cppFile}, - Inputs: []string{lexFile}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: lex, + Output: cppFile, + Input: lexFile, }) return cppFile } -func genSources(ctx common.AndroidModuleContext, srcFiles []string, - buildFlags builderFlags) ([]string, []string) { +func genSources(ctx common.AndroidModuleContext, srcFiles common.Paths, + buildFlags builderFlags) (common.Paths, common.Paths) { - var deps []string + var deps common.Paths for i, srcFile := range srcFiles { - switch filepath.Ext(srcFile) { + switch srcFile.Ext() { case ".y", ".yy": cppFile, headerFile := genYacc(ctx, srcFile, buildFlags.yaccFlags) srcFiles[i] = cppFile diff --git a/cc/mips64_device.go b/cc/mips64_device.go index 5aa5bc3f..44ca4f85 100644 --- a/cc/mips64_device.go +++ b/cc/mips64_device.go @@ -90,7 +90,7 @@ func init() { pctx.StaticVariable("mips64GccVersion", mips64GccVersion) - pctx.StaticVariable("mips64GccRoot", + pctx.SourcePathVariable("mips64GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mips64GccVersion}") pctx.StaticVariable("mips64GccTriple", "mips64el-linux-android") diff --git a/cc/mips_device.go b/cc/mips_device.go index 8b47f8a6..ba6b81aa 100644 --- a/cc/mips_device.go +++ b/cc/mips_device.go @@ -121,7 +121,7 @@ func init() { pctx.StaticVariable("mipsGccVersion", mipsGccVersion) - pctx.StaticVariable("mipsGccRoot", + pctx.SourcePathVariable("mipsGccRoot", "prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mipsGccVersion}") pctx.StaticVariable("mipsGccTriple", "mips64el-linux-android") diff --git a/cc/util.go b/cc/util.go index efc89f05..2fc717b7 100644 --- a/cc/util.go +++ b/cc/util.go @@ -24,12 +24,12 @@ import ( // Efficiently converts a list of include directories to a single string // of cflags with -I prepended to each directory. -func includeDirsToFlags(dirs []string) string { - return common.JoinWithPrefix(dirs, "-I") +func includeDirsToFlags(dirs common.Paths) string { + return common.JoinWithPrefix(dirs.Strings(), "-I") } -func includeFilesToFlags(dirs []string) string { - return common.JoinWithPrefix(dirs, "-include ") +func includeFilesToFlags(files common.Paths) string { + return common.JoinWithPrefix(files.Strings(), "-include ") } func ldDirsToFlags(dirs []string) string { diff --git a/cc/x86_64_device.go b/cc/x86_64_device.go index ba190a02..b4f96b96 100644 --- a/cc/x86_64_device.go +++ b/cc/x86_64_device.go @@ -137,7 +137,7 @@ func init() { pctx.StaticVariable("x86_64GccVersion", x86_64GccVersion) - pctx.StaticVariable("x86_64GccRoot", + pctx.SourcePathVariable("x86_64GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86_64GccVersion}") pctx.StaticVariable("x86_64GccTriple", "x86_64-linux-android") diff --git a/cc/x86_darwin_host.go b/cc/x86_darwin_host.go index 108bb85e..9693de69 100644 --- a/cc/x86_darwin_host.go +++ b/cc/x86_darwin_host.go @@ -83,8 +83,8 @@ func init() { pctx.StaticVariable("macSdkRoot", "${macSdkPath}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk") pctx.StaticVariable("darwinGccVersion", darwinGccVersion) - pctx.StaticVariable("darwinGccRoot", - "${SrcDir}/prebuilts/gcc/${HostPrebuiltTag}/host/i686-apple-darwin-${darwinGccVersion}") + pctx.SourcePathVariable("darwinGccRoot", + "prebuilts/gcc/${HostPrebuiltTag}/host/i686-apple-darwin-${darwinGccVersion}") pctx.StaticVariable("darwinGccTriple", "i686-apple-darwin11") diff --git a/cc/x86_device.go b/cc/x86_device.go index 6dfbd6ad..a44b2933 100644 --- a/cc/x86_device.go +++ b/cc/x86_device.go @@ -139,7 +139,7 @@ func init() { pctx.StaticVariable("x86GccVersion", x86GccVersion) - pctx.StaticVariable("x86GccRoot", + pctx.SourcePathVariable("x86GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86GccVersion}") pctx.StaticVariable("x86GccTriple", "x86_64-linux-android") diff --git a/cc/x86_linux_host.go b/cc/x86_linux_host.go index 98bceef4..a3c50d18 100644 --- a/cc/x86_linux_host.go +++ b/cc/x86_linux_host.go @@ -108,8 +108,8 @@ const ( func init() { pctx.StaticVariable("linuxGccVersion", linuxGccVersion) - pctx.StaticVariable("linuxGccRoot", - "${SrcDir}/prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-linux-glibc2.15-${linuxGccVersion}") + pctx.SourcePathVariable("linuxGccRoot", + "prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-linux-glibc2.15-${linuxGccVersion}") pctx.StaticVariable("linuxGccTriple", "x86_64-linux") diff --git a/cc/x86_windows_host.go b/cc/x86_windows_host.go index 5f06bec2..8556a645 100644 --- a/cc/x86_windows_host.go +++ b/cc/x86_windows_host.go @@ -68,8 +68,8 @@ const ( func init() { pctx.StaticVariable("windowsGccVersion", windowsGccVersion) - pctx.StaticVariable("windowsGccRoot", - "${SrcDir}/prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-w64-mingw32-${windowsGccVersion}") + pctx.SourcePathVariable("windowsGccRoot", + "prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-w64-mingw32-${windowsGccVersion}") pctx.StaticVariable("windowsGccTriple", "x86_64-w64-mingw32") diff --git a/common/androidmk.go b/common/androidmk.go index 5dd422d1..06aa30c5 100644 --- a/common/androidmk.go +++ b/common/androidmk.go @@ -37,11 +37,11 @@ type AndroidMkDataProvider interface { type AndroidMkData struct { Class string - OutputFile string + OutputFile OptionalPath Custom func(w io.Writer, name, prefix string) - Extra func(name, prefix, outputFile string, arch Arch) []string + Extra func(name, prefix string, outputFile Path, arch Arch) []string } func AndroidMkSingleton() blueprint.Singleton { @@ -55,7 +55,7 @@ func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext hasBPDir := make(map[string]bool) bpDirs := []string{} - ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).BuildDir(), "..")) + ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, "..")) ctx.VisitAllModules(func(module blueprint.Module) { if _, ok := module.(AndroidModule); ok { @@ -72,28 +72,13 @@ func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext // Gather list of eligible Android modules for translation androidMkModules := make(map[blueprint.Module]bool) - srcDir := ctx.Config().(Config).SrcDir() - intermediatesDir := filepath.Join(ctx.Config().(Config).IntermediatesDir(), "androidmk") sort.Strings(bpDirs) for _, bpDir := range bpDirs { - mkFile := filepath.Join(srcDir, bpDir, "Android.mk") - - files, err := Glob(ctx, intermediatesDir, mkFile, nil) - if err != nil { - ctx.Errorf("glob: %s", err.Error()) - continue - } - - // Existing Android.mk file, use that instead - if len(files) > 0 { - for _, file := range files { - ctx.AddNinjaFileDeps(file) + mkFile := OptionalPathForSource(ctx, "androidmk", bpDir, "Android.mk") + if !mkFile.Valid() { + for _, mod := range dirModules[bpDir] { + androidMkModules[mod] = true } - continue - } - - for _, mod := range dirModules[bpDir] { - androidMkModules[mod] = true } } @@ -110,16 +95,19 @@ func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext } } - transMk := filepath.Join(ctx.Config().(Config).BuildDir(), "Android.mk") + transMk := PathForOutput(ctx, "Android.mk") + if ctx.Failed() { + return + } - err := translateAndroidMk(ctx, transMk, androidMkModulesList) + err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList) if err != nil { ctx.Errorf(err.Error()) } ctx.Build(pctx, blueprint.BuildParams{ Rule: blueprint.Phony, - Outputs: []string{transMk}, + Outputs: []string{transMk.String()}, Optional: true, }) } @@ -177,7 +165,7 @@ func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod b type archSrc struct { arch Arch - src string + src Path extra []string } @@ -211,6 +199,10 @@ func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod b return } + if !data.OutputFile.Valid() { + return + } + hC := hostClass{ host: amod.HostOrDevice() == Host, class: data.Class, @@ -219,7 +211,7 @@ func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod b src := archSrc{ arch: arch, - src: data.OutputFile, + src: data.OutputFile.Path(), } if data.Extra != nil { @@ -242,7 +234,7 @@ func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod b printed := make(map[string]bool) for _, src := range archSrcs { - io.WriteString(w, "LOCAL_SRC_FILES_"+src.arch.ArchType.String()+" := "+src.src+"\n") + io.WriteString(w, "LOCAL_SRC_FILES_"+src.arch.ArchType.String()+" := "+src.src.String()+"\n") for _, extra := range src.extra { if !printed[extra] { diff --git a/common/config.go b/common/config.go index c67023e3..7f6ee65d 100644 --- a/common/config.go +++ b/common/config.go @@ -20,6 +20,7 @@ import ( "os" "path/filepath" "runtime" + "strings" "sync" ) @@ -38,8 +39,6 @@ func (f *FileConfigurableOptions) SetDefaultConfig() { type Config struct { *config - - dontCreateNinjaFile bool } // A config object represents the entire build configuration for Android. @@ -142,8 +141,24 @@ func NewConfig(srcDir, buildDir string) (Config, error) { }, } + // Sanity check the build and source directories. This won't catch strange + // configurations with symlinks, but at least checks the obvious cases. + absBuildDir, err := filepath.Abs(buildDir) + if err != nil { + return Config{}, err + } + + absSrcDir, err := filepath.Abs(srcDir) + if err != nil { + return Config{}, err + } + + if strings.HasPrefix(absSrcDir, absBuildDir) { + return Config{}, fmt.Errorf("Build dir must not contain source directory") + } + // Load any configurable options from the configuration file - err := loadConfig(config.config) + err = loadConfig(config.config) if err != nil { return Config{}, err } @@ -159,18 +174,6 @@ func NewConfig(srcDir, buildDir string) (Config, error) { return config, nil } -func (c *config) SrcDir() string { - return c.srcDir -} - -func (c *config) BuildDir() string { - return c.buildDir -} - -func (c *config) IntermediatesDir() string { - return filepath.Join(c.BuildDir(), ".intermediates") -} - func (c *config) RemoveAbandonedFiles() bool { return false } @@ -238,37 +241,7 @@ func (c *config) DeviceUsesClang() bool { return false } -// DeviceOut returns the path to out directory for device targets -func (c *config) DeviceOut() string { - return filepath.Join(c.BuildDir(), "target/product", c.DeviceName()) -} - -// HostOut returns the path to out directory for host targets -func (c *config) HostOut() string { - return filepath.Join(c.BuildDir(), "host", c.PrebuiltOS()) -} - -// HostBin returns the path to bin directory for host targets -func (c *config) HostBin() string { - return filepath.Join(c.HostOut(), "bin") -} - -// HostBinTool returns the path to a host tool in the bin directory for host targets -func (c *config) HostBinTool(tool string) (string, error) { - return filepath.Join(c.HostBin(), tool), nil -} - -// HostJavaDir returns the path to framework directory for host targets -func (c *config) HostJavaDir() string { - return filepath.Join(c.HostOut(), "framework") -} - -// HostJavaTool returns the path to a host tool in the frameworks directory for host targets -func (c *config) HostJavaTool(tool string) (string, error) { - return filepath.Join(c.HostJavaDir(), tool), nil -} - -func (c *config) ResourceOverlays() []string { +func (c *config) ResourceOverlays() []SourcePath { return nil } @@ -296,10 +269,10 @@ func (c *config) ProductAaptCharacteristics() string { return "nosdcard" } -func (c *config) DefaultAppCertificateDir() string { - return filepath.Join(c.SrcDir(), "build/target/product/security") +func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath { + return PathForSource(ctx, "build/target/product/security") } -func (c *config) DefaultAppCertificate() string { - return filepath.Join(c.DefaultAppCertificateDir(), "testkey") +func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath { + return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey") } diff --git a/common/defs.go b/common/defs.go index 7b2a7067..9e185e44 100644 --- a/common/defs.go +++ b/common/defs.go @@ -20,13 +20,11 @@ import ( ) var ( - pctx = blueprint.NewPackageContext("android/soong/common") + pctx = NewPackageContext("android/soong/common") cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks", Config.CpPreserveSymlinksFlags) - srcDir = pctx.VariableConfigMethod("srcDir", Config.SrcDir) - // A phony rule that is not the built-in Ninja phony rule. The built-in // phony rule has special behavior that is sometimes not desired. See the // Ninja docs for more details. diff --git a/common/env.go b/common/env.go index 8694c28a..478fffce 100644 --- a/common/env.go +++ b/common/env.go @@ -15,8 +15,6 @@ package common import ( - "path/filepath" - "android/soong" "android/soong/env" @@ -43,12 +41,15 @@ type envSingleton struct{} func (c *envSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) { envDeps := ctx.Config().(Config).EnvDeps() - envFile := filepath.Join(ctx.Config().(Config).BuildDir(), ".soong.environment") + envFile := PathForOutput(ctx, ".soong.environment") + if ctx.Failed() { + return + } - err := env.WriteEnvFile(envFile, envDeps) + err := env.WriteEnvFile(envFile.String(), envDeps) if err != nil { ctx.Errorf(err.Error()) } - ctx.AddNinjaFileDeps(envFile) + ctx.AddNinjaFileDeps(envFile.String()) } diff --git a/common/module.go b/common/module.go index 113768a7..36710c5a 100644 --- a/common/module.go +++ b/common/module.go @@ -32,6 +32,19 @@ var ( HostExecutable = "host_executable" ) +type ModuleBuildParams struct { + Rule blueprint.Rule + Output WritablePath + Outputs WritablePaths + Input Path + Inputs Paths + Implicit Path + Implicits Paths + OrderOnly Paths + Default bool + Args map[string]string +} + type androidBaseContext interface { Arch() Arch HostOrDevice() HostOrDevice @@ -52,12 +65,16 @@ type AndroidModuleContext interface { blueprint.ModuleContext androidBaseContext - ExpandSources(srcFiles, excludes []string) []string - Glob(outDir, globPattern string, excludes []string) []string + // Similar to Build, but takes Paths instead of []string, + // and performs more verification. + ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) + + ExpandSources(srcFiles, excludes []string) Paths + Glob(outDir, globPattern string, excludes []string) Paths - InstallFile(installPath, srcPath string, deps ...string) string - InstallFileName(installPath, name, srcPath string, deps ...string) string - CheckbuildFile(srcPath string) + InstallFile(installPath string, srcPath Path, deps ...Path) Path + InstallFileName(installPath, name string, srcPath Path, deps ...Path) Path + CheckbuildFile(srcPath Path) } type AndroidModule interface { @@ -196,8 +213,8 @@ type AndroidModuleBase struct { archProperties []*archProperties noAddressSanitizer bool - installFiles []string - checkbuildFiles []string + installFiles Paths + checkbuildFiles Paths // Used by buildTargetSingleton to create checkbuild and per-directory build targets // Only set on the final variant of each module @@ -254,9 +271,9 @@ func (a *AndroidModuleBase) Enabled() bool { } func (a *AndroidModuleBase) computeInstallDeps( - ctx blueprint.ModuleContext) []string { + ctx blueprint.ModuleContext) Paths { - result := []string{} + result := Paths{} ctx.VisitDepsDepthFirstIf(isFileInstaller, func(m blueprint.Module) { fileInstaller := m.(fileInstaller) @@ -267,7 +284,7 @@ func (a *AndroidModuleBase) computeInstallDeps( return result } -func (a *AndroidModuleBase) filesToInstall() []string { +func (a *AndroidModuleBase) filesToInstall() Paths { return a.installFiles } @@ -280,8 +297,8 @@ func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) { return } - allInstalledFiles := []string{} - allCheckbuildFiles := []string{} + allInstalledFiles := Paths{} + allCheckbuildFiles := Paths{} ctx.VisitAllModuleVariants(func(module blueprint.Module) { a := module.(AndroidModule).base() allInstalledFiles = append(allInstalledFiles, a.installFiles...) @@ -295,7 +312,7 @@ func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) { ctx.Build(pctx, blueprint.BuildParams{ Rule: blueprint.Phony, Outputs: []string{name}, - Implicits: allInstalledFiles, + Implicits: allInstalledFiles.Strings(), }) deps = append(deps, name) a.installTarget = name @@ -306,7 +323,7 @@ func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) { ctx.Build(pctx, blueprint.BuildParams{ Rule: blueprint.Phony, Outputs: []string{name}, - Implicits: allCheckbuildFiles, + Implicits: allCheckbuildFiles.Strings(), Optional: true, }) deps = append(deps, name) @@ -371,9 +388,9 @@ type androidBaseContextImpl struct { type androidModuleContext struct { blueprint.ModuleContext androidBaseContextImpl - installDeps []string - installFiles []string - checkbuildFiles []string + installDeps Paths + installFiles Paths + checkbuildFiles Paths } func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params blueprint.BuildParams) { @@ -381,6 +398,30 @@ func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params bluep a.ModuleContext.Build(pctx, params) } +func (a *androidModuleContext) ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) { + bparams := blueprint.BuildParams{ + Rule: params.Rule, + Outputs: params.Outputs.Strings(), + Inputs: params.Inputs.Strings(), + Implicits: params.Implicits.Strings(), + OrderOnly: params.OrderOnly.Strings(), + Args: params.Args, + Optional: !params.Default, + } + + if params.Output != nil { + bparams.Outputs = append(bparams.Outputs, params.Output.String()) + } + if params.Input != nil { + bparams.Inputs = append(bparams.Inputs, params.Input.String()) + } + if params.Implicit != nil { + bparams.Implicits = append(bparams.Implicits, params.Implicit.String()) + } + + a.ModuleContext.Build(pctx, bparams) +} + func (a *androidBaseContextImpl) Arch() Arch { return a.arch } @@ -413,31 +454,19 @@ func (a *androidBaseContextImpl) AConfig() Config { return a.config } -func (a *androidModuleContext) InstallFileName(installPath, name, srcPath string, - deps ...string) string { +func (a *androidModuleContext) InstallFileName(installPath, name string, srcPath Path, + deps ...Path) Path { - config := a.AConfig() - var fullInstallPath string - if a.hod.Device() { - // TODO: replace unset with a device name once we have device targeting - fullInstallPath = filepath.Join(config.DeviceOut(), "system", - installPath, name) - } else { - // TODO - if a.ht == Windows { - fullInstallPath = filepath.Join(config.BuildDir(), "host", "windows-x86", installPath, name) - } else { - fullInstallPath = filepath.Join(config.HostOut(), installPath, name) - } - } + fullInstallPath := PathForModuleInstall(a, installPath, name) deps = append(deps, a.installDeps...) - a.ModuleContext.Build(pctx, blueprint.BuildParams{ + a.ModuleBuild(pctx, ModuleBuildParams{ Rule: Cp, - Outputs: []string{fullInstallPath}, - Inputs: []string{srcPath}, - OrderOnly: deps, + Output: fullInstallPath, + Input: srcPath, + OrderOnly: Paths(deps), + Default: true, }) a.installFiles = append(a.installFiles, fullInstallPath) @@ -445,16 +474,16 @@ func (a *androidModuleContext) InstallFileName(installPath, name, srcPath string return fullInstallPath } -func (a *androidModuleContext) InstallFile(installPath, srcPath string, deps ...string) string { - return a.InstallFileName(installPath, filepath.Base(srcPath), srcPath, deps...) +func (a *androidModuleContext) InstallFile(installPath string, srcPath Path, deps ...Path) Path { + return a.InstallFileName(installPath, filepath.Base(srcPath.String()), srcPath, deps...) } -func (a *androidModuleContext) CheckbuildFile(srcPath string) { +func (a *androidModuleContext) CheckbuildFile(srcPath Path) { a.checkbuildFiles = append(a.checkbuildFiles, srcPath) } type fileInstaller interface { - filesToInstall() []string + filesToInstall() Paths } func isFileInstaller(m blueprint.Module) bool { @@ -476,8 +505,8 @@ func findStringInSlice(str string, slice []string) int { return -1 } -func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) []string { - prefix := ModuleSrcDir(ctx) +func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Paths { + prefix := PathForModuleSrc(ctx).String() for i, e := range excludes { j := findStringInSlice(e, srcFiles) if j != -1 { @@ -487,32 +516,24 @@ func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) []st excludes[i] = filepath.Join(prefix, e) } - for i, srcFile := range srcFiles { - srcFiles[i] = filepath.Join(prefix, srcFile) - } - - if !hasGlob(srcFiles) { - return srcFiles - } - - globbedSrcFiles := make([]string, 0, len(srcFiles)) + globbedSrcFiles := make(Paths, 0, len(srcFiles)) for _, s := range srcFiles { if glob.IsGlob(s) { - globbedSrcFiles = append(globbedSrcFiles, ctx.Glob("src_glob", s, excludes)...) + globbedSrcFiles = append(globbedSrcFiles, ctx.Glob("src_glob", filepath.Join(prefix, s), excludes)...) } else { - globbedSrcFiles = append(globbedSrcFiles, s) + globbedSrcFiles = append(globbedSrcFiles, PathForModuleSrc(ctx, s)) } } return globbedSrcFiles } -func (ctx *androidModuleContext) Glob(outDir, globPattern string, excludes []string) []string { - ret, err := Glob(ctx, filepath.Join(ModuleOutDir(ctx), outDir), globPattern, excludes) +func (ctx *androidModuleContext) Glob(outDir, globPattern string, excludes []string) Paths { + ret, err := Glob(ctx, PathForModuleOut(ctx, outDir).String(), globPattern, excludes) if err != nil { ctx.ModuleErrorf("glob: %s", err.Error()) } - return ret + return pathsForModuleSrcFromFullPath(ctx, ret) } func init() { diff --git a/common/package_ctx.go b/common/package_ctx.go new file mode 100644 index 00000000..cd18b658 --- /dev/null +++ b/common/package_ctx.go @@ -0,0 +1,127 @@ +// Copyright 2015 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 common + +import ( + "fmt" + + "github.com/google/blueprint" +) + +// AndroidPackageContext is a wrapper for blueprint.PackageContext that adds +// some android-specific helper functions. +type AndroidPackageContext struct { + blueprint.PackageContext +} + +func NewPackageContext(pkgPath string) AndroidPackageContext { + return AndroidPackageContext{blueprint.NewPackageContext(pkgPath)} +} + +// configErrorWrapper can be used with Path functions when a Context is not +// available. A Config can be provided, and errors are stored as a list for +// later retrieval. +// +// The most common use here will be with VariableFunc, where only a config is +// provided, and an error should be returned. +type configErrorWrapper struct { + config Config + errors []error +} + +var _ PathContext = &configErrorWrapper{} +var _ errorfContext = &configErrorWrapper{} + +func (e *configErrorWrapper) Config() interface{} { + return e.config +} +func (e *configErrorWrapper) Errorf(format string, args ...interface{}) { + e.errors = append(e.errors, fmt.Errorf(format, args...)) +} + +// SourcePathVariable returns a Variable whose value is the source directory +// appended with the supplied path. It may only be called during a Go package's +// initialization - either from the init() function or as part of a +// package-scoped variable's initialization. +func (p AndroidPackageContext) SourcePathVariable(name, path string) blueprint.Variable { + return p.VariableFunc(name, func(config interface{}) (string, error) { + ctx := &configErrorWrapper{config.(Config), []error{}} + p := safePathForSource(ctx, path) + if len(ctx.errors) > 0 { + return "", ctx.errors[0] + } + return p.String(), nil + }) +} + +// HostBinVariable returns a Variable whose value is the path to a host tool +// in the bin directory for host targets. It may only be called during a Go +// package's initialization - either from the init() function or as part of a +// package-scoped variable's initialization. +func (p AndroidPackageContext) HostBinToolVariable(name, path string) blueprint.Variable { + return p.VariableFunc(name, func(config interface{}) (string, error) { + ctx := &configErrorWrapper{config.(Config), []error{}} + p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path) + if len(ctx.errors) > 0 { + return "", ctx.errors[0] + } + return p.String(), nil + }) +} + +// HostJavaToolVariable returns a Variable whose value is the path to a host +// tool in the frameworks directory for host targets. It may only be called +// during a Go package's initialization - either from the init() function or as +// part of a package-scoped variable's initialization. +func (p AndroidPackageContext) HostJavaToolVariable(name, path string) blueprint.Variable { + return p.VariableFunc(name, func(config interface{}) (string, error) { + ctx := &configErrorWrapper{config.(Config), []error{}} + p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path) + if len(ctx.errors) > 0 { + return "", ctx.errors[0] + } + return p.String(), nil + }) +} + +// IntermediatesPathVariable returns a Variable whose value is the intermediate +// directory appended with the supplied path. It may only be called during a Go +// package's initialization - either from the init() function or as part of a +// package-scoped variable's initialization. +func (p AndroidPackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable { + return p.VariableFunc(name, func(config interface{}) (string, error) { + ctx := &configErrorWrapper{config.(Config), []error{}} + p := PathForIntermediates(ctx, path) + if len(ctx.errors) > 0 { + return "", ctx.errors[0] + } + return p.String(), nil + }) +} + +// PrefixedPathsForSourceVariable returns a Variable whose value is the +// list of source paths prefixed with the supplied prefix. It may only be +// called during a Go package's initialization - either from the init() +// function or as part of a package-scoped variable's initialization. +func (p AndroidPackageContext) PrefixedPathsForSourceVariable(name, prefix string, paths []string) blueprint.Variable { + return p.VariableFunc(name, func(config interface{}) (string, error) { + ctx := &configErrorWrapper{config.(Config), []error{}} + paths := PathsForSource(ctx, paths) + if len(ctx.errors) > 0 { + return "", ctx.errors[0] + } + return JoinWithPrefix(paths.Strings(), prefix), nil + }) +} diff --git a/common/paths.go b/common/paths.go index d92dcf91..8a085ea1 100644 --- a/common/paths.go +++ b/common/paths.go @@ -18,103 +18,571 @@ import ( "fmt" "os" "path/filepath" + "reflect" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/pathtools" ) -// ModuleOutDir returns the path to the module-specific output directory. -func ModuleOutDir(ctx AndroidModuleContext) string { - return filepath.Join(ctx.AConfig().IntermediatesDir(), - ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir()) +// PathContext is the subset of a (Module|Singleton)Context required by the +// Path methods. +type PathContext interface { + Config() interface{} } -// ModuleSrcDir returns the path of the directory that all source file paths are -// specified relative to. -func ModuleSrcDir(ctx AndroidModuleContext) string { - return filepath.Join(ctx.AConfig().SrcDir(), ctx.ModuleDir()) +var _ PathContext = blueprint.SingletonContext(nil) +var _ PathContext = blueprint.ModuleContext(nil) + +// errorfContext is the interface containing the Errorf method matching the +// Errorf method in blueprint.SingletonContext. +type errorfContext interface { + Errorf(format string, args ...interface{}) } -// ModuleBinDir returns the path to the module- and architecture-specific binary -// output directory. -func ModuleBinDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "bin") +var _ errorfContext = blueprint.SingletonContext(nil) + +// moduleErrorf is the interface containing the ModuleErrorf method matching +// the ModuleErrorf method in blueprint.ModuleContext. +type moduleErrorf interface { + ModuleErrorf(format string, args ...interface{}) +} + +var _ moduleErrorf = blueprint.ModuleContext(nil) + +// pathConfig returns the android Config interface associated to the context. +// Panics if the context isn't affiliated with an android build. +func pathConfig(ctx PathContext) Config { + if ret, ok := ctx.Config().(Config); ok { + return ret + } + panic("Paths may only be used on Soong builds") +} + +// reportPathError will register an error with the attached context. It +// attempts ctx.ModuleErrorf for a better error message first, then falls +// back to ctx.Errorf. +func reportPathError(ctx PathContext, format string, args ...interface{}) { + if mctx, ok := ctx.(moduleErrorf); ok { + mctx.ModuleErrorf(format, args...) + } else if ectx, ok := ctx.(errorfContext); ok { + ectx.Errorf(format, args...) + } else { + panic(fmt.Sprintf(format, args...)) + } } -// ModuleLibDir returns the path to the module- and architecture-specific -// library output directory. -func ModuleLibDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "lib") +type Path interface { + // Returns the path in string form + String() string + + // Returns the current file extension of the path + Ext() string } -// ModuleGenDir returns the module directory for generated files -// path. -func ModuleGenDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "gen") +// WritablePath is a type of path that can be used as an output for build rules. +type WritablePath interface { + Path + + writablePath() } -// ModuleObjDir returns the module- and architecture-specific object directory -// path. -func ModuleObjDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "obj") +type genPathProvider interface { + genPathWithExt(ctx AndroidModuleContext, ext string) ModuleGenPath +} +type objPathProvider interface { + objPathWithExt(ctx AndroidModuleContext, subdir, ext string) ModuleObjPath +} +type resPathProvider interface { + resPathWithName(ctx AndroidModuleContext, name string) ModuleResPath } -// ModuleGoPackageDir returns the module-specific package root directory path. -// This directory is where the final package .a files are output and where -// dependent modules search for this package via -I arguments. -func ModuleGoPackageDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "pkg") +// GenPathWithExt derives a new file path in ctx's generated sources directory +// from the current path, but with the new extension. +func GenPathWithExt(ctx AndroidModuleContext, p Path, ext string) ModuleGenPath { + if path, ok := p.(genPathProvider); ok { + return path.genPathWithExt(ctx, ext) + } + reportPathError(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p) + return PathForModuleGen(ctx) } -// ModuleIncludeDir returns the module-specific public include directory path. -func ModuleIncludeDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "include") +// ObjPathWithExt derives a new file path in ctx's object directory from the +// current path, but with the new extension. +func ObjPathWithExt(ctx AndroidModuleContext, p Path, subdir, ext string) ModuleObjPath { + if path, ok := p.(objPathProvider); ok { + return path.objPathWithExt(ctx, subdir, ext) + } + reportPathError(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) + return PathForModuleObj(ctx) } -// ModuleProtoDir returns the module-specific public proto include directory path. -func ModuleProtoDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "proto") +// ResPathWithName derives a new path in ctx's output resource directory, using +// the current path to create the directory name, and the `name` argument for +// the filename. +func ResPathWithName(ctx AndroidModuleContext, p Path, name string) ModuleResPath { + if path, ok := p.(resPathProvider); ok { + return path.resPathWithName(ctx, name) + } + reportPathError(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) + return PathForModuleRes(ctx) } -func ModuleJSCompiledDir(ctx AndroidModuleContext) string { - return filepath.Join(ModuleOutDir(ctx), "js") +// OptionalPath is a container that may or may not contain a valid Path. +type OptionalPath struct { + valid bool + path Path } -// CheckModuleSrcDirsExist logs an error on a property if any of the directories relative to the -// Blueprints file don't exist. -func CheckModuleSrcDirsExist(ctx AndroidModuleContext, dirs []string, prop string) { - for _, dir := range dirs { - fullDir := filepath.Join(ModuleSrcDir(ctx), dir) - if _, err := os.Stat(fullDir); err != nil { - if os.IsNotExist(err) { - ctx.PropertyErrorf(prop, "module source directory %q does not exist", dir) - } else { - ctx.PropertyErrorf(prop, "%s", err.Error()) - } +// OptionalPathForPath returns an OptionalPath containing the path. +func OptionalPathForPath(path Path) OptionalPath { + if path == nil { + return OptionalPath{} + } + return OptionalPath{valid: true, path: path} +} + +// Valid returns whether there is a valid path +func (p OptionalPath) Valid() bool { + return p.valid +} + +// Path returns the Path embedded in this OptionalPath. You must be sure that +// there is a valid path, since this method will panic if there is not. +func (p OptionalPath) Path() Path { + if !p.valid { + panic("Requesting an invalid path") + } + return p.path +} + +// String returns the string version of the Path, or "" if it isn't valid. +func (p OptionalPath) String() string { + if p.valid { + return p.path.String() + } else { + return "" + } +} + +// Paths is a slice of Path objects, with helpers to operate on the collection. +type Paths []Path + +// PathsForSource returns Paths rooted from SrcDir +func PathsForSource(ctx PathContext, paths []string) Paths { + ret := make(Paths, len(paths)) + for i, path := range paths { + ret[i] = PathForSource(ctx, path) + } + return ret +} + +// PathsForModuleSrc returns Paths rooted from the module's local source +// directory +func PathsForModuleSrc(ctx AndroidModuleContext, paths []string) Paths { + ret := make(Paths, len(paths)) + for i, path := range paths { + ret[i] = PathForModuleSrc(ctx, path) + } + return ret +} + +// pathsForModuleSrcFromFullPath returns Paths rooted from the module's local +// source directory, but strip the local source directory from the beginning of +// each string. +func pathsForModuleSrcFromFullPath(ctx AndroidModuleContext, paths []string) Paths { + prefix := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir()) + "/" + ret := make(Paths, 0, len(paths)) + for _, p := range paths { + path := filepath.Clean(p) + if !strings.HasPrefix(path, prefix) { + reportPathError(ctx, "Path '%s' is not in module source directory '%s'", p, prefix) + continue } + ret = append(ret, PathForModuleSrc(ctx, path[len(prefix):])) + } + return ret +} + +// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's +// local source directory. If none are provided, use the default if it exists. +func PathsWithOptionalDefaultForModuleSrc(ctx AndroidModuleContext, input []string, def string) Paths { + if len(input) > 0 { + return PathsForModuleSrc(ctx, input) } + // Use Glob so that if the default doesn't exist, a dependency is added so that when it + // is created, we're run again. + path := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir(), def) + return ctx.Glob("default", path, []string{}) } -// CheckModuleSrcDirsExist logs an error on a property if any of the directories relative to the -// top of the source tree don't exist. -func CheckSrcDirsExist(ctx AndroidModuleContext, dirs []string, prop string) { - for _, dir := range dirs { - fullDir := filepath.Join(ctx.AConfig().SrcDir(), dir) - if _, err := os.Stat(fullDir); err != nil { - if os.IsNotExist(err) { - ctx.PropertyErrorf(prop, "top-level source directory %q does not exist", dir) - } else { - ctx.PropertyErrorf(prop, "%s", err.Error()) - } +// Strings returns the Paths in string form +func (p Paths) Strings() []string { + if p == nil { + return nil + } + ret := make([]string, len(p)) + for i, path := range p { + ret[i] = path.String() + } + return ret +} + +// WritablePaths is a slice of WritablePaths, used for multiple outputs. +type WritablePaths []WritablePath + +// Strings returns the string forms of the writable paths. +func (p WritablePaths) Strings() []string { + if p == nil { + return nil + } + ret := make([]string, len(p)) + for i, path := range p { + ret[i] = path.String() + } + return ret +} + +type basePath struct { + path string + config Config +} + +func (p basePath) Ext() string { + return filepath.Ext(p.path) +} + +// SourcePath is a Path representing a file path rooted from SrcDir +type SourcePath struct { + basePath +} + +var _ Path = SourcePath{} + +// safePathForSource is for paths that we expect are safe -- only for use by go +// code that is embedding ninja variables in paths +func safePathForSource(ctx PathContext, path string) SourcePath { + p := validateSafePath(ctx, path) + ret := SourcePath{basePath{p, pathConfig(ctx)}} + + abs, err := filepath.Abs(ret.String()) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return ret + } + buildroot, err := filepath.Abs(pathConfig(ctx).buildDir) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return ret + } + if strings.HasPrefix(abs, buildroot) { + reportPathError(ctx, "source path %s is in output", abs) + return ret + } + + return ret +} + +// PathForSource returns a SourcePath for the provided paths... (which are +// joined together with filepath.Join). This also validates that the path +// doesn't escape the source dir, or is contained in the build dir. On error, it +// will return a usable, but invalid SourcePath, and report a ModuleError. +func PathForSource(ctx PathContext, paths ...string) SourcePath { + p := validatePath(ctx, paths...) + ret := SourcePath{basePath{p, pathConfig(ctx)}} + + abs, err := filepath.Abs(ret.String()) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return ret + } + buildroot, err := filepath.Abs(pathConfig(ctx).buildDir) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return ret + } + if strings.HasPrefix(abs, buildroot) { + reportPathError(ctx, "source path %s is in output", abs) + return ret + } + + if _, err = os.Stat(ret.String()); err != nil { + if os.IsNotExist(err) { + reportPathError(ctx, "source path %s does not exist", ret) + } else { + reportPathError(ctx, "%s: %s", ret, err.Error()) } } + return ret +} + +// OptionalPathForSource returns an OptionalPath with the SourcePath if the +// path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added +// so that the ninja file will be regenerated if the state of the path changes. +func OptionalPathForSource(ctx blueprint.SingletonContext, intermediates string, paths ...string) OptionalPath { + p := validatePath(ctx, paths...) + path := SourcePath{basePath{p, pathConfig(ctx)}} + + abs, err := filepath.Abs(path.String()) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return OptionalPath{} + } + buildroot, err := filepath.Abs(pathConfig(ctx).buildDir) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return OptionalPath{} + } + if strings.HasPrefix(abs, buildroot) { + reportPathError(ctx, "source path %s is in output", abs) + return OptionalPath{} + } + + // Use glob to produce proper dependencies, even though we only want + // a single file. + files, err := Glob(ctx, PathForIntermediates(ctx, intermediates).String(), path.String(), nil) + if err != nil { + reportPathError(ctx, "glob: %s", err.Error()) + return OptionalPath{} + } + + if len(files) == 0 { + return OptionalPath{} + } + return OptionalPathForPath(path) +} + +func (p SourcePath) String() string { + return filepath.Join(p.config.srcDir, p.path) +} + +// Join creates a new SourcePath with paths... joined with the current path. The +// provided paths... may not use '..' to escape from the current path. +func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath { + path := validatePath(ctx, paths...) + return PathForSource(ctx, p.path, path) } -// Returns a path relative to the top level source directory. Panics if path is not inside the -// top level source directory. -func SrcDirRelPath(ctx AndroidModuleContext, path string) string { - srcDir := ctx.AConfig().SrcDir() - relPath, err := filepath.Rel(srcDir, path) +// OverlayPath returns the overlay for `path' if it exists. This assumes that the +// SourcePath is the path to a resource overlay directory. +func (p SourcePath) OverlayPath(ctx AndroidModuleContext, path Path) OptionalPath { + var relDir string + if moduleSrcPath, ok := path.(ModuleSrcPath); ok { + relDir = moduleSrcPath.sourcePath.path + } else if srcPath, ok := path.(SourcePath); ok { + relDir = srcPath.path + } else { + reportPathError(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) + return OptionalPath{} + } + dir := filepath.Join(p.config.srcDir, p.path, relDir) + // Use Glob so that we are run again if the directory is added. + paths, err := Glob(ctx, PathForModuleOut(ctx, "overlay").String(), dir, []string{}) if err != nil { - panic(fmt.Errorf("%q is not inside %q: %s", path, srcDir, err.Error())) + reportPathError(ctx, "glob: %s", err.Error()) + return OptionalPath{} + } + if len(paths) == 0 { + return OptionalPath{} + } + relPath, err := filepath.Rel(p.config.srcDir, paths[0]) + if err != nil { + reportPathError(ctx, "%s", err.Error()) + return OptionalPath{} + } + return OptionalPathForPath(PathForSource(ctx, relPath)) +} + +// OutputPath is a Path representing a file path rooted from the build directory +type OutputPath struct { + basePath +} + +var _ Path = OutputPath{} + +// PathForOutput returns an OutputPath for the provided paths... (which are +// joined together with filepath.Join). This also validates that the path +// does not escape the build dir. On error, it will return a usable, but invalid +// OutputPath, and report a ModuleError. +func PathForOutput(ctx PathContext, paths ...string) OutputPath { + path := validatePath(ctx, paths...) + return OutputPath{basePath{path, pathConfig(ctx)}} +} + +func (p OutputPath) writablePath() {} + +func (p OutputPath) String() string { + return filepath.Join(p.config.buildDir, p.path) +} + +// Join creates a new OutputPath with paths... joined with the current path. The +// provided paths... may not use '..' to escape from the current path. +func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath { + path := validatePath(ctx, paths...) + return PathForOutput(ctx, p.path, path) +} + +// PathForIntermediates returns an OutputPath representing the top-level +// intermediates directory. +func PathForIntermediates(ctx PathContext, paths ...string) OutputPath { + path := validatePath(ctx, paths...) + return PathForOutput(ctx, ".intermediates", path) +} + +// ModuleSrcPath is a Path representing a file rooted from a module's local source dir +type ModuleSrcPath struct { + basePath + sourcePath SourcePath + moduleDir string +} + +var _ Path = ModuleSrcPath{} +var _ genPathProvider = ModuleSrcPath{} +var _ objPathProvider = ModuleSrcPath{} +var _ resPathProvider = ModuleSrcPath{} + +// PathForModuleSrc returns a ModuleSrcPath representing the paths... under the +// module's local source directory. +func PathForModuleSrc(ctx AndroidModuleContext, paths ...string) ModuleSrcPath { + path := validatePath(ctx, paths...) + return ModuleSrcPath{basePath{path, ctx.AConfig()}, PathForSource(ctx, ctx.ModuleDir(), path), ctx.ModuleDir()} +} + +// OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a +// valid path if p is non-nil. +func OptionalPathForModuleSrc(ctx AndroidModuleContext, p *string) OptionalPath { + if p == nil { + return OptionalPath{} + } + return OptionalPathForPath(PathForModuleSrc(ctx, *p)) +} + +func (p ModuleSrcPath) String() string { + return p.sourcePath.String() +} + +func (p ModuleSrcPath) genPathWithExt(ctx AndroidModuleContext, ext string) ModuleGenPath { + return PathForModuleGen(ctx, p.moduleDir, pathtools.ReplaceExtension(p.path, ext)) +} + +func (p ModuleSrcPath) objPathWithExt(ctx AndroidModuleContext, subdir, ext string) ModuleObjPath { + return PathForModuleObj(ctx, subdir, p.moduleDir, pathtools.ReplaceExtension(p.path, ext)) +} + +func (p ModuleSrcPath) resPathWithName(ctx AndroidModuleContext, name string) ModuleResPath { + // TODO: Use full directory if the new ctx is not the current ctx? + return PathForModuleRes(ctx, p.path, name) +} + +// ModuleOutPath is a Path representing a module's output directory. +type ModuleOutPath struct { + OutputPath +} + +var _ Path = ModuleOutPath{} + +// PathForModuleOut returns a Path representing the paths... under the module's +// output directory. +func PathForModuleOut(ctx AndroidModuleContext, paths ...string) ModuleOutPath { + p := validatePath(ctx, paths...) + return ModuleOutPath{PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), p)} +} + +// ModuleGenPath is a Path representing the 'gen' directory in a module's output +// directory. Mainly used for generated sources. +type ModuleGenPath struct { + ModuleOutPath + path string +} + +var _ Path = ModuleGenPath{} +var _ genPathProvider = ModuleGenPath{} +var _ objPathProvider = ModuleGenPath{} + +// PathForModuleGen returns a Path representing the paths... under the module's +// `gen' directory. +func PathForModuleGen(ctx AndroidModuleContext, paths ...string) ModuleGenPath { + p := validatePath(ctx, paths...) + return ModuleGenPath{ + PathForModuleOut(ctx, "gen", p), + p, } +} + +func (p ModuleGenPath) genPathWithExt(ctx AndroidModuleContext, ext string) ModuleGenPath { + // TODO: make a different path for local vs remote generated files? + return PathForModuleGen(ctx, pathtools.ReplaceExtension(p.path, ext)) +} + +func (p ModuleGenPath) objPathWithExt(ctx AndroidModuleContext, subdir, ext string) ModuleObjPath { + return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) +} - return relPath +// ModuleObjPath is a Path representing the 'obj' directory in a module's output +// directory. Used for compiled objects. +type ModuleObjPath struct { + ModuleOutPath +} + +var _ Path = ModuleObjPath{} + +// PathForModuleObj returns a Path representing the paths... under the module's +// 'obj' directory. +func PathForModuleObj(ctx AndroidModuleContext, paths ...string) ModuleObjPath { + p := validatePath(ctx, paths...) + return ModuleObjPath{PathForModuleOut(ctx, "obj", p)} +} + +// ModuleResPath is a a Path representing the 'res' directory in a module's +// output directory. +type ModuleResPath struct { + ModuleOutPath +} + +var _ Path = ModuleResPath{} + +// PathForModuleRes returns a Path representing the paths... under the module's +// 'res' directory. +func PathForModuleRes(ctx AndroidModuleContext, paths ...string) ModuleResPath { + p := validatePath(ctx, paths...) + return ModuleResPath{PathForModuleOut(ctx, "res", p)} +} + +// PathForModuleInstall returns a Path representing the install path for the +// module appended with paths... +func PathForModuleInstall(ctx AndroidModuleContext, paths ...string) OutputPath { + var outPaths []string + if ctx.Device() { + outPaths = []string{"target", "product", ctx.AConfig().DeviceName(), "system"} + } else { + outPaths = []string{"host", ctx.HostType().String() + "-x86"} + } + outPaths = append(outPaths, paths...) + return PathForOutput(ctx, outPaths...) +} + +// validateSafePath validates a path that we trust (may contain ninja variables). +// Ensures that it does not attempt to leave the containing directory. +func validateSafePath(ctx PathContext, paths ...string) string { + // TODO: filepath.Join isn't necessarily correct with embedded ninja + // variables. '..' may remove the entire ninja variable, even if it + // will be expanded to multiple nested directories. + p := filepath.Join(paths...) + if p == ".." || strings.HasPrefix(p, "../") || strings.HasPrefix(p, "/") { + reportPathError(ctx, "Path is outside directory: %s", p) + return "" + } + return p +} + +// validatePath validates that a path does not include ninja variables, and does +// not attempt to leave the containing directory. +func validatePath(ctx PathContext, paths ...string) string { + for _, path := range paths { + if strings.Contains(path, "$") { + reportPathError(ctx, "Path contains invalid character($): %s", path) + return "" + } + } + return validateSafePath(ctx, paths...) } diff --git a/common/paths_test.go b/common/paths_test.go new file mode 100644 index 00000000..16ede0d2 --- /dev/null +++ b/common/paths_test.go @@ -0,0 +1,167 @@ +// Copyright 2015 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 common + +import ( + "errors" + "fmt" + "reflect" + "strings" + "testing" +) + +type strsTestCase struct { + in []string + out string + err []error +} + +var commonValidatePathTestCases = []strsTestCase{ + { + in: []string{""}, + out: "", + }, + { + in: []string{"a/b"}, + out: "a/b", + }, + { + in: []string{"a/b", "c"}, + out: "a/b/c", + }, + { + in: []string{"a/.."}, + out: ".", + }, + { + in: []string{"."}, + out: ".", + }, + { + in: []string{".."}, + out: "", + err: []error{errors.New("Path is outside directory: ..")}, + }, + { + in: []string{"../a"}, + out: "", + err: []error{errors.New("Path is outside directory: ../a")}, + }, + { + in: []string{"b/../../a"}, + out: "", + err: []error{errors.New("Path is outside directory: ../a")}, + }, + { + in: []string{"/a"}, + out: "", + err: []error{errors.New("Path is outside directory: /a")}, + }, +} + +var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ + { + in: []string{"$host/../$a"}, + out: "$a", + }, +}...) + +var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ + { + in: []string{"$host/../$a"}, + out: "", + err: []error{errors.New("Path contains invalid character($): $host/../$a")}, + }, + { + in: []string{"$host/.."}, + out: "", + err: []error{errors.New("Path contains invalid character($): $host/..")}, + }, +}...) + +func TestValidateSafePath(t *testing.T) { + for _, testCase := range validateSafePathTestCases { + ctx := &configErrorWrapper{} + out := validateSafePath(ctx, testCase.in...) + check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) + } +} + +func TestValidatePath(t *testing.T) { + for _, testCase := range validatePathTestCases { + ctx := &configErrorWrapper{} + out := validatePath(ctx, testCase.in...) + check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) + } +} + +func TestOptionalPath(t *testing.T) { + var path OptionalPath + checkInvalidOptionalPath(t, path) + + path = OptionalPathForPath(nil) + checkInvalidOptionalPath(t, path) +} + +func checkInvalidOptionalPath(t *testing.T, path OptionalPath) { + if path.Valid() { + t.Errorf("Uninitialized OptionalPath should not be valid") + } + if path.String() != "" { + t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String()) + } + defer func() { + if r := recover(); r == nil { + t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath") + } + }() + path.Path() +} + +func check(t *testing.T, testType, testString string, + got interface{}, err []error, + expected interface{}, expectedErr []error) { + + printedTestCase := false + e := func(s string, expected, got interface{}) { + if !printedTestCase { + t.Errorf("test case %s: %s", testType, testString) + printedTestCase = true + } + t.Errorf("incorrect %s", s) + t.Errorf(" expected: %s", p(expected)) + t.Errorf(" got: %s", p(got)) + } + + if !reflect.DeepEqual(expectedErr, err) { + e("errors:", expectedErr, err) + } + + if !reflect.DeepEqual(expected, got) { + e("output:", expected, got) + } +} + +func p(in interface{}) string { + if v, ok := in.([]interface{}); ok { + s := make([]string, len(v)) + for i := range v { + s[i] = fmt.Sprintf("%#v", v[i]) + } + return "[" + strings.Join(s, ", ") + "]" + } else { + return fmt.Sprintf("%#v", in) + } +} diff --git a/genrule/genrule.go b/genrule/genrule.go index 76b4f16a..b5543570 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -15,10 +15,7 @@ package genrule import ( - "path/filepath" - "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "android/soong" "android/soong/common" @@ -32,20 +29,20 @@ func init() { } var ( - pctx = blueprint.NewPackageContext("android/soong/genrule") + pctx = common.NewPackageContext("android/soong/genrule") ) func init() { - pctx.VariableConfigMethod("srcDir", common.Config.SrcDir) - pctx.VariableConfigMethod("hostBin", common.Config.HostBin) + pctx.SourcePathVariable("srcDir", "") + pctx.HostBinToolVariable("hostBin", "") } type SourceFileGenerator interface { - GeneratedSourceFiles() []string + GeneratedSourceFiles() common.Paths } type HostToolProvider interface { - HostToolPath() string + HostToolPath() common.OptionalPath } type generatorProperties struct { @@ -68,20 +65,20 @@ type generator struct { tasks taskFunc - deps []string + deps common.Paths rule blueprint.Rule - outputFiles []string + outputFiles common.Paths } type taskFunc func(ctx common.AndroidModuleContext) []generateTask type generateTask struct { - in []string - out string + in common.Paths + out common.ModuleGenPath } -func (g *generator) GeneratedSourceFiles() []string { +func (g *generator) GeneratedSourceFiles() common.Paths { return g.outputFiles } @@ -104,8 +101,8 @@ func (g *generator) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) ctx.VisitDirectDeps(func(module blueprint.Module) { if t, ok := module.(HostToolProvider); ok { p := t.HostToolPath() - if p != "" { - g.deps = append(g.deps, p) + if p.Valid() { + g.deps = append(g.deps, p.Path()) } else { ctx.ModuleErrorf("host tool %q missing output file", ctx.OtherModuleName(module)) } @@ -120,12 +117,11 @@ func (g *generator) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) } func (g *generator) generateSourceFile(ctx common.AndroidModuleContext, task generateTask) { - - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: g.rule, + Output: task.out, Inputs: task.in, Implicits: g.deps, - Outputs: []string{task.out}, }) g.outputFiles = append(g.outputFiles, task.out) @@ -148,9 +144,10 @@ func GenSrcsFactory() (blueprint.Module, []interface{}) { srcFiles := ctx.ExpandSources(properties.Srcs, nil) tasks := make([]generateTask, 0, len(srcFiles)) for _, in := range srcFiles { - out := pathtools.ReplaceExtension(in, properties.Output_extension) - out = filepath.Join(common.ModuleGenDir(ctx), out) - tasks = append(tasks, generateTask{[]string{in}, out}) + tasks = append(tasks, generateTask{ + in: common.Paths{in}, + out: common.GenPathWithExt(ctx, in, properties.Output_extension), + }) } return tasks } @@ -173,7 +170,7 @@ func GenRuleFactory() (blueprint.Module, []interface{}) { return []generateTask{ { in: ctx.ExpandSources(properties.Srcs, nil), - out: filepath.Join(common.ModuleGenDir(ctx), properties.Out), + out: properties.Out, }, } } @@ -186,5 +183,5 @@ type genRuleProperties struct { Srcs []string // name of the output file that will be generated - Out string + Out common.ModuleGenPath } diff --git a/java/app.go b/java/app.go index 74e32699..f0eb3c8a 100644 --- a/java/app.go +++ b/java/app.go @@ -17,12 +17,10 @@ package java // This file contains the module types for compiling Android apps. import ( - "os" "path/filepath" "strings" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "android/soong/common" ) @@ -63,8 +61,8 @@ type AndroidApp struct { appProperties androidAppProperties - aaptJavaFileList string - exportPackage string + aaptJavaFileList common.Path + exportPackage common.Path } func (a *AndroidApp) JavaDependencies(ctx AndroidJavaModuleContext) []string { @@ -117,7 +115,7 @@ func (a *AndroidApp) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { } // apps manifests are handled by aapt, don't let javaBase see them - a.properties.Manifest = "" + a.properties.Manifest = nil //if !ctx.ContainsProperty("proguard.enabled") { // a.properties.Proguard.Enabled = true @@ -141,16 +139,16 @@ func (a *AndroidApp) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { certificate := a.appProperties.Certificate if certificate == "" { - certificate = ctx.AConfig().DefaultAppCertificate() + certificate = ctx.AConfig().DefaultAppCertificate(ctx).String() } else if dir, _ := filepath.Split(certificate); dir == "" { - certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(), certificate) + certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(ctx).String(), certificate) } else { - certificate = filepath.Join(ctx.AConfig().SrcDir(), certificate) + certificate = filepath.Join(common.PathForSource(ctx).String(), certificate) } certificates := []string{certificate} for _, c := range a.appProperties.Additional_certificates { - certificates = append(certificates, filepath.Join(ctx.AConfig().SrcDir(), c)) + certificates = append(certificates, filepath.Join(common.PathForSource(ctx).String(), c)) } a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates) @@ -169,7 +167,7 @@ var aaptIgnoreFilenames = []string{ "*~", } -func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, []string, bool) { +func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, common.Paths, bool) { aaptFlags := a.appProperties.Aaptflags hasVersionCode := false hasVersionName := false @@ -185,54 +183,17 @@ func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, []str aaptFlags = append(aaptFlags, "-z") } - assetDirs := a.appProperties.Asset_dirs - if len(assetDirs) == 0 { - defaultAssetDir := filepath.Join(common.ModuleSrcDir(ctx), "assets") - if _, err := os.Stat(defaultAssetDir); err == nil { - assetDirs = []string{defaultAssetDir} - } else { - // Default asset directory doesn't exist, add a dep on the parent directory to - // regenerate the manifest if it is created later - // TODO: use glob to avoid rerunning whole regenerate if a different file is created? - ctx.AddNinjaFileDeps(common.ModuleSrcDir(ctx)) - } - } else { - assetDirs = pathtools.PrefixPaths(assetDirs, common.ModuleSrcDir(ctx)) - } + assetDirs := common.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets") + resourceDirs := common.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Android_resource_dirs, "res") - resourceDirs := a.appProperties.Android_resource_dirs - if len(resourceDirs) == 0 { - defaultResourceDir := filepath.Join(common.ModuleSrcDir(ctx), "res") - if _, err := os.Stat(defaultResourceDir); err == nil { - resourceDirs = []string{defaultResourceDir} - } else { - // Default resource directory doesn't exist, add a dep on the parent directory to - // regenerate the manifest if it is created later - // TODO: use glob to avoid rerunning whole regenerate if a different file is created? - ctx.AddNinjaFileDeps(common.ModuleSrcDir(ctx)) - } - } else { - resourceDirs = pathtools.PrefixPaths(resourceDirs, common.ModuleSrcDir(ctx)) - } - - rootSrcDir := ctx.AConfig().SrcDir() - var overlayResourceDirs []string + var overlayResourceDirs common.Paths // For every resource directory, check if there is an overlay directory with the same path. // If found, it will be prepended to the list of resource directories. for _, overlayDir := range ctx.AConfig().ResourceOverlays() { for _, resourceDir := range resourceDirs { - relResourceDir, err := filepath.Rel(rootSrcDir, resourceDir) - if err != nil { - ctx.ModuleErrorf("resource directory %q is not in source tree", resourceDir) - continue - } - overlayResourceDir := filepath.Join(overlayDir, relResourceDir) - if _, err := os.Stat(overlayResourceDir); err == nil { - overlayResourceDirs = append(overlayResourceDirs, overlayResourceDir) - } else { - // Overlay resource directory doesn't exist, add a dep to regenerate the manifest if - // it is created later - ctx.AddNinjaFileDeps(overlayResourceDir) + overlay := overlayDir.OverlayPath(ctx, resourceDir) + if overlay.Valid() { + overlayResourceDirs = append(overlayResourceDirs, overlay.Path()) } } } @@ -243,44 +204,46 @@ func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, []str // aapt needs to rerun if any files are added or modified in the assets or resource directories, // use glob to create a filelist. - var aaptDeps []string + var aaptDeps common.Paths var hasResources bool for _, d := range resourceDirs { - newDeps := ctx.Glob("app_resources", filepath.Join(d, "**/*"), aaptIgnoreFilenames) + newDeps := ctx.Glob("app_resources", filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames) aaptDeps = append(aaptDeps, newDeps...) if len(newDeps) > 0 { hasResources = true } } for _, d := range assetDirs { - newDeps := ctx.Glob("app_assets", filepath.Join(d, "**/*"), aaptIgnoreFilenames) + newDeps := ctx.Glob("app_assets", filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames) aaptDeps = append(aaptDeps, newDeps...) } - manifestFile := a.properties.Manifest - if manifestFile == "" { + var manifestFile string + if a.properties.Manifest == nil { manifestFile = "AndroidManifest.xml" + } else { + manifestFile = *a.properties.Manifest } - manifestFile = filepath.Join(common.ModuleSrcDir(ctx), manifestFile) - aaptDeps = append(aaptDeps, manifestFile) + manifestPath := common.PathForModuleSrc(ctx, manifestFile) + aaptDeps = append(aaptDeps, manifestPath) - aaptFlags = append(aaptFlags, "-M "+manifestFile) - aaptFlags = append(aaptFlags, common.JoinWithPrefix(assetDirs, "-A ")) - aaptFlags = append(aaptFlags, common.JoinWithPrefix(resourceDirs, "-S ")) + aaptFlags = append(aaptFlags, "-M "+manifestPath.String()) + aaptFlags = append(aaptFlags, common.JoinWithPrefix(assetDirs.Strings(), "-A ")) + aaptFlags = append(aaptFlags, common.JoinWithPrefix(resourceDirs.Strings(), "-S ")) ctx.VisitDirectDeps(func(module blueprint.Module) { - var depFile string + var depFile common.OptionalPath if sdkDep, ok := module.(sdkDependency); ok { - depFile = sdkDep.ClasspathFile() + depFile = common.OptionalPathForPath(sdkDep.ClasspathFile()) } else if javaDep, ok := module.(JavaDependency); ok { if ctx.OtherModuleName(module) == "framework-res" { - depFile = javaDep.(*javaBase).module.(*AndroidApp).exportPackage + depFile = common.OptionalPathForPath(javaDep.(*javaBase).module.(*AndroidApp).exportPackage) } } - if depFile != "" { - aaptFlags = append(aaptFlags, "-I "+depFile) - aaptDeps = append(aaptDeps, depFile) + if depFile.Valid() { + aaptFlags = append(aaptFlags, "-I "+depFile.String()) + aaptDeps = append(aaptDeps, depFile.Path()) } }) diff --git a/java/app_builder.go b/java/app_builder.go index 849abfd3..2a475196 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -19,7 +19,6 @@ package java // functions. import ( - "path/filepath" "strings" "github.com/google/blueprint" @@ -75,44 +74,40 @@ var ( ) func init() { - pctx.StaticVariable("androidManifestMergerCmd", "${srcDir}/prebuilts/devtools/tools/lib/manifest-merger.jar") - pctx.VariableFunc("aaptCmd", func(c interface{}) (string, error) { - return c.(common.Config).HostBinTool("aapt") - }) - pctx.VariableFunc("signapkCmd", func(c interface{}) (string, error) { - return c.(common.Config).HostJavaTool("signapk.jar") - }) + pctx.SourcePathVariable("androidManifestMergerCmd", "prebuilts/devtools/tools/lib/manifest-merger.jar") + pctx.HostBinToolVariable("aaptCmd", "aapt") + pctx.HostJavaToolVariable("signapkCmd", "signapk.jar") } func CreateResourceJavaFiles(ctx common.AndroidModuleContext, flags []string, - deps []string) (string, string, string) { - javaDir := filepath.Join(common.ModuleGenDir(ctx), "R") - javaFileList := filepath.Join(common.ModuleOutDir(ctx), "R.filelist") - publicResourcesFile := filepath.Join(common.ModuleOutDir(ctx), "public_resources.xml") - proguardOptionsFile := filepath.Join(common.ModuleOutDir(ctx), "proguard.options") + deps common.Paths) (common.Path, common.Path, common.Path) { + javaDir := common.PathForModuleGen(ctx, "R") + javaFileList := common.PathForModuleOut(ctx, "R.filelist") + publicResourcesFile := common.PathForModuleOut(ctx, "public_resources.xml") + proguardOptionsFile := common.PathForModuleOut(ctx, "proguard.options") - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: aaptCreateResourceJavaFile, - Outputs: []string{publicResourcesFile, proguardOptionsFile, javaFileList}, + Outputs: common.WritablePaths{publicResourcesFile, proguardOptionsFile, javaFileList}, Implicits: deps, Args: map[string]string{ "aaptFlags": strings.Join(flags, " "), - "publicResourcesFile": publicResourcesFile, - "proguardOptionsFile": proguardOptionsFile, - "javaDir": javaDir, - "javaFileList": javaFileList, + "publicResourcesFile": publicResourcesFile.String(), + "proguardOptionsFile": proguardOptionsFile.String(), + "javaDir": javaDir.String(), + "javaFileList": javaFileList.String(), }, }) return publicResourcesFile, proguardOptionsFile, javaFileList } -func CreateExportPackage(ctx common.AndroidModuleContext, flags []string, deps []string) string { - outputFile := filepath.Join(common.ModuleOutDir(ctx), "package-export.apk") +func CreateExportPackage(ctx common.AndroidModuleContext, flags []string, deps common.Paths) common.ModuleOutPath { + outputFile := common.PathForModuleOut(ctx, "package-export.apk") - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: aaptCreateAssetsPackage, - Outputs: []string{outputFile}, + Output: outputFile, Implicits: deps, Args: map[string]string{ "aaptFlags": strings.Join(flags, " "), @@ -122,31 +117,31 @@ func CreateExportPackage(ctx common.AndroidModuleContext, flags []string, deps [ return outputFile } -func CreateAppPackage(ctx common.AndroidModuleContext, flags []string, jarFile string, - certificates []string) string { +func CreateAppPackage(ctx common.AndroidModuleContext, flags []string, jarFile common.Path, + certificates []string) common.Path { - resourceApk := filepath.Join(common.ModuleOutDir(ctx), "resources.apk") + resourceApk := common.PathForModuleOut(ctx, "resources.apk") - ctx.Build(pctx, blueprint.BuildParams{ - Rule: aaptAddResources, - Outputs: []string{resourceApk}, - Inputs: []string{jarFile}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: aaptAddResources, + Output: resourceApk, + Input: jarFile, Args: map[string]string{ "aaptFlags": strings.Join(flags, " "), }, }) - outputFile := filepath.Join(common.ModuleOutDir(ctx), "package.apk") + outputFile := common.PathForModuleOut(ctx, "package.apk") var certificateArgs []string for _, c := range certificates { certificateArgs = append(certificateArgs, c+".x509.pem", c+".pk8") } - ctx.Build(pctx, blueprint.BuildParams{ - Rule: signapk, - Outputs: []string{outputFile}, - Inputs: []string{resourceApk}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: signapk, + Output: outputFile, + Input: resourceApk, Args: map[string]string{ "certificates": strings.Join(certificateArgs, " "), }, diff --git a/java/builder.go b/java/builder.go index 36506ae0..024af43f 100644 --- a/java/builder.go +++ b/java/builder.go @@ -29,7 +29,7 @@ import ( ) var ( - pctx = blueprint.NewPackageContext("android/soong/java") + pctx = common.NewPackageContext("android/soong/java") // Compiling java is not conducive to proper dependency tracking. The path-matches-class-name // requirement leads to unpredictable generated source file names, and a single .java file @@ -91,12 +91,8 @@ func init() { pctx.StaticVariable("commonJdkFlags", "-source 1.7 -target 1.7 -Xmaxerrs 9999999") pctx.StaticVariable("javacCmd", "javac -J-Xmx1024M $commonJdkFlags") pctx.StaticVariable("jarCmd", filepath.Join("${bootstrap.BinDir}", "soong_jar")) - pctx.VariableFunc("dxCmd", func(c interface{}) (string, error) { - return c.(common.Config).HostBinTool("dx") - }) - pctx.VariableFunc("jarjarCmd", func(c interface{}) (string, error) { - return c.(common.Config).HostJavaTool("jarjar.jar") - }) + pctx.HostBinToolVariable("dxCmd", "dx") + pctx.HostJavaToolVariable("jarjarCmd", "jarjar.jar") } type javaBuilderFlags struct { @@ -108,33 +104,33 @@ type javaBuilderFlags struct { } type jarSpec struct { - fileList, dir string + fileList, dir common.Path } func (j jarSpec) soongJarArgs() string { - return "-C " + j.dir + " -l " + j.fileList + return "-C " + j.dir.String() + " -l " + j.fileList.String() } -func TransformJavaToClasses(ctx common.AndroidModuleContext, srcFiles []string, srcFileLists []string, - flags javaBuilderFlags, deps []string) jarSpec { +func TransformJavaToClasses(ctx common.AndroidModuleContext, srcFiles common.Paths, srcFileLists common.Paths, + flags javaBuilderFlags, deps common.Paths) jarSpec { - classDir := filepath.Join(common.ModuleOutDir(ctx), "classes") - classFileList := filepath.Join(common.ModuleOutDir(ctx), "classes.list") + classDir := common.PathForModuleOut(ctx, "classes") + classFileList := common.PathForModuleOut(ctx, "classes.list") - javacFlags := flags.javacFlags + common.JoinWithPrefix(srcFileLists, "@") + javacFlags := flags.javacFlags + common.JoinWithPrefix(srcFileLists.Strings(), "@") deps = append(deps, srcFileLists...) - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: javac, - Outputs: []string{classFileList}, + Output: classFileList, Inputs: srcFiles, Implicits: deps, Args: map[string]string{ "javacFlags": javacFlags, "bootClasspath": flags.bootClasspath, "classpath": flags.classpath, - "outDir": classDir, + "outDir": classDir.String(), }, }) @@ -142,11 +138,11 @@ func TransformJavaToClasses(ctx common.AndroidModuleContext, srcFiles []string, } func TransformClassesToJar(ctx common.AndroidModuleContext, classes []jarSpec, - manifest string) string { + manifest common.OptionalPath) common.Path { - outputFile := filepath.Join(common.ModuleOutDir(ctx), "classes-full-debug.jar") + outputFile := common.PathForModuleOut(ctx, "classes-full-debug.jar") - deps := []string{} + deps := common.Paths{} jarArgs := []string{} for _, j := range classes { @@ -154,14 +150,14 @@ func TransformClassesToJar(ctx common.AndroidModuleContext, classes []jarSpec, jarArgs = append(jarArgs, j.soongJarArgs()) } - if manifest != "" { - deps = append(deps, manifest) - jarArgs = append(jarArgs, "-m "+manifest) + if manifest.Valid() { + deps = append(deps, manifest.Path()) + jarArgs = append(jarArgs, "-m "+manifest.String()) } - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: jar, - Outputs: []string{outputFile}, + Output: outputFile, Implicits: deps, Args: map[string]string{ "jarArgs": strings.Join(jarArgs, " "), @@ -171,19 +167,19 @@ func TransformClassesToJar(ctx common.AndroidModuleContext, classes []jarSpec, return outputFile } -func TransformClassesJarToDex(ctx common.AndroidModuleContext, classesJar string, +func TransformClassesJarToDex(ctx common.AndroidModuleContext, classesJar common.Path, flags javaBuilderFlags) jarSpec { - outDir := filepath.Join(common.ModuleOutDir(ctx), "dex") - outputFile := filepath.Join(common.ModuleOutDir(ctx), "dex.filelist") + outDir := common.PathForModuleOut(ctx, "dex") + outputFile := common.PathForModuleOut(ctx, "dex.filelist") - ctx.Build(pctx, blueprint.BuildParams{ - Rule: dx, - Outputs: []string{outputFile}, - Inputs: []string{classesJar}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: dx, + Output: outputFile, + Input: classesJar, Args: map[string]string{ "dxFlags": flags.dxFlags, - "outDir": outDir, + "outDir": outDir.String(), }, }) @@ -191,10 +187,10 @@ func TransformClassesJarToDex(ctx common.AndroidModuleContext, classesJar string } func TransformDexToJavaLib(ctx common.AndroidModuleContext, resources []jarSpec, - dexJarSpec jarSpec) string { + dexJarSpec jarSpec) common.Path { - outputFile := filepath.Join(common.ModuleOutDir(ctx), "javalib.jar") - var deps []string + outputFile := common.PathForModuleOut(ctx, "javalib.jar") + var deps common.Paths var jarArgs []string for _, j := range resources { @@ -205,9 +201,9 @@ func TransformDexToJavaLib(ctx common.AndroidModuleContext, resources []jarSpec, deps = append(deps, dexJarSpec.fileList) jarArgs = append(jarArgs, dexJarSpec.soongJarArgs()) - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: jar, - Outputs: []string{outputFile}, + Output: outputFile, Implicits: deps, Args: map[string]string{ "jarArgs": strings.Join(jarArgs, " "), @@ -217,14 +213,15 @@ func TransformDexToJavaLib(ctx common.AndroidModuleContext, resources []jarSpec, return outputFile } -func TransformJarJar(ctx common.AndroidModuleContext, classesJar string, rulesFile string) string { - outputFile := filepath.Join(common.ModuleOutDir(ctx), "classes-jarjar.jar") - ctx.Build(pctx, blueprint.BuildParams{ - Rule: jarjar, - Outputs: []string{outputFile}, - Inputs: []string{classesJar}, +func TransformJarJar(ctx common.AndroidModuleContext, classesJar common.Path, rulesFile common.Path) common.Path { + outputFile := common.PathForModuleOut(ctx, "classes-jarjar.jar") + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: jarjar, + Output: outputFile, + Input: classesJar, + Implicit: rulesFile, Args: map[string]string{ - "rulesFile": rulesFile, + "rulesFile": rulesFile.String(), }, }) @@ -232,21 +229,20 @@ func TransformJarJar(ctx common.AndroidModuleContext, classesJar string, rulesFi } func TransformPrebuiltJarToClasses(ctx common.AndroidModuleContext, - prebuilt string) (classJarSpec, resourceJarSpec jarSpec) { + prebuilt common.Path) (classJarSpec, resourceJarSpec jarSpec) { - extractedDir := filepath.Join(common.ModuleOutDir(ctx), "extracted") - classDir := filepath.Join(extractedDir, "classes") - classFileList := filepath.Join(extractedDir, "classes.list") - resourceFileList := filepath.Join(extractedDir, "resources.list") + classDir := common.PathForModuleOut(ctx, "extracted/classes") + classFileList := common.PathForModuleOut(ctx, "extracted/classes.list") + resourceFileList := common.PathForModuleOut(ctx, "extracted/resources.list") - ctx.Build(pctx, blueprint.BuildParams{ + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ Rule: extractPrebuilt, - Outputs: []string{classFileList, resourceFileList}, - Inputs: []string{prebuilt}, + Outputs: common.WritablePaths{classFileList, resourceFileList}, + Input: prebuilt, Args: map[string]string{ - "outDir": classDir, - "classFile": classFileList, - "resourceFile": resourceFileList, + "outDir": classDir.String(), + "classFile": classFileList.String(), + "resourceFile": resourceFileList.String(), }, }) diff --git a/java/gen.go b/java/gen.go index f9898754..51f9959d 100644 --- a/java/gen.go +++ b/java/gen.go @@ -19,25 +19,17 @@ package java // functions. import ( - "path/filepath" - "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "android/soong/common" ) func init() { - pctx.VariableFunc("aidlCmd", func(c interface{}) (string, error) { - return c.(common.Config).HostBinTool("aidl") - }) - pctx.StaticVariable("logtagsCmd", "${srcDir}/build/tools/java-event-log-tags.py") - pctx.StaticVariable("mergeLogtagsCmd", "${srcDir}/build/tools/merge-event-log-tags.py") - pctx.VariableConfigMethod("srcDir", common.Config.SrcDir) + pctx.HostBinToolVariable("aidlCmd", "aidl") + pctx.SourcePathVariable("logtagsCmd", "build/tools/java-event-log-tags.py") + pctx.SourcePathVariable("mergeLogtagsCmd", "build/tools/merge-event-log-tags.py") - pctx.VariableFunc("allLogtagsFile", func(c interface{}) (string, error) { - return filepath.Join(c.(common.Config).IntermediatesDir(), "all-event-log-tags.txt"), nil - }) + pctx.IntermediatesPathVariable("allLogtagsFile", "all-event-log-tags.txt") } var ( @@ -64,16 +56,14 @@ var ( }) ) -func genAidl(ctx common.AndroidModuleContext, aidlFile, aidlFlags string) string { - javaFile := common.SrcDirRelPath(ctx, aidlFile) - javaFile = filepath.Join(common.ModuleGenDir(ctx), javaFile) - javaFile = pathtools.ReplaceExtension(javaFile, "java") - depFile := javaFile + ".d" +func genAidl(ctx common.AndroidModuleContext, aidlFile common.Path, aidlFlags string) common.Path { + javaFile := common.GenPathWithExt(ctx, aidlFile, "java") + depFile := javaFile.String() + ".d" - ctx.Build(pctx, blueprint.BuildParams{ - Rule: aidl, - Outputs: []string{javaFile}, - Inputs: []string{aidlFile}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: aidl, + Output: javaFile, + Input: aidlFile, Args: map[string]string{ "depFile": depFile, "aidlFlags": aidlFlags, @@ -83,25 +73,23 @@ func genAidl(ctx common.AndroidModuleContext, aidlFile, aidlFlags string) string return javaFile } -func genLogtags(ctx common.AndroidModuleContext, logtagsFile string) string { - javaFile := common.SrcDirRelPath(ctx, logtagsFile) - javaFile = filepath.Join(common.ModuleGenDir(ctx), javaFile) - javaFile = pathtools.ReplaceExtension(javaFile, "java") +func genLogtags(ctx common.AndroidModuleContext, logtagsFile common.Path) common.Path { + javaFile := common.GenPathWithExt(ctx, logtagsFile, "java") - ctx.Build(pctx, blueprint.BuildParams{ - Rule: logtags, - Outputs: []string{javaFile}, - Inputs: []string{logtagsFile}, + ctx.ModuleBuild(pctx, common.ModuleBuildParams{ + Rule: logtags, + Output: javaFile, + Input: logtagsFile, }) return javaFile } -func (j *javaBase) genSources(ctx common.AndroidModuleContext, srcFiles []string, - flags javaBuilderFlags) []string { +func (j *javaBase) genSources(ctx common.AndroidModuleContext, srcFiles common.Paths, + flags javaBuilderFlags) common.Paths { for i, srcFile := range srcFiles { - switch filepath.Ext(srcFile) { + switch srcFile.Ext() { case ".aidl": javaFile := genAidl(ctx, srcFile, flags.aidlFlags) srcFiles[i] = javaFile @@ -120,13 +108,13 @@ func LogtagsSingleton() blueprint.Singleton { } type logtagsProducer interface { - logtags() []string + logtags() common.Paths } type logtagsSingleton struct{} func (l *logtagsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) { - var allLogtags []string + var allLogtags common.Paths ctx.VisitAllModules(func(module blueprint.Module) { if logtags, ok := module.(logtagsProducer); ok { allLogtags = append(allLogtags, logtags.logtags()...) @@ -136,6 +124,6 @@ func (l *logtagsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) ctx.Build(pctx, blueprint.BuildParams{ Rule: mergeLogtags, Outputs: []string{"$allLogtagsFile"}, - Inputs: allLogtags, + Inputs: allLogtags.Strings(), }) } diff --git a/java/java.go b/java/java.go index 2bd5bffa..839fb01d 100644 --- a/java/java.go +++ b/java/java.go @@ -20,11 +20,9 @@ package java import ( "fmt" - "path/filepath" "strings" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "android/soong" "android/soong/common" @@ -93,7 +91,7 @@ type javaBaseProperties struct { Java_static_libs []string `android:"arch_variant"` // manifest file to be included in resulting jar - Manifest string + Manifest *string // if not blank, set to the version of the sdk to compile against Sdk_version string @@ -103,7 +101,7 @@ type javaBaseProperties struct { Dex bool `blueprint:"mutated"` // if not blank, run jarjar using the specified rules file - Jarjar_rules string + Jarjar_rules *string // directories to pass to aidl tool Aidl_includes []string @@ -122,10 +120,10 @@ type javaBase struct { properties javaBaseProperties // output file suitable for inserting into the classpath of another compile - classpathFile string + classpathFile common.Path // output file suitable for installing or running - outputFile string + outputFile common.Path // jarSpecs suitable for inserting classes from a static library into another jar classJarSpecs []jarSpec @@ -133,16 +131,16 @@ type javaBase struct { // jarSpecs suitable for inserting resources from a static library into another jar resourceJarSpecs []jarSpec - exportAidlIncludeDirs []string + exportAidlIncludeDirs common.Paths - logtagsSrcs []string + logtagsSrcs common.Paths // filelists of extra source files that should be included in the javac command line, // for example R.java generated by aapt for android apps - ExtraSrcLists []string + ExtraSrcLists common.Paths // installed file for binary dependency - installFile string + installFile common.Path } type AndroidJavaModuleContext common.AndroidBaseContext @@ -153,10 +151,10 @@ type JavaModuleType interface { } type JavaDependency interface { - ClasspathFile() string + ClasspathFile() common.Path ClassJarSpecs() []jarSpec ResourceJarSpecs() []jarSpec - AidlIncludeDirs() []string + AidlIncludeDirs() common.Paths } func NewJavaBase(base *javaBase, module JavaModuleType, hod common.HostOrDeviceSupported, @@ -217,35 +215,35 @@ func (j *javaBase) JavaDependencies(ctx AndroidJavaModuleContext) []string { return deps } -func (j *javaBase) aidlFlags(ctx common.AndroidModuleContext, aidlPreprocess string, - aidlIncludeDirs []string) []string { +func (j *javaBase) aidlFlags(ctx common.AndroidModuleContext, aidlPreprocess common.OptionalPath, + aidlIncludeDirs common.Paths) []string { - localAidlIncludes := pathtools.PrefixPaths(j.properties.Aidl_includes, common.ModuleSrcDir(ctx)) + localAidlIncludes := common.PathsForModuleSrc(ctx, j.properties.Aidl_includes) var flags []string - if aidlPreprocess != "" { - flags = append(flags, "-p"+aidlPreprocess) + if aidlPreprocess.Valid() { + flags = append(flags, "-p"+aidlPreprocess.String()) } else { - flags = append(flags, common.JoinWithPrefix(aidlIncludeDirs, "-I")) + flags = append(flags, common.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I")) } - flags = append(flags, common.JoinWithPrefix(j.exportAidlIncludeDirs, "-I")) - flags = append(flags, common.JoinWithPrefix(localAidlIncludes, "-I")) - flags = append(flags, "-I"+common.ModuleSrcDir(ctx)) - flags = append(flags, "-I"+filepath.Join(common.ModuleSrcDir(ctx), "src")) + flags = append(flags, common.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I")) + flags = append(flags, common.JoinWithPrefix(localAidlIncludes.Strings(), "-I")) + flags = append(flags, "-I"+common.PathForModuleSrc(ctx).String()) + flags = append(flags, "-I"+common.PathForModuleSrc(ctx, "src").String()) return flags } -func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath []string, - bootClasspath string, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess string, - aidlIncludeDirs []string, srcFileLists []string) { +func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath common.Paths, + bootClasspath common.OptionalPath, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess common.OptionalPath, + aidlIncludeDirs common.Paths, srcFileLists common.Paths) { ctx.VisitDirectDeps(func(module blueprint.Module) { otherName := ctx.OtherModuleName(module) if javaDep, ok := module.(JavaDependency); ok { if otherName == j.BootClasspath(ctx) { - bootClasspath = javaDep.ClasspathFile() + bootClasspath = common.OptionalPathForPath(javaDep.ClasspathFile()) } else if inList(otherName, defaultJavaLibraries) { classpath = append(classpath, javaDep.ClasspathFile()) } else if inList(otherName, j.properties.Java_libs) { @@ -265,8 +263,8 @@ func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath []str } aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...) if sdkDep, ok := module.(sdkDependency); ok { - if sdkDep.AidlPreprocessed() != "" { - if aidlPreprocess != "" { + if sdkDep.AidlPreprocessed().Valid() { + if aidlPreprocess.Valid() { ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q", aidlPreprocess, sdkDep.AidlPreprocessed()) } else { @@ -287,8 +285,7 @@ func (j *javaBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { - j.exportAidlIncludeDirs = pathtools.PrefixPaths(j.properties.Export_aidl_include_dirs, - common.ModuleSrcDir(ctx)) + j.exportAidlIncludeDirs = common.PathsForModuleSrc(ctx, j.properties.Export_aidl_include_dirs) classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess, aidlIncludeDirs, srcFileLists := j.collectDeps(ctx) @@ -307,15 +304,15 @@ func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { flags.aidlFlags = "$aidlFlags" } - var javacDeps []string + var javacDeps common.Paths - if bootClasspath != "" { - flags.bootClasspath = "-bootclasspath " + bootClasspath - javacDeps = append(javacDeps, bootClasspath) + if bootClasspath.Valid() { + flags.bootClasspath = "-bootclasspath " + bootClasspath.String() + javacDeps = append(javacDeps, bootClasspath.Path()) } if len(classpath) > 0 { - flags.classpath = "-classpath " + strings.Join(classpath, ":") + flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":") javacDeps = append(javacDeps, classpath...) } @@ -344,10 +341,7 @@ func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs), resourceJarSpecs...) - manifest := j.properties.Manifest - if manifest != "" { - manifest = filepath.Join(common.ModuleSrcDir(ctx), manifest) - } + manifest := common.OptionalPathForModuleSrc(ctx, j.properties.Manifest) allJarSpecs := append([]jarSpec(nil), classJarSpecs...) allJarSpecs = append(allJarSpecs, resourceJarSpecs...) @@ -358,8 +352,8 @@ func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { return } - if j.properties.Jarjar_rules != "" { - jarjar_rules := filepath.Join(common.ModuleSrcDir(ctx), j.properties.Jarjar_rules) + if j.properties.Jarjar_rules != nil { + jarjar_rules := common.PathForModuleSrc(ctx, *j.properties.Jarjar_rules) // Transform classes-full-debug.jar into classes-jarjar.jar outputFile = TransformJarJar(ctx, outputFile, jarjar_rules) if ctx.Failed() { @@ -394,7 +388,7 @@ func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { dxFlags = append(dxFlags, "--debug", "--verbose", - "--dump-to="+filepath.Join(common.ModuleOutDir(ctx), "classes.lst"), + "--dump-to="+common.PathForModuleOut(ctx, "classes.lst").String(), "--dump-width=1000") } @@ -415,7 +409,7 @@ func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { var _ JavaDependency = (*JavaLibrary)(nil) -func (j *javaBase) ClasspathFile() string { +func (j *javaBase) ClasspathFile() common.Path { return j.classpathFile } @@ -427,13 +421,13 @@ func (j *javaBase) ResourceJarSpecs() []jarSpec { return j.resourceJarSpecs } -func (j *javaBase) AidlIncludeDirs() []string { +func (j *javaBase) AidlIncludeDirs() common.Paths { return j.exportAidlIncludeDirs } var _ logtagsProducer = (*javaBase)(nil) -func (j *javaBase) logtags() []string { +func (j *javaBase) logtags() common.Paths { return j.logtagsSrcs } @@ -485,7 +479,7 @@ func (j *JavaBinary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { // Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by // another build rule before the jar has been installed. - ctx.InstallFile("bin", filepath.Join(common.ModuleSrcDir(ctx), j.binaryProperties.Wrapper), + ctx.InstallFile("bin", common.PathForModuleSrc(ctx, j.binaryProperties.Wrapper), j.installFile) } @@ -516,7 +510,7 @@ type JavaPrebuilt struct { properties javaPrebuiltProperties - classpathFile string + classpathFile common.Path classJarSpecs, resourceJarSpecs []jarSpec } @@ -525,7 +519,7 @@ func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleConte ctx.ModuleErrorf("expected exactly one jar in srcs") return } - prebuilt := filepath.Join(common.ModuleSrcDir(ctx), j.properties.Srcs[0]) + prebuilt := common.PathForModuleSrc(ctx, j.properties.Srcs[0]) classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt) @@ -537,7 +531,7 @@ func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleConte var _ JavaDependency = (*JavaPrebuilt)(nil) -func (j *JavaPrebuilt) ClasspathFile() string { +func (j *JavaPrebuilt) ClasspathFile() common.Path { return j.classpathFile } @@ -549,7 +543,7 @@ func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec { return j.resourceJarSpecs } -func (j *JavaPrebuilt) AidlIncludeDirs() []string { +func (j *JavaPrebuilt) AidlIncludeDirs() common.Paths { return nil } @@ -566,13 +560,13 @@ func JavaPrebuiltFactory() (blueprint.Module, []interface{}) { type sdkDependency interface { JavaDependency - AidlPreprocessed() string + AidlPreprocessed() common.OptionalPath } var _ sdkDependency = (*sdkPrebuilt)(nil) type sdkPrebuiltProperties struct { - Aidl_preprocessed string + Aidl_preprocessed *string } type sdkPrebuilt struct { @@ -580,18 +574,16 @@ type sdkPrebuilt struct { sdkProperties sdkPrebuiltProperties - aidlPreprocessed string + aidlPreprocessed common.OptionalPath } func (j *sdkPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) { j.JavaPrebuilt.GenerateAndroidBuildActions(ctx) - if j.sdkProperties.Aidl_preprocessed != "" { - j.aidlPreprocessed = filepath.Join(common.ModuleSrcDir(ctx), j.sdkProperties.Aidl_preprocessed) - } + j.aidlPreprocessed = common.OptionalPathForModuleSrc(ctx, j.sdkProperties.Aidl_preprocessed) } -func (j *sdkPrebuilt) AidlPreprocessed() string { +func (j *sdkPrebuilt) AidlPreprocessed() common.OptionalPath { return j.aidlPreprocessed } diff --git a/java/resources.go b/java/resources.go index 405d8b05..4f734f20 100644 --- a/java/resources.go +++ b/java/resources.go @@ -42,7 +42,7 @@ func ResourceDirsToJarSpecs(ctx common.AndroidModuleContext, resourceDirs, exclu var excludes []string for _, exclude := range excludeDirs { - excludes = append(excludes, filepath.Join(common.ModuleSrcDir(ctx), exclude, "**/*")) + excludes = append(excludes, common.PathForModuleSrc(ctx, exclude, "**/*").String()) } excludes = append(excludes, resourceExcludes...) @@ -53,15 +53,14 @@ func ResourceDirsToJarSpecs(ctx common.AndroidModuleContext, resourceDirs, exclu if isStringInSlice(resourceDir, excludeDirs) { continue } - resourceDir := filepath.Join(common.ModuleSrcDir(ctx), resourceDir) - dirs := ctx.Glob("java_resources", resourceDir, nil) + resourceDir := common.PathForModuleSrc(ctx, resourceDir) + dirs := ctx.Glob("java_resources", resourceDir.String(), nil) for _, dir := range dirs { - relDir := common.SrcDirRelPath(ctx, dir) - fileListFile := filepath.Join(common.ModuleOutDir(ctx), "res", relDir, "resources.list") - depFile := fileListFile + ".d" + fileListFile := common.ResPathWithName(ctx, dir, "resources.list") + depFile := fileListFile.String() + ".d" - glob := filepath.Join(dir, "**/*") - common.GlobRule(ctx, glob, excludes, fileListFile, depFile) + glob := filepath.Join(dir.String(), "**/*") + common.GlobRule(ctx, glob, excludes, fileListFile.String(), depFile) jarSpecs = append(jarSpecs, jarSpec{fileListFile, dir}) } } -- cgit v1.2.3