diff --git a/apex/apex.go b/apex/apex.go index 321e2e890..96a4bd5e4 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -333,6 +333,7 @@ type apexFile struct { installDir string class apexFileClass module android.Module + symlinks []string } type apexBundle struct { @@ -396,7 +397,8 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { a.properties.Multilib.Both.Binaries, target.String(), a.getImageVariation(config)) - if i == 0 { + isPrimaryAbi := i == 0 + if isPrimaryAbi { // When multilib.* is omitted for binaries, it implies // multilib.first. ctx.AddFarVariationDependencies([]blueprint.Variation{ @@ -571,7 +573,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case sharedLibTag: if cc, ok := child.(*cc.Module); ok { fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc) - filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc}) + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc, nil}) return true } else { ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName) @@ -584,7 +586,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return true } fileToCopy, dirInApex := getCopyManifestForExecutable(cc) - filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable, cc}) + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable, cc, cc.Symlinks()}) return true } else { ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName) @@ -595,7 +597,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { if fileToCopy == nil { ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) } else { - filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib, java}) + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib, java, nil}) } return true } else { @@ -604,7 +606,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case prebuiltTag: if prebuilt, ok := child.(*android.PrebuiltEtc); ok { fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt) - filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc, prebuilt}) + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc, prebuilt, nil}) return true } else { ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName) @@ -639,7 +641,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } depName := ctx.OtherModuleName(child) fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc) - filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc}) + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc, nil}) return true } } @@ -732,6 +734,10 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile and dest_path := filepath.Join(android.PathForModuleOut(ctx, "image"+suffix).String(), dest) copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path)) copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path) + for _, sym := range a.filesInfo[i].symlinks { + symlinkDest := filepath.Join(filepath.Dir(dest_path), sym) + copyCommands = append(copyCommands, "ln -s "+filepath.Base(dest)+" "+symlinkDest) + } } implicitInputs := append(android.Paths(nil), filesToCopy...) implicitInputs = append(implicitInputs, manifest) @@ -747,6 +753,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile and pathInApex := filepath.Join(f.installDir, f.builtFile.Base()) if f.installDir == "bin" { executablePaths = append(executablePaths, pathInApex) + for _, s := range f.symlinks { + executablePaths = append(executablePaths, filepath.Join("bin", s)) + } } else { readOnlyPaths = append(readOnlyPaths, pathInApex) } @@ -879,7 +888,7 @@ func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { Input: manifest, Output: copiedManifest, }) - a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil}) + a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil, nil}) for _, fi := range a.filesInfo { dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir) diff --git a/apex/apex_test.go b/apex/apex_test.go index 4ca5b148f..7ae49f6a0 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -107,6 +107,16 @@ func testApex(t *testing.T, bp string) *android.TestContext { recovery_available: true, } + cc_object { + name: "crtbegin_static", + stl: "none", + } + + cc_object { + name: "crtend_android", + stl: "none", + } + llndk_library { name: "libc", symbol_file: "", @@ -194,6 +204,11 @@ func TestBasicApex(t *testing.T) { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], + multilib: { + both: { + binaries: ["foo",], + } + } } apex_key { @@ -210,6 +225,25 @@ func TestBasicApex(t *testing.T) { stl: "none", } + cc_binary { + name: "foo", + srcs: ["mylib.cpp"], + compile_multilib: "both", + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + symlinks: ["foo_link_"], + symlink_preferred_arch: true, + system_shared_libs: [], + static_executable: true, + stl: "none", + } + cc_library { name: "mylib2", srcs: ["mylib.cpp"], @@ -237,6 +271,23 @@ func TestBasicApex(t *testing.T) { // Ensure that the platform variant ends with _core_shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared") ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared") + + // Ensure that all symlinks are present. + found_foo_link_64 := false + found_foo := false + for _, cmd := range strings.Split(copyCmds, " && ") { + if strings.HasPrefix(cmd, "ln -s foo64") { + if strings.HasSuffix(cmd, "bin/foo") { + found_foo = true + } else if strings.HasSuffix(cmd, "bin/foo_link_64") { + found_foo_link_64 = true + } + } + } + good := found_foo && found_foo_link_64 + if !good { + t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds) + } } func TestBasicZipApex(t *testing.T) { @@ -671,17 +722,6 @@ func TestStaticLinking(t *testing.T) { system_shared_libs: [], stl: "none", } - - cc_object { - name: "crtbegin_static", - stl: "none", - } - - cc_object { - name: "crtend_android", - stl: "none", - } - `) ldFlags := ctx.ModuleForTests("not_in_apex", "android_arm64_armv8-a_core").Rule("ld").Args["libFlags"] diff --git a/cc/binary.go b/cc/binary.go index 65e8eb52f..4c863712d 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -382,11 +382,8 @@ func (binary *binaryDecorator) link(ctx ModuleContext, objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...) binary.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, binary.getStem(ctx)) - return ret -} - -func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { - binary.baseInstaller.install(ctx, file) + // Need to determine symlinks early since some targets (ie APEX) need this + // information but will not call 'install' for _, symlink := range binary.Properties.Symlinks { binary.symlinks = append(binary.symlinks, symlink+String(binary.Properties.Suffix)+ctx.toolchain().ExecutableSuffix()) @@ -401,6 +398,15 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { } } + return ret +} + +func (binary *binaryDecorator) symlinkList() []string { + return binary.symlinks +} + +func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { + binary.baseInstaller.install(ctx, file) for _, symlink := range binary.symlinks { ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path) } diff --git a/cc/cc.go b/cc/cc.go index 1f5097682..a30708a5f 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -772,6 +772,15 @@ func (c *Module) Name() string { return name } +func (c *Module) Symlinks() []string { + if p, ok := c.installer.(interface { + symlinkList() []string + }); ok { + return p.symlinkList() + } + return nil +} + // orderDeps reorders dependencies into a list such that if module A depends on B, then // A will precede B in the resultant list. // This is convenient for passing into a linker.