Merge "Add support for thin LTO"
diff --git a/Android.bp b/Android.bp
index cc28c98..0875a2b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -53,6 +53,7 @@
"android/package_ctx.go",
"android/paths.go",
"android/prebuilt.go",
+ "android/proto.go",
"android/register.go",
"android/testing.go",
"android/util.go",
@@ -222,6 +223,7 @@
],
srcs: [
"java/config/config.go",
+ "java/config/error_prone.go",
"java/config/makevars.go",
],
}
@@ -237,6 +239,7 @@
"python/androidmk.go",
"python/binary.go",
"python/builder.go",
+ "python/defaults.go",
"python/installer.go",
"python/library.go",
"python/python.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 46e7fcf..319f711 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -42,6 +42,7 @@
SubName string
OutputFile OptionalPath
Disabled bool
+ Include string
Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
@@ -163,6 +164,10 @@
data := provider.AndroidMk()
+ if data.Include == "" {
+ data.Include = "$(BUILD_PREBUILT)"
+ }
+
// Make does not understand LinuxBionic
if amod.Os() == LinuxBionic {
return nil
@@ -232,6 +237,9 @@
if amod.commonProperties.Owner != nil {
fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
}
+ if amod.commonProperties.Notice != nil {
+ fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", "$(LOCAL_PATH)/"+*amod.commonProperties.Notice)
+ }
}
if host {
@@ -265,5 +273,5 @@
extra(w, data.OutputFile.Path())
}
- fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+ fmt.Fprintln(w, "include "+data.Include)
}
diff --git a/android/api_levels.go b/android/api_levels.go
index 370d553..2c4ae1a 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -67,6 +67,7 @@
"M": 23,
"N": 24,
"N-MR1": 25,
+ "O": 26,
}
for i, codename := range ctx.Config().(Config).PlatformVersionCombinedCodenames() {
apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/config.go b/android/config.go
index c435e85..4f35114 100644
--- a/android/config.go
+++ b/android/config.go
@@ -84,7 +84,8 @@
inMake bool
- captureBuild bool // true for tests, saves build parameters for each module
+ captureBuild bool // true for tests, saves build parameters for each module
+ ignoreEnvironment bool // true for tests, returns empty from all Getenv calls
OncePer
}
@@ -173,8 +174,9 @@
DeviceName: stringPtr("test_device"),
},
- buildDir: buildDir,
- captureBuild: true,
+ buildDir: buildDir,
+ captureBuild: true,
+ ignoreEnvironment: true,
}
config.deviceConfig = &deviceConfig{
config: config,
@@ -314,7 +316,9 @@
if c.envFrozen {
panic("Cannot access new environment variables after envdeps are frozen")
}
- val, _ = originalEnv[key]
+ if !c.ignoreEnvironment {
+ val, _ = originalEnv[key]
+ }
c.envDeps[key] = val
}
return val
@@ -382,6 +386,14 @@
return 14
}
+func (c *config) DefaultAppTargetSdkInt() int {
+ if Bool(c.ProductVariables.Platform_sdk_final) {
+ return c.PlatformSdkVersionInt()
+ } else {
+ return 10000
+ }
+}
+
// Codenames that are active in the current lunch target.
func (c *config) PlatformVersionActiveCodenames() []string {
return c.ProductVariables.Platform_version_active_codenames
diff --git a/android/defs.go b/android/defs.go
index ec8dcf9..cd8b4e3 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -52,6 +52,13 @@
},
"cpFlags")
+ CpExecutable = pctx.AndroidStaticRule("CpExecutable",
+ blueprint.RuleParams{
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out",
+ Description: "cp $out",
+ },
+ "cpFlags")
+
// A timestamp touch rule.
Touch = pctx.AndroidStaticRule("Touch",
blueprint.RuleParams{
diff --git a/android/module.go b/android/module.go
index 3a3d173..bacf666 100644
--- a/android/module.go
+++ b/android/module.go
@@ -83,8 +83,8 @@
ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths
Glob(globPattern string, excludes []string) Paths
- InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath
- InstallFileName(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
+ InstallExecutable(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
+ InstallFile(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath
CheckbuildFile(srcPath Path)
@@ -162,6 +162,9 @@
// names of other modules to install if this module is installed
Required []string `android:"arch_variant"`
+ // relative path to a file to include in the list of notices for the device
+ Notice *string
+
// Set by TargetMutator
CompileTarget Target `blueprint:"mutated"`
CompilePrimary bool `blueprint:"mutated"`
@@ -717,8 +720,18 @@
return false
}
-func (a *androidModuleContext) InstallFileName(installPath OutputPath, name string, srcPath Path,
+func (a *androidModuleContext) InstallFile(installPath OutputPath, name string, srcPath Path,
deps ...Path) OutputPath {
+ return a.installFile(installPath, name, srcPath, Cp, deps)
+}
+
+func (a *androidModuleContext) InstallExecutable(installPath OutputPath, name string, srcPath Path,
+ deps ...Path) OutputPath {
+ return a.installFile(installPath, name, srcPath, CpExecutable, deps)
+}
+
+func (a *androidModuleContext) installFile(installPath OutputPath, name string, srcPath Path,
+ rule blueprint.Rule, deps []Path) OutputPath {
fullInstallPath := installPath.Join(a, name)
a.module.base().hooks.runInstallHooks(a, fullInstallPath, false)
@@ -738,7 +751,7 @@
}
a.ModuleBuild(pctx, ModuleBuildParams{
- Rule: Cp,
+ Rule: rule,
Description: "install " + fullInstallPath.Base(),
Output: fullInstallPath,
Input: srcPath,
@@ -753,10 +766,6 @@
return fullInstallPath
}
-func (a *androidModuleContext) InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath {
- return a.InstallFileName(installPath, filepath.Base(srcPath.String()), srcPath, deps...)
-}
-
func (a *androidModuleContext) InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath {
fullInstallPath := installPath.Join(a, name)
a.module.base().hooks.runInstallHooks(a, fullInstallPath, true)
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 2bc98aa..6743fb3 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "strings"
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
@@ -75,6 +76,25 @@
})
}
+// SourcePathsVariable returns a Variable whose value is the source directory
+// appended with the supplied paths, joined with separator. 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) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
+ return p.VariableFunc(name, func(config interface{}) (string, error) {
+ ctx := &configErrorWrapper{p, config.(Config), []error{}}
+ var ret []string
+ for _, path := range paths {
+ p := safePathForSource(ctx, path)
+ if len(ctx.errors) > 0 {
+ return "", ctx.errors[0]
+ }
+ ret = append(ret, p.String())
+ }
+ return strings.Join(ret, separator), nil
+ })
+}
+
// SourcePathVariableWithEnvOverride returns a Variable whose value is the source directory
// appended with the supplied path, or the value of the given environment variable if it is set.
// The environment variable is not required to point to a path inside the source tree.
diff --git a/android/paths.go b/android/paths.go
index b5b4730..9c8e93a 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -283,6 +283,23 @@
return ret
}
+// FirstUniqueElements returns all unique elements of a slice, keeping the first copy of each
+// modifies the slice contents in place, and returns a subslice of the original slice
+func FirstUniquePaths(list Paths) Paths {
+ k := 0
+outer:
+ for i := 0; i < len(list); i++ {
+ for j := 0; j < k; j++ {
+ if list[i] == list[j] {
+ continue outer
+ }
+ }
+ list[k] = list[i]
+ k++
+ }
+ return list[:k]
+}
+
// WritablePaths is a slice of WritablePaths, used for multiple outputs.
type WritablePaths []WritablePath
diff --git a/android/proto.go b/android/proto.go
new file mode 100644
index 0000000..9bb9cfb
--- /dev/null
+++ b/android/proto.go
@@ -0,0 +1,103 @@
+// Copyright 2017 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 android
+
+import (
+ "github.com/google/blueprint"
+)
+
+func init() {
+ pctx.HostBinToolVariable("protocCmd", "aprotoc")
+}
+
+var (
+ proto = pctx.AndroidStaticRule("protoc",
+ blueprint.RuleParams{
+ Command: "$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in",
+ CommandDeps: []string{"$protocCmd"},
+ }, "protoFlags", "protoOut", "protoOutFlags", "outDir")
+)
+
+// TODO(ccross): protos are often used to communicate between multiple modules. If the only
+// way to convert a proto to source is to reference it as a source file, and external modules cannot
+// reference source files in other modules, then every module that owns a proto file will need to
+// export a library for every type of external user (lite vs. full, c vs. c++ vs. java). It would
+// be better to support a proto module type that exported a proto file along with some include dirs,
+// and then external modules could depend on the proto module but use their own settings to
+// generate the source.
+
+func GenProto(ctx ModuleContext, protoFile Path,
+ protoFlags string, protoOut, protoOutFlags string, extensions []string) WritablePaths {
+
+ var outFiles WritablePaths
+ for _, ext := range extensions {
+ outFiles = append(outFiles, GenPathWithExt(ctx, "proto", protoFile, ext))
+ }
+
+ ctx.ModuleBuild(pctx, ModuleBuildParams{
+ Rule: proto,
+ Description: "protoc " + protoFile.Rel(),
+ Outputs: outFiles,
+ Input: protoFile,
+ Args: map[string]string{
+ "outDir": ProtoDir(ctx).String(),
+ "protoOut": protoOut,
+ "protoOutFlags": protoOutFlags,
+ "protoFlags": protoFlags,
+ },
+ })
+
+ return outFiles
+}
+
+func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string {
+ var protoFlags []string
+ if len(p.Proto.Local_include_dirs) > 0 {
+ localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
+ protoFlags = append(protoFlags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
+ }
+ if len(p.Proto.Include_dirs) > 0 {
+ rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
+ protoFlags = append(protoFlags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
+ }
+
+ protoFlags = append(protoFlags, "-I .")
+
+ return protoFlags
+}
+
+// ProtoDir returns the module's "gen/proto" directory
+func ProtoDir(ctx ModuleContext) ModuleGenPath {
+ return PathForModuleGen(ctx, "proto")
+}
+
+// ProtoSubDir returns the module's "gen/proto/path/to/module" directory
+func ProtoSubDir(ctx ModuleContext) ModuleGenPath {
+ return PathForModuleGen(ctx, "proto", ctx.ModuleDir())
+}
+
+type ProtoProperties struct {
+ Proto struct {
+ // Proto generator type. C++: full or lite. Java: micro, nano, stream, or lite.
+ Type *string `android:"arch_variant"`
+
+ // list of directories that will be added to the protoc include paths.
+ Include_dirs []string
+
+ // list of directories relative to the bp file that will
+ // be added to the protoc include paths.
+ Local_include_dirs []string
+ } `android:"arch_variant"`
+}
diff --git a/android/variable.go b/android/variable.go
index 1ecd9fb..9dd9d25 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -108,6 +108,7 @@
Make_suffix *string `json:",omitempty"`
Platform_sdk_version *int `json:",omitempty"`
+ Platform_sdk_final *bool `json:",omitempty"`
Platform_version_active_codenames []string `json:",omitempty"`
Platform_version_future_codenames []string `json:",omitempty"`
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 19ed4ec..bdd3e97 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -37,6 +37,7 @@
"LOCAL_SANITIZE": sanitize(""),
"LOCAL_SANITIZE_DIAG": sanitize("diag."),
"LOCAL_CFLAGS": cflags,
+ "LOCAL_UNINSTALLABLE_MODULE": invert("installable"),
// composite functions
"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
@@ -74,6 +75,8 @@
"LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type",
"LOCAL_MODULE_OWNER": "owner",
"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
+ "LOCAL_NOTICE_FILE": "notice",
+ "LOCAL_JAVA_LANGUAGE_VERSION": "java_version",
})
addStandardProperties(bpparser.ListType,
map[string]string{
@@ -112,23 +115,25 @@
"LOCAL_AAPT_FLAGS": "aaptflags",
"LOCAL_PACKAGE_SPLITS": "package_splits",
"LOCAL_COMPATIBILITY_SUITE": "test_suites",
+
+ "LOCAL_ANNOTATION_PROCESSORS": "annotation_processors",
+ "LOCAL_ANNOTATION_PROCESSOR_CLASSES": "annotation_processor_classes",
})
addStandardProperties(bpparser.BoolType,
map[string]string{
// Bool properties
- "LOCAL_IS_HOST_MODULE": "host",
- "LOCAL_CLANG": "clang",
- "LOCAL_FORCE_STATIC_EXECUTABLE": "static_executable",
- "LOCAL_NATIVE_COVERAGE": "native_coverage",
- "LOCAL_NO_CRT": "nocrt",
- "LOCAL_ALLOW_UNDEFINED_SYMBOLS": "allow_undefined_symbols",
- "LOCAL_RTTI_FLAG": "rtti",
- "LOCAL_NO_STANDARD_LIBRARIES": "no_standard_libraries",
- "LOCAL_PACK_MODULE_RELOCATIONS": "pack_relocations",
- "LOCAL_TIDY": "tidy",
- "LOCAL_PROPRIETARY_MODULE": "proprietary",
- "LOCAL_VENDOR_MODULE": "vendor",
-
+ "LOCAL_IS_HOST_MODULE": "host",
+ "LOCAL_CLANG": "clang",
+ "LOCAL_FORCE_STATIC_EXECUTABLE": "static_executable",
+ "LOCAL_NATIVE_COVERAGE": "native_coverage",
+ "LOCAL_NO_CRT": "nocrt",
+ "LOCAL_ALLOW_UNDEFINED_SYMBOLS": "allow_undefined_symbols",
+ "LOCAL_RTTI_FLAG": "rtti",
+ "LOCAL_NO_STANDARD_LIBRARIES": "no_standard_libs",
+ "LOCAL_PACK_MODULE_RELOCATIONS": "pack_relocations",
+ "LOCAL_TIDY": "tidy",
+ "LOCAL_PROPRIETARY_MODULE": "proprietary",
+ "LOCAL_VENDOR_MODULE": "vendor",
"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
})
}
@@ -527,6 +532,19 @@
return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx)
}
+func invert(name string) func(ctx variableAssignmentContext) error {
+ return func(ctx variableAssignmentContext) error {
+ val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.BoolType)
+ if err != nil {
+ return err
+ }
+
+ val.(*bpparser.Bool).Value = !val.(*bpparser.Bool).Value
+
+ return setVariable(ctx.file, ctx.append, ctx.prefix, name, val, true)
+ }
+}
+
// given a conditional, returns a function that will insert a variable assignment or not, based on the conditional
func includeVariableIf(bpVar bpVariable, conditional func(ctx variableAssignmentContext) bool) func(ctx variableAssignmentContext) error {
return func(ctx variableAssignmentContext) error {
@@ -643,6 +661,15 @@
return fmt.Sprintf("%s/**/*.java", dir)
}
+func allProtoFilesUnder(args []string) string {
+ dir := ""
+ if len(args) > 0 {
+ dir = strings.TrimSpace(args[0])
+ }
+
+ return fmt.Sprintf("%s/**/*.proto", dir)
+}
+
func allSubdirJavaFiles(args []string) string {
return "**/*.java"
}
@@ -671,7 +698,7 @@
"SHARED_LIBRARIES": "cc_prebuilt_library_shared",
"STATIC_LIBRARIES": "cc_prebuilt_library_static",
"EXECUTABLES": "cc_prebuilt_binary",
- "JAVA_LIBRARIES": "prebuilt_java_library",
+ "JAVA_LIBRARIES": "java_import",
}
var soongModuleTypes = map[string]bool{}
@@ -681,6 +708,7 @@
globalScope.Set("CLEAR_VARS", clear_vars)
globalScope.SetFunc("my-dir", mydir)
globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
+ globalScope.SetFunc("all-proto-files-under", allProtoFilesUnder)
globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles)
for k, v := range moduleTypes {
diff --git a/cc/binary.go b/cc/binary.go
index f6e62b7..4ddaf94 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -35,6 +35,9 @@
// if set, add an extra objcopy --prefix-symbols= step
Prefix_symbols string
+ // local file name to pass to the linker as --version_script
+ Version_script *string `android:"arch_variant"`
+
// if set, install a symlink to the preferred architecture
Symlink_preferred_arch bool
@@ -231,7 +234,6 @@
"-Bstatic",
"-Wl,--gc-sections",
)
-
} else {
if flags.DynamicLinker == "" {
if binary.Properties.DynamicLinker != "" {
@@ -266,6 +268,7 @@
"-Wl,--gc-sections",
"-Wl,-z,nocopyreloc",
)
+
}
} else {
if binary.static() {
@@ -282,6 +285,7 @@
func (binary *binaryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
+ versionScript := android.OptionalPathForModuleSrc(ctx, binary.Properties.Version_script)
fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
outputFile := android.PathForModuleOut(ctx, fileName)
ret := outputFile
@@ -291,6 +295,15 @@
sharedLibs := deps.SharedLibs
sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
+ if versionScript.Valid() {
+ if ctx.Darwin() {
+ ctx.PropertyErrorf("version_script", "Not supported on Darwin")
+ } else {
+ flags.LdFlags = append(flags.LdFlags, "-Wl,--version-script,"+versionScript.String())
+ linkerDeps = append(linkerDeps, versionScript.Path())
+ }
+ }
+
if flags.DynamicLinker != "" {
flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
}
diff --git a/cc/builder.go b/cc/builder.go
index 1a4f505..b5bdc3d 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -158,6 +158,13 @@
},
"asFlags")
+ windres = pctx.AndroidStaticRule("windres",
+ blueprint.RuleParams{
+ Command: "$windresCmd $flags -I$$(dirname $in) -i $in -o $out",
+ CommandDeps: []string{"$windresCmd"},
+ },
+ "windresCmd", "flags")
+
_ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper")
// -w has been added since header-abi-dumper does not need to produce any sort of diagnostic information.
@@ -332,7 +339,8 @@
objFiles[i] = objFile
- if srcFile.Ext() == ".asm" {
+ switch srcFile.Ext() {
+ case ".asm":
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: yasm,
Description: "yasm " + srcFile.Rel(),
@@ -344,6 +352,19 @@
},
})
continue
+ case ".rc":
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: windres,
+ Description: "windres " + srcFile.Rel(),
+ Output: objFile,
+ Input: srcFile,
+ OrderOnly: deps,
+ Args: map[string]string{
+ "windresCmd": gccCmd(flags.toolchain, "windres"),
+ "flags": flags.toolchain.WindresFlags(),
+ },
+ })
+ continue
}
var moduleCflags string
diff --git a/cc/cc.go b/cc/cc.go
index 4dafc63..fe9c4a4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -465,7 +465,7 @@
// Create source abi dumps if the module belongs to the list of VndkLibraries.
func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
- return ctx.ctx.Device() && (ctx.mod.isVndk() || inList(ctx.baseModuleName(), llndkLibraries))
+ return ctx.ctx.Device() && ((ctx.vndk() && ctx.isVndk()) || inList(ctx.baseModuleName(), llndkLibraries))
}
func (ctx *moduleContextImpl) selectedStl() string {
@@ -1138,6 +1138,13 @@
// Dedup exported flags from dependencies
depPaths.Flags = firstUniqueElements(depPaths.Flags)
+ depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
+ depPaths.ReexportedFlags = firstUniqueElements(depPaths.ReexportedFlags)
+ depPaths.ReexportedFlagsDeps = android.FirstUniquePaths(depPaths.ReexportedFlagsDeps)
+
+ if c.sabi != nil {
+ c.sabi.Properties.ReexportedIncludeFlags = firstUniqueElements(c.sabi.Properties.ReexportedIncludeFlags)
+ }
return depPaths
}
@@ -1166,6 +1173,10 @@
return c.installer.hostToolPath()
}
+func (c *Module) IntermPathForModuleOut() android.OptionalPath {
+ return c.outputFile
+}
+
//
// Defaults
//
diff --git a/cc/compiler.go b/cc/compiler.go
index 0cc809d..a65ddf8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -141,6 +141,11 @@
}
}
+ Proto struct {
+ // Link statically against the protobuf runtime
+ Static bool `android:"arch_variant"`
+ } `android:"arch_variant"`
+
// Stores the original list of source files before being cleared by library reuse
OriginalSrcs []string `blueprint:"mutated"`
}
@@ -151,7 +156,7 @@
type baseCompiler struct {
Properties BaseCompilerProperties
- Proto ProtoProperties
+ Proto android.ProtoProperties
deps android.Paths
srcs android.Paths
flags builderFlags
@@ -188,7 +193,7 @@
android.ExtractSourcesDeps(ctx, compiler.Properties.Srcs)
if compiler.hasSrcExt(".proto") {
- deps = protoDeps(ctx, deps, &compiler.Proto)
+ deps = protoDeps(ctx, deps, &compiler.Proto, compiler.Properties.Proto.Static)
}
return deps
@@ -429,6 +434,11 @@
"-I"+android.PathForModuleGen(ctx, "yacc", ctx.ModuleDir()).String())
}
+ if compiler.hasSrcExt(".mc") {
+ flags.GlobalFlags = append(flags.GlobalFlags,
+ "-I"+android.PathForModuleGen(ctx, "windmc", ctx.ModuleDir()).String())
+ }
+
if compiler.hasSrcExt(".aidl") {
if len(compiler.Properties.Aidl.Local_include_dirs) > 0 {
localAidlIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Aidl.Local_include_dirs)
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index fc0282b..d62ebe4 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -70,6 +70,8 @@
YasmFlags() string
+ WindresFlags() string
+
Is64Bit() bool
ShlibSuffix() string
@@ -135,6 +137,10 @@
return ""
}
+func (toolchainBase) WindresFlags() string {
+ return ""
+}
+
func (toolchainBase) SanitizerRuntimeLibraryArch() string {
return ""
}
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 4709823..270084e 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -81,7 +81,10 @@
windowsAvailableLibraries = addPrefix([]string{
"gdi32",
"imagehlp",
+ "iphlpapi",
+ "netapi32",
"ole32",
+ "powrprof",
"psapi",
"pthread",
"userenv",
@@ -172,6 +175,14 @@
return "${config.WindowsIncludeFlags}"
}
+func (t *toolchainWindowsX86) WindresFlags() string {
+ return "-F pe-i386"
+}
+
+func (t *toolchainWindowsX8664) WindresFlags() string {
+ return "-F pe-x86-64"
+}
+
func (t *toolchainWindows) ClangSupported() bool {
return false
}
diff --git a/cc/gen.go b/cc/gen.go
index 7a22abd..9fc14c5 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -54,6 +54,13 @@
Deps: blueprint.DepsGCC,
},
"aidlFlags", "outDir")
+
+ windmc = pctx.AndroidStaticRule("windmc",
+ blueprint.RuleParams{
+ Command: "$windmcCmd -r$$(dirname $out) -h$$(dirname $out) $in",
+ CommandDeps: []string{"$windmcCmd"},
+ },
+ "windmcCmd")
)
func genYacc(ctx android.ModuleContext, yaccFile android.Path, outFile android.ModuleGenPath, yaccFlags string) (headerFile android.ModuleGenPath) {
@@ -100,6 +107,26 @@
})
}
+func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
+ headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h")
+ rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc")
+
+ windmcCmd := gccCmd(flags.toolchain, "windmc")
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: windmc,
+ Description: "windmc " + srcFile.Rel(),
+ Output: rcFile,
+ ImplicitOutput: headerFile,
+ Input: srcFile,
+ Args: map[string]string{
+ "windmcCmd": windmcCmd,
+ },
+ })
+
+ return rcFile, headerFile
+}
+
func genSources(ctx android.ModuleContext, srcFiles android.Paths,
buildFlags builderFlags) (android.Paths, android.Paths) {
@@ -126,9 +153,10 @@
srcFiles[i] = cppFile
genLex(ctx, srcFile, cppFile)
case ".proto":
- cppFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags)
- srcFiles[i] = cppFile
- deps = append(deps, headerFile)
+ protoFiles := android.GenProto(ctx, srcFile, buildFlags.protoFlags,
+ "--cpp_out", "", []string{"pb.cc", "pb.h"})
+ srcFiles[i] = protoFiles[0]
+ deps = append(deps, protoFiles[1])
case ".aidl":
cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
srcFiles[i] = cppFile
@@ -137,6 +165,10 @@
cppFile := rsGeneratedCppFile(ctx, srcFile)
rsFiles = append(rsFiles, srcFiles[i])
srcFiles[i] = cppFile
+ case ".mc":
+ rcFile, headerFile := genWinMsg(ctx, srcFile, buildFlags)
+ srcFiles[i] = rcFile
+ deps = append(deps, headerFile)
}
}
diff --git a/cc/installer.go b/cc/installer.go
index 7bedc56..027d191 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -76,7 +76,7 @@
}
func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
- installer.path = ctx.InstallFile(installer.installDir(ctx), file)
+ installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
}
func (installer *baseInstaller) inData() bool {
diff --git a/cc/library.go b/cc/library.go
index 1537fd4..2a866dc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -349,7 +349,7 @@
return Objects{}
}
if ctx.createVndkSourceAbiDump() || library.sabi.Properties.CreateSAbiDumps {
- exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+ exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
var SourceAbiFlags []string
for _, dir := range exportIncludeDirs.Strings() {
SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
@@ -600,7 +600,7 @@
if versionScript.Valid() {
symbolFile = versionScript
}
- exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+ exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
var SourceAbiFlags []string
for _, dir := range exportIncludeDirs.Strings() {
SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
@@ -655,8 +655,8 @@
if library.Properties.Proto.Export_proto_headers {
if library.baseCompiler.hasSrcExt(".proto") {
flags := []string{
- "-I" + protoSubDir(ctx).String(),
- "-I" + protoDir(ctx).String(),
+ "-I" + android.ProtoSubDir(ctx).String(),
+ "-I" + android.ProtoDir(ctx).String(),
}
library.reexportFlags(flags)
library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
diff --git a/cc/linker.go b/cc/linker.go
index 678b992..59c979d 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -213,6 +213,18 @@
CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs)
flags.LdFlags = append(flags.LdFlags, linker.Properties.Host_ldlibs...)
+
+ if !ctx.Windows() {
+ // Add -ldl, -lpthread and -lrt to host builds to match the default behavior of device
+ // builds
+ flags.LdFlags = append(flags.LdFlags,
+ "-ldl",
+ "-lpthread",
+ )
+ if !ctx.Darwin() {
+ flags.LdFlags = append(flags.LdFlags, "-lrt")
+ }
+ }
}
}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5fa3232..140cc2f 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -122,7 +122,7 @@
srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
for _, header := range srcFiles {
installDir := getHeaderInstallDir(ctx, header, m.properties.From, m.properties.To)
- installedPath := ctx.InstallFile(installDir, header)
+ installedPath := ctx.InstallFile(installDir, header.Base(), header)
installPath := installDir.Join(ctx, header.Base())
if installPath != installedPath {
panic(fmt.Sprintf(
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index fc7cd91..a408fc5 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -341,7 +341,7 @@
installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
- stub.installPath = ctx.InstallFile(installDir, path).String()
+ stub.installPath = ctx.InstallFile(installDir, path.Base(), path).String()
}
func newStubLibrary() *Module {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 089ce28..9fca053 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -125,7 +125,7 @@
outputFile := android.PathForModuleOut(ctx, fileName)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
- Rule: android.Cp,
+ Rule: android.CpExecutable,
Description: "prebuilt",
Output: outputFile,
Input: p.Prebuilt.SingleSourcePath(ctx),
diff --git a/cc/proto.go b/cc/proto.go
index 6c1789a..6049d44 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -15,81 +15,13 @@
package cc
import (
- "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
)
-func init() {
- pctx.HostBinToolVariable("protocCmd", "aprotoc")
-}
-
-var (
- proto = pctx.AndroidStaticRule("protoc",
- blueprint.RuleParams{
- Command: "$protocCmd --cpp_out=$outDir $protoFlags $in",
- CommandDeps: []string{"$protocCmd"},
- }, "protoFlags", "outDir")
-)
-
-// TODO(ccross): protos are often used to communicate between multiple modules. If the only
-// way to convert a proto to source is to reference it as a source file, and external modules cannot
-// reference source files in other modules, then every module that owns a proto file will need to
-// export a library for every type of external user (lite vs. full, c vs. c++ vs. java). It would
-// be better to support a proto module type that exported a proto file along with some include dirs,
-// and then external modules could depend on the proto module but use their own settings to
-// generate the source.
-
-func genProto(ctx android.ModuleContext, protoFile android.Path,
- protoFlags string) (android.ModuleGenPath, android.ModuleGenPath) {
-
- outFile := android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc")
- headerFile := android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
- ctx.ModuleBuild(pctx, android.ModuleBuildParams{
- Rule: proto,
- Description: "protoc " + protoFile.Rel(),
- Outputs: android.WritablePaths{outFile, headerFile},
- Input: protoFile,
- Args: map[string]string{
- "outDir": protoDir(ctx).String(),
- "protoFlags": protoFlags,
- },
- })
-
- return outFile, headerFile
-}
-
-// protoDir returns the module's "gen/proto" directory
-func protoDir(ctx android.ModuleContext) android.ModuleGenPath {
- return android.PathForModuleGen(ctx, "proto")
-}
-
-// protoSubDir returns the module's "gen/proto/path/to/module" directory
-func protoSubDir(ctx android.ModuleContext) android.ModuleGenPath {
- return android.PathForModuleGen(ctx, "proto", ctx.ModuleDir())
-}
-
-type ProtoProperties struct {
- Proto struct {
- // Proto generator type (full, lite)
- Type *string `android:"arch_variant"`
-
- // Link statically against the protobuf runtime
- Static bool `android:"arch_variant"`
-
- // list of directories that will be added to the protoc include paths.
- Include_dirs []string
-
- // list of directories relative to the Android.bp file that will
- // be added to the protoc include paths.
- Local_include_dirs []string
- } `android:"arch_variant"`
-}
-
-func protoDeps(ctx BaseModuleContext, deps Deps, p *ProtoProperties) Deps {
+func protoDeps(ctx BaseModuleContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
var lib string
- var static bool
switch proptools.String(p.Proto.Type) {
case "full":
@@ -105,9 +37,6 @@
static = true
} else {
lib = "libprotobuf-cpp-lite"
- if p.Proto.Static {
- static = true
- }
}
default:
ctx.PropertyErrorf("proto.type", "unknown proto type %q",
@@ -125,23 +54,14 @@
return deps
}
-func protoFlags(ctx ModuleContext, flags Flags, p *ProtoProperties) Flags {
+func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags {
flags.CFlags = append(flags.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
flags.GlobalFlags = append(flags.GlobalFlags,
- "-I"+protoSubDir(ctx).String(),
- "-I"+protoDir(ctx).String(),
+ "-I"+android.ProtoSubDir(ctx).String(),
+ "-I"+android.ProtoDir(ctx).String(),
)
- if len(p.Proto.Local_include_dirs) > 0 {
- localProtoIncludeDirs := android.PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
- flags.protoFlags = append(flags.protoFlags, includeDirsToFlags(localProtoIncludeDirs))
- }
- if len(p.Proto.Include_dirs) > 0 {
- rootProtoIncludeDirs := android.PathsForSource(ctx, p.Proto.Include_dirs)
- flags.protoFlags = append(flags.protoFlags, includeDirsToFlags(rootProtoIncludeDirs))
- }
-
- flags.protoFlags = append(flags.protoFlags, "-I .")
+ flags.protoFlags = android.ProtoFlags(ctx, p)
return flags
}
diff --git a/cc/sabi.go b/cc/sabi.go
index 15d980c..e45b040 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -79,7 +79,7 @@
func sabiDepsMutator(mctx android.TopDownMutatorContext) {
if c, ok := mctx.Module().(*Module); ok &&
- (c.isVndk() || inList(c.Name(), llndkLibraries) ||
+ ((c.isVndk() && c.vndk()) || inList(c.Name(), llndkLibraries) ||
(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
mctx.VisitDirectDeps(func(m blueprint.Module) {
tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/test.go b/cc/test.go
index a52e94a..1501a26 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -337,8 +337,8 @@
func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) {
benchmark.data = ctx.ExpandSources(benchmark.Properties.Data, nil)
- benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName())
- benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName())
+ benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName())
+ benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
benchmark.binaryDecorator.baseInstaller.install(ctx, file)
}
@@ -355,7 +355,7 @@
module, binary := NewBinary(hod)
module.multilib = android.MultilibBoth
- binary.baseInstaller = NewTestInstaller()
+ binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData)
benchmark := &benchmarkDecorator{
binaryDecorator: binary,
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
new file mode 100644
index 0000000..ace079d
--- /dev/null
+++ b/cmd/merge_zips/Android.bp
@@ -0,0 +1,25 @@
+// Copyright 2017 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.
+
+blueprint_go_binary {
+ name: "merge_zips",
+ deps: [
+ "android-archive-zip",
+ "soong-jar",
+ ],
+ srcs: [
+ "merge_zips.go",
+ ],
+}
+
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
new file mode 100644
index 0000000..7874a41
--- /dev/null
+++ b/cmd/merge_zips/merge_zips.go
@@ -0,0 +1,182 @@
+// Copyright 2017 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 main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "sort"
+ "strings"
+
+ "android/soong/jar"
+ "android/soong/third_party/zip"
+)
+
+var (
+ sortEntries = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
+ emulateJar = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
+)
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprintln(os.Stderr, "usage: merge_zips [-j] output [inputs...]")
+ flag.PrintDefaults()
+ }
+
+ // parse args
+ flag.Parse()
+ args := flag.Args()
+ if len(args) < 2 {
+ flag.Usage()
+ os.Exit(1)
+ }
+ outputPath := args[0]
+ inputs := args[1:]
+
+ log.SetFlags(log.Lshortfile)
+
+ // make writer
+ output, err := os.Create(outputPath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer output.Close()
+ writer := zip.NewWriter(output)
+ defer func() {
+ err := writer.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ // make readers
+ readers := []namedZipReader{}
+ for _, input := range inputs {
+ reader, err := zip.OpenReader(input)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer reader.Close()
+ namedReader := namedZipReader{path: input, reader: reader}
+ readers = append(readers, namedReader)
+ }
+
+ // do merge
+ if err := mergeZips(readers, writer, *sortEntries, *emulateJar); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// a namedZipReader reads a .zip file and can say which file it's reading
+type namedZipReader struct {
+ path string
+ reader *zip.ReadCloser
+}
+
+// a zipEntryPath refers to a file contained in a zip
+type zipEntryPath struct {
+ zipName string
+ entryName string
+}
+
+func (p zipEntryPath) String() string {
+ return p.zipName + "/" + p.entryName
+}
+
+// a zipEntry knows the location and content of a file within a zip
+type zipEntry struct {
+ path zipEntryPath
+ content *zip.File
+}
+
+// a fileMapping specifies to copy a zip entry from one place to another
+type fileMapping struct {
+ source zipEntry
+ dest string
+}
+
+func mergeZips(readers []namedZipReader, writer *zip.Writer, sortEntries bool, emulateJar bool) error {
+
+ mappingsByDest := make(map[string]fileMapping, 0)
+ orderedMappings := []fileMapping{}
+
+ for _, namedReader := range readers {
+ for _, file := range namedReader.reader.File {
+ // check for other files or directories destined for the same path
+ dest := file.Name
+ mapKey := dest
+ if strings.HasSuffix(mapKey, "/") {
+ mapKey = mapKey[:len(mapKey)-1]
+ }
+ existingMapping, exists := mappingsByDest[mapKey]
+
+ // make a new entry to add
+ source := zipEntry{path: zipEntryPath{zipName: namedReader.path, entryName: file.Name}, content: file}
+ newMapping := fileMapping{source: source, dest: dest}
+
+ if exists {
+ // handle duplicates
+ wasDir := existingMapping.source.content.FileHeader.FileInfo().IsDir()
+ isDir := newMapping.source.content.FileHeader.FileInfo().IsDir()
+ if wasDir != isDir {
+ return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
+ dest, existingMapping.source.path, newMapping.source.path)
+ }
+ if emulateJar &&
+ file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass {
+ // Skip manifest and module info files that are not from the first input file
+ continue
+ }
+ if !isDir {
+ return fmt.Errorf("Duplicate path %v found in %v and %v\n",
+ dest, existingMapping.source.path, newMapping.source.path)
+ }
+ } else {
+ // save entry
+ mappingsByDest[mapKey] = newMapping
+ orderedMappings = append(orderedMappings, newMapping)
+ }
+ }
+
+ }
+
+ if emulateJar {
+ jarSort(orderedMappings)
+ } else if sortEntries {
+ alphanumericSort(orderedMappings)
+ }
+
+ for _, entry := range orderedMappings {
+ if err := writer.CopyFrom(entry.source.content, entry.dest); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func jarSort(files []fileMapping) {
+ sort.SliceStable(files, func(i, j int) bool {
+ return jar.EntryNamesLess(files[i].dest, files[j].dest)
+ })
+}
+
+func alphanumericSort(files []fileMapping) {
+ sort.SliceStable(files, func(i, j int) bool {
+ return files[i].dest < files[j].dest
+ })
+}
diff --git a/cmd/soong_zip/soong_zip.go b/cmd/soong_zip/soong_zip.go
index bb2a70f..4cf0764 100644
--- a/cmd/soong_zip/soong_zip.go
+++ b/cmd/soong_zip/soong_zip.go
@@ -57,9 +57,15 @@
return nil
}
+type byteReaderCloser struct {
+ bytes.Reader
+ io.Closer
+}
+
type fileArg struct {
pathPrefixInZip, sourcePrefixToStrip string
sourceFiles []string
+ globDir string
}
type pathMapping struct {
@@ -89,13 +95,15 @@
type listFiles struct{}
+type dir struct{}
+
func (f *file) String() string {
return `""`
}
func (f *file) Set(s string) error {
if *relativeRoot == "" {
- return fmt.Errorf("must pass -C before -f or -l")
+ return fmt.Errorf("must pass -C before -f")
}
fArgs = append(fArgs, fileArg{
@@ -113,7 +121,7 @@
func (l *listFiles) Set(s string) error {
if *relativeRoot == "" {
- return fmt.Errorf("must pass -C before -f or -l")
+ return fmt.Errorf("must pass -C before -l")
}
list, err := ioutil.ReadFile(s)
@@ -130,12 +138,30 @@
return nil
}
+func (d *dir) String() string {
+ return `""`
+}
+
+func (d *dir) Set(s string) error {
+ if *relativeRoot == "" {
+ return fmt.Errorf("must pass -C before -D")
+ }
+
+ fArgs = append(fArgs, fileArg{
+ pathPrefixInZip: filepath.Clean(*rootPrefix),
+ sourcePrefixToStrip: filepath.Clean(*relativeRoot),
+ globDir: filepath.Clean(s),
+ })
+
+ return nil
+}
+
var (
out = flag.String("o", "", "file to write zip file to")
manifest = flag.String("m", "", "input jar manifest file name")
directories = flag.Bool("d", false, "include directories in zip")
rootPrefix = flag.String("P", "", "path prefix within the zip at which to place files")
- relativeRoot = flag.String("C", "", "path to use as relative root of files in next -f or -l argument")
+ relativeRoot = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments")
parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use")
compLevel = flag.Int("L", 5, "deflate compression level (0-9)")
emulateJar = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
@@ -149,6 +175,7 @@
func init() {
flag.Var(&listFiles{}, "l", "file containing list of .class files")
+ flag.Var(&dir{}, "D", "directory to include in zip")
flag.Var(&file{}, "f", "file to include in zip")
flag.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
}
@@ -160,9 +187,10 @@
}
type zipWriter struct {
- time time.Time
- createdDirs map[string]bool
- directories bool
+ time time.Time
+ createdFiles map[string]string
+ createdDirs map[string]string
+ directories bool
errors chan error
writeOps chan chan *zipEntry
@@ -224,19 +252,23 @@
}
w := &zipWriter{
- time: time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
- createdDirs: make(map[string]bool),
- directories: *directories,
- compLevel: *compLevel,
+ time: time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC),
+ createdDirs: make(map[string]string),
+ createdFiles: make(map[string]string),
+ directories: *directories,
+ compLevel: *compLevel,
}
pathMappings := []pathMapping{}
- set := make(map[string]string)
for _, fa := range fArgs {
- for _, src := range fa.sourceFiles {
+ srcs := fa.sourceFiles
+ if fa.globDir != "" {
+ srcs = append(srcs, recursiveGlobFiles(fa.globDir)...)
+ }
+ for _, src := range srcs {
if err := fillPathPairs(fa.pathPrefixInZip,
- fa.sourcePrefixToStrip, src, set, &pathMappings); err != nil {
+ fa.sourcePrefixToStrip, src, &pathMappings); err != nil {
log.Fatal(err)
}
}
@@ -249,7 +281,7 @@
}
}
-func fillPathPairs(prefix, rel, src string, set map[string]string, pathMappings *[]pathMapping) error {
+func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping) error {
src = strings.TrimSpace(src)
if src == "" {
return nil
@@ -261,14 +293,6 @@
}
dest = filepath.Join(prefix, dest)
- if _, found := set[dest]; found {
- return fmt.Errorf("found two file paths to be copied into dest path: %q,"+
- " both [%q]%q and [%q]%q!",
- dest, dest, src, dest, set[dest])
- } else {
- set[dest] = src
- }
-
zipMethod := zip.Deflate
if _, found := nonDeflatedFiles[dest]; found {
zipMethod = zip.Store
@@ -286,6 +310,13 @@
sort.SliceStable(mappings, less)
}
+type readerSeekerCloser interface {
+ io.Reader
+ io.ReaderAt
+ io.Closer
+ io.Seeker
+}
+
func (z *zipWriter) write(out string, pathMappings []pathMapping, manifest string) error {
f, err := os.Create(out)
if err != nil {
@@ -326,7 +357,7 @@
if !*emulateJar {
return errors.New("must specify --jar when specifying a manifest via -m")
}
- pathMappings = append(pathMappings, pathMapping{"META-INF/MANIFEST.MF", manifest, zip.Deflate})
+ pathMappings = append(pathMappings, pathMapping{jar.ManifestFile, manifest, zip.Deflate})
}
if *emulateJar {
@@ -338,7 +369,11 @@
defer close(z.writeOps)
for _, ele := range pathMappings {
- err = z.writeFile(ele.dest, ele.src, ele.zipMethod)
+ if *emulateJar && ele.dest == jar.ManifestFile {
+ err = z.addManifest(ele.dest, ele.src, ele.zipMethod)
+ } else {
+ err = z.addFile(ele.dest, ele.src, ele.zipMethod)
+ }
if err != nil {
z.errors <- err
return
@@ -434,7 +469,8 @@
}
}
-func (z *zipWriter) writeFile(dest, src string, method uint16) error {
+// imports (possibly with compression) <src> into the zip at sub-path <dest>
+func (z *zipWriter) addFile(dest, src string, method uint16) error {
var fileSize int64
var executable bool
@@ -442,42 +478,31 @@
return err
} else if s.IsDir() {
if z.directories {
- return z.writeDirectory(dest)
+ return z.writeDirectory(dest, src)
}
return nil
- } else if s.Mode()&os.ModeSymlink != 0 {
- return z.writeSymlink(dest, src)
- } else if !s.Mode().IsRegular() {
- return fmt.Errorf("%s is not a file, directory, or symlink", src)
} else {
- fileSize = s.Size()
- executable = s.Mode()&0100 != 0
- }
-
- if z.directories {
- dir, _ := filepath.Split(dest)
- err := z.writeDirectory(dir)
- if err != nil {
+ if err := z.writeDirectory(filepath.Dir(dest), src); err != nil {
return err
}
- }
- compressChan := make(chan *zipEntry, 1)
- z.writeOps <- compressChan
+ if prev, exists := z.createdDirs[dest]; exists {
+ return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
+ }
+ if prev, exists := z.createdFiles[dest]; exists {
+ return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+ }
- // Pre-fill a zipEntry, it will be sent in the compressChan once
- // we're sure about the Method and CRC.
- ze := &zipEntry{
- fh: &zip.FileHeader{
- Name: dest,
- Method: method,
+ z.createdFiles[dest] = src
- UncompressedSize64: uint64(fileSize),
- },
- }
- ze.fh.SetModTime(z.time)
- if executable {
- ze.fh.SetMode(0700)
+ if s.Mode()&os.ModeSymlink != 0 {
+ return z.writeSymlink(dest, src)
+ } else if !s.Mode().IsRegular() {
+ return fmt.Errorf("%s is not a file, directory, or symlink", src)
+ }
+
+ fileSize = s.Size()
+ executable = s.Mode()&0100 != 0
}
r, err := os.Open(src)
@@ -485,11 +510,78 @@
return err
}
- ze.allocatedSize = fileSize
+ header := &zip.FileHeader{
+ Name: dest,
+ Method: method,
+ UncompressedSize64: uint64(fileSize),
+ }
+
+ if executable {
+ header.SetMode(0700)
+ }
+
+ return z.writeFileContents(header, r)
+}
+
+func (z *zipWriter) addManifest(dest string, src string, method uint16) error {
+ givenBytes, err := ioutil.ReadFile(src)
+ if err != nil {
+ return err
+ }
+
+ if prev, exists := z.createdDirs[dest]; exists {
+ return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
+ }
+ if prev, exists := z.createdFiles[dest]; exists {
+ return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+ }
+
+ manifestMarker := []byte("Manifest-Version:")
+ header := append(manifestMarker, []byte(" 1.0\nCreated-By: soong_zip\n")...)
+
+ var finalBytes []byte
+ if !bytes.Contains(givenBytes, manifestMarker) {
+ finalBytes = append(append(header, givenBytes...), byte('\n'))
+ } else {
+ finalBytes = givenBytes
+ }
+
+ byteReader := bytes.NewReader(finalBytes)
+
+ reader := &byteReaderCloser{*byteReader, ioutil.NopCloser(nil)}
+
+ fileHeader := &zip.FileHeader{
+ Name: dest,
+ Method: zip.Store,
+ UncompressedSize64: uint64(byteReader.Len()),
+ }
+
+ return z.writeFileContents(fileHeader, reader)
+}
+
+func (z *zipWriter) writeFileContents(header *zip.FileHeader, r readerSeekerCloser) (err error) {
+
+ header.SetModTime(z.time)
+
+ compressChan := make(chan *zipEntry, 1)
+ z.writeOps <- compressChan
+
+ // Pre-fill a zipEntry, it will be sent in the compressChan once
+ // we're sure about the Method and CRC.
+ ze := &zipEntry{
+ fh: header,
+ }
+
+ ze.allocatedSize = int64(header.UncompressedSize64)
z.cpuRateLimiter.Request()
z.memoryRateLimiter.Request(ze.allocatedSize)
- if method == zip.Deflate && fileSize >= minParallelFileSize {
+ fileSize := int64(header.UncompressedSize64)
+ if fileSize == 0 {
+ fileSize = int64(header.UncompressedSize)
+ }
+
+ if header.Method == zip.Deflate && fileSize >= minParallelFileSize {
wg := new(sync.WaitGroup)
// Allocate enough buffer to hold all readers. We'll limit
@@ -499,7 +591,7 @@
// Calculate the CRC in the background, since reading the entire
// file could take a while.
//
- // We could split this up into chuncks as well, but it's faster
+ // We could split this up into chunks as well, but it's faster
// than the compression. Due to the Go Zip API, we also need to
// know the result before we can begin writing the compressed
// data out to the zipfile.
@@ -517,6 +609,9 @@
var dict []byte
if start >= windowSize {
dict, err = ioutil.ReadAll(io.NewSectionReader(r, start-windowSize, windowSize))
+ if err != nil {
+ return err
+ }
}
wg.Add(1)
@@ -526,12 +621,15 @@
close(ze.futureReaders)
// Close the file handle after all readers are done
- go func(wg *sync.WaitGroup, f *os.File) {
+ go func(wg *sync.WaitGroup, closer io.Closer) {
wg.Wait()
- f.Close()
+ closer.Close()
}(wg, r)
} else {
- go z.compressWholeFile(ze, r, compressChan)
+ go func() {
+ z.compressWholeFile(ze, r, compressChan)
+ r.Close()
+ }()
}
return nil
@@ -601,8 +699,7 @@
return buf, nil
}
-func (z *zipWriter) compressWholeFile(ze *zipEntry, r *os.File, compressChan chan *zipEntry) {
- defer r.Close()
+func (z *zipWriter) compressWholeFile(ze *zipEntry, r io.ReadSeeker, compressChan chan *zipEntry) {
crc := crc32.NewIEEE()
_, err := io.Copy(crc, r)
@@ -619,13 +716,13 @@
return
}
- readFile := func(r *os.File) ([]byte, error) {
- _, err = r.Seek(0, 0)
+ readFile := func(reader io.ReadSeeker) ([]byte, error) {
+ _, err := reader.Seek(0, 0)
if err != nil {
return nil, err
}
- buf, err := ioutil.ReadAll(r)
+ buf, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
@@ -686,53 +783,57 @@
zipHeader.Extra = append(zipHeader.Extra, data...)
}
-func (z *zipWriter) writeDirectory(dir string) error {
+// writeDirectory annotates that dir is a directory created for the src file or directory, and adds
+// the directory entry to the zip file if directories are enabled.
+func (z *zipWriter) writeDirectory(dir, src string) error {
// clean the input
- cleanDir := filepath.Clean(dir)
+ dir = filepath.Clean(dir)
// discover any uncreated directories in the path
zipDirs := []string{}
- for cleanDir != "" && cleanDir != "." && !z.createdDirs[cleanDir] {
+ for dir != "" && dir != "." {
+ if _, exists := z.createdDirs[dir]; exists {
+ break
+ }
- z.createdDirs[cleanDir] = true
+ if prev, exists := z.createdFiles[dir]; exists {
+ return fmt.Errorf("destination %q is both a directory %q and a file %q", dir, src, prev)
+ }
+
+ z.createdDirs[dir] = src
// parent directories precede their children
- zipDirs = append([]string{cleanDir}, zipDirs...)
+ zipDirs = append([]string{dir}, zipDirs...)
- cleanDir = filepath.Dir(cleanDir)
+ dir = filepath.Dir(dir)
}
- // make a directory entry for each uncreated directory
- for _, cleanDir := range zipDirs {
- dirHeader := &zip.FileHeader{
- Name: cleanDir + "/",
- }
- dirHeader.SetMode(0700 | os.ModeDir)
- dirHeader.SetModTime(z.time)
+ if z.directories {
+ // make a directory entry for each uncreated directory
+ for _, cleanDir := range zipDirs {
+ dirHeader := &zip.FileHeader{
+ Name: cleanDir + "/",
+ }
+ dirHeader.SetMode(0700 | os.ModeDir)
+ dirHeader.SetModTime(z.time)
- if *emulateJar && dir == "META-INF/" {
- // Jar files have a 0-length extra field with header "CAFE"
- z.addExtraField(dirHeader, [2]byte{0xca, 0xfe}, []byte{})
- }
+ if *emulateJar && dir == "META-INF/" {
+ // Jar files have a 0-length extra field with header "CAFE"
+ z.addExtraField(dirHeader, [2]byte{0xca, 0xfe}, []byte{})
+ }
- ze := make(chan *zipEntry, 1)
- ze <- &zipEntry{
- fh: dirHeader,
+ ze := make(chan *zipEntry, 1)
+ ze <- &zipEntry{
+ fh: dirHeader,
+ }
+ close(ze)
+ z.writeOps <- ze
}
- close(ze)
- z.writeOps <- ze
}
return nil
}
func (z *zipWriter) writeSymlink(rel, file string) error {
- if z.directories {
- dir, _ := filepath.Split(rel)
- if err := z.writeDirectory(dir); err != nil {
- return err
- }
- }
-
fileHeader := &zip.FileHeader{
Name: rel,
}
@@ -761,3 +862,15 @@
return nil
}
+
+func recursiveGlobFiles(path string) []string {
+ var files []string
+ filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+ if !info.IsDir() {
+ files = append(files, path)
+ }
+ return nil
+ })
+
+ return files
+}
diff --git a/jar/jar.go b/jar/jar.go
index d8f063c..5960bf0 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -19,6 +19,12 @@
"strings"
)
+const (
+ MetaDir = "META-INF/"
+ ManifestFile = MetaDir + "MANIFEST.MF"
+ ModuleInfoClass = "module-info.class"
+)
+
// EntryNamesLess tells whether <filepathA> should precede <filepathB> in
// the order of files with a .jar
func EntryNamesLess(filepathA string, filepathB string) (less bool) {
@@ -39,9 +45,9 @@
}
var jarOrder = []string{
- "META-INF/",
- "META-INF/MANIFEST.MF",
- "META-INF/*",
+ MetaDir,
+ ManifestFile,
+ MetaDir + "*",
"*",
}
diff --git a/java/androidmk.go b/java/androidmk.go
index 12643cf..680d864 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -26,9 +26,12 @@
return android.AndroidMkData{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(library.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := .jar")
+ if library.properties.Installable != nil && *library.properties.Installable == false {
+ fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ }
},
},
}
@@ -38,9 +41,10 @@
return android.AndroidMkData{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(prebuilt.combinedClasspathFile),
+ Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := .jar")
+ fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
},
},
}
@@ -50,10 +54,11 @@
return android.AndroidMkData{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(binary.outputFile),
- SubName: ".jar",
+ Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
android.WriteAndroidMkData(w, data)
+ fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
fmt.Fprintln(w, "include $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_MODULE := "+name)
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := EXECUTABLES")
@@ -61,9 +66,12 @@
fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
}
fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+name+".jar")
- fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE := "+binary.wrapperFile.String())
+ fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", binary.wrapperFile.String())
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+
+ // Ensure that the wrapper script timestamp is always updated when the jar is updated
+ fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
+ fmt.Fprintln(w, "jar_installed_module :=")
},
}
}
diff --git a/java/app.go b/java/app.go
index ceb7791..e6b91a7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -21,6 +21,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
)
@@ -68,7 +69,7 @@
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
- if !a.properties.No_standard_libraries {
+ if !proptools.Bool(a.properties.No_standard_libs) {
switch a.deviceProperties.Sdk_version { // TODO: Res_sdk_version?
case "current", "system_current", "":
ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
@@ -150,7 +151,7 @@
}
a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates)
- ctx.InstallFileName(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+ ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
}
var aaptIgnoreFilenames = []string{
diff --git a/java/builder.go b/java/builder.go
index efe0a6b..d6f8c5b 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -21,9 +21,10 @@
import (
"strings"
- "android/soong/android"
-
"github.com/google/blueprint"
+
+ "android/soong/android"
+ "android/soong/java/config"
)
var (
@@ -38,12 +39,31 @@
javac = pctx.AndroidGomaStaticRule("javac",
blueprint.RuleParams{
Command: `rm -rf "$outDir" "$annoDir" && mkdir -p "$outDir" "$annoDir" && ` +
- `${config.JavacWrapper}${config.JavacCmd} ${config.CommonJdkFlags} ` +
+ `${config.JavacWrapper}${config.JavacCmd} ${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
`$javacFlags $bootClasspath $classpath ` +
`-source $javaVersion -target $javaVersion ` +
`-d $outDir -s $annoDir @$out.rsp && ` +
- `find $outDir -type f | sort | ${config.JarArgsCmd} $outDir > $out`,
- CommandDeps: []string{"${config.JavacCmd}", "${config.JarArgsCmd}"},
+ `${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
+ CommandDeps: []string{"${config.JavacCmd}", "${config.SoongZipCmd}"},
+ Rspfile: "$out.rsp",
+ RspfileContent: "$in",
+ },
+ "javacFlags", "bootClasspath", "classpath", "outDir", "annoDir", "javaVersion")
+
+ errorprone = pctx.AndroidStaticRule("errorprone",
+ blueprint.RuleParams{
+ Command: `rm -rf "$outDir" "$annoDir" && mkdir -p "$outDir" "$annoDir" && ` +
+ `${config.ErrorProneCmd} ` +
+ `$javacFlags $bootClasspath $classpath ` +
+ `-source $javaVersion -target $javaVersion ` +
+ `-d $outDir -s $annoDir @$out.rsp && ` +
+ `${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
+ CommandDeps: []string{
+ "${config.JavaCmd}",
+ "${config.ErrorProneJavacJar}",
+ "${config.ErrorProneJar}",
+ "${config.SoongZipCmd}",
+ },
Rspfile: "$out.rsp",
RspfileContent: "$in",
},
@@ -51,17 +71,24 @@
jar = pctx.AndroidStaticRule("jar",
blueprint.RuleParams{
- Command: `${config.JarCmd} $operation ${out}.tmp $manifest $jarArgs && ${config.Zip2ZipCmd} -t -i ${out}.tmp -o ${out} && rm ${out}.tmp`,
- CommandDeps: []string{"${config.JarCmd}"},
+ Command: `${config.SoongZipCmd} -jar -o $out $jarArgs`,
+ CommandDeps: []string{"${config.SoongZipCmd}"},
},
- "operation", "manifest", "jarArgs")
+ "jarArgs")
+
+ combineJar = pctx.AndroidStaticRule("combineJar",
+ blueprint.RuleParams{
+ Command: `${config.MergeZipsCmd} -j $out $in`,
+ CommandDeps: []string{"${config.MergeZipsCmd}"},
+ },
+ "outDir")
dx = pctx.AndroidStaticRule("dx",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `${config.DxCmd} --dex --output=$outDir $dxFlags $in && ` +
- `find "$outDir" -name "classes*.dex" | sort | ${config.JarArgsCmd} ${outDir} > $out`,
- CommandDeps: []string{"${config.DxCmd}", "${config.JarArgsCmd}"},
+ `${config.DxCmd} --dex --output=$outDir $dxFlags $in || ( rm -rf "$outDir"; exit 41 ) && ` +
+ `find "$outDir" -name "classes*.dex" | sort > $out`,
+ CommandDeps: []string{"${config.DxCmd}"},
},
"outDir", "dxFlags")
@@ -71,22 +98,6 @@
CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
},
"rulesFile")
-
- extractPrebuilt = pctx.AndroidStaticRule("extractPrebuilt",
- blueprint.RuleParams{
- Command: `rm -rf $outDir && unzip -qo $in -d $outDir && ` +
- `find $outDir -name "*.class" | sort | ${config.JarArgsCmd} ${outDir} > $classFile && ` +
- `find $outDir -type f -a \! -name "*.class" -a \! -name "MANIFEST.MF" | sort | ${config.JarArgsCmd} ${outDir} > $resourceFile`,
- CommandDeps: []string{"${config.JarArgsCmd}"},
- },
- "outDir", "classFile", "resourceFile")
-
- fileListToJarArgs = pctx.AndroidStaticRule("fileListToJarArgs",
- blueprint.RuleParams{
- Command: `${config.JarArgsCmd} -f $in -p ${outDir} -o $out`,
- CommandDeps: []string{"${config.JarjarCmd}"},
- },
- "outDir")
)
func init() {
@@ -103,23 +114,19 @@
}
type jarSpec struct {
- android.ModuleOutPath
+ fileList, dir android.Path
}
-func (j jarSpec) jarArgs() string {
- return "@" + j.String()
+func (j jarSpec) soongJarArgs() string {
+ return "-C " + j.dir.String() + " -l " + j.fileList.String()
}
-func (j jarSpec) path() android.Path {
- return j.ModuleOutPath
-}
-
-func TransformJavaToClasses(ctx android.ModuleContext, srcFiles android.Paths, srcFileLists android.Paths,
- flags javaBuilderFlags, deps android.Paths) jarSpec {
+func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths,
+ flags javaBuilderFlags, deps android.Paths) android.ModuleOutPath {
classDir := android.PathForModuleOut(ctx, "classes")
annoDir := android.PathForModuleOut(ctx, "anno")
- classFileList := android.PathForModuleOut(ctx, "classes.list")
+ classJar := android.PathForModuleOut(ctx, "classes.jar")
javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@")
@@ -128,6 +135,41 @@
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: javac,
Description: "javac",
+ Output: classJar,
+ Inputs: srcFiles,
+ Implicits: deps,
+ Args: map[string]string{
+ "javacFlags": javacFlags,
+ "bootClasspath": flags.bootClasspath,
+ "classpath": flags.classpath,
+ "outDir": classDir.String(),
+ "annoDir": annoDir.String(),
+ "javaVersion": flags.javaVersion,
+ },
+ })
+
+ return classJar
+}
+
+func RunErrorProne(ctx android.ModuleContext, srcFiles android.Paths, srcFileLists android.Paths,
+ flags javaBuilderFlags, deps android.Paths) android.Path {
+
+ if config.ErrorProneJar == "" {
+ ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
+ return nil
+ }
+
+ classDir := android.PathForModuleOut(ctx, "classes-errorprone")
+ annoDir := android.PathForModuleOut(ctx, "anno-errorprone")
+ classFileList := android.PathForModuleOut(ctx, "classes-errorprone.list")
+
+ javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@")
+
+ deps = append(deps, srcFileLists...)
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: errorprone,
+ Description: "errorprone",
Output: classFileList,
Inputs: srcFiles,
Implicits: deps,
@@ -141,26 +183,24 @@
},
})
- return jarSpec{classFileList}
+ return classFileList
}
-func TransformClassesToJar(ctx android.ModuleContext, classes []jarSpec,
- manifest android.OptionalPath) android.Path {
+func TransformResourcesToJar(ctx android.ModuleContext, resources []jarSpec,
+ manifest android.OptionalPath, deps android.Paths) android.Path {
- outputFile := android.PathForModuleOut(ctx, "classes-full-debug.jar")
+ outputFile := android.PathForModuleOut(ctx, "res.jar")
- deps := android.Paths{}
jarArgs := []string{}
- for _, j := range classes {
- deps = append(deps, j.path())
- jarArgs = append(jarArgs, j.jarArgs())
+ for _, j := range resources {
+ deps = append(deps, j.fileList)
+ jarArgs = append(jarArgs, j.soongJarArgs())
}
- operation := "cf"
if manifest.Valid() {
- operation = "cfm"
deps = append(deps, manifest.Path())
+ jarArgs = append(jarArgs, "-m "+manifest.String())
}
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@@ -169,15 +209,31 @@
Output: outputFile,
Implicits: deps,
Args: map[string]string{
- "jarArgs": strings.Join(jarArgs, " "),
- "operation": operation,
- "manifest": manifest.String(),
+ "jarArgs": strings.Join(jarArgs, " "),
},
})
return outputFile
}
+func TransformJarsToJar(ctx android.ModuleContext, stem string, jars android.Paths) android.Path {
+
+ outputFile := android.PathForModuleOut(ctx, stem)
+
+ if len(jars) == 1 {
+ return jars[0]
+ }
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: combineJar,
+ Description: "combine jars",
+ Output: outputFile,
+ Inputs: jars,
+ })
+
+ return outputFile
+}
+
func TransformClassesJarToDex(ctx android.ModuleContext, classesJar android.Path,
flags javaBuilderFlags) jarSpec {
@@ -195,7 +251,7 @@
},
})
- return jarSpec{outputFile}
+ return jarSpec{outputFile, outDir}
}
func TransformDexToJavaLib(ctx android.ModuleContext, resources []jarSpec,
@@ -206,12 +262,12 @@
var jarArgs []string
for _, j := range resources {
- deps = append(deps, j.path())
- jarArgs = append(jarArgs, j.jarArgs())
+ deps = append(deps, j.fileList)
+ jarArgs = append(jarArgs, j.soongJarArgs())
}
- deps = append(deps, dexJarSpec.path())
- jarArgs = append(jarArgs, dexJarSpec.jarArgs())
+ deps = append(deps, dexJarSpec.fileList)
+ jarArgs = append(jarArgs, dexJarSpec.soongJarArgs())
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: jar,
@@ -219,15 +275,14 @@
Output: outputFile,
Implicits: deps,
Args: map[string]string{
- "operation": "cf",
- "jarArgs": strings.Join(jarArgs, " "),
+ "jarArgs": strings.Join(jarArgs, " "),
},
})
return outputFile
}
-func TransformJarJar(ctx android.ModuleContext, classesJar android.Path, rulesFile android.Path) android.Path {
+func TransformJarJar(ctx android.ModuleContext, classesJar android.Path, rulesFile android.Path) android.ModuleOutPath {
outputFile := android.PathForModuleOut(ctx, "classes-jarjar.jar")
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: jarjar,
@@ -242,41 +297,3 @@
return outputFile
}
-
-func TransformPrebuiltJarToClasses(ctx android.ModuleContext,
- subdir string, prebuilt android.Path) (classJarSpec, resourceJarSpec jarSpec) {
-
- classDir := android.PathForModuleOut(ctx, subdir, "classes")
- classFileList := android.PathForModuleOut(ctx, subdir, "classes.list")
- resourceFileList := android.PathForModuleOut(ctx, subdir, "resources.list")
-
- ctx.ModuleBuild(pctx, android.ModuleBuildParams{
- Rule: extractPrebuilt,
- Description: "extract classes",
- Outputs: android.WritablePaths{classFileList, resourceFileList},
- Input: prebuilt,
- Args: map[string]string{
- "outDir": classDir.String(),
- "classFile": classFileList.String(),
- "resourceFile": resourceFileList.String(),
- },
- })
-
- return jarSpec{classFileList}, jarSpec{resourceFileList}
-}
-
-func TransformFileListToJarSpec(ctx android.ModuleContext, dir, fileListFile android.Path) jarSpec {
- outputFile := android.PathForModuleOut(ctx, fileListFile.Base()+".jarArgs")
-
- ctx.ModuleBuild(pctx, android.ModuleBuildParams{
- Rule: fileListToJarArgs,
- Description: "file list to jar args",
- Output: outputFile,
- Input: fileListFile,
- Args: map[string]string{
- "outDir": dir.String(),
- },
- })
-
- return jarSpec{outputFile}
-}
diff --git a/java/config/config.go b/java/config/config.go
index 90d0fb5..5773164 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -32,8 +32,10 @@
func init() {
pctx.Import("github.com/google/blueprint/bootstrap")
+ pctx.StaticVariable("JavacHeapSize", "2048M")
+ pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
+
pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
- `-J-Xmx2048M`,
`-Xmaxerrs 9999999`,
`-encoding UTF-8`,
`-sourcepath ""`,
@@ -52,9 +54,12 @@
pctx.SourcePathVariable("JavaCmd", "${JavaToolchain}/java")
pctx.SourcePathVariable("JarCmd", "${JavaToolchain}/jar")
pctx.SourcePathVariable("JavadocCmd", "${JavaToolchain}/javadoc")
+ pctx.SourcePathVariable("JlinkCmd", "${JavaToolchain}/jlink")
+ pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
- pctx.StaticVariable("Zip2ZipCmd", filepath.Join("${bootstrap.ToolDir}", "zip2zip"))
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
+ pctx.StaticVariable("SoongZipCmd", filepath.Join("${bootstrap.ToolDir}", "soong_zip"))
+ pctx.StaticVariable("MergeZipsCmd", filepath.Join("${bootstrap.ToolDir}", "merge_zips"))
pctx.HostBinToolVariable("DxCmd", "dx")
pctx.HostJavaToolVariable("JarjarCmd", "jarjar.jar")
@@ -65,3 +70,17 @@
return "", nil
})
}
+
+func StripJavac9Flags(flags []string) []string {
+ var ret []string
+ for _, f := range flags {
+ switch {
+ case strings.HasPrefix(f, "-J--add-modules="):
+ // drop
+ default:
+ ret = append(ret, f)
+ }
+ }
+
+ return ret
+}
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
new file mode 100644
index 0000000..31cbf2c
--- /dev/null
+++ b/java/config/error_prone.go
@@ -0,0 +1,45 @@
+// Copyright 2017 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 config
+
+var (
+ // These will be filled out by external/error_prone/soong/error_prone.go if it is available
+ ErrorProneJavacJar string
+ ErrorProneJar string
+ ErrorProneClasspath string
+ ErrorProneChecksError string
+ ErrorProneFlags string
+)
+
+// Wrapper that grabs value of val late so it can be initialized by a later module's init function
+func errorProneVar(name string, val *string) {
+ pctx.VariableFunc(name, func(config interface{}) (string, error) {
+ return *val, nil
+ })
+}
+
+func init() {
+ errorProneVar("ErrorProneJar", &ErrorProneJar)
+ errorProneVar("ErrorProneJavacJar", &ErrorProneJavacJar)
+ errorProneVar("ErrorProneClasspath", &ErrorProneClasspath)
+ errorProneVar("ErrorProneChecksError", &ErrorProneChecksError)
+ errorProneVar("ErrorProneFlags", &ErrorProneFlags)
+
+ pctx.StaticVariable("ErrorProneCmd",
+ "${JavaCmd} -Xmx${JavacHeapSize} -Xbootclasspath/p:${ErrorProneJavacJar} "+
+ "-cp ${ErrorProneJar}:${ErrorProneClasspath} "+
+ "${ErrorProneFlags} ${CommonJdkFlags} ${ErrorProneChecksError}")
+
+}
diff --git a/java/config/makevars.go b/java/config/makevars.go
index ac02782..eda6c09 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -37,4 +37,17 @@
ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
ctx.Strict("JAVADOC", "${JavadocCmd}")
ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}")
+
+ if ctx.Config().IsEnvTrue("RUN_ERROR_PRONE") {
+ ctx.Strict("TARGET_JAVAC", "${ErrorProneCmd}")
+ ctx.Strict("HOST_JAVAC", "${ErrorProneCmd}")
+ } else {
+ ctx.Strict("TARGET_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
+ ctx.Strict("HOST_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
+ }
+
+ if ctx.Config().IsEnvTrue("EXPERIMENTAL_USE_OPENJDK9") {
+ ctx.Strict("JLINK", "${JlinkCmd}")
+ ctx.Strict("JMOD", "${JmodCmd}")
+ }
}
diff --git a/java/java.go b/java/java.go
index ac88020..2298acc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/genrule"
@@ -76,7 +77,7 @@
// don't build against the default libraries (legacy-test, core-junit,
// ext, and framework for device targets)
- No_standard_libraries bool
+ No_standard_libs *bool
// list of module-specific flags that will be used for javac compiles
Javacflags []string `android:"arch_variant"`
@@ -95,6 +96,15 @@
// If not blank, set the java version passed to javac as -source and -target
Java_version *string
+
+ // If set to false, don't allow this module to be installed. Defaults to true.
+ Installable *bool
+
+ // List of modules to use as annotation processors
+ Annotation_processors []string
+
+ // List of classes to pass to javac to use as annotation processors
+ Annotation_processor_classes []string
}
type CompilerDeviceProperties struct {
@@ -130,12 +140,6 @@
// output file suitable for installing or running
outputFile android.Path
- // jarSpecs suitable for inserting classes from a static library into another jar
- classJarSpecs []jarSpec
-
- // jarSpecs suitable for inserting resources from a static library into another jar
- resourceJarSpecs []jarSpec
-
exportAidlIncludeDirs android.Paths
logtagsSrcs android.Paths
@@ -150,8 +154,6 @@
type Dependency interface {
ClasspathFiles() android.Paths
- ClassJarSpecs() []jarSpec
- ResourceJarSpecs() []jarSpec
AidlIncludeDirs() android.Paths
}
@@ -166,23 +168,27 @@
}
var (
- staticLibTag = dependencyTag{name: "staticlib"}
- libTag = dependencyTag{name: "javalib"}
- bootClasspathTag = dependencyTag{name: "bootclasspath"}
- frameworkResTag = dependencyTag{name: "framework-res"}
- sdkDependencyTag = dependencyTag{name: "sdk"}
+ staticLibTag = dependencyTag{name: "staticlib"}
+ libTag = dependencyTag{name: "javalib"}
+ bootClasspathTag = dependencyTag{name: "bootclasspath"}
+ frameworkResTag = dependencyTag{name: "framework-res"}
+ sdkDependencyTag = dependencyTag{name: "sdk"}
+ annotationProcessorTag = dependencyTag{name: "annotation processor"}
)
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
- if !j.properties.No_standard_libraries {
+ if !proptools.Bool(j.properties.No_standard_libs) {
if ctx.Device() {
switch j.deviceProperties.Sdk_version {
case "":
- ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+ ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-oj", "core-libart")
+ ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
case "current":
// TODO: !TARGET_BUILD_APPS
// TODO: export preprocessed framework.aidl from android_stubs_current
ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_stubs_current")
+ case "test_current":
+ ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_test_stubs_current")
case "system_current":
ctx.AddDependency(ctx.Module(), bootClasspathTag, "android_system_stubs_current")
default:
@@ -190,16 +196,15 @@
}
} else {
if j.deviceProperties.Dex {
- ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-libart")
+ ctx.AddDependency(ctx.Module(), bootClasspathTag, "core-oj", "core-libart")
}
}
-
- if ctx.Device() && j.deviceProperties.Sdk_version == "" {
- ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
- }
}
ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
ctx.AddDependency(ctx.Module(), staticLibTag, j.properties.Static_libs...)
+ ctx.AddDependency(ctx.Module(), annotationProcessorTag, j.properties.Annotation_processors...)
+
+ android.ExtractSourcesDeps(ctx, j.properties.Srcs)
}
func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
@@ -224,10 +229,18 @@
return flags
}
-func (j *Module) collectDeps(ctx android.ModuleContext) (classpath android.Paths,
- bootClasspath android.Paths, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess android.OptionalPath,
- aidlIncludeDirs android.Paths, srcFileLists android.Paths) {
+type deps struct {
+ classpath android.Paths
+ bootClasspath android.Paths
+ staticJars android.Paths
+ aidlIncludeDirs android.Paths
+ srcFileLists android.Paths
+ annotationProcessors android.Paths
+ aidlPreprocess android.OptionalPath
+}
+func (j *Module) collectDeps(ctx android.ModuleContext) deps {
+ var deps deps
ctx.VisitDirectDeps(func(module blueprint.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -244,50 +257,62 @@
switch tag {
case bootClasspathTag:
- bootClasspath = append(bootClasspath, dep.ClasspathFiles()...)
+ deps.bootClasspath = append(deps.bootClasspath, dep.ClasspathFiles()...)
case libTag:
- classpath = append(classpath, dep.ClasspathFiles()...)
+ deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
case staticLibTag:
- classpath = append(classpath, dep.ClasspathFiles()...)
- classJarSpecs = append(classJarSpecs, dep.ClassJarSpecs()...)
- resourceJarSpecs = append(resourceJarSpecs, dep.ResourceJarSpecs()...)
+ deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
+ deps.staticJars = append(deps.staticJars, dep.ClasspathFiles()...)
+ case annotationProcessorTag:
+ deps.annotationProcessors = append(deps.annotationProcessors, dep.ClasspathFiles()...)
case frameworkResTag:
if ctx.ModuleName() == "framework" {
// framework.jar has a one-off dependency on the R.java and Manifest.java files
// generated by framework-res.apk
- srcFileLists = append(srcFileLists, module.(*AndroidApp).aaptJavaFileList)
+ deps.srcFileLists = append(deps.srcFileLists, module.(*AndroidApp).aaptJavaFileList)
}
case sdkDependencyTag:
sdkDep := module.(sdkDependency)
+ deps.bootClasspath = append(deps.bootClasspath, sdkDep.ClasspathFiles()...)
if sdkDep.AidlPreprocessed().Valid() {
- if aidlPreprocess.Valid() {
+ if deps.aidlPreprocess.Valid() {
ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
- aidlPreprocess, sdkDep.AidlPreprocessed())
+ deps.aidlPreprocess, sdkDep.AidlPreprocessed())
} else {
- aidlPreprocess = sdkDep.AidlPreprocessed()
+ deps.aidlPreprocess = sdkDep.AidlPreprocessed()
}
}
default:
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
}
- aidlIncludeDirs = append(aidlIncludeDirs, dep.AidlIncludeDirs()...)
+ deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
})
- return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
- aidlIncludeDirs, srcFileLists
+ return deps
}
func (j *Module) compile(ctx android.ModuleContext) {
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Export_aidl_include_dirs)
- classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
- aidlIncludeDirs, srcFileLists := j.collectDeps(ctx)
+ deps := j.collectDeps(ctx)
var flags javaBuilderFlags
javacFlags := j.properties.Javacflags
+ if ctx.AConfig().Getenv("EXPERIMENTAL_USE_OPENJDK9") == "" {
+ javacFlags = config.StripJavac9Flags(javacFlags)
+ }
+
+ if len(deps.annotationProcessors) > 0 {
+ javacFlags = append(javacFlags,
+ "-processorpath "+strings.Join(deps.annotationProcessors.Strings(), ":"))
+ }
+
+ for _, c := range j.properties.Annotation_processor_classes {
+ javacFlags = append(javacFlags, "-processor "+c)
+ }
if j.properties.Java_version != nil {
flags.javaVersion = *j.properties.Java_version
@@ -300,22 +325,25 @@
flags.javacFlags = "$javacFlags"
}
- aidlFlags := j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs)
+ aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
if len(aidlFlags) > 0 {
ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
flags.aidlFlags = "$aidlFlags"
}
- var deps android.Paths
+ var extraDeps android.Paths
- if len(bootClasspath) > 0 {
- flags.bootClasspath = "-bootclasspath " + strings.Join(bootClasspath.Strings(), ":")
- deps = append(deps, bootClasspath...)
+ if len(deps.bootClasspath) > 0 {
+ flags.bootClasspath = "-bootclasspath " + strings.Join(deps.bootClasspath.Strings(), ":")
+ extraDeps = append(extraDeps, deps.bootClasspath...)
+ } else if ctx.Device() {
+ // Explicitly clear the bootclasspath for device builds
+ flags.bootClasspath = `-bootclasspath ""`
}
- if len(classpath) > 0 {
- flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":")
- deps = append(deps, classpath...)
+ if len(deps.classpath) > 0 {
+ flags.classpath = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
+ extraDeps = append(extraDeps, deps.classpath...)
}
srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
@@ -328,46 +356,61 @@
}
})
- srcFileLists = append(srcFileLists, j.ExtraSrcLists...)
+ deps.srcFileLists = append(deps.srcFileLists, j.ExtraSrcLists...)
+
+ var extraJarDeps android.Paths
+
+ var jars android.Paths
if len(srcFiles) > 0 {
// Compile java sources into .class files
- classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, deps)
+ classes := TransformJavaToClasses(ctx, srcFiles, deps.srcFileLists, flags, extraDeps)
if ctx.Failed() {
return
}
- classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
+ if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
+ // If error-prone is enabled, add an additional rule to compile the java files into
+ // a separate set of classes (so that they don't overwrite the normal ones and require
+ // a rebuild when error-prone is turned off). Add the classes as a dependency to
+ // the jar command so the two compiles can run in parallel.
+ // TODO(ccross): Once we always compile with javac9 we may be able to conditionally
+ // enable error-prone without affecting the output class files.
+ errorprone := RunErrorProne(ctx, srcFiles, deps.srcFileLists, flags, extraDeps)
+ extraJarDeps = append(extraJarDeps, errorprone)
+ }
+
+ jars = append(jars, classes)
}
- resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs, j.properties.Exclude_resource_dirs),
- resourceJarSpecs...)
-
+ resourceJarSpecs := ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs, j.properties.Exclude_resource_dirs)
manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
- allJarSpecs := append([]jarSpec(nil), classJarSpecs...)
- allJarSpecs = append(allJarSpecs, resourceJarSpecs...)
+ if len(resourceJarSpecs) > 0 || manifest.Valid() {
+ // Combine classes + resources into classes-full-debug.jar
+ resourceJar := TransformResourcesToJar(ctx, resourceJarSpecs, manifest, extraJarDeps)
+ if ctx.Failed() {
+ return
+ }
- // Combine classes + resources into classes-full-debug.jar
- outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest)
- if ctx.Failed() {
- return
+ jars = append(jars, resourceJar)
}
+ jars = append(jars, deps.staticJars...)
+
+ // Combine the classes built from sources, any manifests, and any static libraries into
+ // classes-combined.jar. If there is only one input jar this step will be skipped.
+ outputFile := TransformJarsToJar(ctx, "classes-combined.jar", jars)
+
if j.properties.Jarjar_rules != nil {
jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
- // Transform classes-full-debug.jar into classes-jarjar.jar
+ // Transform classes-combined.jar into classes-jarjar.jar
outputFile = TransformJarJar(ctx, outputFile, jarjar_rules)
if ctx.Failed() {
return
}
-
- classes, _ := TransformPrebuiltJarToClasses(ctx, "jarjar_extracted", outputFile)
- classJarSpecs = []jarSpec{classes}
}
- j.resourceJarSpecs = resourceJarSpecs
- j.classJarSpecs = classJarSpecs
j.classpathFile = outputFile
if j.deviceProperties.Dex && len(srcFiles) > 0 {
@@ -394,6 +437,16 @@
"--dump-width=1000")
}
+ var minSdkVersion string
+ switch j.deviceProperties.Sdk_version {
+ case "", "current", "test_current", "system_current":
+ minSdkVersion = strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
+ default:
+ minSdkVersion = j.deviceProperties.Sdk_version
+ }
+
+ dxFlags = append(dxFlags, "--min-sdk-version="+minSdkVersion)
+
flags.dxFlags = strings.Join(dxFlags, " ")
// Compile classes.jar into classes.dex
@@ -415,14 +468,6 @@
return android.Paths{j.classpathFile}
}
-func (j *Module) ClassJarSpecs() []jarSpec {
- return j.classJarSpecs
-}
-
-func (j *Module) ResourceJarSpecs() []jarSpec {
- return j.resourceJarSpecs
-}
-
func (j *Module) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
@@ -444,7 +489,10 @@
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.compile(ctx)
- j.installFile = ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile)
+ if j.properties.Installable == nil || *j.properties.Installable == true {
+ j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+ ctx.ModuleName()+".jar", j.outputFile)
+ }
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -497,8 +545,8 @@
// 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.
j.wrapperFile = android.PathForModuleSrc(ctx, j.binaryProperties.Wrapper)
- j.binaryFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"),
- j.wrapperFile, j.installFile)
+ j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
+ ctx.ModuleName(), j.wrapperFile, j.installFile)
}
func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -545,9 +593,8 @@
properties ImportProperties
- classpathFiles android.Paths
- combinedClasspathFile android.Path
- classJarSpecs, resourceJarSpecs []jarSpec
+ classpathFiles android.Paths
+ combinedClasspathFile android.Path
}
func (j *Import) Prebuilt() *android.Prebuilt {
@@ -568,17 +615,7 @@
func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.classpathFiles = android.PathsForModuleSrc(ctx, j.properties.Jars)
- for i, prebuilt := range j.classpathFiles {
- subdir := "extracted" + strconv.Itoa(i)
- classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, subdir, prebuilt)
- j.classJarSpecs = append(j.classJarSpecs, classJarSpec)
- j.resourceJarSpecs = append(j.resourceJarSpecs, resourceJarSpec)
- }
-
- j.combinedClasspathFile = TransformClassesToJar(ctx, j.classJarSpecs, android.OptionalPath{})
-
- ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"),
- ctx.ModuleName()+".jar", j.combinedClasspathFile)
+ j.combinedClasspathFile = TransformJarsToJar(ctx, "classes.jar", j.classpathFiles)
}
var _ Dependency = (*Import)(nil)
@@ -587,14 +624,6 @@
return j.classpathFiles
}
-func (j *Import) ClassJarSpecs() []jarSpec {
- return j.classJarSpecs
-}
-
-func (j *Import) ResourceJarSpecs() []jarSpec {
- return j.resourceJarSpecs
-}
-
func (j *Import) AidlIncludeDirs() android.Paths {
return nil
}
diff --git a/java/java_test.go b/java/java_test.go
index eb116c9..4f5c0ec 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"strings"
"testing"
)
@@ -62,13 +63,14 @@
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.Register()
- extraModules := []string{"core-libart", "frameworks", "sdk_v14"}
+ extraModules := []string{"core-oj", "core-libart", "frameworks", "sdk_v14"}
for _, extra := range extraModules {
bp += fmt.Sprintf(`
java_library {
name: "%s",
- no_standard_libraries: true,
+ srcs: ["a.java"],
+ no_standard_libs: true,
}
`, extra)
}
@@ -111,20 +113,25 @@
`)
javac := ctx.ModuleForTests("foo", "").Rule("javac")
- jar := ctx.ModuleForTests("foo", "").Rule("jar")
+ combineJar := ctx.ModuleForTests("foo", "").Rule("combineJar")
if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
}
- bar := filepath.Join(buildDir, ".intermediates", "bar", "classes-full-debug.jar")
+ bar := filepath.Join(buildDir, ".intermediates", "bar", "classes.jar")
+ baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.jar")
+
if !strings.Contains(javac.Args["classpath"], bar) {
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
}
- baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.list")
- if !strings.Contains(jar.Args["jarArgs"], baz) {
- t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+ if !strings.Contains(javac.Args["classpath"], baz) {
+ t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], baz)
+ }
+
+ if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
+ t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
}
}
@@ -173,10 +180,11 @@
bootclasspathLib
)
- check := func(module, dep string, depType depType) {
- if dep != "" {
- dep = filepath.Join(buildDir, ".intermediates", dep, "classes-full-debug.jar")
+ check := func(module string, depType depType, deps ...string) {
+ for i := range deps {
+ deps[i] = filepath.Join(buildDir, ".intermediates", deps[i], "classes.jar")
}
+ dep := strings.Join(deps, ":")
javac := ctx.ModuleForTests(module, "").Rule("javac")
@@ -192,12 +200,18 @@
}
}
- if len(javac.Implicits) != 1 || javac.Implicits[0].String() != dep {
- t.Errorf("module %q implicits != [%q]", dep)
+ if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
+ t.Errorf("module %q implicits %q != %q", module, javac.Implicits.Strings(), deps)
}
}
- check("foo1", "core-libart", bootclasspathLib)
+ check("foo1", bootclasspathLib, "core-oj", "core-libart")
+ check("foo2", bootclasspathLib, "core-oj", "core-libart")
+ // TODO(ccross): these need the arch mutator to run to work correctly
+ //check("foo3", bootclasspathLib, "sdk_v14")
+ //check("foo4", bootclasspathLib, "android_stubs_current")
+ //check("foo5", bootclasspathLib, "android_system_stubs_current")
+ //check("foo6", bootclasspathLib, "android_test_stubs_current")
}
func TestPrebuilts(t *testing.T) {
@@ -221,16 +235,15 @@
`)
javac := ctx.ModuleForTests("foo", "").Rule("javac")
- jar := ctx.ModuleForTests("foo", "").Rule("jar")
+ combineJar := ctx.ModuleForTests("foo", "").Rule("combineJar")
bar := "a.jar"
if !strings.Contains(javac.Args["classpath"], bar) {
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
}
- baz := filepath.Join(buildDir, ".intermediates", "baz", "extracted0", "classes.list")
- if !strings.Contains(jar.Args["jarArgs"], baz) {
- t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+ if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != "b.jar" {
+ t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, "b.jar")
}
}
@@ -260,20 +273,20 @@
`)
javac := ctx.ModuleForTests("foo", "").Rule("javac")
- jar := ctx.ModuleForTests("foo", "").Rule("jar")
+ combineJar := ctx.ModuleForTests("foo", "").Rule("combineJar")
if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
}
- bar := filepath.Join(buildDir, ".intermediates", "bar", "classes-full-debug.jar")
+ bar := filepath.Join(buildDir, ".intermediates", "bar", "classes.jar")
if !strings.Contains(javac.Args["classpath"], bar) {
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
}
- baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.list")
- if !strings.Contains(jar.Args["jarArgs"], baz) {
- t.Errorf("foo jarArgs %v does not contain %q", jar.Args["jarArgs"], baz)
+ baz := filepath.Join(buildDir, ".intermediates", "baz", "classes.jar")
+ if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
+ t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
}
}
diff --git a/java/resources.go b/java/resources.go
index f1c9d06..60dc934 100644
--- a/java/resources.go
+++ b/java/resources.go
@@ -63,7 +63,7 @@
pattern := filepath.Join(dir.String(), "**/*")
bootstrap.GlobFile(ctx, pattern, excludes, fileListFile.String(), depFile)
- jarSpecs = append(jarSpecs, TransformFileListToJarSpec(ctx, dir, fileListFile))
+ jarSpecs = append(jarSpecs, jarSpec{fileListFile, dir})
}
}
diff --git a/python/androidmk.go b/python/androidmk.go
index ab24e99..25abdc9 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -23,10 +23,10 @@
)
type subAndroidMkProvider interface {
- AndroidMk(*pythonBaseModule, *android.AndroidMkData)
+ AndroidMk(*Module, *android.AndroidMkData)
}
-func (p *pythonBaseModule) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (p *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
if p.subAndroidMkOnce == nil {
p.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
}
@@ -38,7 +38,7 @@
}
}
-func (p *pythonBaseModule) AndroidMk() android.AndroidMkData {
+func (p *Module) AndroidMk() android.AndroidMkData {
ret := android.AndroidMkData{}
p.subAndroidMk(&ret, p.installer)
@@ -46,17 +46,17 @@
return ret
}
-func (p *pythonBinaryHostDecorator) AndroidMk(base *pythonBaseModule, ret *android.AndroidMkData) {
+func (p *binaryDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
ret.Class = "EXECUTABLES"
- base.subAndroidMk(ret, p.pythonDecorator.baseInstaller)
+ base.subAndroidMk(ret, p.baseInstaller)
}
-func (p *pythonTestHostDecorator) AndroidMk(base *pythonBaseModule, ret *android.AndroidMkData) {
+func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
ret.Class = "NATIVE_TESTS"
- base.subAndroidMk(ret, p.pythonDecorator.baseInstaller)
+ base.subAndroidMk(ret, p.binaryDecorator.baseInstaller)
}
-func (installer *pythonInstaller) AndroidMk(base *pythonBaseModule, ret *android.AndroidMkData) {
+func (installer *pythonInstaller) AndroidMk(base *Module, ret *android.AndroidMkData) {
// Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation.
if base.Target().Os.Class == android.Host {
diff --git a/python/binary.go b/python/binary.go
index ae2693b..91b7a54 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -21,6 +21,8 @@
"path/filepath"
"strings"
+ "github.com/google/blueprint"
+
"android/soong/android"
)
@@ -28,67 +30,63 @@
android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
}
-type PythonBinaryBaseProperties struct {
+type BinaryProperties struct {
// the name of the source file that is the main entry point of the program.
// this file must also be listed in srcs.
// If left unspecified, module name is used instead.
// If name doesn’t match any filename in srcs, main must be specified.
- Main string
+ Main string `android:"arch_variant"`
// set the name of the output binary.
- Stem string
+ Stem string `android:"arch_variant"`
// append to the name of the output binary.
- Suffix string
+ Suffix string `android:"arch_variant"`
}
-type pythonBinaryBase struct {
- pythonBaseModule
+type binaryDecorator struct {
+ binaryProperties BinaryProperties
- binaryProperties PythonBinaryBaseProperties
-
- // soong_zip arguments from all its dependencies.
- depsParSpecs []parSpec
-
- // Python runfiles paths from all its dependencies.
- depsPyRunfiles []string
+ baseInstaller *pythonInstaller
}
-type PythonBinaryHost struct {
- pythonBinaryBase
+type IntermPathProvider interface {
+ IntermPathForModuleOut() android.OptionalPath
}
-var _ PythonSubModule = (*PythonBinaryHost)(nil)
-
-type pythonBinaryHostDecorator struct {
- pythonDecorator
-}
-
-func (p *pythonBinaryHostDecorator) install(ctx android.ModuleContext, file android.Path) {
- p.pythonDecorator.baseInstaller.install(ctx, file)
+func (binary *binaryDecorator) install(ctx android.ModuleContext, file android.Path) {
+ binary.baseInstaller.install(ctx, file)
}
var (
stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
)
-func PythonBinaryHostFactory() android.Module {
- decorator := &pythonBinaryHostDecorator{
- pythonDecorator: pythonDecorator{baseInstaller: NewPythonInstaller("bin")}}
+func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+ decorator := &binaryDecorator{baseInstaller: NewPythonInstaller("bin")}
- module := &PythonBinaryHost{}
- module.pythonBaseModule.installer = decorator
- module.AddProperties(&module.binaryProperties)
+ module.bootstrapper = decorator
+ module.installer = decorator
- return InitPythonBaseModule(&module.pythonBinaryBase.pythonBaseModule,
- &module.pythonBinaryBase, android.HostSupportedNoCross)
+ return module, decorator
}
-func (p *pythonBinaryBase) GeneratePythonBuildActions(ctx android.ModuleContext) android.OptionalPath {
- p.pythonBaseModule.GeneratePythonBuildActions(ctx)
+func PythonBinaryHostFactory() android.Module {
+ module, _ := NewBinary(android.HostSupportedNoCross)
- // no Python source file for compiling par file.
- if len(p.pythonBaseModule.srcsPathMappings) == 0 && len(p.depsPyRunfiles) == 0 {
+ return module.Init()
+}
+
+func (binary *binaryDecorator) bootstrapperProps() []interface{} {
+ return []interface{}{&binary.binaryProperties}
+}
+
+func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actual_version string,
+ embedded_launcher bool, srcsPathMappings []pathMapping, parSpec parSpec,
+ depsPyRunfiles []string, depsParSpecs []parSpec) android.OptionalPath {
+ // no Python source file for compiling .par file.
+ if len(srcsPathMappings) == 0 {
return android.OptionalPath{}
}
@@ -100,10 +98,10 @@
existingPyPkgSet := make(map[string]bool)
wholePyRunfiles := []string{}
- for _, path := range p.pythonBaseModule.srcsPathMappings {
+ for _, path := range srcsPathMappings {
wholePyRunfiles = append(wholePyRunfiles, path.dest)
}
- wholePyRunfiles = append(wholePyRunfiles, p.depsPyRunfiles...)
+ wholePyRunfiles = append(wholePyRunfiles, depsPyRunfiles...)
// find all the runfiles dirs which have been treated as packages.
for _, path := range wholePyRunfiles {
@@ -130,50 +128,62 @@
populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs)
}
- main := p.getPyMainFile(ctx)
+ main := binary.getPyMainFile(ctx, srcsPathMappings)
if main == "" {
return android.OptionalPath{}
}
- interp := p.getInterpreter(ctx)
- if interp == "" {
- return android.OptionalPath{}
+
+ var launcher_path android.Path
+ if embedded_launcher {
+ ctx.VisitDirectDeps(func(m blueprint.Module) {
+ if ctx.OtherModuleDependencyTag(m) != launcherTag {
+ return
+ }
+ if provider, ok := m.(IntermPathProvider); ok {
+ if launcher_path != nil {
+ panic(fmt.Errorf("launcher path was found before: %q",
+ launcher_path))
+ }
+ launcher_path = provider.IntermPathForModuleOut().Path()
+ }
+ })
}
- // we need remove "runfiles/" suffix since stub script starts
- // searching for main file in each sub-dir of "runfiles" directory tree.
- binFile := registerBuildActionForParFile(ctx, p.getInterpreter(ctx),
- strings.TrimPrefix(main, runFiles+"/"), p.getStem(ctx),
- newPyPkgs, append(p.depsParSpecs, p.pythonBaseModule.parSpec))
+ binFile := registerBuildActionForParFile(ctx, embedded_launcher, launcher_path,
+ binary.getHostInterpreterName(ctx, actual_version),
+ main, binary.getStem(ctx), newPyPkgs, append(depsParSpecs, parSpec))
return android.OptionalPathForPath(binFile)
}
-// get interpreter path.
-func (p *pythonBinaryBase) getInterpreter(ctx android.ModuleContext) string {
+// get host interpreter name.
+func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext,
+ actual_version string) string {
var interp string
- switch p.pythonBaseModule.properties.ActualVersion {
+ switch actual_version {
case pyVersion2:
interp = "python2"
case pyVersion3:
interp = "python3"
default:
panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
- p.properties.ActualVersion, ctx.ModuleName()))
+ actual_version, ctx.ModuleName()))
}
return interp
}
// find main program path within runfiles tree.
-func (p *pythonBinaryBase) getPyMainFile(ctx android.ModuleContext) string {
+func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext,
+ srcsPathMappings []pathMapping) string {
var main string
- if p.binaryProperties.Main == "" {
- main = p.BaseModuleName() + pyExt
+ if binary.binaryProperties.Main == "" {
+ main = ctx.ModuleName() + pyExt
} else {
- main = p.binaryProperties.Main
+ main = binary.binaryProperties.Main
}
- for _, path := range p.pythonBaseModule.srcsPathMappings {
+ for _, path := range srcsPathMappings {
if main == path.src.Rel() {
return path.dest
}
@@ -183,13 +193,13 @@
return ""
}
-func (p *pythonBinaryBase) getStem(ctx android.ModuleContext) string {
+func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string {
stem := ctx.ModuleName()
- if p.binaryProperties.Stem != "" {
- stem = p.binaryProperties.Stem
+ if binary.binaryProperties.Stem != "" {
+ stem = binary.binaryProperties.Stem
}
- return stem + p.binaryProperties.Suffix
+ return stem + binary.binaryProperties.Suffix
}
// Sets the given directory and all its ancestor directories as Python packages.
diff --git a/python/builder.go b/python/builder.go
index b823fcb..a459d3d 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -17,6 +17,7 @@
// This file contains Ninja build actions for building Python program.
import (
+ "fmt"
"strings"
"android/soong/android"
@@ -28,7 +29,7 @@
var (
pctx = android.NewPackageContext("android/soong/python")
- par = pctx.AndroidStaticRule("par",
+ host_par = pctx.AndroidStaticRule("host_par",
blueprint.RuleParams{
Command: `touch $initFile && ` +
`sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' $template > $stub && ` +
@@ -37,6 +38,16 @@
CommandDeps: []string{"$parCmd", "$template"},
},
"initFile", "interp", "main", "template", "stub", "parCmd", "parFile", "parArgs")
+
+ embedded_par = pctx.AndroidStaticRule("embedded_par",
+ blueprint.RuleParams{
+ Command: `touch $initFile && ` +
+ `echo '$main' > $entry_point && ` +
+ `$parCmd -o $parFile $parArgs && cat $launcher | cat - $parFile > $out && ` +
+ `chmod +x $out && (rm -f $initFile; rm -f $entry_point; rm -f $parFile)`,
+ CommandDeps: []string{"$parCmd"},
+ },
+ "initFile", "main", "entry_point", "parCmd", "parFile", "parArgs", "launcher")
)
func init() {
@@ -58,10 +69,10 @@
}
func (p parSpec) soongParArgs() string {
- ret := "-P " + p.rootPrefix
+ ret := `-P ` + p.rootPrefix
for _, spec := range p.fileListSpecs {
- ret += " -C " + spec.relativeRoot + " -l " + spec.fileList.String()
+ ret += ` -C ` + spec.relativeRoot + ` -l ` + spec.fileList.String()
}
return ret
@@ -89,22 +100,17 @@
return fileList
}
-func registerBuildActionForParFile(ctx android.ModuleContext,
- interpreter, main, binName string, newPyPkgs []string, parSpecs []parSpec) android.Path {
+func registerBuildActionForParFile(ctx android.ModuleContext, embedded_launcher bool,
+ launcher_path android.Path, interpreter, main, binName string,
+ newPyPkgs []string, parSpecs []parSpec) android.Path {
- // intermediate output path for __init__.py
+ // .intermediate output path for __init__.py
initFile := android.PathForModuleOut(ctx, initFileName).String()
- // the path of stub_template_host.txt from source tree.
- template := android.PathForSource(ctx, stubTemplateHost)
-
- // intermediate output path for __main__.py
- stub := android.PathForModuleOut(ctx, mainFileName).String()
-
- // intermediate output path for par file.
+ // .intermediate output path for par file.
parFile := android.PathForModuleOut(ctx, binName+parFileExt)
- // intermediate output path for bin executable.
+ // .intermediate output path for bin executable.
binFile := android.PathForModuleOut(ctx, binName)
// implicit dependency for parFile build action.
@@ -116,32 +122,68 @@
}
parArgs := []string{}
- parArgs = append(parArgs, "-C "+strings.TrimSuffix(stub, mainFileName)+" -f "+stub)
- parArgs = append(parArgs, "-C "+strings.TrimSuffix(initFile, initFileName)+" -f "+initFile)
+ parArgs = append(parArgs, `-P "" `+`-C `+strings.TrimSuffix(initFile, initFileName)+` -f `+initFile)
for _, pkg := range newPyPkgs {
- parArgs = append(parArgs, "-P "+pkg+" -f "+initFile)
+ parArgs = append(parArgs, `-P `+pkg+` -f `+initFile)
}
for _, p := range parSpecs {
parArgs = append(parArgs, p.soongParArgs())
}
- ctx.ModuleBuild(pctx, android.ModuleBuildParams{
- Rule: par,
- Description: "python archive",
- Output: binFile,
- Implicits: implicits,
- Args: map[string]string{
- "initFile": initFile,
- // the "\" isn't being interpreted by regex parser, it's being
- // interpreted in the string literal.
- "interp": strings.Replace(interpreter, "/", `\/`, -1),
- "main": strings.Replace(main, "/", `\/`, -1),
- "template": template.String(),
- "stub": stub,
- "parFile": parFile.String(),
- "parArgs": strings.Join(parArgs, " "),
- },
- })
+ if !embedded_launcher {
+ // the path of stub_template_host.txt from source tree.
+ template := android.PathForSource(ctx, stubTemplateHost)
+
+ // intermediate output path for __main__.py
+ stub := android.PathForModuleOut(ctx, mainFileName).String()
+
+ // added stub file to the soong_zip args.
+ parArgs = append(parArgs, `-P "" `+`-C `+strings.TrimSuffix(stub, mainFileName)+` -f `+stub)
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: host_par,
+ Description: "host python archive",
+ Output: binFile,
+ Implicits: implicits,
+ Args: map[string]string{
+ "initFile": initFile,
+ "interp": strings.Replace(interpreter, "/", `\/`, -1),
+ // we need remove "runfiles/" suffix since stub script starts
+ // searching for main file in each sub-dir of "runfiles" directory tree.
+ "main": strings.Replace(strings.TrimPrefix(main, runFiles+"/"),
+ "/", `\/`, -1),
+ "template": template.String(),
+ "stub": stub,
+ "parFile": parFile.String(),
+ "parArgs": strings.Join(parArgs, " "),
+ },
+ })
+ } else {
+ // added launcher_path to the implicits Ninja dependencies.
+ implicits = append(implicits, launcher_path)
+
+ // .intermediate output path for entry_point.txt
+ entryPoint := android.PathForModuleOut(ctx, entryPointFile).String()
+
+ // added entry_point file to the soong_zip args.
+ parArgs = append(parArgs, `-P "" `+`-C `+fmt.Sprintf(
+ "%q", strings.TrimSuffix(entryPoint, entryPointFile))+` -f `+entryPoint)
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: embedded_par,
+ Description: "embedded python archive",
+ Output: binFile,
+ Implicits: implicits,
+ Args: map[string]string{
+ "initFile": initFile,
+ "main": main,
+ "entry_point": entryPoint,
+ "parFile": parFile.String(),
+ "parArgs": strings.Join(parArgs, " "),
+ "launcher": launcher_path.String(),
+ },
+ })
+ }
return binFile
}
diff --git a/python/defaults.go b/python/defaults.go
new file mode 100644
index 0000000..641aca4
--- /dev/null
+++ b/python/defaults.go
@@ -0,0 +1,51 @@
+// Copyright 2017 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 python
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("python_defaults", defaultsFactory)
+}
+
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(
+ &BaseProperties{},
+ )
+
+ android.InitDefaultsModule(module)
+
+ return module
+}
diff --git a/python/installer.go b/python/installer.go
index 9c12f5f..04698c5 100644
--- a/python/installer.go
+++ b/python/installer.go
@@ -35,5 +35,6 @@
var _ installer = (*pythonInstaller)(nil)
func (installer *pythonInstaller) install(ctx android.ModuleContext, file android.Path) {
- installer.path = ctx.InstallFile(android.PathForModuleInstall(ctx, installer.dir), file)
+ installer.path = ctx.InstallFile(android.PathForModuleInstall(ctx, installer.dir),
+ file.Base(), file)
}
diff --git a/python/library.go b/python/library.go
index 2039e56..58ee55f 100644
--- a/python/library.go
+++ b/python/library.go
@@ -24,14 +24,8 @@
android.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
}
-type PythonLibrary struct {
- pythonBaseModule
-}
-
-var _ PythonSubModule = (*PythonLibrary)(nil)
-
func PythonLibraryHostFactory() android.Module {
- module := &PythonLibrary{}
+ module := newModule(android.HostSupportedNoCross, android.MultilibFirst)
- return InitPythonBaseModule(&module.pythonBaseModule, module, android.HostSupportedNoCross)
+ return module.Init()
}
diff --git a/python/python.go b/python/python.go
index df5999d..e63c26c 100644
--- a/python/python.go
+++ b/python/python.go
@@ -24,6 +24,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
)
@@ -35,58 +36,70 @@
}
// the version properties that apply to python libraries and binaries.
-type PythonVersionProperties struct {
+type VersionProperties struct {
// true, if the module is required to be built with this version.
- Enabled *bool
-
- // if specified, common src files are converted to specific version with converter tool.
- // Converter bool
+ Enabled *bool `android:"arch_variant"`
// non-empty list of .py files under this strict Python version.
// srcs may reference the outputs of other modules that produce source files like genrule
// or filegroup using the syntax ":module".
- Srcs []string
+ Srcs []string `android:"arch_variant"`
+
+ // list of source files that should not be used to build the Python module.
+ // This is most useful in the arch/multilib variants to remove non-common files
+ Exclude_srcs []string `android:"arch_variant"`
// list of the Python libraries under this Python version.
- Libs []string
+ Libs []string `android:"arch_variant"`
+
+ // true, if the binary is required to be built with embedded launcher.
+ // TODO(nanzhang): Remove this flag when embedded Python3 is supported later.
+ Embedded_launcher *bool `android:"arch_variant"`
}
// properties that apply to python libraries and binaries.
-type PythonBaseModuleProperties struct {
+type BaseProperties struct {
// the package path prefix within the output artifact at which to place the source/data
// files of the current module.
// eg. Pkg_path = "a/b/c"; Other packages can reference this module by using
// (from a.b.c import ...) statement.
// if left unspecified, all the source/data files of current module are copied to
// "runfiles/" tree directory directly.
- Pkg_path string
+ Pkg_path string `android:"arch_variant"`
+
+ // true, if the Python module is used internally, eg, Python std libs.
+ Is_internal *bool `android:"arch_variant"`
// list of source (.py) files compatible both with Python2 and Python3 used to compile the
// Python module.
// srcs may reference the outputs of other modules that produce source files like genrule
// or filegroup using the syntax ":module".
// Srcs has to be non-empty.
- Srcs []string
+ Srcs []string `android:"arch_variant"`
+
+ // list of source files that should not be used to build the C/C++ module.
+ // This is most useful in the arch/multilib variants to remove non-common files
+ Exclude_srcs []string `android:"arch_variant"`
// list of files or filegroup modules that provide data that should be installed alongside
// the test. the file extension can be arbitrary except for (.py).
- Data []string
+ Data []string `android:"arch_variant"`
// list of the Python libraries compatible both with Python2 and Python3.
- Libs []string
+ Libs []string `android:"arch_variant"`
Version struct {
// all the "srcs" or Python dependencies that are to be used only for Python2.
- Py2 PythonVersionProperties
+ Py2 VersionProperties `android:"arch_variant"`
// all the "srcs" or Python dependencies that are to be used only for Python3.
- Py3 PythonVersionProperties
- }
+ Py3 VersionProperties `android:"arch_variant"`
+ } `android:"arch_variant"`
// the actual version each module uses after variations created.
// this property name is hidden from users' perspectives, and soong will populate it during
// runtime.
- ActualVersion string `blueprint:"mutated"`
+ Actual_version string `blueprint:"mutated"`
}
type pathMapping struct {
@@ -94,11 +107,22 @@
src android.Path
}
-type pythonBaseModule struct {
+type Module struct {
android.ModuleBase
- subModule PythonSubModule
+ android.DefaultableModuleBase
- properties PythonBaseModuleProperties
+ properties BaseProperties
+
+ // initialize before calling Init
+ hod android.HostOrDeviceSupported
+ multilib android.Multilib
+
+ // the bootstrapper is used to bootstrap .par executable.
+ // bootstrapper might be nil (Python library module).
+ bootstrapper bootstrapper
+
+ // the installer might be nil.
+ installer installer
// the Python files of current module after expanding source dependencies.
// pathMapping: <dest: runfile_path, src: source_path>
@@ -108,17 +132,37 @@
// pathMapping: <dest: runfile_path, src: source_path>
dataPathMappings []pathMapping
+ // soong_zip arguments of all its dependencies.
+ depsParSpecs []parSpec
+
+ // Python runfiles paths of all its dependencies.
+ depsPyRunfiles []string
+
+ // (.intermediate) module output path as installation source.
+ installSource android.OptionalPath
+
// the soong_zip arguments for zipping current module source/data files.
parSpec parSpec
- // the installer might be nil.
- installer installer
-
subAndroidMkOnce map[subAndroidMkProvider]bool
}
-type PythonSubModule interface {
- GeneratePythonBuildActions(ctx android.ModuleContext) android.OptionalPath
+func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+ return &Module{
+ hod: hod,
+ multilib: multilib,
+ }
+}
+
+type bootstrapper interface {
+ bootstrapperProps() []interface{}
+ bootstrap(ctx android.ModuleContext, Actual_version string, embedded_launcher bool,
+ srcsPathMappings []pathMapping, parSpec parSpec,
+ depsPyRunfiles []string, depsParSpecs []parSpec) android.OptionalPath
+}
+
+type installer interface {
+ install(ctx android.ModuleContext, path android.Path)
}
type PythonDependency interface {
@@ -127,64 +171,59 @@
GetParSpec() parSpec
}
-type pythonDecorator struct {
- baseInstaller *pythonInstaller
-}
-
-type installer interface {
- install(ctx android.ModuleContext, path android.Path)
-}
-
-func (p *pythonBaseModule) GetSrcsPathMappings() []pathMapping {
+func (p *Module) GetSrcsPathMappings() []pathMapping {
return p.srcsPathMappings
}
-func (p *pythonBaseModule) GetDataPathMappings() []pathMapping {
+func (p *Module) GetDataPathMappings() []pathMapping {
return p.dataPathMappings
}
-func (p *pythonBaseModule) GetParSpec() parSpec {
+func (p *Module) GetParSpec() parSpec {
return p.parSpec
}
-var _ PythonDependency = (*pythonBaseModule)(nil)
+var _ PythonDependency = (*Module)(nil)
-var _ android.AndroidMkDataProvider = (*pythonBaseModule)(nil)
+var _ android.AndroidMkDataProvider = (*Module)(nil)
-func InitPythonBaseModule(baseModule *pythonBaseModule, subModule PythonSubModule,
- hod android.HostOrDeviceSupported) android.Module {
+func (p *Module) Init() android.Module {
- baseModule.subModule = subModule
+ p.AddProperties(&p.properties)
+ if p.bootstrapper != nil {
+ p.AddProperties(p.bootstrapper.bootstrapperProps()...)
+ }
- baseModule.AddProperties(&baseModule.properties)
+ android.InitAndroidArchModule(p, p.hod, p.multilib)
+ android.InitDefaultableModule(p)
- android.InitAndroidArchModule(baseModule, hod, android.MultilibCommon)
-
- return baseModule
+ return p
}
-// the tag used to mark dependencies within "py_libs" attribute.
-type pythonDependencyTag struct {
+type dependencyTag struct {
blueprint.BaseDependencyTag
+ name string
}
-var pyDependencyTag pythonDependencyTag
-
var (
+ pythonLibTag = dependencyTag{name: "pythonLib"}
+ launcherTag = dependencyTag{name: "launcher"}
pyIdentifierRegexp = regexp.MustCompile(`^([a-z]|[A-Z]|_)([a-z]|[A-Z]|[0-9]|_)*$`)
pyExt = ".py"
pyVersion2 = "PY2"
pyVersion3 = "PY3"
initFileName = "__init__.py"
mainFileName = "__main__.py"
+ entryPointFile = "entry_point.txt"
parFileExt = ".zip"
runFiles = "runfiles"
+ internal = "internal"
)
// create version variants for modules.
func versionSplitMutator() func(android.BottomUpMutatorContext) {
return func(mctx android.BottomUpMutatorContext) {
- if base, ok := mctx.Module().(*pythonBaseModule); ok {
+ if base, ok := mctx.Module().(*Module); ok {
versionNames := []string{}
if base.properties.Version.Py2.Enabled != nil &&
*(base.properties.Version.Py2.Enabled) == true {
@@ -197,36 +236,61 @@
modules := mctx.CreateVariations(versionNames...)
for i, v := range versionNames {
// set the actual version for Python module.
- modules[i].(*pythonBaseModule).properties.ActualVersion = v
+ modules[i].(*Module).properties.Actual_version = v
}
}
}
}
-func (p *pythonBaseModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
+ switch actual_version {
+ case pyVersion2:
+ return proptools.Bool(p.properties.Version.Py2.Embedded_launcher)
+ case pyVersion3:
+ return proptools.Bool(p.properties.Version.Py3.Embedded_launcher)
+ }
+
+ return false
+}
+
+func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
// deps from "data".
android.ExtractSourcesDeps(ctx, p.properties.Data)
// deps from "srcs".
android.ExtractSourcesDeps(ctx, p.properties.Srcs)
- switch p.properties.ActualVersion {
+ switch p.properties.Actual_version {
case pyVersion2:
// deps from "version.py2.srcs" property.
android.ExtractSourcesDeps(ctx, p.properties.Version.Py2.Srcs)
- ctx.AddVariationDependencies(nil, pyDependencyTag,
+ ctx.AddVariationDependencies(nil, pythonLibTag,
uniqueLibs(ctx, p.properties.Libs, "version.py2.libs",
p.properties.Version.Py2.Libs)...)
+
+ if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion2) {
+ ctx.AddVariationDependencies(nil, pythonLibTag, "py2-stdlib")
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {"arch", ctx.Target().String()},
+ }, launcherTag, "py2-launcher")
+ }
+
case pyVersion3:
// deps from "version.py3.srcs" property.
android.ExtractSourcesDeps(ctx, p.properties.Version.Py3.Srcs)
- ctx.AddVariationDependencies(nil, pyDependencyTag,
+ ctx.AddVariationDependencies(nil, pythonLibTag,
uniqueLibs(ctx, p.properties.Libs, "version.py3.libs",
p.properties.Version.Py3.Libs)...)
+
+ if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion3) {
+ //TODO(nanzhang): Add embedded launcher for Python3.
+ ctx.PropertyErrorf("version.py3.embedded_launcher",
+ "is not supported yet for Python3.")
+ }
default:
- panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
- p.properties.ActualVersion, ctx.ModuleName()))
+ panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
+ p.properties.Actual_version, ctx.ModuleName()))
}
}
@@ -258,27 +322,43 @@
return ret
}
-func (p *pythonBaseModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- installSource := p.subModule.GeneratePythonBuildActions(ctx)
+func (p *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ p.GeneratePythonBuildActions(ctx)
- if p.installer != nil && installSource.Valid() {
- p.installer.install(ctx, installSource.Path())
+ if p.bootstrapper != nil {
+ // TODO(nanzhang): Since embedded launcher is not supported for Python3 for now,
+ // so we initialize "embedded_launcher" to false.
+ embedded_launcher := false
+ if p.properties.Actual_version == pyVersion2 {
+ embedded_launcher = p.isEmbeddedLauncherEnabled(pyVersion2)
+ }
+ p.installSource = p.bootstrapper.bootstrap(ctx, p.properties.Actual_version,
+ embedded_launcher, p.srcsPathMappings, p.parSpec, p.depsPyRunfiles,
+ p.depsParSpecs)
}
+
+ if p.installer != nil && p.installSource.Valid() {
+ p.installer.install(ctx, p.installSource.Path())
+ }
+
}
-func (p *pythonBaseModule) GeneratePythonBuildActions(ctx android.ModuleContext) android.OptionalPath {
+func (p *Module) GeneratePythonBuildActions(ctx android.ModuleContext) {
// expand python files from "srcs" property.
srcs := p.properties.Srcs
- switch p.properties.ActualVersion {
+ exclude_srcs := p.properties.Exclude_srcs
+ switch p.properties.Actual_version {
case pyVersion2:
srcs = append(srcs, p.properties.Version.Py2.Srcs...)
+ exclude_srcs = append(exclude_srcs, p.properties.Version.Py2.Exclude_srcs...)
case pyVersion3:
srcs = append(srcs, p.properties.Version.Py3.Srcs...)
+ exclude_srcs = append(exclude_srcs, p.properties.Version.Py3.Exclude_srcs...)
default:
- panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
- p.properties.ActualVersion, ctx.ModuleName()))
+ panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
+ p.properties.Actual_version, ctx.ModuleName()))
}
- expandedSrcs := ctx.ExpandSources(srcs, nil)
+ expandedSrcs := ctx.ExpandSources(srcs, exclude_srcs)
if len(expandedSrcs) == 0 {
ctx.ModuleErrorf("doesn't have any source files!")
}
@@ -292,15 +372,26 @@
pkg_path = filepath.Clean(p.properties.Pkg_path)
if pkg_path == ".." || strings.HasPrefix(pkg_path, "../") ||
strings.HasPrefix(pkg_path, "/") {
- ctx.PropertyErrorf("pkg_path", "%q is not a valid format.",
+ ctx.PropertyErrorf("pkg_path",
+ "%q must be a relative path contained in par file.",
p.properties.Pkg_path)
- return android.OptionalPath{}
+ return
}
- // pkg_path starts from "runfiles/" implicitly.
- pkg_path = filepath.Join(runFiles, pkg_path)
+ if p.properties.Is_internal != nil && *p.properties.Is_internal {
+ // pkg_path starts from "internal/" implicitly.
+ pkg_path = filepath.Join(internal, pkg_path)
+ } else {
+ // pkg_path starts from "runfiles/" implicitly.
+ pkg_path = filepath.Join(runFiles, pkg_path)
+ }
} else {
- // pkg_path starts from "runfiles/" implicitly.
- pkg_path = runFiles
+ if p.properties.Is_internal != nil && *p.properties.Is_internal {
+ // pkg_path starts from "runfiles/" implicitly.
+ pkg_path = internal
+ } else {
+ // pkg_path starts from "runfiles/" implicitly.
+ pkg_path = runFiles
+ }
}
p.genModulePathMappings(ctx, pkg_path, expandedSrcs, expandedData)
@@ -308,13 +399,11 @@
p.parSpec = p.dumpFileList(ctx, pkg_path)
p.uniqWholeRunfilesTree(ctx)
-
- return android.OptionalPath{}
}
// generate current module unique pathMappings: <dest: runfiles_path, src: source_path>
// for python/data files.
-func (p *pythonBaseModule) genModulePathMappings(ctx android.ModuleContext, pkg_path string,
+func (p *Module) genModulePathMappings(ctx android.ModuleContext, pkg_path string,
expandedSrcs, expandedData android.Paths) {
// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
// check duplicates.
@@ -355,7 +444,7 @@
}
// register build actions to dump filelist to disk.
-func (p *pythonBaseModule) dumpFileList(ctx android.ModuleContext, pkg_path string) parSpec {
+func (p *Module) dumpFileList(ctx android.ModuleContext, pkg_path string) parSpec {
relativeRootMap := make(map[string]android.Paths)
// the soong_zip params in order to pack current module's Python/data files.
ret := parSpec{rootPrefix: pkg_path}
@@ -365,7 +454,8 @@
// "srcs" or "data" properties may have filegroup so it might happen that
// the relative root for each source path is different.
for _, path := range pathMappings {
- relativeRoot := strings.TrimSuffix(path.src.String(), path.src.Rel())
+ var relativeRoot string
+ relativeRoot = strings.TrimSuffix(path.src.String(), path.src.Rel())
if v, found := relativeRootMap[relativeRoot]; found {
relativeRootMap[relativeRoot] = append(v, path.src)
} else {
@@ -392,8 +482,19 @@
return ret
}
-// check Python/data files duplicates from current module and its whole dependencies.
-func (p *pythonBaseModule) uniqWholeRunfilesTree(ctx android.ModuleContext) {
+func isPythonLibModule(module blueprint.Module) bool {
+ if m, ok := module.(*Module); ok {
+ // Python library has no bootstrapper or installer.
+ if m.bootstrapper != nil || m.installer != nil {
+ return false
+ }
+ return true
+ }
+ return false
+}
+
+// check Python source/data files duplicates from current module and its whole dependencies.
+func (p *Module) uniqWholeRunfilesTree(ctx android.ModuleContext) {
// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
// check duplicates.
destToPySrcs := make(map[string]string)
@@ -408,16 +509,15 @@
// visit all its dependencies in depth first.
ctx.VisitDepsDepthFirst(func(module blueprint.Module) {
- // module can only depend on Python library.
- if base, ok := module.(*pythonBaseModule); ok {
- if _, ok := base.subModule.(*PythonLibrary); !ok {
- panic(fmt.Errorf(
- "the dependency %q of module %q is not Python library!",
- ctx.ModuleName(), ctx.OtherModuleName(module)))
- }
- } else {
+ if ctx.OtherModuleDependencyTag(module) != pythonLibTag {
return
}
+ // Python module cannot depend on modules, except for Python library.
+ if !isPythonLibModule(module) {
+ panic(fmt.Errorf(
+ "the dependency %q of module %q is not Python library!",
+ ctx.ModuleName(), ctx.OtherModuleName(module)))
+ }
if dep, ok := module.(PythonDependency); ok {
srcs := dep.GetSrcsPathMappings()
for _, path := range srcs {
@@ -428,9 +528,7 @@
}
// binary needs the Python runfiles paths from all its
// dependencies to fill __init__.py in each runfiles dir.
- if sub, ok := p.subModule.(*pythonBinaryBase); ok {
- sub.depsPyRunfiles = append(sub.depsPyRunfiles, path.dest)
- }
+ p.depsPyRunfiles = append(p.depsPyRunfiles, path.dest)
}
data := dep.GetDataPathMappings()
for _, path := range data {
@@ -440,9 +538,7 @@
}
// binary needs the soong_zip arguments from all its
// dependencies to generate executable par file.
- if sub, ok := p.subModule.(*pythonBinaryBase); ok {
- sub.depsParSpecs = append(sub.depsParSpecs, dep.GetParSpec())
- }
+ p.depsParSpecs = append(p.depsParSpecs, dep.GetParSpec())
}
})
}
diff --git a/python/python_test.go b/python/python_test.go
index 4c30d95..8737302 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -28,7 +28,7 @@
"android/soong/android"
)
-type pyBinary struct {
+type pyModule struct {
name string
actualVersion string
pyRunfiles []string
@@ -41,7 +41,7 @@
buildNamePrefix = "soong_python_test"
moduleVariantErrTemplate = "%s: module %q variant %q: "
pkgPathErrTemplate = moduleVariantErrTemplate +
- "pkg_path: %q is not a valid format."
+ "pkg_path: %q must be a relative path contained in par file."
badIdentifierErrTemplate = moduleVariantErrTemplate +
"srcs: the path %q contains invalid token %q."
dupRunfileErrTemplate = moduleVariantErrTemplate +
@@ -58,7 +58,7 @@
mockFiles map[string][]byte
errors []string
- expectedBinaries []pyBinary
+ expectedBinaries []pyModule
}{
{
desc: "module without any src files",
@@ -222,7 +222,28 @@
mockFiles: map[string][]byte{
bpFile: []byte(`subdirs = ["dir"]`),
filepath.Join("dir", bpFile): []byte(
- `python_library_host {
+ `python_defaults {
+ name: "default_lib",
+ srcs: [
+ "default.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ srcs: [
+ "default_py2.py",
+ ],
+ },
+ py3: {
+ enabled: false,
+ srcs: [
+ "default_py3.py",
+ ],
+ },
+ },
+ }
+
+ python_library_host {
name: "lib5",
pkg_path: "a/b/",
srcs: [
@@ -251,6 +272,7 @@
python_binary_host {
name: "bin",
+ defaults: ["default_lib"],
pkg_path: "e/",
srcs: [
"bin.py",
@@ -271,19 +293,24 @@
},
}`,
),
- filepath.Join("dir", "file1.py"): nil,
- filepath.Join("dir", "file2.py"): nil,
- filepath.Join("dir", "bin.py"): nil,
- filepath.Join("dir", "file4.py"): nil,
+ filepath.Join("dir", "default.py"): nil,
+ filepath.Join("dir", "default_py2.py"): nil,
+ filepath.Join("dir", "default_py3.py"): nil,
+ filepath.Join("dir", "file1.py"): nil,
+ filepath.Join("dir", "file2.py"): nil,
+ filepath.Join("dir", "bin.py"): nil,
+ filepath.Join("dir", "file4.py"): nil,
stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
MAIN_FILE = '%main%'`),
},
- expectedBinaries: []pyBinary{
+ expectedBinaries: []pyModule{
{
name: "bin",
actualVersion: "PY3",
pyRunfiles: []string{
+ "runfiles/e/default.py",
"runfiles/e/bin.py",
+ "runfiles/e/default_py3.py",
"runfiles/e/file4.py",
},
depsPyRunfiles: []string{
@@ -314,6 +341,9 @@
android.ModuleFactoryAdaptor(PythonLibraryHostFactory))
ctx.RegisterModuleType("python_binary_host",
android.ModuleFactoryAdaptor(PythonBinaryHostFactory))
+ ctx.RegisterModuleType("python_defaults",
+ android.ModuleFactoryAdaptor(defaultsFactory))
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.Register()
ctx.MockFileSystem(d.mockFiles)
_, testErrs := ctx.ParseBlueprintsFiles(bpFile)
@@ -363,14 +393,10 @@
expParSpec string, expDepsParSpecs []string) (testErrs []error) {
module := ctx.ModuleForTests(name, variant)
- base, baseOk := module.Module().(*pythonBaseModule)
+ base, baseOk := module.Module().(*Module)
if !baseOk {
t.Fatalf("%s is not Python module!", name)
}
- sub, subOk := base.subModule.(*pythonBinaryBase)
- if !subOk {
- t.Fatalf("%s is not Python binary!", name)
- }
actPyRunfiles := []string{}
for _, path := range base.srcsPathMappings {
@@ -381,28 +407,28 @@
testErrs = append(testErrs, errors.New(fmt.Sprintf(
`binary "%s" variant "%s" has unexpected pyRunfiles: %q!`,
base.Name(),
- base.properties.ActualVersion,
+ base.properties.Actual_version,
actPyRunfiles)))
}
- if !reflect.DeepEqual(sub.depsPyRunfiles, expDepsPyRunfiles) {
+ if !reflect.DeepEqual(base.depsPyRunfiles, expDepsPyRunfiles) {
testErrs = append(testErrs, errors.New(fmt.Sprintf(
`binary "%s" variant "%s" has unexpected depsPyRunfiles: %q!`,
base.Name(),
- base.properties.ActualVersion,
- sub.depsPyRunfiles)))
+ base.properties.Actual_version,
+ base.depsPyRunfiles)))
}
if base.parSpec.soongParArgs() != strings.Replace(expParSpec, "@prefix@", buildDir, 1) {
testErrs = append(testErrs, errors.New(fmt.Sprintf(
`binary "%s" variant "%s" has unexpected parSpec: %q!`,
base.Name(),
- base.properties.ActualVersion,
+ base.properties.Actual_version,
base.parSpec.soongParArgs())))
}
actDepsParSpecs := []string{}
- for i, p := range sub.depsParSpecs {
+ for i, p := range base.depsParSpecs {
actDepsParSpecs = append(actDepsParSpecs, p.soongParArgs())
expDepsParSpecs[i] = strings.Replace(expDepsParSpecs[i], "@prefix@", buildDir, 1)
}
@@ -411,7 +437,7 @@
testErrs = append(testErrs, errors.New(fmt.Sprintf(
`binary "%s" variant "%s" has unexpected depsParSpecs: %q!`,
base.Name(),
- base.properties.ActualVersion,
+ base.properties.Actual_version,
actDepsParSpecs)))
}
diff --git a/python/test.go b/python/test.go
index 837eb25..de2b13e 100644
--- a/python/test.go
+++ b/python/test.go
@@ -16,7 +16,6 @@
import (
"android/soong/android"
- "path/filepath"
)
// This file contains the module types for building Python test.
@@ -25,30 +24,29 @@
android.RegisterModuleType("python_test_host", PythonTestHostFactory)
}
-type PythonTestHost struct {
- pythonBinaryBase
+type testDecorator struct {
+ *binaryDecorator
}
-var _ PythonSubModule = (*PythonTestHost)(nil)
-
-type pythonTestHostDecorator struct {
- pythonDecorator
+func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) {
+ test.binaryDecorator.baseInstaller.install(ctx, file)
}
-func (p *pythonTestHostDecorator) install(ctx android.ModuleContext, file android.Path) {
- p.pythonDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName())
- p.pythonDecorator.baseInstaller.install(ctx, file)
+func NewTest(hod android.HostOrDeviceSupported) *Module {
+ module, binary := NewBinary(hod)
+
+ binary.baseInstaller = NewPythonInstaller("nativetest")
+
+ test := &testDecorator{binaryDecorator: binary}
+
+ module.bootstrapper = test
+ module.installer = test
+
+ return module
}
func PythonTestHostFactory() android.Module {
- decorator := &pythonTestHostDecorator{
- pythonDecorator: pythonDecorator{baseInstaller: NewPythonInstaller("nativetest")}}
+ module := NewTest(android.HostSupportedNoCross)
- module := &PythonBinaryHost{}
- module.pythonBaseModule.installer = decorator
-
- module.AddProperties(&module.binaryProperties)
-
- return InitPythonBaseModule(&module.pythonBinaryBase.pythonBaseModule,
- &module.pythonBinaryBase, android.HostSupportedNoCross)
+ return module.Init()
}
diff --git a/root.bp b/root.bp
index 582552e..f27d28b 100644
--- a/root.bp
+++ b/root.bp
@@ -18,6 +18,7 @@
"development/*",
"device/*/*",
"external/*",
+ "external/python/*",
"frameworks/*",
"frameworks/compile/*",
"frameworks/hardware/interfaces",
@@ -35,5 +36,7 @@
"system/tools/*",
"test/vts",
"test/vts-testcase/*",
+ "tools/*",
+ "toolchain/*",
"vendor/*/*",
]
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index f8ce349..197a38d 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -13,7 +13,7 @@
# PLATFORM_VERSION_ALL_CODESNAMES is a comma separated list like O,P. We need to
# turn this into ["O","P"].
-PLATFORM_VERSION_ALL_CODENAMES=${PLATFORM_VERSION_ALL_CODENAMES/,/","}
+PLATFORM_VERSION_ALL_CODENAMES=${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}
PLATFORM_VERSION_ALL_CODENAMES="[\"${PLATFORM_VERSION_ALL_CODENAMES}\"]"
SOONG_OUT=${OUT_DIR}/soong
diff --git a/ui/build/config.go b/ui/build/config.go
index 1c2f73b..2b0da4d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -403,11 +403,7 @@
}
func (c *configImpl) ProductOut() string {
- if buildType, ok := c.environ.Get("TARGET_BUILD_TYPE"); ok && buildType == "debug" {
- return filepath.Join(c.OutDir(), "debug", "target", "product", c.TargetDevice())
- } else {
- return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
- }
+ return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
}
func (c *configImpl) DevicePreviousProductConfig() string {
@@ -415,11 +411,7 @@
}
func (c *configImpl) hostOutRoot() string {
- if buildType, ok := c.environ.Get("HOST_BUILD_TYPE"); ok && buildType == "debug" {
- return filepath.Join(c.OutDir(), "debug", "host")
- } else {
- return filepath.Join(c.OutDir(), "host")
- }
+ return filepath.Join(c.OutDir(), "host")
}
func (c *configImpl) HostOut() string {