diff --git a/apex/apex_test.go b/apex/apex_test.go index 8a02a4a7f..103406eb8 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -1001,7 +1001,7 @@ func TestApexWithStubs(t *testing.T) { // Ensure that stub dependency from a rust module is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so") // The rust module is linked to the stub cc library - rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"] + rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"] ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so") ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so") @@ -1077,7 +1077,7 @@ func TestApexCanUsePrivateApis(t *testing.T) { mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") - rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"] + rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"] ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so") ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so") } diff --git a/rust/binary.go b/rust/binary.go index 056888ef2..2de92c17f 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -72,11 +72,14 @@ func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) + if ctx.Os().Linux() { + flags.LinkFlags = append(flags.LinkFlags, "-Wl,--gc-sections") + } + if ctx.toolchain().Bionic() { // no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined, // but we can apply this to binaries. flags.LinkFlags = append(flags.LinkFlags, - "-Wl,--gc-sections", "-Wl,-z,nocopyreloc", "-Wl,--no-undefined-version") @@ -136,7 +139,7 @@ func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps Path flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) - flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...) if binary.stripper.NeedsStrip(ctx) { strippedOutputFile := outputFile diff --git a/rust/binary_test.go b/rust/binary_test.go index 7dac2490a..dd4f99314 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -123,7 +123,7 @@ func TestBootstrap(t *testing.T) { bootstrap: true, }`) - foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") + foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustLink") flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64" if !strings.Contains(foo.Args["linkFlags"], flag) { @@ -140,10 +140,11 @@ func TestStaticBinaryFlags(t *testing.T) { }`) fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") + fizzOutLink := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustLink") fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) flags := fizzOut.Args["rustcFlags"] - linkFlags := fizzOut.Args["linkFlags"] + linkFlags := fizzOutLink.Args["linkFlags"] if !strings.Contains(flags, "-C relocation-model=static") { t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags) } @@ -173,7 +174,7 @@ func TestLinkObjects(t *testing.T) { name: "libfoo", }`) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc") + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustLink") linkFlags := fizzBuzz.Args["linkFlags"] if !strings.Contains(linkFlags, "/libfoo.so") { t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags) diff --git a/rust/builder.go b/rust/builder.go index 0aef13d44..0aa2225f7 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -26,14 +26,14 @@ import ( var ( _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc") + _ = pctx.SourcePathVariable("mkcraterspCmd", "build/soong/scripts/mkcratersp.py") rustc = pctx.AndroidStaticRule("rustc", blueprint.RuleParams{ Command: "$envVars $rustcCmd " + - "-C linker=${config.RustLinker} " + - "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " + + "-C linker=$mkcraterspCmd " + "--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" + " && grep \"^$out:\" $out.d.raw > $out.d", - CommandDeps: []string{"$rustcCmd"}, + CommandDeps: []string{"$rustcCmd", "$mkcraterspCmd"}, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633 // Rustc emits unneeded dependency lines for the .d and input .rs files. // Those extra lines cause ninja warning: @@ -42,7 +42,12 @@ var ( Deps: blueprint.DepsGCC, Depfile: "$out.d", }, - "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars") + "rustcFlags", "libFlags", "envVars") + rustLink = pctx.AndroidStaticRule("rustLink", + blueprint.RuleParams{ + Command: "${config.RustLinker} -o $out ${crtBegin} ${config.RustLinkerArgs} @$in ${linkFlags} ${crtEnd}", + }, + "linkFlags", "crtBegin", "crtEnd") _ = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc") rustdoc = pctx.AndroidStaticRule("rustdoc", @@ -101,14 +106,13 @@ var ( `KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` + `$rustExtractor $envVars ` + `$rustcCmd ` + - `-C linker=${config.RustLinker} ` + - `-C link-args="${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}" ` + + `-C linker=true ` + `$in ${libFlags} $rustcFlags`, CommandDeps: []string{"$rustExtractor", "$kytheVnames"}, Rspfile: "${out}.rsp", RspfileContent: "$in", }, - "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars") + "rustcFlags", "libFlags", "envVars") ) type buildOutput struct { @@ -220,11 +224,9 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl outputFile android.WritablePath, crateType string) buildOutput { var inputs android.Paths - var implicits android.Paths - var orderOnly android.Paths + var implicits, linkImplicits, linkOrderOnly android.Paths var output buildOutput var rustcFlags, linkFlags []string - var implicitOutputs android.WritablePaths output.outputFile = outputFile crateName := ctx.RustModule().CrateName() @@ -281,15 +283,15 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl implicits = append(implicits, rustLibsToPaths(deps.RLibs)...) implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...) implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...) - implicits = append(implicits, deps.StaticLibs...) - implicits = append(implicits, deps.SharedLibDeps...) - implicits = append(implicits, deps.srcProviderFiles...) implicits = append(implicits, deps.AfdoProfiles...) + implicits = append(implicits, deps.srcProviderFiles...) + implicits = append(implicits, deps.WholeStaticLibs...) - implicits = append(implicits, deps.CrtBegin...) - implicits = append(implicits, deps.CrtEnd...) + linkImplicits = append(linkImplicits, deps.LibDeps...) + linkImplicits = append(linkImplicits, deps.CrtBegin...) + linkImplicits = append(linkImplicits, deps.CrtEnd...) - orderOnly = append(orderOnly, deps.SharedLibs...) + linkOrderOnly = append(linkOrderOnly, deps.linkObjects...) if len(deps.SrcDeps) > 0 { moduleGenDir := ctx.RustModule().compiler.CargoOutDir() @@ -328,16 +330,16 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl } } + envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar") + if flags.Clippy { clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy") ctx.Build(pctx, android.BuildParams{ - Rule: clippyDriver, - Description: "clippy " + main.Rel(), - Output: clippyFile, - ImplicitOutputs: nil, - Inputs: inputs, - Implicits: implicits, - OrderOnly: orderOnly, + Rule: clippyDriver, + Description: "clippy " + main.Rel(), + Output: clippyFile, + Inputs: inputs, + Implicits: implicits, Args: map[string]string{ "rustcFlags": strings.Join(rustcFlags, " "), "libFlags": strings.Join(libFlags, " "), @@ -349,24 +351,41 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl implicits = append(implicits, clippyFile) } + rustcOutputFile := outputFile + usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro" + if usesLinker { + rustcOutputFile = android.PathForModuleOut(ctx, outputFile.Base()+".rsp") + } + ctx.Build(pctx, android.BuildParams{ - Rule: rustc, - Description: "rustc " + main.Rel(), - Output: outputFile, - ImplicitOutputs: implicitOutputs, - Inputs: inputs, - Implicits: implicits, - OrderOnly: orderOnly, + Rule: rustc, + Description: "rustc " + main.Rel(), + Output: rustcOutputFile, + Inputs: inputs, + Implicits: implicits, Args: map[string]string{ "rustcFlags": strings.Join(rustcFlags, " "), - "linkFlags": strings.Join(linkFlags, " "), "libFlags": strings.Join(libFlags, " "), - "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), - "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), "envVars": strings.Join(envVars, " "), }, }) + if usesLinker { + ctx.Build(pctx, android.BuildParams{ + Rule: rustLink, + Description: "rustLink " + main.Rel(), + Output: outputFile, + Inputs: android.Paths{rustcOutputFile}, + Implicits: linkImplicits, + OrderOnly: linkOrderOnly, + Args: map[string]string{ + "linkFlags": strings.Join(linkFlags, " "), + "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), + "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), + }, + }) + } + if flags.EmitXrefs { kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip") ctx.Build(pctx, android.BuildParams{ @@ -375,13 +394,9 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl Output: kytheFile, Inputs: inputs, Implicits: implicits, - OrderOnly: orderOnly, Args: map[string]string{ "rustcFlags": strings.Join(rustcFlags, " "), - "linkFlags": strings.Join(linkFlags, " "), "libFlags": strings.Join(libFlags, " "), - "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), - "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), "envVars": strings.Join(envVars, " "), }, }) diff --git a/rust/coverage.go b/rust/coverage.go index bc6504ddc..5216d6098 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -65,7 +65,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags "-C instrument-coverage", "-g") flags.LinkFlags = append(flags.LinkFlags, profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open") - deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) + deps.LibDeps = append(deps.LibDeps, coverage.OutputFile().Path()) // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency. if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() { diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 0f599d745..64077cf00 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -55,6 +55,10 @@ func TestCoverageFlags(t *testing.T) { libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc") fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") + libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustLink") + libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustLink") + fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustLink") + buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustLink") rustcCoverageFlags := []string{"-C instrument-coverage", " -g "} for _, flag := range rustcCoverageFlags { @@ -80,17 +84,17 @@ func TestCoverageFlags(t *testing.T) { missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v" containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v" - if !strings.Contains(fizzCov.Args["linkFlags"], flag) { - t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"]) + if !strings.Contains(fizzCovLink.Args["linkFlags"], flag) { + t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.Args["linkFlags"]) } - if !strings.Contains(libfooCov.Args["linkFlags"], flag) { - t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"]) + if !strings.Contains(libfooCovLink.Args["linkFlags"], flag) { + t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.Args["linkFlags"]) } - if strings.Contains(buzzNoCov.Args["linkFlags"], flag) { - t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"]) + if strings.Contains(buzzNoCovLink.Args["linkFlags"], flag) { + t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.Args["linkFlags"]) } - if strings.Contains(libbarNoCov.Args["linkFlags"], flag) { - t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"]) + if strings.Contains(libbarNoCovLink.Args["linkFlags"], flag) { + t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.Args["linkFlags"]) } } @@ -103,7 +107,7 @@ func TestCoverageDeps(t *testing.T) { srcs: ["foo.rs"], }`) - fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc") + fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustLink") if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") { t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"]) } diff --git a/rust/library.go b/rust/library.go index bc9c9aa38..a3a567281 100644 --- a/rust/library.go +++ b/rust/library.go @@ -520,7 +520,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) - flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...) if library.dylib() { // We need prefer-dynamic for now to avoid linking in the static stdlib. See: @@ -543,6 +543,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa if library.rlib() || library.dylib() { library.flagExporter.exportLinkDirs(deps.linkDirs...) library.flagExporter.exportLinkObjects(deps.linkObjects...) + library.flagExporter.exportLibDeps(deps.LibDeps...) } if library.static() || library.shared() { diff --git a/rust/library_test.go b/rust/library_test.go index e3e4d0f03..d4b525f2e 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -148,7 +148,7 @@ func TestSharedLibrary(t *testing.T) { libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared") - libfooOutput := libfoo.Rule("rustc") + libfooOutput := libfoo.Rule("rustLink") if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") { t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", libfooOutput.Args["linkFlags"]) diff --git a/rust/rust.go b/rust/rust.go index 56b463160..7b520cdb0 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -420,13 +420,12 @@ type Deps struct { } type PathDeps struct { - DyLibs RustLibraries - RLibs RustLibraries - SharedLibs android.Paths - SharedLibDeps android.Paths - StaticLibs android.Paths - ProcMacros RustLibraries - AfdoProfiles android.Paths + DyLibs RustLibraries + RLibs RustLibraries + LibDeps android.Paths + WholeStaticLibs android.Paths + ProcMacros RustLibraries + AfdoProfiles android.Paths // depFlags and depLinkFlags are rustc and linker (clang) flags. depFlags []string @@ -435,7 +434,7 @@ type PathDeps struct { // linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker. // Both of these are exported and propagate to dependencies. linkDirs []string - linkObjects []string + linkObjects android.Paths // Used by bindgen modules which call clang depClangFlags []string @@ -498,7 +497,7 @@ type compiler interface { type exportedFlagsProducer interface { exportLinkDirs(...string) - exportLinkObjects(...string) + exportLinkObjects(...android.Path) } type xref interface { @@ -507,21 +506,27 @@ type xref interface { type flagExporter struct { linkDirs []string - linkObjects []string + linkObjects android.Paths + libDeps android.Paths } func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) { flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...)) } -func (flagExporter *flagExporter) exportLinkObjects(flags ...string) { - flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...)) +func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) { + flagExporter.linkObjects = android.FirstUniquePaths(append(flagExporter.linkObjects, flags...)) +} + +func (flagExporter *flagExporter) exportLibDeps(paths ...android.Path) { + flagExporter.libDeps = android.FirstUniquePaths(append(flagExporter.libDeps, paths...)) } func (flagExporter *flagExporter) setProvider(ctx ModuleContext) { ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{ LinkDirs: flagExporter.linkDirs, LinkObjects: flagExporter.linkObjects, + LibDeps: flagExporter.libDeps, }) } @@ -534,7 +539,8 @@ func NewFlagExporter() *flagExporter { type FlagExporterInfo struct { Flags []string LinkDirs []string // TODO: this should be android.Paths - LinkObjects []string // TODO: this should be android.Paths + LinkObjects android.Paths + LibDeps android.Paths } var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{}) @@ -1250,6 +1256,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...) depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...) depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...) + depPaths.LibDeps = append(depPaths.LibDeps, exportedInfo.LibDeps...) } if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag { @@ -1293,6 +1300,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", linkObject.Path().String(), "-Wl,--no-whole-archive"}...) } else if libName, ok := libNameFromFilePath(linkObject.Path()); ok { depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName) + depPaths.WholeStaticLibs = append(depPaths.WholeStaticLibs, linkObject.Path()) } else { ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName()) } @@ -1300,7 +1308,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Add this to linkObjects to pass the library directly to the linker as well. This propagates // to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant. - depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...) depPaths.linkDirs = append(depPaths.linkDirs, linkPath) exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo) @@ -1326,7 +1334,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { linkPath = linkPathFromFilePath(linkObject.Path()) depPaths.linkDirs = append(depPaths.linkDirs, linkPath) - depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...) depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...) depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) @@ -1352,7 +1360,9 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Make sure these dependencies are propagated if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep { lib.exportLinkDirs(linkPath) - lib.exportLinkObjects(linkObject.String()) + if linkObject.Valid() { + lib.exportLinkObjects(linkObject.Path()) + } } } else { switch { @@ -1384,19 +1394,16 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()}) } - var staticLibDepFiles android.Paths + var libDepFiles android.Paths for _, dep := range directStaticLibDeps { - staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path()) + libDepFiles = append(libDepFiles, dep.OutputFile().Path()) } - var sharedLibFiles android.Paths - var sharedLibDepFiles android.Paths for _, dep := range directSharedLibDeps { - sharedLibFiles = append(sharedLibFiles, dep.SharedLibrary) if dep.TableOfContents.Valid() { - sharedLibDepFiles = append(sharedLibDepFiles, dep.TableOfContents.Path()) + libDepFiles = append(libDepFiles, dep.TableOfContents.Path()) } else { - sharedLibDepFiles = append(sharedLibDepFiles, dep.SharedLibrary) + libDepFiles = append(libDepFiles, dep.SharedLibrary) } } @@ -1412,15 +1419,13 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...) depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...) - depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibFiles...) - depPaths.SharedLibDeps = append(depPaths.SharedLibDeps, sharedLibDepFiles...) - depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...) + depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...) depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...) depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...) // Dedup exported flags from dependencies depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs) - depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects) + depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects) depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags) depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags) depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths) diff --git a/rust/rust_test.go b/rust/rust_test.go index e8e58009b..2a38b8983 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -258,6 +258,7 @@ func TestDepsTracking(t *testing.T) { `) module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") + rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink") // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up. if !android.InList("libdylib", module.Properties.AndroidMkDylibs) { @@ -284,16 +285,16 @@ func TestDepsTracking(t *testing.T) { t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"]) } - if !strings.Contains(rustc.Args["linkFlags"], "cc_stubs_dep.so") { - t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustc.Args["linkFlags"]) + if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") { + t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"]) } - if !android.SuffixInList(rustc.OrderOnly.Strings(), "cc_stubs_dep.so") { - t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustc.OrderOnly.Strings()) + if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") { + t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings()) } - if !android.SuffixInList(rustc.Implicits.Strings(), "cc_stubs_dep.so.toc") { - t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustc.Implicits.Strings()) + if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") { + t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings()) } } diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go index d6a14b295..43e95f477 100644 --- a/rust/sanitize_test.go +++ b/rust/sanitize_test.go @@ -35,7 +35,7 @@ func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNo note_sync := "note_memtag_heap_sync" found := None - implicits := m.Rule("rustc").Implicits + implicits := m.Rule("rustLink").Implicits for _, lib := range implicits { if strings.Contains(lib.Rel(), note_async) { found = Async diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go index e1b3c86a2..2e7a33027 100644 --- a/rust/vendor_snapshot_test.go +++ b/rust/vendor_snapshot_test.go @@ -941,7 +941,7 @@ func TestVendorSnapshotUse(t *testing.T) { ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31") // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot - libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").Args["linkFlags"] + libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"] for _, input := range [][]string{ []string{sharedVariant, "libvndk.vndk.30.arm64"}, []string{staticVariant, "libvendor.vendor_static.30.arm64"}, @@ -997,7 +997,7 @@ func TestVendorSnapshotUse(t *testing.T) { t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, expectedRustVendorSnapshotName) } - binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").Args["linkFlags"] + binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"] libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"}) if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) { t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py new file mode 100755 index 000000000..86b4aa3fb --- /dev/null +++ b/scripts/mkcratersp.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 The Android Open Source Project +# +# 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. +# + +""" +This script is used as a replacement for the Rust linker. It converts a linker +command line into a rspfile that can be used during the link phase. +""" + +import os +import shutil +import subprocess +import sys + +def create_archive(out, objects, archives): + mricmd = f'create {out}\n' + for o in objects: + mricmd += f'addmod {o}\n' + for a in archives: + mricmd += f'addlib {a}\n' + mricmd += 'save\nend\n' + subprocess.run([os.getenv('AR'), '-M'], encoding='utf-8', input=mricmd, check=True) + +objects = [] +archives = [] +linkdirs = [] +libs = [] +temp_archives = [] +version_script = None + +for i, arg in enumerate(sys.argv): + if arg == '-o': + out = sys.argv[i+1] + if arg == '-L': + linkdirs.append(sys.argv[i+1]) + if arg.startswith('-l') or arg == '-shared': + libs.append(arg) + if arg.startswith('-Wl,--version-script='): + version_script = arg[21:] + if arg[0] == '-': + continue + if arg.endswith('.o') or arg.endswith('.rmeta'): + objects.append(arg) + if arg.endswith('.rlib'): + if arg.startswith(os.getenv('TMPDIR')): + temp_archives.append(arg) + else: + archives.append(arg) + +create_archive(f'{out}.whole.a', objects, []) +create_archive(f'{out}.a', [], temp_archives) + +with open(out, 'w') as f: + print(f'-Wl,--whole-archive', file=f) + print(f'{out}.whole.a', file=f) + print(f'-Wl,--no-whole-archive', file=f) + print(f'{out}.a', file=f) + for a in archives: + print(a, file=f) + for linkdir in linkdirs: + print(f'-L{linkdir}', file=f) + for l in libs: + print(l, file=f) + if version_script: + shutil.copyfile(version_script, f'{out}.version_script') + print(f'-Wl,--version-script={out}.version_script', file=f)