Symlink prebuilt binaries on host.

This means binaries will run from their source location and look up
shared libs relative to there.

Test: m nothing
Test: Set up a prebuilt binary with shared libs, check that it can
  be executed during build, and check that its symlinks get updated
  when a shared lib is touched.
Bug: 145934348
Change-Id: I1a600c7163ce0ec34ee8caf0ffe87fef4feb3064
This commit is contained in:
Martin Stjernholm 2020-08-20 02:54:52 +01:00
parent 3618f0a02e
commit 837ee1a6df
2 changed files with 96 additions and 16 deletions

View file

@ -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)

View file

@ -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"))
}