diff options
35 files changed, 881 insertions, 138 deletions
diff --git a/android/test_suites.go b/android/test_suites.go index 7b2d7dcd1..79d0fbc60 100644 --- a/android/test_suites.go +++ b/android/test_suites.go @@ -68,7 +68,7 @@ func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) W FlagWithOutput("-o ", outputFile). FlagWithArg("-P ", "host/testcases"). FlagWithArg("-C ", testCasesDir.String()). - FlagWithRspFileInputList("-l ", installedPaths.Paths()) + FlagWithRspFileInputList("-r ", installedPaths.Paths()) rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip") return outputFile diff --git a/apex/apex_test.go b/apex/apex_test.go index 70464fc7a..e9843fc1a 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -5399,29 +5399,6 @@ func TestApexMutatorsDontRunIfDisabled(t *testing.T) { } } -func TestApexWithJniLibs_Errors(t *testing.T) { - testApexError(t, `jni_libs: "xxx" is not a cc_library`, ` - apex { - name: "myapex", - key: "myapex.key", - jni_libs: ["xxx"], - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - prebuilt_etc { - name: "xxx", - src: "xxx", - } - `, withFiles(map[string][]byte{ - "xxx": nil, - })) -} - func TestAppBundle(t *testing.T) { ctx, _ := testApex(t, ` apex { diff --git a/cc/androidmk.go b/cc/androidmk.go index 9ed8d8189..c899cdd72 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -167,6 +167,14 @@ func AndroidMkDataPaths(data []android.DataPath) []string { return testFiles } +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + }) + } +} + func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) { testFiles := AndroidMkDataPaths(data) if len(testFiles) > 0 { @@ -372,6 +380,7 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android. }) androidMkWriteTestData(test.data, ctx, entries) + androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries) } func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { diff --git a/cc/binary.go b/cc/binary.go index 6769fa778..8fcdd806a 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -445,7 +445,7 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { // The original path becomes a symlink to the corresponding file in the // runtime APEX. translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled - if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { + if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { if ctx.Device() && isBionic(ctx.baseModuleName()) { binary.installSymlinkToRuntimeApex(ctx, file) } diff --git a/cc/builder.go b/cc/builder.go index 28a573f23..f2bab8cb4 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -186,8 +186,8 @@ var ( // OutputFile here is $in for remote-execution since its possible that // clang-tidy modifies the given input file itself and $out refers to the // ".tidy" file generated for ninja-dependency reasons. - OutputFiles: []string{"$in"}, - Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, + OutputFiles: []string{"$in"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, }, []string{"cFlags", "tidyFlags"}, []string{}) _ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm") @@ -265,9 +265,9 @@ var ( zip = pctx.AndroidStaticRule("zip", blueprint.RuleParams{ - Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp", + Command: "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp", CommandDeps: []string{"${SoongZipCmd}"}, - Rspfile: "$out.rsp", + Rspfile: "${out}.rsp", RspfileContent: "$in", }) diff --git a/cc/compiler.go b/cc/compiler.go index e06243b50..0d3df27a4 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -189,8 +189,14 @@ type BaseCompilerProperties struct { // Build and link with OpenMP Openmp *bool `android:"arch_variant"` + // Deprecated. // Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__ Use_apex_name_macro *bool + + // Adds two macros for apex variants in addition to __ANDROID_APEX__ + // * __ANDROID_APEX_COM_ANDROID_FOO__ + // * __ANDROID_APEX_NAME__="com.android.foo" + UseApexNameMacro bool `blueprint:"mutated"` } func NewBaseCompiler() *baseCompiler { @@ -254,6 +260,10 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (compiler *baseCompiler) useApexNameMacro() bool { + return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro +} + // Return true if the module is in the WarningAllowedProjects. func warningsAreAllowed(subdir string) bool { subdir += "/" @@ -337,8 +347,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if ctx.apexVariationName() != "" { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__") - if Bool(compiler.Properties.Use_apex_name_macro) { + if compiler.useApexNameMacro() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__") + flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'") } if ctx.Device() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion())) @@ -557,7 +568,7 @@ func (compiler *baseCompiler) hasSrcExt(ext string) bool { } func (compiler *baseCompiler) uniqueApexVariations() bool { - return Bool(compiler.Properties.Use_apex_name_macro) + return compiler.useApexNameMacro() } // makeDefineString transforms a name of an APEX module into a value to be used as value for C define diff --git a/cc/fuzz.go b/cc/fuzz.go index 58c1888ad..529541859 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -402,7 +402,7 @@ func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { command := builder.Command().BuiltTool(ctx, "soong_zip"). Flag("-j"). FlagWithOutput("-o ", corpusZip) - command.FlagWithRspFileInputList("-l ", fuzzModule.corpus) + command.FlagWithRspFileInputList("-r ", fuzzModule.corpus) files = append(files, fileToZip{corpusZip, ""}) } diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index cff00b668..9328a2596 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -212,6 +212,11 @@ var includeDirProperties = []includeDirsProperty{ // Add properties that may, or may not, be arch specific. func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) { + if libInfo.SanitizeNever { + sanitizeSet := outputProperties.AddPropertySet("sanitize") + sanitizeSet.AddProperty("never", true) + } + // Copy the generated library to the snapshot and add a reference to it in the .bp module. if libInfo.outputFile != nil { nativeLibraryPath := nativeLibraryPathFor(libInfo) @@ -359,6 +364,9 @@ type nativeLibInfoProperties struct { // not vary by arch so cannot be android specific. StubsVersion string `sdk:"ignored-on-host"` + // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects. + SanitizeNever bool `android:"arch_variant"` + // outputFile is not exported as it is always arch specific. outputFile android.Path } @@ -405,6 +413,10 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte if ccModule.HasStubsVariants() { p.StubsVersion = ccModule.StubsVersion() } + + if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) { + p.SanitizeNever = true + } } func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { diff --git a/cc/test.go b/cc/test.go index 9b6864a4e..a8056479f 100644 --- a/cc/test.go +++ b/cc/test.go @@ -40,8 +40,12 @@ type TestProperties struct { type TestOptions struct { // The UID that you want to run the test as on a device. Run_test_as *string + // A list of free-formed strings without spaces that categorize the test. Test_suite_tag []string + + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` } type TestBinaryProperties struct { @@ -309,9 +313,10 @@ type testBinary struct { testDecorator *binaryDecorator *baseCompiler - Properties TestBinaryProperties - data []android.DataPath - testConfig android.Path + Properties TestBinaryProperties + data []android.DataPath + testConfig android.Path + extraTestConfigs android.Paths } func (test *testBinary) linkerProps() []interface{} { @@ -408,6 +413,8 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config, test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config) + test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs) + test.binaryDecorator.baseInstaller.dir = "nativetest" test.binaryDecorator.baseInstaller.dir64 = "nativetest64" diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp index 7b8352b6a..4ebbe6895 100644 --- a/cmd/soong_build/Android.bp +++ b/cmd/soong_build/Android.bp @@ -28,5 +28,8 @@ bootstrap_go_binary { "writedocs.go", "bazel_overlay.go", ], + testSrcs: [ + "bazel_overlay_test.go", + ], primaryBuilder: true, } diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go index e37c163d4..308076d52 100644 --- a/cmd/soong_build/bazel_overlay.go +++ b/cmd/soong_build/bazel_overlay.go @@ -20,14 +20,17 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "strings" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) const ( soongModuleLoad = `package(default_visibility = ["//visibility:public"]) load("//:soong_module.bzl", "soong_module") + ` // A BUILD file target snippet representing a Soong module @@ -36,15 +39,11 @@ load("//:soong_module.bzl", "soong_module") module_name = "%s", module_type = "%s", module_variant = "%s", - deps = [ - %s - ], -) -` + module_deps = %s, +%s)` // The soong_module rule implementation in a .bzl file - soongModuleBzl = ` -SoongModuleInfo = provider( + soongModuleBzl = `SoongModuleInfo = provider( fields = { "name": "Name of module", "type": "Type of module", @@ -52,7 +51,17 @@ SoongModuleInfo = provider( }, ) -def _soong_module_impl(ctx): +def _merge_dicts(*dicts): + """Adds a list of dictionaries into a single dictionary.""" + + # If keys are repeated in multiple dictionaries, the latter one "wins". + result = {} + for d in dicts: + result.update(d) + + return result + +def _generic_soong_module_impl(ctx): return [ SoongModuleInfo( name = ctx.attr.module_name, @@ -61,21 +70,66 @@ def _soong_module_impl(ctx): ), ] -soong_module = rule( - implementation = _soong_module_impl, - attrs = { - "module_name": attr.string(mandatory = True), - "module_type": attr.string(mandatory = True), - "module_variant": attr.string(), - "deps": attr.label_list(providers = [SoongModuleInfo]), - }, +_COMMON_ATTRS = { + "module_name": attr.string(mandatory = True), + "module_type": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), +} + + +generic_soong_module = rule( + implementation = _generic_soong_module_impl, + attrs = _COMMON_ATTRS, ) + +# TODO(jingwen): auto generate Soong module shims +def _soong_filegroup_impl(ctx): + return [SoongModuleInfo(),] + +soong_filegroup = rule( + implementation = _soong_filegroup_impl, + # Matches https://cs.android.com/android/platform/superproject/+/master:build/soong/android/filegroup.go;l=25-40;drc=6a6478d49e78703ba22a432c41d819c8df79ef6c + attrs = _merge_dicts(_COMMON_ATTRS, { + "srcs": attr.string_list(doc = "srcs lists files that will be included in this filegroup"), + "exclude_srcs": attr.string_list(), + "path": attr.string(doc = "The base path to the files. May be used by other modules to determine which portion of the path to use. For example, when a filegroup is used as data in a cc_test rule, the base path is stripped off the path and the remaining path is used as the installation directory."), + "export_to_make_var": attr.string(doc = "Create a make variable with the specified name that contains the list of files in the filegroup, relative to the root of the source tree."), + }) +) + +soong_module_rule_map = { + "filegroup": soong_filegroup, +} + +# soong_module is a macro that supports arbitrary kwargs, and uses module_type to +# expand to the right underlying shim. +def soong_module(name, module_type, **kwargs): + soong_module_rule = soong_module_rule_map.get(module_type) + + if soong_module_rule == None: + # This module type does not have an existing rule to map to, so use the + # generic_soong_module rule instead. + generic_soong_module( + name = name, + module_type = module_type, + module_name = kwargs.pop("module_name", ""), + module_variant = kwargs.pop("module_variant", ""), + module_deps = kwargs.pop("module_deps", []), + ) + else: + soong_module_rule( + name = name, + module_type = module_type, + **kwargs, + ) ` ) func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string { name := "" if c.ModuleSubDir(logicModule) != "" { + // TODO(b/162720883): Figure out a way to drop the "--" variant suffixes. name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule) } else { name = c.ModuleName(logicModule) @@ -95,6 +149,153 @@ func packagePath(c *blueprint.Context, logicModule blueprint.Module) string { return filepath.Dir(c.BlueprintFile(logicModule)) } +func escapeString(s string) string { + s = strings.ReplaceAll(s, "\\", "\\\\") + return strings.ReplaceAll(s, "\"", "\\\"") +} + +func makeIndent(indent int) string { + if indent < 0 { + panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent)) + } + return strings.Repeat(" ", indent) +} + +// prettyPrint a property value into the equivalent Starlark representation +// recursively. +func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { + if isZero(propertyValue) { + // A property value being set or unset actually matters -- Soong does set default + // values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at + // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480 + // + // In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default + // value of unset attributes. + return "", nil + } + + var ret string + switch propertyValue.Kind() { + case reflect.String: + ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String())) + case reflect.Bool: + ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface())) + case reflect.Int, reflect.Uint, reflect.Int64: + ret = fmt.Sprintf("%v", propertyValue.Interface()) + case reflect.Ptr: + return prettyPrint(propertyValue.Elem(), indent) + case reflect.Slice: + ret = "[\n" + for i := 0; i < propertyValue.Len(); i++ { + indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1) + if err != nil { + return "", err + } + + if indexedValue != "" { + ret += makeIndent(indent + 1) + ret += indexedValue + ret += ",\n" + } + } + ret += makeIndent(indent) + ret += "]" + case reflect.Struct: + ret = "{\n" + // Sort and print the struct props by the key. + structProps := extractStructProperties(propertyValue, indent) + for _, k := range android.SortedStringKeys(structProps) { + ret += makeIndent(indent + 1) + ret += "\"" + k + "\": " + ret += structProps[k] + ret += ",\n" + } + ret += makeIndent(indent) + ret += "}" + case reflect.Interface: + // TODO(b/164227191): implement pretty print for interfaces. + // Interfaces are used for for arch, multilib and target properties. + return "", nil + default: + return "", fmt.Errorf( + "unexpected kind for property struct field: %s", propertyValue.Kind()) + } + return ret, nil +} + +func extractStructProperties(structValue reflect.Value, indent int) map[string]string { + if structValue.Kind() != reflect.Struct { + panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())) + } + + ret := map[string]string{} + structType := structValue.Type() + for i := 0; i < structValue.NumField(); i++ { + field := structType.Field(i) + if field.PkgPath != "" { + // Skip unexported fields. Some properties are + // internal to Soong only, and these fields do not have PkgPath. + continue + } + if proptools.HasTag(field, "blueprint", "mutated") { + continue + } + + fieldValue := structValue.Field(i) + if isZero(fieldValue) { + // Ignore zero-valued fields + continue + } + + propertyName := proptools.PropertyNameForField(field.Name) + prettyPrintedValue, err := prettyPrint(fieldValue, indent+1) + if err != nil { + panic( + fmt.Errorf( + "Error while parsing property: %q. %s", + propertyName, + err)) + } + if prettyPrintedValue != "" { + ret[propertyName] = prettyPrintedValue + } + } + + return ret +} + +func isStructPtr(t reflect.Type) bool { + return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct +} + +// Generically extract module properties and types into a map, keyed by the module property name. +func extractModuleProperties(aModule android.Module) map[string]string { + ret := map[string]string{} + + // Iterate over this android.Module's property structs. + for _, properties := range aModule.GetProperties() { + propertiesValue := reflect.ValueOf(properties) + // Check that propertiesValue is a pointer to the Properties struct, like + // *cc.BaseLinkerProperties or *java.CompilerProperties. + // + // propertiesValue can also be type-asserted to the structs to + // manipulate internal props, if needed. + if isStructPtr(propertiesValue.Type()) { + structValue := propertiesValue.Elem() + for k, v := range extractStructProperties(structValue, 0) { + ret[k] = v + } + } else { + panic(fmt.Errorf( + "properties must be a pointer to a struct, got %T", + propertiesValue.Interface())) + } + + } + + return ret +} + func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { blueprintCtx := ctx.Context blueprintCtx.VisitAllModules(func(module blueprint.Module) { @@ -103,27 +304,7 @@ func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { panic(err) } - // TODO(b/163018919): DirectDeps can have duplicate (module, variant) - // items, if the modules are added using different DependencyTag. Figure - // out the implications of that. - depLabels := map[string]bool{} - blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) { - depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true - }) - - var depLabelList string - for depLabel, _ := range depLabels { - depLabelList += "\"" + depLabel + "\",\n " - } - buildFile.Write([]byte( - fmt.Sprintf( - soongModuleTarget, - targetNameWithVariant(blueprintCtx, module), - blueprintCtx.ModuleName(module), - blueprintCtx.ModuleType(module), - // misleading name, this actually returns the variant. - blueprintCtx.ModuleSubDir(module), - depLabelList))) + buildFile.Write([]byte(generateSoongModuleTarget(blueprintCtx, module) + "\n\n")) buildFile.Close() }) @@ -138,6 +319,70 @@ func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", soongModuleBzl) } +var ignoredProps map[string]bool = map[string]bool{ + "name": true, // redundant, since this is explicitly generated for every target + "from": true, // reserved keyword + "in": true, // reserved keyword + "arch": true, // interface prop type is not supported yet. + "multilib": true, // interface prop type is not supported yet. + "target": true, // interface prop type is not supported yet. + "visibility": true, // Bazel has native visibility semantics. Handle later. +} + +func shouldGenerateAttribute(prop string) bool { + return !ignoredProps[prop] +} + +// props is an unsorted map. This function ensures that +// the generated attributes are sorted to ensure determinism. +func propsToAttributes(props map[string]string) string { + var attributes string + for _, propName := range android.SortedStringKeys(props) { + if shouldGenerateAttribute(propName) { + attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName]) + } + } + return attributes +} + +// Convert a module and its deps and props into a Bazel macro/rule +// representation in the BUILD file. +func generateSoongModuleTarget( + blueprintCtx *blueprint.Context, + module blueprint.Module) string { + + var props map[string]string + if aModule, ok := module.(android.Module); ok { + props = extractModuleProperties(aModule) + } + attributes := propsToAttributes(props) + + // TODO(b/163018919): DirectDeps can have duplicate (module, variant) + // items, if the modules are added using different DependencyTag. Figure + // out the implications of that. + depLabels := map[string]bool{} + blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) { + depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true + }) + + depLabelList := "[\n" + for depLabel, _ := range depLabels { + depLabelList += " \"" + depLabelList += depLabel + depLabelList += "\",\n" + } + depLabelList += " ]" + + return fmt.Sprintf( + soongModuleTarget, + targetNameWithVariant(blueprintCtx, module), + blueprintCtx.ModuleName(module), + blueprintCtx.ModuleType(module), + blueprintCtx.ModuleSubDir(module), + depLabelList, + attributes) +} + func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.File, error) { // Create nested directories for the BUILD file dirPath := filepath.Join(bazelOverlayDir, packagePath(ctx, module)) @@ -171,3 +416,34 @@ func writeReadOnlyFile(dir string, baseName string, content string) error { // 0444 is read-only return ioutil.WriteFile(workspaceFile, []byte(content), 0444) } + +func isZero(value reflect.Value) bool { + switch value.Kind() { + case reflect.Func, reflect.Map, reflect.Slice: + return value.IsNil() + case reflect.Array: + valueIsZero := true + for i := 0; i < value.Len(); i++ { + valueIsZero = valueIsZero && isZero(value.Index(i)) + } + return valueIsZero + case reflect.Struct: + valueIsZero := true + for i := 0; i < value.NumField(); i++ { + if value.Field(i).CanSet() { + valueIsZero = valueIsZero && isZero(value.Field(i)) + } + } + return valueIsZero + case reflect.Ptr: + if !value.IsNil() { + return isZero(reflect.Indirect(value)) + } else { + return true + } + default: + zeroValue := reflect.Zero(value.Type()) + result := value.Interface() == zeroValue.Interface() + return result + } +} diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go new file mode 100644 index 000000000..8db784d6b --- /dev/null +++ b/cmd/soong_build/bazel_overlay_test.go @@ -0,0 +1,255 @@ +// Copyright 2020 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 ( + "android/soong/android" + "io/ioutil" + "os" + "testing" +) + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "bazel_overlay_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + +type customModule struct { + android.ModuleBase +} + +func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // nothing for now. +} + +func customModuleFactory() android.Module { + module := &customModule{} + android.InitAndroidModule(module) + return module +} + +func TestGenerateBazelOverlayFromBlueprint(t *testing.T) { + testCases := []struct { + bp string + expectedBazelTarget string + }{ + { + bp: `custom { + name: "foo", +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], +)`, + }, + { + bp: `custom { + name: "foo", + ramdisk: true, +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + ramdisk = True, +)`, + }, + { + bp: `custom { + name: "foo", + owner: "a_string_with\"quotes\"_and_\\backslashes\\\\", +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + owner = "a_string_with\"quotes\"_and_\\backslashes\\\\", +)`, + }, + { + bp: `custom { + name: "foo", + required: ["bar"], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + required = [ + "bar", + ], +)`, + }, + { + bp: `custom { + name: "foo", + target_required: ["qux", "bazqux"], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + target_required = [ + "qux", + "bazqux", + ], +)`, + }, + { + bp: `custom { + name: "foo", + dist: { + targets: ["goal_foo"], + tag: ".foo", + }, + dists: [ + { + targets: ["goal_bar"], + tag: ".bar", + }, + ], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + dist = { + "tag": ".foo", + "targets": [ + "goal_foo", + ], + }, + dists = [ + { + "tag": ".bar", + "targets": [ + "goal_bar", + ], + }, + ], +)`, + }, + { + bp: `custom { + name: "foo", + required: ["bar"], + target_required: ["qux", "bazqux"], + ramdisk: true, + owner: "custom_owner", + dists: [ + { + tag: ".tag", + targets: ["my_goal"], + }, + ], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + dists = [ + { + "tag": ".tag", + "targets": [ + "my_goal", + ], + }, + ], + owner = "custom_owner", + ramdisk = True, + required = [ + "bar", + ], + target_required = [ + "qux", + "bazqux", + ], +)`, + }, + } + + for _, testCase := range testCases { + config := android.TestConfig(buildDir, nil, testCase.bp, nil) + ctx := android.NewTestContext() + ctx.RegisterModuleType("custom", customModuleFactory) + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + module := ctx.ModuleForTests("foo", "").Module().(*customModule) + blueprintCtx := ctx.Context.Context + + actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module) + if actualBazelTarget != testCase.expectedBazelTarget { + t.Errorf( + "Expected generated Bazel target to be '%s', got '%s'", + testCase.expectedBazelTarget, + actualBazelTarget, + ) + } + } +} @@ -8,4 +8,4 @@ replace github.com/golang/protobuf v0.0.0 => ../../external/golang-protobuf replace github.com/google/blueprint v0.0.0 => ../blueprint -go 1.13 +go 1.15 diff --git a/java/androidmk.go b/java/androidmk.go index c822add74..2c02e5f38 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -161,6 +161,7 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { if j.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig) } + androidMkWriteExtraTestConfigs(j.extraTestConfigs, entries) androidMkWriteTestData(j.data, entries) if !BoolDefault(j.testProperties.Auto_gen_config, true) { entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true") @@ -170,6 +171,12 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { return entriesList } +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + } +} + func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries { entriesList := j.Library.AndroidMkEntries() entries := &entriesList[0] @@ -195,7 +202,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -431,6 +438,7 @@ func (a *AndroidTest) AndroidMkEntries() []android.AndroidMkEntries { if a.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig) } + androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries) androidMkWriteTestData(a.data, entries) }) diff --git a/java/app.go b/java/app.go index bfec83fad..5e3a9d9bf 100755 --- a/java/app.go +++ b/java/app.go @@ -1034,8 +1034,9 @@ type AndroidTest struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths } func (a *AndroidTest) InstallInTestcases() bool { @@ -1063,6 +1064,7 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs) a.testConfig = a.FixTestConfig(ctx, testConfig) + a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) } diff --git a/java/java.go b/java/java.go index 25fba13e2..4d7d568ad 100644 --- a/java/java.go +++ b/java/java.go @@ -2124,6 +2124,12 @@ func LibraryHostFactory() android.Module { // Java Tests // +// Test option struct. +type TestOptions struct { + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` +} + type testProperties struct { // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. @@ -2149,6 +2155,9 @@ type testProperties struct { // Add parameterized mainline modules to auto generated test config. The options will be // handled by TradeFed to do downloading and installing the specified modules on the device. Test_mainline_modules []string + + // Test options. + Test_options TestOptions } type hostTestProperties struct { @@ -2177,8 +2186,9 @@ type Test struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths } type TestHost struct { @@ -2217,6 +2227,8 @@ func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data) + j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) + ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) @@ -2530,6 +2542,10 @@ func (j *Import) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.properties.Sdk_version)) } +func (j *Import) makeSdkVersion() string { + return j.sdkVersion().raw +} + func (j *Import) minSdkVersion() sdkSpec { return j.sdkVersion() } diff --git a/java/lint.go b/java/lint.go index b37f69265..3a210cc0b 100644 --- a/java/lint.go +++ b/java/lint.go @@ -513,7 +513,7 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android rule.Command().BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", outputPath). FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). - FlagWithRspFileInputList("-l ", paths) + FlagWithRspFileInputList("-r ", paths) rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base()) } diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index b10e6c7fe..ac8337dc5 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -34,6 +34,10 @@ func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) { type prebuiltApisProperties struct { // list of api version directories Api_dirs []string + + // The sdk_version of java_import modules generated based on jar files. + // Defaults to "current" + Imports_sdk_version *string } type prebuiltApis struct { @@ -74,7 +78,7 @@ func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope st return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module } -func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) { +func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk_version string) { props := struct { Name *string Jars []string @@ -83,7 +87,7 @@ func createImport(mctx android.LoadHookContext, module string, scope string, api }{} props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver)) props.Jars = append(props.Jars, path) - props.Sdk_version = proptools.StringPtr(scope) + props.Sdk_version = proptools.StringPtr(sdk_version) props.Installable = proptools.BoolPtr(false) mctx.CreateModule(ImportFactory, &props) @@ -100,10 +104,10 @@ func createFilegroup(mctx android.LoadHookContext, module string, scope string, mctx.CreateModule(android.FileGroupFactory, &filegroupProps) } -func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { +func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string { mydir := mctx.ModuleDir() + "/" var files []string - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { + for _, apiver := range p.properties.Api_dirs { for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} { vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil) if err != nil { @@ -115,16 +119,18 @@ func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { return files } -func prebuiltSdkStubs(mctx android.LoadHookContext) { +func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/<module>.jar - files := getPrebuiltFiles(mctx, "*.jar") + files := getPrebuiltFiles(mctx, p, "*.jar") + + sdk_version := proptools.StringDefault(p.properties.Imports_sdk_version, "current") for _, f := range files { // create a Import module for each jar file localPath := strings.TrimPrefix(f, mydir) module, apiver, scope := parseJarPath(localPath) - createImport(mctx, module, scope, apiver, localPath) + createImport(mctx, module, scope, apiver, localPath, sdk_version) } } @@ -139,8 +145,8 @@ func createSystemModules(mctx android.LoadHookContext, apiver string) { mctx.CreateModule(SystemModulesFactory, &props) } -func prebuiltSdkSystemModules(mctx android.LoadHookContext) { - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { +func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) { + for _, apiver := range p.properties.Api_dirs { jar := android.ExistentPathForSource(mctx, mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar") if jar.Valid() { @@ -149,10 +155,10 @@ func prebuiltSdkSystemModules(mctx android.LoadHookContext) { } } -func prebuiltApiFiles(mctx android.LoadHookContext) { +func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/api/<module>.txt - files := getPrebuiltFiles(mctx, "api/*.txt") + files := getPrebuiltFiles(mctx, p, "api/*.txt") if len(files) == 0 { mctx.ModuleErrorf("no api file found under %q", mydir) @@ -200,10 +206,10 @@ func prebuiltApiFiles(mctx android.LoadHookContext) { } func createPrebuiltApiModules(mctx android.LoadHookContext) { - if _, ok := mctx.Module().(*prebuiltApis); ok { - prebuiltApiFiles(mctx) - prebuiltSdkStubs(mctx) - prebuiltSdkSystemModules(mctx) + if p, ok := mctx.Module().(*prebuiltApis); ok { + prebuiltApiFiles(mctx, p) + prebuiltSdkStubs(mctx, p) + prebuiltSdkSystemModules(mctx, p) } } diff --git a/rust/binary.go b/rust/binary.go index 1a82c9208..f75018626 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -24,9 +24,6 @@ func init() { } type BinaryCompilerProperties struct { - // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib - // (assuming it has no dylib dependencies already) - Prefer_dynamic *bool } type binaryDecorator struct { @@ -60,10 +57,6 @@ func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator return module, binary } -func (binary *binaryDecorator) preferDynamic() bool { - return Bool(binary.Properties.Prefer_dynamic) -} - func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) @@ -76,9 +69,6 @@ func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Fla "-Wl,--no-undefined-version") } - if binary.preferDynamic() { - flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") - } return flags } @@ -132,8 +122,9 @@ func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath { return binary.coverageOutputZipFile } -func (binary *binaryDecorator) autoDep() autoDep { - if binary.preferDynamic() { +func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { + // Binaries default to dylib dependencies for device, rlib for host. + if ctx.Device() { return dylibAutoDep } else { return rlibAutoDep diff --git a/rust/binary_test.go b/rust/binary_test.go index b9c8698b9..5c9bd6530 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -17,44 +17,64 @@ package rust import ( "strings" "testing" + + "android/soong/android" ) -// Test that the prefer_dynamic property is handled correctly. -func TestPreferDynamicBinary(t *testing.T) { +// Test that rustlibs default linkage is correct for binaries. +func TestBinaryLinkage(t *testing.T) { ctx := testRust(t, ` - rust_binary_host { - name: "fizz-buzz-dynamic", + rust_binary { + name: "fizz-buzz", srcs: ["foo.rs"], - prefer_dynamic: true, + rustlibs: ["libfoo"], + host_supported: true, } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + host_supported: true, + }`) + + fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") + } + + if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) { + t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") + } +} +// Test that the path returned by HostToolPath is correct +func TestHostToolPath(t *testing.T) { + ctx := testRust(t, ` rust_binary_host { name: "fizz-buzz", srcs: ["foo.rs"], }`) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") - fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic") - path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { t.Errorf("wrong host tool path, expected %q got %q", w, g) } +} - // Do not compile binary modules with the --test flag. - flags := fizzBuzzDynamic.Args["rustcFlags"] - if strings.Contains(flags, "--test") { - t.Errorf("extra --test flag, rustcFlags: %#v", flags) - } - if !strings.Contains(flags, "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags) - } +// Test that the flags being passed to rust_binary modules are as expected +func TestBinaryFlags(t *testing.T) { + ctx := testRust(t, ` + rust_binary_host { + name: "fizz-buzz", + srcs: ["foo.rs"], + }`) - flags = fizzBuzz.Args["rustcFlags"] + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") + + flags := fizzBuzz.Args["rustcFlags"] if strings.Contains(flags, "--test") { t.Errorf("extra --test flag, rustcFlags: %#v", flags) } - if strings.Contains(flags, "prefer-dynamic") { - t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags) - } } diff --git a/rust/compiler.go b/rust/compiler.go index ef7fb8cfc..2600f4d0f 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -145,6 +145,10 @@ func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { panic("baseCompiler does not implement coverageOutputZipPath()") } +func (compiler *baseCompiler) static() bool { + return false +} + var _ compiler = (*baseCompiler)(nil) func (compiler *baseCompiler) inData() bool { @@ -216,7 +220,15 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } - deps.Rustlibs = append(deps.Rustlibs, stdlib) + // For devices, we always link stdlibs in as dylibs except for ffi static libraries. + // (rustc does not support linking libstd as a dylib for ffi static libraries) + if ctx.Host() { + deps.Rustlibs = append(deps.Rustlibs, stdlib) + } else if ctx.RustModule().compiler.static() { + deps.Rlibs = append(deps.Rlibs, stdlib) + } else { + deps.Dylibs = append(deps.Dylibs, stdlib) + } } } return deps diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 8b9fccc61..56a8ef8ac 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -177,3 +177,30 @@ func TestLints(t *testing.T) { }) } } + +// Test that devices are linking the stdlib dynamically +func TestStdDeviceLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz", + srcs: ["foo.rs"], + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) + fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module) + fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + + if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for device binaries") + } + if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for rlibs") + } + if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for dylibs") + } +} diff --git a/rust/coverage.go b/rust/coverage.go index 223ba4f19..26375f507 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -53,7 +53,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags flags.Coverage = true coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface) flags.RustFlags = append(flags.RustFlags, - "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads") + "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code") flags.LinkFlags = append(flags.LinkFlags, "--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv") deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 357c2e8b1..73673d035 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -56,7 +56,7 @@ func TestCoverageFlags(t *testing.T) { fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") - rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"} + rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"} for _, flag := range rustcCoverageFlags { missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v" containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v" diff --git a/rust/library.go b/rust/library.go index 6766d618b..91fbe0fda 100644 --- a/rust/library.go +++ b/rust/library.go @@ -176,13 +176,13 @@ func (library *libraryDecorator) setStatic() { library.MutatedProperties.VariantIsDylib = false } -func (library *libraryDecorator) autoDep() autoDep { +func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep { if library.rlib() || library.static() { return rlibAutoDep } else if library.dylib() || library.shared() { return dylibAutoDep } else { - return rlibAutoDep + panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.") } } diff --git a/rust/library_test.go b/rust/library_test.go index 8a91cf10f..0fd9e32f9 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -144,6 +144,22 @@ func TestSharedLibrary(t *testing.T) { } } +func TestStaticLibraryLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_ffi_static { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + + if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) { + t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v", + libfoo.Module().(*Module).Properties.AndroidMkDylibs) + } +} + // Test that variants pull in the right type of rustlib autodep func TestAutoDeps(t *testing.T) { diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 3dd2521a3..748879cc8 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -80,6 +80,6 @@ func (procMacro *procMacroDecorator) getStem(ctx ModuleContext) string { return stem + String(procMacro.baseCompiler.Properties.Suffix) } -func (procMacro *procMacroDecorator) autoDep() autoDep { +func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/rust/rust.go b/rust/rust.go index b69786976..80fe62243 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -289,6 +289,8 @@ type compiler interface { Disabled() bool SetDisabled() + + static() bool } type exportedFlagsProducer interface { @@ -740,7 +742,7 @@ var ( ) type autoDeppable interface { - autoDep() autoDep + autoDep(ctx BaseModuleContext) autoDep } func (mod *Module) begin(ctx BaseModuleContext) { @@ -988,8 +990,8 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { {Mutator: "rust_libraries", Variation: "dylib"}}...), dylibDepTag, deps.Dylibs...) - if deps.Rustlibs != nil { - autoDep := mod.compiler.(autoDeppable).autoDep() + if deps.Rustlibs != nil && !mod.compiler.Disabled() { + autoDep := mod.compiler.(autoDeppable).autoDep(ctx) actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ {Mutator: "rust_libraries", Variation: autoDep.variation}}...), diff --git a/rust/test.go b/rust/test.go index 05c361e87..19802e392 100644 --- a/rust/test.go +++ b/rust/test.go @@ -114,7 +114,7 @@ func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func (test *testDecorator) autoDep() autoDep { +func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index b8ffc11c4..84b905c9d 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -340,6 +340,9 @@ func TestSnapshotWithObject(t *testing.T) { cc_object { name: "crtobj", stl: "none", + sanitize: { + never: true, + }, } `) @@ -352,6 +355,9 @@ cc_prebuilt_object { sdk_member_name: "crtobj", stl: "none", compile_multilib: "both", + sanitize: { + never: true, + }, arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -367,6 +373,9 @@ cc_prebuilt_object { prefer: false, stl: "none", compile_multilib: "both", + sanitize: { + never: true, + }, arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], diff --git a/sdk/update.go b/sdk/update.go index 936696a01..537ab13cb 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -43,7 +43,7 @@ var ( zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles", blueprint.RuleParams{ - Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`, + Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`, CommandDeps: []string{ "${config.SoongZipCmd}", }, diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 217a4e163..f3f4a4aa7 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -64,6 +64,12 @@ type shBinaryProperties struct { // install symlinks to the binary Symlinks []string `android:"arch_variant"` + + // Make this module available when building for ramdisk. + Ramdisk_available *bool + + // Make this module available when building for recovery. + Recovery_available *bool } type TestProperties struct { @@ -158,6 +164,29 @@ func (s *ShBinary) Symlinks() []string { return s.properties.Symlinks } +var _ android.ImageInterface = (*ShBinary)(nil) + +func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {} + +func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk() +} + +func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk() +} + +func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery() +} + +func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string { + return nil +} + +func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +} + func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) { s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src)) filename := proptools.String(s.properties.Filename) diff --git a/zip/cmd/main.go b/zip/cmd/main.go index fba2e4b1e..d603586e6 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -62,6 +62,15 @@ func (listFiles) Set(s string) error { return nil } +type rspFiles struct{} + +func (rspFiles) String() string { return `""` } + +func (rspFiles) Set(s string) error { + fileArgsBuilder.RspFile(s) + return nil +} + type dir struct{} func (dir) String() string { return `""` } @@ -143,7 +152,8 @@ func main() { traceFile := flags.String("trace", "", "write trace to file") flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") - flags.Var(&listFiles{}, "l", "file containing list of .class files") + flags.Var(&listFiles{}, "l", "file containing list of files to zip") + flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping") flags.Var(&dir{}, "D", "directory to include in zip") flags.Var(&file{}, "f", "file to include in zip") flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") diff --git a/zip/zip.go b/zip/zip.go index 3c710a782..e27432cbb 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -150,6 +150,30 @@ func (b *FileArgsBuilder) List(name string) *FileArgsBuilder { return b } +func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder { + if b.err != nil { + return b + } + + f, err := b.fs.Open(name) + if err != nil { + b.err = err + return b + } + defer f.Close() + + list, err := ioutil.ReadAll(f) + if err != nil { + b.err = err + return b + } + + arg := b.state + arg.SourceFiles = ReadRespFile(list) + b.fileArgs = append(b.fileArgs, arg) + return b +} + func (b *FileArgsBuilder) Error() error { if b == nil { return nil diff --git a/zip/zip_test.go b/zip/zip_test.go index 9705d6c49..302a749a3 100644 --- a/zip/zip_test.go +++ b/zip/zip_test.go @@ -49,6 +49,9 @@ var mockFs = pathtools.MockFs(map[string][]byte{ "l_nl": []byte("a/a/a\na/a/b\nc\n"), "l_sp": []byte("a/a/a a/a/b c"), "l2": []byte("missing\n"), + "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'"), + "@ -> c": nil, + "foo'bar -> c": nil, "manifest.txt": fileCustomManifest, }) @@ -247,6 +250,19 @@ func TestZip(t *testing.T) { }, }, { + name: "rsp", + args: fileArgsBuilder(). + RspFile("rsp"), + compressionLevel: 9, + + files: []zip.FileHeader{ + fh("a/a/a", fileA, zip.Deflate), + fh("a/a/b", fileB, zip.Deflate), + fh("@", fileC, zip.Deflate), + fh("foo'bar", fileC, zip.Deflate), + }, + }, + { name: "prefix in zip", args: fileArgsBuilder(). PathPrefixInZip("foo"). @@ -568,6 +584,11 @@ func TestReadRespFile(t *testing.T) { in: `./cmd "\""-C`, out: []string{"./cmd", `"-C`}, }, + { + name: "ninja rsp file", + in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'", + out: []string{"a", "b", "@", "foo'bar", `foo"bar`}, + }, } for _, testCase := range testCases { |