Merge "Add D8 support"
diff --git a/Android.bp b/Android.bp
index 32b89d1..1f6ebe2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5,6 +5,7 @@
"fs",
"finder",
"jar",
+ "zip",
"third_party/zip",
"ui/*",
]
diff --git a/android/paths.go b/android/paths.go
index f88d650..7443547 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -199,9 +199,9 @@
if pathConfig(ctx).AllowMissingDependencies() {
if modCtx, ok := ctx.(ModuleContext); ok {
ret := make(Paths, 0, len(paths))
- intermediates := filepath.Join(modCtx.ModuleDir(), modCtx.ModuleName(), modCtx.ModuleSubDir(), "missing")
+ intermediates := pathForModule(modCtx).withRel("missing")
for _, path := range paths {
- p := ExistentPathForSource(ctx, intermediates, path)
+ p := ExistentPathForSource(ctx, intermediates.String(), path)
if p.Valid() {
ret = append(ret, p.Path())
} else {
@@ -303,6 +303,32 @@
return list[:k]
}
+func indexPathList(s Path, list []Path) int {
+ for i, l := range list {
+ if l == s {
+ return i
+ }
+ }
+
+ return -1
+}
+
+func inPathList(p Path, list []Path) bool {
+ return indexPathList(p, list) != -1
+}
+
+func FilterPathList(list []Path, filter []Path) (remainder []Path, filtered []Path) {
+ for _, l := range list {
+ if inPathList(l, filter) {
+ filtered = append(filtered, l)
+ } else {
+ remainder = append(remainder, l)
+ }
+ }
+
+ return
+}
+
// HasExt returns true of any of the paths have extension ext, otherwise false
func (p Paths) HasExt(ext string) bool {
for _, path := range p {
@@ -546,6 +572,12 @@
basePath
}
+func (p OutputPath) withRel(rel string) OutputPath {
+ p.basePath.path = filepath.Join(p.basePath.path, rel)
+ p.basePath.rel = rel
+ return p
+}
+
var _ Path = OutputPath{}
// PathForOutput joins the provided paths and returns an OutputPath that is
@@ -640,6 +672,10 @@
var _ Path = ModuleOutPath{}
+func pathForModule(ctx ModuleContext) OutputPath {
+ return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
+}
+
// PathForVndkRefDump returns an OptionalPath representing the path of the reference
// abi dump for the given module. This is not guaranteed to be valid.
func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string, vndkOrNdk, isSourceDump bool) OptionalPath {
@@ -668,14 +704,15 @@
// output directory.
func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
p := validatePath(ctx, paths...)
- return ModuleOutPath{PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), p)}
+ return ModuleOutPath{
+ OutputPath: pathForModule(ctx).withRel(p),
+ }
}
// ModuleGenPath is a Path representing the 'gen' directory in a module's output
// directory. Mainly used for generated sources.
type ModuleGenPath struct {
ModuleOutPath
- path string
}
var _ Path = ModuleGenPath{}
@@ -687,8 +724,9 @@
func PathForModuleGen(ctx ModuleContext, paths ...string) ModuleGenPath {
p := validatePath(ctx, paths...)
return ModuleGenPath{
- PathForModuleOut(ctx, "gen", p),
- p,
+ ModuleOutPath: ModuleOutPath{
+ OutputPath: pathForModule(ctx).withRel("gen").withRel(p),
+ },
}
}
diff --git a/android/testing.go b/android/testing.go
index 519e279..62b91e2 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -65,7 +65,14 @@
})
if module == nil {
- panic(fmt.Errorf("failed to find module %q variant %q", name, variant))
+ // find all the modules that do exist
+ allModuleNames := []string{}
+ ctx.VisitAllModules(func(m blueprint.Module) {
+ allModuleNames = append(allModuleNames, m.(Module).Name()+"("+ctx.ModuleSubDir(m)+")")
+ })
+
+ panic(fmt.Errorf("failed to find module %q variant %q."+
+ "\nall modules: %v", name, variant, allModuleNames))
}
return TestingModule{module}
@@ -95,7 +102,7 @@
outputs = append(outputs, p.Output)
}
for _, f := range outputs {
- if f.Base() == file {
+ if f.Rel() == file {
return p
}
}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index f5858a7..0de5009 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -135,6 +135,7 @@
"LOCAL_PROPRIETARY_MODULE": "proprietary",
"LOCAL_VENDOR_MODULE": "vendor",
"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
+ "LOCAL_DEX_PREOPT": "dex_preopt",
})
}
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index a49f620..5cb3f7a 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -80,11 +80,23 @@
}
func (f *bpFile) setMkPos(pos, end scanner.Position) {
- if pos.Line < f.mkPos.Line {
- panic(fmt.Errorf("out of order lines, %q after %q", pos, f.mkPos))
+ // It is unusual but not forbidden for pos.Line to be smaller than f.mkPos.Line
+ // For example:
+ //
+ // if true # this line is emitted 1st
+ // if true # this line is emitted 2nd
+ // some-target: some-file # this line is emitted 3rd
+ // echo doing something # this recipe is emitted 6th
+ // endif #some comment # this endif is emitted 4th; this comment is part of the recipe
+ // echo doing more stuff # this is part of the recipe
+ // endif # this endif is emitted 5th
+ //
+ // However, if pos.Line < f.mkPos.Line, we treat it as though it were equal
+ if pos.Line >= f.mkPos.Line {
+ f.bpPos.Line += (pos.Line - f.mkPos.Line)
+ f.mkPos = end
}
- f.bpPos.Line += (pos.Line - f.mkPos.Line)
- f.mkPos = end
+
}
type conditional struct {
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 4681a7d..0b86540 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -425,6 +425,41 @@
}
}`,
},
+ {
+ // the important part of this test case is that it confirms that androidmk doesn't
+ // panic in this case
+ desc: "multiple directives inside recipe",
+ in: `
+ifeq ($(a),true)
+ifeq ($(b),false)
+imABuildStatement: somefile
+ echo begin
+endif # a==true
+ echo middle
+endif # b==false
+ echo end
+`,
+ expected: `
+// ANDROIDMK TRANSLATION ERROR: unsupported conditional
+// ifeq ($(a),true)
+
+// ANDROIDMK TRANSLATION ERROR: unsupported conditional
+// ifeq ($(b),false)
+
+// ANDROIDMK TRANSLATION ERROR: unsupported line
+// rule: imABuildStatement: somefile
+// echo begin
+// # a==true
+// echo middle
+// # b==false
+// echo end
+//
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// endif
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// endif
+ `,
+ },
}
func reformatBlueprint(input string) string {
diff --git a/cc/cc.go b/cc/cc.go
index 2fafaa2..7163696 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -326,6 +326,11 @@
// Flags used to compile this module
flags Flags
+
+ // When calling a linker, if module A depends on module B, then A must precede B in its command
+ // line invocation. staticDepsInLinkOrder stores the proper ordering of all of the transitive
+ // deps of this module
+ staticDepsInLinkOrder android.Paths
}
func (c *Module) Init() android.Module {
@@ -540,6 +545,51 @@
return name
}
+// orderDeps reorders dependencies into a list such that if module A depends on B, then
+// A will precede B in the resultant list.
+// This is convenient for passing into a linker.
+func orderDeps(directDeps []android.Path, transitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
+ // If A depends on B, then
+ // Every list containing A will also contain B later in the list
+ // So, after concatenating all lists, the final instance of B will have come from the same
+ // original list as the final instance of A
+ // So, the final instance of B will be later in the concatenation than the final A
+ // So, keeping only the final instance of A and of B ensures that A is earlier in the output
+ // list than B
+ for _, dep := range directDeps {
+ orderedAllDeps = append(orderedAllDeps, dep)
+ orderedAllDeps = append(orderedAllDeps, transitiveDeps[dep]...)
+ }
+
+ orderedAllDeps = lastUniquePaths(orderedAllDeps)
+
+ // We don't want to add any new dependencies into directDeps (to allow the caller to
+ // intentionally exclude or replace any unwanted transitive dependencies), so we limit the
+ // resultant list to only what the caller has chosen to include in directDeps
+ _, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directDeps)
+
+ return orderedAllDeps, orderedDeclaredDeps
+}
+
+func orderStaticModuleDeps(module *Module, deps []*Module) (results []android.Path) {
+ // make map of transitive dependencies
+ transitiveStaticDepNames := make(map[android.Path][]android.Path, len(deps))
+ for _, dep := range deps {
+ transitiveStaticDepNames[dep.outputFile.Path()] = dep.staticDepsInLinkOrder
+ }
+ // get the output file for each declared dependency
+ depFiles := []android.Path{}
+ for _, dep := range deps {
+ depFiles = append(depFiles, dep.outputFile.Path())
+ }
+
+ // reorder the dependencies based on transitive dependencies
+ module.staticDepsInLinkOrder, results = orderDeps(depFiles, transitiveStaticDepNames)
+
+ return results
+
+}
+
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
ctx := &moduleContext{
@@ -985,6 +1035,8 @@
func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
+ directStaticDeps := []*Module{}
+
ctx.VisitDirectDeps(func(dep blueprint.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1108,7 +1160,8 @@
depPtr = &depPaths.LateSharedLibsDeps
depFile = ccDep.linker.(libraryInterface).toc()
case staticDepTag, staticExportDepTag:
- ptr = &depPaths.StaticLibs
+ ptr = nil
+ directStaticDeps = append(directStaticDeps, ccDep)
case lateStaticDepTag:
ptr = &depPaths.LateStaticLibs
case wholeStaticDepTag:
@@ -1192,6 +1245,9 @@
}
})
+ // use the ordered dependencies as this module's dependencies
+ depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps)...)
+
// Dedup exported flags from dependencies
depPaths.Flags = firstUniqueElements(depPaths.Flags)
depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
@@ -1417,6 +1473,23 @@
return list[totalSkip:]
}
+// lastUniquePaths is the same as lastUniqueElements but uses Path structs
+func lastUniquePaths(list []android.Path) []android.Path {
+ totalSkip := 0
+ for i := len(list) - 1; i >= totalSkip; i-- {
+ skip := 0
+ for j := i - 1; j >= totalSkip; j-- {
+ if list[i] == list[j] {
+ skip++
+ } else {
+ list[j+skip] = list[j]
+ }
+ }
+ totalSkip += skip
+ }
+ return list[totalSkip:]
+}
+
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
if ctx.AConfig().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 94e3e66..b9cdba5 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2,9 +2,12 @@
import (
"android/soong/android"
+ "fmt"
"io/ioutil"
"os"
"reflect"
+ "sort"
+ "strings"
"testing"
"github.com/google/blueprint/proptools"
@@ -43,6 +46,7 @@
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(libraryFactory))
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("image", vendorMutator).Parallel()
ctx.BottomUp("link", linkageMutator).Parallel()
@@ -50,6 +54,64 @@
})
ctx.Register()
+ // add some modules that are required by the compiler and/or linker
+ bp = bp + `
+ toolchain_library {
+ name: "libatomic",
+ vendor_available: true,
+ }
+
+ toolchain_library {
+ name: "libcompiler_rt-extras",
+ vendor_available: true,
+ }
+
+ toolchain_library {
+ name: "libgcc",
+ vendor_available: true,
+ }
+
+ cc_library {
+ name: "libc",
+ no_libgcc : true,
+ nocrt : true,
+ system_shared_libs: [],
+ }
+ llndk_library {
+ name: "libc",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libm",
+ no_libgcc : true,
+ nocrt : true,
+ system_shared_libs: [],
+ }
+ llndk_library {
+ name: "libm",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libdl",
+ no_libgcc : true,
+ nocrt : true,
+ system_shared_libs: [],
+ }
+ llndk_library {
+ name: "libdl",
+ symbol_file: "",
+ }
+
+ cc_object {
+ name: "crtbegin_so",
+ }
+
+ cc_object {
+ name: "crtend_so",
+ }
+
+`
+
ctx.MockFileSystem(map[string][]byte{
"Android.bp": []byte(bp),
"foo.c": nil,
@@ -57,9 +119,9 @@
})
_, errs := ctx.ParseBlueprintsFiles("Android.bp")
- fail(t, errs)
+ failIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
- fail(t, errs)
+ failIfErrored(t, errs)
return ctx
}
@@ -79,44 +141,6 @@
},
},
}
- toolchain_library {
- name: "libatomic",
- vendor_available: true,
- }
- toolchain_library {
- name: "libcompiler_rt-extras",
- vendor_available: true,
- }
- cc_library {
- name: "libc",
- no_libgcc : true,
- nocrt : true,
- system_shared_libs: [],
- }
- llndk_library {
- name: "libc",
- symbol_file: "",
- }
- cc_library {
- name: "libm",
- no_libgcc : true,
- nocrt : true,
- system_shared_libs: [],
- }
- llndk_library {
- name: "libm",
- symbol_file: "",
- }
- cc_library {
- name: "libdl",
- no_libgcc : true,
- nocrt : true,
- system_shared_libs: [],
- }
- llndk_library {
- name: "libdl",
- symbol_file: "",
- }
`)
ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld")
@@ -339,3 +363,245 @@
}
}
}
+
+var staticLinkDepOrderTestCases = []struct {
+ // This is a string representation of a map[moduleName][]moduleDependency .
+ // It models the dependencies declared in an Android.bp file.
+ in string
+
+ // allOrdered is a string representation of a map[moduleName][]moduleDependency .
+ // The keys of allOrdered specify which modules we would like to check.
+ // The values of allOrdered specify the expected result (of the transitive closure of all
+ // dependencies) for each module to test
+ allOrdered string
+
+ // outOrdered is a string representation of a map[moduleName][]moduleDependency .
+ // The keys of outOrdered specify which modules we would like to check.
+ // The values of outOrdered specify the expected result (of the ordered linker command line)
+ // for each module to test.
+ outOrdered string
+}{
+ // Simple tests
+ {
+ in: "",
+ outOrdered: "",
+ },
+ {
+ in: "a:",
+ outOrdered: "a:",
+ },
+ {
+ in: "a:b; b:",
+ outOrdered: "a:b; b:",
+ },
+ // Tests of reordering
+ {
+ // diamond example
+ in: "a:d,b,c; b:d; c:d; d:",
+ outOrdered: "a:b,c,d; b:d; c:d; d:",
+ },
+ {
+ // somewhat real example
+ in: "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
+ outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
+ },
+ {
+ // multiple reorderings
+ in: "a:b,c,d,e; d:b; e:c",
+ outOrdered: "a:d,b,e,c; d:b; e:c",
+ },
+ {
+ // should reorder without adding new transitive dependencies
+ in: "bin:lib2,lib1; lib1:lib2,liboptional",
+ allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
+ outOrdered: "bin:lib1,lib2; lib1:lib2,liboptional",
+ },
+ {
+ // multiple levels of dependencies
+ in: "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
+ allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
+ outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
+ },
+ // tiebreakers for when two modules specifying different orderings and there is no dependency
+ // to dictate an order
+ {
+ // if the tie is between two modules at the end of a's deps, then a's order wins
+ in: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
+ outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
+ },
+ {
+ // if the tie is between two modules at the start of a's deps, then c's order is used
+ in: "a1:d,e,b1,c1; b1:d,e; c1:e,d; a2:d,e,b2,c2; b2:d,e; c2:d,e",
+ outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d; a2:b2,c2,d,e; b2:d,e; c2:d,e",
+ },
+ // Tests involving duplicate dependencies
+ {
+ // simple duplicate
+ in: "a:b,c,c,b",
+ outOrdered: "a:c,b",
+ },
+ {
+ // duplicates with reordering
+ in: "a:b,c,d,c; c:b",
+ outOrdered: "a:d,c,b",
+ },
+ // Tests to confirm the nonexistence of infinite loops.
+ // These cases should never happen, so as long as the test terminates and the
+ // result is deterministic then that should be fine.
+ {
+ in: "a:a",
+ outOrdered: "a:a",
+ },
+ {
+ in: "a:b; b:c; c:a",
+ allOrdered: "a:b,c; b:c,a; c:a,b",
+ outOrdered: "a:b; b:c; c:a",
+ },
+ {
+ in: "a:b,c; b:c,a; c:a,b",
+ allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
+ outOrdered: "a:c,b; b:a,c; c:b,a",
+ },
+}
+
+// converts from a string like "a:b,c; d:e" to (["a","b"], {"a":["b","c"], "d":["e"]}, [{"a", "a.o"}, {"b", "b.o"}])
+func parseModuleDeps(text string) (modulesInOrder []android.Path, allDeps map[android.Path][]android.Path) {
+ // convert from "a:b,c; d:e" to "a:b,c;d:e"
+ strippedText := strings.Replace(text, " ", "", -1)
+ if len(strippedText) < 1 {
+ return []android.Path{}, make(map[android.Path][]android.Path, 0)
+ }
+ allDeps = make(map[android.Path][]android.Path, 0)
+
+ // convert from "a:b,c;d:e" to ["a:b,c", "d:e"]
+ moduleTexts := strings.Split(strippedText, ";")
+
+ outputForModuleName := func(moduleName string) android.Path {
+ return android.PathForTesting(moduleName)
+ }
+
+ for _, moduleText := range moduleTexts {
+ // convert from "a:b,c" to ["a", "b,c"]
+ components := strings.Split(moduleText, ":")
+ if len(components) != 2 {
+ panic(fmt.Sprintf("illegal module dep string %q from larger string %q; must contain one ':', not %v", moduleText, text, len(components)-1))
+ }
+ moduleName := components[0]
+ moduleOutput := outputForModuleName(moduleName)
+ modulesInOrder = append(modulesInOrder, moduleOutput)
+
+ depString := components[1]
+ // convert from "b,c" to ["b", "c"]
+ depNames := strings.Split(depString, ",")
+ if len(depString) < 1 {
+ depNames = []string{}
+ }
+ var deps []android.Path
+ for _, depName := range depNames {
+ deps = append(deps, outputForModuleName(depName))
+ }
+ allDeps[moduleOutput] = deps
+ }
+ return modulesInOrder, allDeps
+}
+
+func TestStaticLinkDependencyOrdering(t *testing.T) {
+ for _, testCase := range staticLinkDepOrderTestCases {
+ errs := []string{}
+
+ // parse testcase
+ _, givenTransitiveDeps := parseModuleDeps(testCase.in)
+ expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
+ if testCase.allOrdered == "" {
+ // allow the test case to skip specifying allOrdered
+ testCase.allOrdered = testCase.outOrdered
+ }
+ _, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
+
+ // For each module whose post-reordered dependencies were specified, validate that
+ // reordering the inputs produces the expected outputs.
+ for _, moduleName := range expectedModuleNames {
+ moduleDeps := givenTransitiveDeps[moduleName]
+ orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
+
+ correctAllOrdered := expectedAllDeps[moduleName]
+ if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
+ errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
+ "\nInput: %q"+
+ "\nmodule: %v"+
+ "\nexpected: %s"+
+ "\nactual: %s",
+ testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
+ }
+
+ correctOutputDeps := expectedTransitiveDeps[moduleName]
+ if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
+ errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
+ "\nInput: %q"+
+ "\nmodule: %v"+
+ "\nexpected: %s"+
+ "\nactual: %s",
+ testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
+ }
+ }
+
+ if len(errs) > 0 {
+ sort.Strings(errs)
+ for _, err := range errs {
+ t.Error(err)
+ }
+ }
+ }
+}
+func failIfErrored(t *testing.T, errs []error) {
+ if len(errs) > 0 {
+ for _, err := range errs {
+ t.Error(err)
+ }
+ t.FailNow()
+ }
+}
+
+func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
+ for _, moduleName := range moduleNames {
+ module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
+ output := module.outputFile.Path()
+ paths = append(paths, output)
+ }
+ return paths
+}
+
+func TestLibDeps(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "a",
+ static_libs: ["b", "c", "d"],
+ }
+ cc_library {
+ name: "b",
+ }
+ cc_library {
+ name: "c",
+ static_libs: ["b"],
+ }
+ cc_library {
+ name: "d",
+ }
+
+ `)
+
+ variant := "android_arm64_armv8-a_core_static"
+ moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
+ actual := moduleA.staticDepsInLinkOrder
+ expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("staticDeps orderings were not propagated correctly"+
+ "\nactual: %v"+
+ "\nexpected: %v",
+ actual,
+ expected,
+ )
+ }
+
+}
diff --git a/cc/library.go b/cc/library.go
index e963ecb..1434f2c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -64,6 +64,12 @@
// export headers generated from .proto sources
Export_proto_headers bool
}
+ Target struct {
+ Vendor struct {
+ // version script for this vendor variant
+ Version_script *string `android:"arch_variant"`
+ }
+ }
}
type LibraryMutatedProperties struct {
@@ -455,7 +461,11 @@
deps.StaticLibs = append(deps.StaticLibs, library.Properties.Shared.Static_libs...)
deps.SharedLibs = append(deps.SharedLibs, library.Properties.Shared.Shared_libs...)
}
-
+ if ctx.useVndk() {
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
+ deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
+ }
return deps
}
@@ -491,6 +501,9 @@
unexportedSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Unexported_symbols_list)
forceNotWeakSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Force_symbols_not_weak_list)
forceWeakSymbols := android.OptionalPathForModuleSrc(ctx, library.Properties.Force_symbols_weak_list)
+ if ctx.useVndk() && library.Properties.Target.Vendor.Version_script != nil {
+ versionScript = android.OptionalPathForModuleSrc(ctx, library.Properties.Target.Vendor.Version_script)
+ }
if !ctx.Darwin() {
if versionScript.Valid() {
flags.LdFlags = append(flags.LdFlags, "-Wl,--version-script,"+versionScript.String())
diff --git a/cc/linker.go b/cc/linker.go
index 6ec5630..1cf3f61 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -89,6 +89,10 @@
// list of shared libs that should not be used to build
// the vendor variant of the C/C++ module.
Exclude_shared_libs []string
+
+ // list of static libs that should not be used to build
+ // the vendor variant of the C/C++ module.
+ Exclude_static_libs []string
}
}
}
@@ -135,6 +139,9 @@
if ctx.useVndk() {
deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor.Exclude_shared_libs)
deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor.Exclude_shared_libs)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
+ deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs)
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
}
if ctx.ModuleName() != "libcompiler_rt-extras" {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b8b5ffa..74f4bdb 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -342,6 +342,10 @@
diagSanitizers = append(diagSanitizers, "address")
}
+ if Bool(sanitize.Properties.Sanitize.Thread) {
+ sanitizers = append(sanitizers, "thread")
+ }
+
if Bool(sanitize.Properties.Sanitize.Coverage) {
flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp")
}
@@ -408,6 +412,8 @@
runtimeLibrary := ""
if Bool(sanitize.Properties.Sanitize.Address) {
runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
+ } else if Bool(sanitize.Properties.Sanitize.Thread) {
+ runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(ctx.toolchain())
} else if len(diagSanitizers) > 0 {
runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
}
diff --git a/java/androidmk.go b/java/androidmk.go
index e349de4..97924f3 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -36,6 +36,9 @@
}
if library.dexJarFile != nil {
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
+ if library.deviceProperties.Dex_preopt == nil || *library.deviceProperties.Dex_preopt == false {
+ fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+ }
}
fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.deviceProperties.Sdk_version)
},
diff --git a/java/builder.go b/java/builder.go
index 9086d51..4aaf841 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -160,7 +160,7 @@
srcFiles android.Paths, srcJars classpath,
flags javaBuilderFlags) {
- classDir := android.PathForModuleOut(ctx, "classes-kt")
+ classDir := android.PathForModuleOut(ctx, "kotlinc", "classes")
inputs := append(android.Paths(nil), srcFiles...)
inputs = append(inputs, srcJars...)
@@ -184,7 +184,7 @@
flags javaBuilderFlags, deps android.Paths) {
transformJavaToClasses(ctx, outputFile, srcFiles, srcJars, flags, deps,
- "", "javac", javac)
+ "javac", "javac", javac)
}
func RunErrorProne(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -196,7 +196,7 @@
}
transformJavaToClasses(ctx, outputFile, srcFiles, srcJars, flags, nil,
- "-errorprone", "errorprone", errorprone)
+ "errorprone", "errorprone", errorprone)
}
// transformJavaToClasses takes source files and converts them to a jar containing .class files.
@@ -211,7 +211,7 @@
func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
srcFiles android.Paths, srcJars classpath,
flags javaBuilderFlags, deps android.Paths,
- intermediatesSuffix, desc string, rule blueprint.Rule) {
+ intermediatesDir, desc string, rule blueprint.Rule) {
deps = append(deps, srcJars...)
@@ -237,8 +237,8 @@
"bootClasspath": bootClasspath,
"sourcepath": srcJars.JavaSourcepath(),
"classpath": flags.classpath.JavaClasspath(),
- "outDir": android.PathForModuleOut(ctx, "classes"+intermediatesSuffix).String(),
- "annoDir": android.PathForModuleOut(ctx, "anno"+intermediatesSuffix).String(),
+ "outDir": android.PathForModuleOut(ctx, intermediatesDir, "classes").String(),
+ "annoDir": android.PathForModuleOut(ctx, intermediatesDir, "anno").String(),
"javaVersion": flags.javaVersion,
},
})
@@ -288,7 +288,7 @@
func TransformDesugar(ctx android.ModuleContext, outputFile android.WritablePath,
classesJar android.Path, flags javaBuilderFlags) {
- dumpDir := android.PathForModuleOut(ctx, "desugar_dumped_classes")
+ dumpDir := android.PathForModuleOut(ctx, "desugar", "classes")
javaFlags := ""
if ctx.AConfig().UseOpenJDK9() {
diff --git a/java/java.go b/java/java.go
index 76e574e..6973915 100644
--- a/java/java.go
+++ b/java/java.go
@@ -143,6 +143,10 @@
// If true, export a copy of the module as a -hostdex module for host testing.
Hostdex *bool
+ // If false, prevent dexpreopting and stripping the dex file from the final jar. Defaults to
+ // true.
+ Dex_preopt *bool
+
// When targeting 1.9, override the modules to use with --system
System_modules *string
}
@@ -502,6 +506,8 @@
var jars android.Paths
+ jarName := ctx.ModuleName() + ".jar"
+
if srcFiles.HasExt(".kt") {
// If there are kotlin files, compile them first but pass all the kotlin and java files
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
@@ -515,7 +521,7 @@
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.kotlinStdlib...)
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.classpath...)
- kotlinJar := android.PathForModuleOut(ctx, "classes-kt.jar")
+ kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
TransformKotlinToClasses(ctx, kotlinJar, srcFiles, srcJars, flags)
if ctx.Failed() {
return
@@ -536,13 +542,13 @@
// a rebuild when error-prone is turned off).
// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
// enable error-prone without affecting the output class files.
- errorprone := android.PathForModuleOut(ctx, "classes-errorprone.list")
+ errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
RunErrorProne(ctx, errorprone, javaSrcFiles, srcJars, flags)
extraJarDeps = append(extraJarDeps, errorprone)
}
// Compile java sources into .class files
- classes := android.PathForModuleOut(ctx, "classes-compiled.jar")
+ classes := android.PathForModuleOut(ctx, "javac", jarName)
TransformJavaToClasses(ctx, classes, javaSrcFiles, srcJars, flags, extraJarDeps)
if ctx.Failed() {
return
@@ -570,7 +576,7 @@
}
if len(resArgs) > 0 {
- resourceJar := android.PathForModuleOut(ctx, "res.jar")
+ resourceJar := android.PathForModuleOut(ctx, "res", jarName)
TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
if ctx.Failed() {
return
@@ -592,7 +598,7 @@
// Optimization: skip the combine step if there is nothing to do
outputFile = jars[0]
} else {
- combinedJar := android.PathForModuleOut(ctx, "classes.jar")
+ combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
TransformJarsToJar(ctx, combinedJar, jars, manifest, false)
outputFile = combinedJar
}
@@ -600,7 +606,7 @@
if j.properties.Jarjar_rules != nil {
jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
// Transform classes.jar into classes-jarjar.jar
- jarjarFile := android.PathForModuleOut(ctx, "classes-jarjar.jar")
+ jarjarFile := android.PathForModuleOut(ctx, "jarjar", jarName)
TransformJarJar(ctx, jarjarFile, outputFile, jarjar_rules)
outputFile = jarjarFile
if ctx.Failed() {
@@ -658,17 +664,17 @@
flags.desugarFlags = strings.Join(desugarFlags, " ")
- desugarJar := android.PathForModuleOut(ctx, "classes-desugar.jar")
+ desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
TransformDesugar(ctx, desugarJar, outputFile, flags)
outputFile = desugarJar
if ctx.Failed() {
return
}
- // Compile classes.jar into classes.dex and then javalib.jar
- javalibJar := android.PathForModuleOut(ctx, "javalib.jar")
- TransformClassesJarToDexJar(ctx, javalibJar, desugarJar, flags)
- outputFile = javalibJar
+ // Compile classes.jar into classes.dex and then a dex jar
+ dexJar := android.PathForModuleOut(ctx, "dex", jarName)
+ TransformClassesJarToDexJar(ctx, dexJar, desugarJar, flags)
+ outputFile = dexJar
if ctx.Failed() {
return
}
diff --git a/java/java_test.go b/java/java_test.go
index d64688f..6dde938 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -142,7 +142,7 @@
case strings.HasSuffix(name, ".jar"):
return name
default:
- return filepath.Join(buildDir, ".intermediates", name, "android_common", "classes-compiled.jar")
+ return filepath.Join(buildDir, ".intermediates", name, "android_common", "javac", name+".jar")
}
}
@@ -173,8 +173,8 @@
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
}
- bar := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "classes-compiled.jar")
- baz := filepath.Join(buildDir, ".intermediates", "baz", "android_common", "classes-compiled.jar")
+ bar := ctx.ModuleForTests("bar", "android_common").Rule("javac").Output.String()
+ baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
if !strings.Contains(javac.Args["classpath"], bar) {
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bar)
@@ -465,12 +465,12 @@
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
}
- bar := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "classes-compiled.jar")
+ bar := ctx.ModuleForTests("bar", "android_common").Rule("javac").Output.String()
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", "android_common", "classes-compiled.jar")
+ baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
}
@@ -530,8 +530,8 @@
}
`+test.extra)
- foo := ctx.ModuleForTests("foo", "android_common").Output("classes.jar")
- fooRes := ctx.ModuleForTests("foo", "android_common").Output("res.jar")
+ foo := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
+ fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
if !inList(fooRes.Output.String(), foo.Inputs.Strings()) {
t.Errorf("foo combined jars %v does not contain %q",
@@ -563,7 +563,7 @@
}
`)
- fooRes := ctx.ModuleForTests("foo", "android_common").Output("res.jar")
+ fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
expected := "-C res -f res/a -f res/b"
if fooRes.Args["jarArgs"] != expected {
@@ -572,7 +572,7 @@
}
- barRes := ctx.ModuleForTests("bar", "android_common").Output("res.jar")
+ barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
expected = "-C . -f res/a"
if barRes.Args["jarArgs"] != expected {
@@ -625,7 +625,7 @@
kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
- jar := ctx.ModuleForTests("foo", "android_common").Output("classes.jar")
+ jar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" ||
kotlinc.Inputs[1].String() != "b.kt" {
diff --git a/ui/logger/logger.go b/ui/logger/logger.go
index 7d9687b..15c413d 100644
--- a/ui/logger/logger.go
+++ b/ui/logger/logger.go
@@ -38,6 +38,7 @@
"path/filepath"
"strconv"
"sync"
+ "syscall"
)
type Logger interface {
@@ -93,10 +94,19 @@
// existing files to <filename>.#.<ext>, keeping up to maxCount files.
// <filename>.1.<ext> is the most recent backup, <filename>.2.<ext> is the
// second most recent backup, etc.
-//
-// TODO: This function is not guaranteed to be atomic, if there are multiple
-// users attempting to do the same operation, the result is undefined.
func CreateFileWithRotation(filename string, maxCount int) (*os.File, error) {
+ lockFileName := filepath.Join(filepath.Dir(filename), ".lock_"+filepath.Base(filename))
+ lockFile, err := os.OpenFile(lockFileName, os.O_RDWR|os.O_CREATE, 0666)
+ if err != nil {
+ return nil, err
+ }
+ defer lockFile.Close()
+
+ err = syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX)
+ if err != nil {
+ return nil, err
+ }
+
if _, err := os.Lstat(filename); err == nil {
ext := filepath.Ext(filename)
basename := filename[:len(filename)-len(ext)]
diff --git a/ui/logger/logger_test.go b/ui/logger/logger_test.go
index 0f88ab3..dc6f2e9 100644
--- a/ui/logger/logger_test.go
+++ b/ui/logger/logger_test.go
@@ -67,7 +67,7 @@
t.Fatalf("Failed to read dir: %v", err)
}
sort.Strings(names)
- expected := []string{"build.1.log", "build.2.log", "build.3.log", "build.log"}
+ expected := []string{".lock_build.log", "build.1.log", "build.2.log", "build.3.log", "build.log"}
if !reflect.DeepEqual(names, expected) {
t.Errorf("File list does not match.")
t.Errorf(" got: %v", names)
diff --git a/ui/tracer/microfactory.go b/ui/tracer/microfactory.go
index 320d9d8..acb9be4 100644
--- a/ui/tracer/microfactory.go
+++ b/ui/tracer/microfactory.go
@@ -28,7 +28,7 @@
f, err := os.Open(filename)
if err != nil {
- t.log.Println("Error opening microfactory trace:", err)
+ t.log.Verboseln("Error opening microfactory trace:", err)
return
}
defer f.Close()
diff --git a/cmd/soong_zip/Android.bp b/zip/Android.bp
similarity index 85%
copy from cmd/soong_zip/Android.bp
copy to zip/Android.bp
index 3e69336..d708089 100644
--- a/cmd/soong_zip/Android.bp
+++ b/zip/Android.bp
@@ -12,14 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-blueprint_go_binary {
- name: "soong_zip",
+subdirs = ["cmd"]
+
+bootstrap_go_package {
+ name: "soong-zip",
+ pkgPath: "android/soong/zip",
deps: [
"android-archive-zip",
"soong-jar",
],
srcs: [
- "soong_zip.go",
+ "zip.go",
"rate_limit.go",
],
}
+
diff --git a/cmd/soong_zip/Android.bp b/zip/cmd/Android.bp
similarity index 86%
rename from cmd/soong_zip/Android.bp
rename to zip/cmd/Android.bp
index 3e69336..6029a69 100644
--- a/cmd/soong_zip/Android.bp
+++ b/zip/cmd/Android.bp
@@ -15,11 +15,9 @@
blueprint_go_binary {
name: "soong_zip",
deps: [
- "android-archive-zip",
- "soong-jar",
+ "soong-zip",
],
srcs: [
- "soong_zip.go",
- "rate_limit.go",
+ "main.go",
],
}
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
new file mode 100644
index 0000000..348728c
--- /dev/null
+++ b/zip/cmd/main.go
@@ -0,0 +1,171 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "android/soong/zip"
+)
+
+type byteReaderCloser struct {
+ *bytes.Reader
+ io.Closer
+}
+
+type pathMapping struct {
+ dest, src string
+ zipMethod uint16
+}
+
+type uniqueSet map[string]bool
+
+func (u *uniqueSet) String() string {
+ return `""`
+}
+
+func (u *uniqueSet) Set(s string) error {
+ if _, found := (*u)[s]; found {
+ return fmt.Errorf("File %q was specified twice as a file to not deflate", s)
+ } else {
+ (*u)[s] = true
+ }
+
+ return nil
+}
+
+type file struct{}
+
+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")
+ }
+
+ fArgs = append(fArgs, zip.FileArg{
+ PathPrefixInZip: filepath.Clean(*rootPrefix),
+ SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+ SourceFiles: []string{s},
+ })
+
+ return nil
+}
+
+func (l *listFiles) String() string {
+ return `""`
+}
+
+func (l *listFiles) Set(s string) error {
+ if *relativeRoot == "" {
+ return fmt.Errorf("must pass -C before -l")
+ }
+
+ list, err := ioutil.ReadFile(s)
+ if err != nil {
+ return err
+ }
+
+ fArgs = append(fArgs, zip.FileArg{
+ PathPrefixInZip: filepath.Clean(*rootPrefix),
+ SourcePrefixToStrip: filepath.Clean(*relativeRoot),
+ SourceFiles: strings.Split(string(list), "\n"),
+ })
+
+ 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, zip.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 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'")
+
+ fArgs zip.FileArgs
+ nonDeflatedFiles = make(uniqueSet)
+
+ cpuProfile = flag.String("cpuprofile", "", "write cpu profile to file")
+ traceFile = flag.String("trace", "", "write trace to file")
+)
+
+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")
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func main() {
+ flag.Parse()
+
+ err := zip.Run(zip.ZipArgs{
+ FileArgs: fArgs,
+ OutputFilePath: *out,
+ CpuProfileFilePath: *cpuProfile,
+ TraceFilePath: *traceFile,
+ EmulateJar: *emulateJar,
+ AddDirectoryEntriesToZip: *directories,
+ CompressionLevel: *compLevel,
+ ManifestSourcePath: *manifest,
+ NumParallelJobs: *parallelJobs,
+ NonDeflatedFiles: nonDeflatedFiles,
+ })
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+}
diff --git a/cmd/soong_zip/rate_limit.go b/zip/rate_limit.go
similarity index 99%
rename from cmd/soong_zip/rate_limit.go
rename to zip/rate_limit.go
index 9cb5fdd..0ea2ef0 100644
--- a/cmd/soong_zip/rate_limit.go
+++ b/zip/rate_limit.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package zip
import (
"fmt"
diff --git a/cmd/soong_zip/soong_zip.go b/zip/zip.go
similarity index 84%
rename from cmd/soong_zip/soong_zip.go
rename to zip/zip.go
index 2bcc9a5..95520fe 100644
--- a/cmd/soong_zip/soong_zip.go
+++ b/zip/zip.go
@@ -12,13 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package zip
import (
"bytes"
"compress/flate"
"errors"
- "flag"
"fmt"
"hash/crc32"
"io"
@@ -26,7 +25,6 @@
"log"
"os"
"path/filepath"
- "runtime"
"runtime/pprof"
"runtime/trace"
"sort"
@@ -83,122 +81,6 @@
return nil
}
-type file struct{}
-
-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")
- }
-
- fArgs = append(fArgs, FileArg{
- PathPrefixInZip: filepath.Clean(*rootPrefix),
- SourcePrefixToStrip: filepath.Clean(*relativeRoot),
- SourceFiles: []string{s},
- })
-
- return nil
-}
-
-func (l *listFiles) String() string {
- return `""`
-}
-
-func (l *listFiles) Set(s string) error {
- if *relativeRoot == "" {
- return fmt.Errorf("must pass -C before -l")
- }
-
- list, err := ioutil.ReadFile(s)
- if err != nil {
- return err
- }
-
- fArgs = append(fArgs, FileArg{
- PathPrefixInZip: filepath.Clean(*rootPrefix),
- SourcePrefixToStrip: filepath.Clean(*relativeRoot),
- SourceFiles: strings.Split(string(list), "\n"),
- })
-
- 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 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'")
-
- fArgs FileArgs
- nonDeflatedFiles = make(uniqueSet)
-
- cpuProfile = flag.String("cpuprofile", "", "write cpu profile to file")
- traceFile = flag.String("trace", "", "write trace to file")
-)
-
-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")
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] -C dir [-f|-l file]...\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-func main() {
- flag.Parse()
-
- err := Run(ZipArgs{
- FileArgs: fArgs,
- OutputFilePath: *out,
- CpuProfileFilePath: *cpuProfile,
- TraceFilePath: *traceFile,
- EmulateJar: *emulateJar,
- AddDirectoryEntriesToZip: *directories,
- CompressionLevel: *compLevel,
- ManifestSourcePath: *manifest,
- NumParallelJobs: *parallelJobs,
- NonDeflatedFiles: nonDeflatedFiles,
- })
- if err != nil {
- fmt.Fprintln(os.Stderr, err.Error())
- os.Exit(1)
- }
-}
-
type FileArg struct {
PathPrefixInZip, SourcePrefixToStrip string
SourceFiles []string