diff --git a/android/android_test.go b/android/android_test.go index fb82e3765..64ceedc4d 100644 --- a/android/android_test.go +++ b/android/android_test.go @@ -15,10 +15,32 @@ package android import ( + "io/ioutil" "os" "testing" ) -func TestMain(m *testing.M) { - os.Exit(m.Run()) +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "android_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()) } diff --git a/android/module.go b/android/module.go index a150e6191..68d9f8e75 100644 --- a/android/module.go +++ b/android/module.go @@ -3546,10 +3546,29 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P reportPathError(ctx, err) return nil } + if len(paths) == 0 { + type addMissingDependenciesIntf interface { + AddMissingDependencies([]string) + OtherModuleName(blueprint.Module) string + } + if mctx, ok := ctx.(addMissingDependenciesIntf); ok && ctx.Config().AllowMissingDependencies() { + mctx.AddMissingDependencies([]string{mctx.OtherModuleName(module)}) + } else { + ReportPathErrorf(ctx, "failed to get output files from module %q", pathContextName(ctx, module)) + } + // Return a fake output file to avoid nil dereferences of Path objects later. + // This should never get used for an actual build as the error or missing + // dependency has already been reported. + p, err := pathForSource(ctx, filepath.Join("missing_output_file", pathContextName(ctx, module))) + if err != nil { + reportPathError(ctx, err) + return nil + } + return p + } if len(paths) > 1 { ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", pathContextName(ctx, module)) - return nil } return paths[0] } @@ -3561,18 +3580,12 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) return nil, fmt.Errorf("failed to get output file from module %q: %s", pathContextName(ctx, module), err.Error()) } - if len(paths) == 0 { - return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) - } return paths, nil } else if sourceFileProducer, ok := module.(SourceFileProducer); ok { if tag != "" { return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) } paths := sourceFileProducer.Srcs() - if len(paths) == 0 { - return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) - } return paths, nil } else { return nil, fmt.Errorf("module %q is not an OutputFileProducer", pathContextName(ctx, module)) diff --git a/android/module_test.go b/android/module_test.go index 0580bef24..1ca742213 100644 --- a/android/module_test.go +++ b/android/module_test.go @@ -15,6 +15,7 @@ package android import ( + "github.com/google/blueprint" "path/filepath" "runtime" "testing" @@ -978,3 +979,88 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { }) } } + +type fakeBlueprintModule struct{} + +func (fakeBlueprintModule) Name() string { return "foo" } + +func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} + +type sourceProducerTestModule struct { + fakeBlueprintModule + source Path +} + +func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } + +type outputFileProducerTestModule struct { + fakeBlueprintModule + output map[string]Path + error map[string]error +} + +func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { + return PathsIfNonNil(o.output[tag]), o.error[tag] +} + +type pathContextAddMissingDependenciesWrapper struct { + PathContext + missingDeps []string +} + +func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { + p.missingDeps = append(p.missingDeps, deps...) +} +func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { + return module.Name() +} + +func TestOutputFileForModule(t *testing.T) { + testcases := []struct { + name string + module blueprint.Module + tag string + env map[string]string + config func(*config) + expected string + missingDeps []string + }{ + { + name: "SourceFileProducer", + module: &sourceProducerTestModule{source: PathForTesting("foo.txt")}, + expected: "foo.txt", + }, + { + name: "OutputFileProducer", + module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, + expected: "foo.txt", + }, + { + name: "OutputFileProducer_tag", + module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, + tag: "foo", + expected: "foo.txt", + }, + { + name: "OutputFileProducer_AllowMissingDependencies", + config: func(config *config) { + config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) + }, + module: &outputFileProducerTestModule{}, + missingDeps: []string{"foo"}, + expected: "missing_output_file/foo", + }, + } + for _, tt := range testcases { + config := TestConfig(buildDir, tt.env, "", nil) + if tt.config != nil { + tt.config(config.config) + } + ctx := &pathContextAddMissingDependenciesWrapper{ + PathContext: PathContextForTesting(config), + } + got := OutputFileForModule(ctx, tt.module, tt.tag) + AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) + AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) + } +} diff --git a/apex/apex.go b/apex/apex.go index 498c8c0ff..c4d64d835 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -286,6 +286,9 @@ type apexArchBundleProperties struct { Arm64 struct { ApexNativeDependencies } + Riscv64 struct { + ApexNativeDependencies + } X86 struct { ApexNativeDependencies } @@ -787,6 +790,8 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { depsList = append(depsList, a.archProperties.Arch.Arm.ApexNativeDependencies) case android.Arm64: depsList = append(depsList, a.archProperties.Arch.Arm64.ApexNativeDependencies) + case android.Riscv64: + depsList = append(depsList, a.archProperties.Arch.Riscv64.ApexNativeDependencies) case android.X86: depsList = append(depsList, a.archProperties.Arch.X86.ApexNativeDependencies) case android.X86_64: @@ -1559,7 +1564,7 @@ func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, h dirInApex = filepath.Join(dirInApex, "bionic") } - fileToCopy := ccMod.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, ccMod, "") androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod) } @@ -1570,7 +1575,7 @@ func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFil dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath) } dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath()) - fileToCopy := cc.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, cc, "") androidMkModuleName := cc.BaseModuleName() + cc.Properties.SubName af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, cc) af.symlinks = cc.Symlinks() @@ -1583,7 +1588,7 @@ func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module if rustm.Target().NativeBridge == android.NativeBridgeEnabled { dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) } - fileToCopy := rustm.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, rustm, "") androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm) return af @@ -1602,7 +1607,7 @@ func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) a if rustm.Target().NativeBridge == android.NativeBridgeEnabled { dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) } - fileToCopy := rustm.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, rustm, "") androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm) } diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 25ae5bf7c..0f57911c6 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -537,7 +537,11 @@ func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext, } if src == "" { - ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String()) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{ctx.OtherModuleName(prebuilt)}) + } else { + ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String()) + } // Drop through to return an empty string as the src (instead of nil) to avoid the prebuilt // logic from reporting a more general, less useful message. } diff --git a/cc/api_level.go b/cc/api_level.go index fd145a9e2..8c2b2c2ac 100644 --- a/cc/api_level.go +++ b/cc/api_level.go @@ -28,6 +28,8 @@ func minApiForArch(ctx android.BaseModuleContext, return ctx.Config().MinSupportedSdkVersion() case android.Arm64, android.X86_64: return android.FirstLp64Version + case android.Riscv64: + return android.FutureApiLevel default: panic(fmt.Errorf("Unknown arch %q", arch)) } diff --git a/cc/cc.go b/cc/cc.go index 61499ac1e..9252b8734 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -3330,6 +3330,11 @@ func (c *Module) OutputFiles(tag string) (android.Paths, error) { return android.Paths{c.outputFile.Path()}, nil } return android.Paths{}, nil + case "unstripped": + if c.linker != nil { + return android.PathsIfNonNil(c.linker.unstrippedOutputFilePath()), nil + } + return nil, nil default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } diff --git a/cc/fuzz.go b/cc/fuzz.go index 8a8c10723..13c94adb3 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -103,6 +103,7 @@ type fuzzBinary struct { *baseCompiler fuzzPackagedModule fuzz.FuzzPackagedModule installedSharedDeps []string + sharedLibraries android.Paths } func (fuzz *fuzzBinary) fuzzBinary() bool { @@ -142,13 +143,6 @@ func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func UnstrippedOutputFile(module android.Module) android.Path { - if mod, ok := module.(LinkableInterface); ok { - return mod.UnstrippedOutputFile() - } - panic("UnstrippedOutputFile called on non-LinkableInterface module: " + module.Name()) -} - // IsValidSharedDependency takes a module and determines if it is a unique shared library // that should be installed in the fuzz target output directories. This function // returns true, unless: @@ -270,22 +264,9 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { } // Grab the list of required shared libraries. - seen := make(map[string]bool) - var sharedLibraries android.Paths - ctx.WalkDeps(func(child, parent android.Module) bool { - if seen[child.Name()] { - return false - } - seen[child.Name()] = true + fuzzBin.sharedLibraries = CollectAllSharedDependencies(ctx) - if IsValidSharedDependency(child) { - sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile()) - return true - } - return false - }) - - for _, lib := range sharedLibraries { + for _, lib := range fuzzBin.sharedLibraries { fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, sharedLibraryInstallLocation( lib, ctx.Host(), installBase, ctx.Arch().ArchType.String())) @@ -412,9 +393,6 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString) archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} - // Grab the list of required shared libraries. - sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, UnstrippedOutputFile, IsValidSharedDependency) - var files []fuzz.FileToZip builder := android.NewRuleBuilder(pctx, ctx) @@ -422,10 +400,10 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { files = s.PackageArtifacts(ctx, module, fpm, archDir, builder) // Package shared libraries - files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) + files = append(files, GetSharedLibsToZip(fuzzModule.sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) // The executable. - files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""}) + files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""}) archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok { @@ -494,3 +472,46 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, } return files } + +// CollectAllSharedDependencies search over the provided module's dependencies using +// VisitDirectDeps and WalkDeps to enumerate all shared library dependencies. +// VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer +// runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies +// have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc. +func CollectAllSharedDependencies(ctx android.ModuleContext) android.Paths { + seen := make(map[string]bool) + recursed := make(map[string]bool) + + var sharedLibraries android.Paths + + // Enumerate the first level of dependencies, as we discard all non-library + // modules in the BFS loop below. + ctx.VisitDirectDeps(func(dep android.Module) { + if !IsValidSharedDependency(dep) { + return + } + if seen[ctx.OtherModuleName(dep)] { + return + } + seen[ctx.OtherModuleName(dep)] = true + sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped")) + }) + + ctx.WalkDeps(func(child, parent android.Module) bool { + if !IsValidSharedDependency(child) { + return false + } + if !seen[ctx.OtherModuleName(child)] { + seen[ctx.OtherModuleName(child)] = true + sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped")) + } + + if recursed[ctx.OtherModuleName(child)] { + return false + } + recursed[ctx.OtherModuleName(child)] = true + return true + }) + + return sharedLibraries +} diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 362a8ef3c..baad58eed 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -296,27 +296,37 @@ func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool { } func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if p.properties.Src == nil { - ctx.PropertyErrorf("src", "missing prebuilt source file") - return - } - p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src)) - - // Determine the output file basename. - // If Filename is set, use the name specified by the property. - // If Filename_from_src is set, use the source file name. - // Otherwise use the module name. filename := proptools.String(p.properties.Filename) filenameFromSrc := proptools.Bool(p.properties.Filename_from_src) - if filename != "" { - if filenameFromSrc { - ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true") - return + if p.properties.Src != nil { + p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src)) + + // Determine the output file basename. + // If Filename is set, use the name specified by the property. + // If Filename_from_src is set, use the source file name. + // Otherwise use the module name. + if filename != "" { + if filenameFromSrc { + ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true") + return + } + } else if filenameFromSrc { + filename = p.sourceFilePath.Base() + } else { + filename = ctx.ModuleName() + } + } else if ctx.Config().AllowMissingDependencies() { + // If no srcs was set and AllowMissingDependencies is enabled then + // mark the module as missing dependencies and set a fake source path + // and file name. + ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"}) + p.sourceFilePath = android.PathForModuleSrc(ctx) + if filename == "" { + filename = ctx.ModuleName() } - } else if filenameFromSrc { - filename = p.sourceFilePath.Base() } else { - filename = ctx.ModuleName() + ctx.PropertyErrorf("src", "missing prebuilt source file") + return } p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index cf1f6d717..a6477dd6a 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -195,6 +195,30 @@ func TestPrebuiltEtcHost(t *testing.T) { } } +func TestPrebuiltEtcAllowMissingDependencies(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForPrebuiltEtcTest, + android.PrepareForTestDisallowNonExistentPaths, + android.FixtureModifyConfig( + func(config android.Config) { + config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) + }), + ).RunTestWithBp(t, ` + prebuilt_etc { + name: "foo.conf", + filename_from_src: true, + arch: { + x86: { + src: "x86.conf", + }, + }, + } + `) + + android.AssertStringEquals(t, "expected error rule", "android/soong/android.Error", + result.ModuleForTests("foo.conf", "android_arm64_armv8-a").Output("foo.conf").Rule.String()) +} + func TestPrebuiltRootInstallDirPath(t *testing.T) { result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` prebuilt_root { diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index c8cd21b7e..eb248bb40 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -379,42 +379,3 @@ func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets str sort.Strings(fuzzTargets) ctx.Strict(targets, strings.Join(fuzzTargets, " ")) } - -// CollectAllSharedDependencies performs a breadth-first search over the provided module's -// dependencies using `visitDirectDeps` to enumerate all shared library -// dependencies. We require breadth-first expansion, as otherwise we may -// incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.) -// from a dependency. This may cause issues when dependencies have explicit -// sanitizer tags, as we may get a dependency on an unsanitized libc, etc. -func CollectAllSharedDependencies(ctx android.SingletonContext, module android.Module, unstrippedOutputFile func(module android.Module) android.Path, isValidSharedDependency func(dependency android.Module) bool) android.Paths { - var fringe []android.Module - - seen := make(map[string]bool) - - // Enumerate the first level of dependencies, as we discard all non-library - // modules in the BFS loop below. - ctx.VisitDirectDeps(module, func(dep android.Module) { - if isValidSharedDependency(dep) { - fringe = append(fringe, dep) - } - }) - - var sharedLibraries android.Paths - - for i := 0; i < len(fringe); i++ { - module := fringe[i] - if seen[module.Name()] { - continue - } - seen[module.Name()] = true - - sharedLibraries = append(sharedLibraries, unstrippedOutputFile(module)) - ctx.VisitDirectDeps(module, func(dep android.Module) { - if isValidSharedDependency(dep) && !seen[dep.Name()] { - fringe = append(fringe, dep) - } - }) - } - - return sharedLibraries -} diff --git a/java/app_set.go b/java/app_set.go index 694b1670e..d99fadb34 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -90,10 +90,11 @@ func (as *AndroidAppSet) APKCertsFile() android.Path { } var TargetCpuAbi = map[string]string{ - "arm": "ARMEABI_V7A", - "arm64": "ARM64_V8A", - "x86": "X86", - "x86_64": "X86_64", + "arm": "ARMEABI_V7A", + "arm64": "ARM64_V8A", + "riscv64": "RISCV64", + "x86": "X86", + "x86_64": "X86_64", } func SupportedAbis(ctx android.ModuleContext) []string { diff --git a/rust/config/riscv64_device.go b/rust/config/riscv64_device.go index 3b41a10ad..d014dbf8b 100644 --- a/rust/config/riscv64_device.go +++ b/rust/config/riscv64_device.go @@ -25,7 +25,7 @@ var ( Riscv64ArchFeatureRustFlags = map[string][]string{"": {}} Riscv64LinkFlags = []string{} - Riscv64ArchVariantRustFlags = map[string][]string{} + Riscv64ArchVariantRustFlags = map[string][]string{"": {}} ) func init() { diff --git a/rust/fuzz.go b/rust/fuzz.go index 586095c49..76cf21aa0 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -34,6 +34,7 @@ type fuzzDecorator struct { *binaryDecorator fuzzPackagedModule fuzz.FuzzPackagedModule + sharedLibraries android.Paths } var _ compiler = (*fuzzDecorator)(nil) @@ -86,6 +87,15 @@ func (fuzzer *fuzzDecorator) compilerProps() []interface{} { &fuzzer.fuzzPackagedModule.FuzzProperties) } +func (fuzzer *fuzzDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { + out := fuzzer.binaryDecorator.compile(ctx, flags, deps) + + // Grab the list of required shared libraries. + fuzzer.sharedLibraries = cc.CollectAllSharedDependencies(ctx) + + return out +} + func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage { return RlibLinkage } @@ -149,11 +159,8 @@ func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { // The executable. files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""}) - // Grab the list of required shared libraries. - sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency) - // Package shared libraries - files = append(files, cc.GetSharedLibsToZip(sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...) + files = append(files, cc.GetSharedLibsToZip(fuzzModule.sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...) archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok {