Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 837ee1a6 authored by Martin Stjernholm's avatar Martin Stjernholm
Browse files

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
parent 3618f0a0
Loading
Loading
Loading
Loading
+50 −16
Original line number Diff line number Diff line
@@ -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 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.

			// 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, stripFlags)
				p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags))
				in = stripped
			}

			// 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,
			})
		}

		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)

+46 −0
Original line number Diff line number Diff line
@@ -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"))
}