diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 3af65d654..1ee096e18 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -324,35 +324,68 @@ func prebuiltObjectFactory() android.Module { type prebuiltBinaryLinker struct { *binaryDecorator prebuiltLinker + + toolPath android.OptionalPath } var _ prebuiltLinkerInterface = (*prebuiltBinaryLinker)(nil) +func (p *prebuiltBinaryLinker) hostToolPath() android.OptionalPath { + return p.toolPath +} + func (p *prebuiltBinaryLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { // TODO(ccross): verify shared library dependencies if len(p.properties.Srcs) > 0 { - stripFlags := flagsToStripFlags(flags) - fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix() in := p.Prebuilt.SingleSourcePath(ctx) - + outputFile := android.PathForModuleOut(ctx, fileName) p.unstrippedOutputFile = in - if p.stripper.NeedsStrip(ctx) { - stripped := android.PathForModuleOut(ctx, "stripped", fileName) - p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) - in = stripped - } + if ctx.Host() { + // Host binaries are symlinked to their prebuilt source locations. That + // way they are executed directly from there so the linker resolves their + // shared library dependencies relative to that location (using + // $ORIGIN/../lib(64):$ORIGIN/lib(64) as RUNPATH). This way the prebuilt + // repository can supply the expected versions of the shared libraries + // without interference from what is in the out tree. - // Copy binaries to a name matching the final installed name - outputFile := android.PathForModuleOut(ctx, fileName) - ctx.Build(pctx, android.BuildParams{ - Rule: android.CpExecutable, - Description: "prebuilt", - Output: outputFile, - Input: in, - }) + // These shared lib paths may point to copies of the libs in + // .intermediates, which isn't where the binary will load them from, but + // it's fine for dependency tracking. If a library dependency is updated, + // the symlink will get a new timestamp, along with any installed symlinks + // handled in make. + sharedLibPaths := deps.EarlySharedLibs + sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...) + sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...) + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Symlink, + Output: outputFile, + Input: in, + Implicits: sharedLibPaths, + Args: map[string]string{ + "fromPath": "$$PWD/" + in.String(), + }, + }) + + p.toolPath = android.OptionalPathForPath(outputFile) + } else { + if p.stripper.NeedsStrip(ctx) { + stripped := android.PathForModuleOut(ctx, "stripped", fileName) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags)) + in = stripped + } + + // Copy binaries to a name matching the final installed name + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpExecutable, + Description: "prebuilt", + Output: outputFile, + Input: in, + }) + } return outputFile } @@ -379,6 +412,7 @@ func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecor binaryDecorator: binary, } module.linker = prebuilt + module.installer = prebuilt module.AddProperties(&prebuilt.properties) diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index adb44bd71..d94d59ab8 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -15,6 +15,7 @@ package cc import ( + "path/filepath" "testing" "android/soong/android" @@ -271,3 +272,48 @@ func TestPrebuiltLibrarySharedStem(t *testing.T) { shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libbar.so") } + +func TestPrebuiltSymlinkedHostBinary(t *testing.T) { + ctx := testPrebuilt(t, ` + cc_prebuilt_library_shared { + name: "libfoo", + device_supported: false, + host_supported: true, + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/lib64/libfoo.so"], + }, + }, + } + + cc_prebuilt_binary { + name: "foo", + device_supported: false, + host_supported: true, + shared_libs: ["libfoo"], + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/bin/foo"], + }, + }, + } + `, map[string][]byte{ + "libfoo.so": nil, + "foo": nil, + }) + + fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink") + assertString(t, fooRule.Output.String(), + filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo")) + assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo") + + var libfooDep android.Path + for _, dep := range fooRule.Implicits { + if dep.Base() == "libfoo.so" { + libfooDep = dep + break + } + } + assertString(t, libfooDep.String(), + filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so")) +}