Merge "Add Darwin x86_64+arm64 universal binary support"
diff --git a/android/arch.go b/android/arch.go
index 3bf54b7..3cc5e82 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -566,6 +566,8 @@
return variants
}
+var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
+
// archMutator splits a module into a variant for each Target requested by the module. Target selection
// for a module is in three levels, OsClass, multilib, and then Target.
// OsClass selection is determined by:
@@ -652,7 +654,7 @@
prefer32 := os == Windows
// Determine the multilib selection for this module.
- multilib, extraMultilib := decodeMultilib(base, os.Class)
+ multilib, extraMultilib := decodeMultilib(base, os)
// Convert the multilib selection into a list of Targets.
targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
@@ -702,6 +704,16 @@
m.base().commonProperties.SkipInstall = true
}
}
+
+ // Create a dependency for Darwin Universal binaries from the primary to secondary
+ // architecture. The module itself will be responsible for calling lipo to merge the outputs.
+ if os == Darwin {
+ if multilib == "darwin_universal" && len(modules) == 2 {
+ mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0])
+ } else if multilib == "darwin_universal_common_first" && len(modules) == 3 {
+ mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1])
+ }
+ }
}
// addTargetProperties annotates a variant with the Target is is being compiled for, the list
@@ -717,9 +729,9 @@
// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
// the actual multilib in extraMultilib.
-func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
+func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string) {
// First check the "android.compile_multilib" or "host.compile_multilib" properties.
- switch class {
+ switch os.Class {
case Device:
multilib = String(base.commonProperties.Target.Android.Compile_multilib)
case Host:
@@ -737,6 +749,26 @@
}
if base.commonProperties.UseTargetVariants {
+ // Darwin has the concept of "universal binaries" which is implemented in Soong by
+ // building both x86_64 and arm64 variants, and having select module types know how to
+ // merge the outputs of their corresponding variants together into a final binary. Most
+ // module types don't need to understand this logic, as we only build a small portion
+ // of the tree for Darwin, and only module types writing macho files need to do the
+ // merging.
+ //
+ // This logic is not enabled for:
+ // "common", as it's not an arch-specific variant
+ // "32", as Darwin never has a 32-bit variant
+ // !UseTargetVariants, as the module has opted into handling the arch-specific logic on
+ // its own.
+ if os == Darwin && multilib != "common" && multilib != "32" {
+ if multilib == "common_first" {
+ multilib = "darwin_universal_common_first"
+ } else {
+ multilib = "darwin_universal"
+ }
+ }
+
return multilib, ""
} else {
// For app modules a single arch variant will be created per OS class which is expected to handle all the
@@ -1793,6 +1825,15 @@
if len(buildTargets) == 0 {
buildTargets = filterMultilibTargets(targets, "lib64")
}
+ case "darwin_universal":
+ buildTargets = filterMultilibTargets(targets, "lib64")
+ // Reverse the targets so that the first architecture can depend on the second
+ // architecture module in order to merge the outputs.
+ reverseSliceInPlace(buildTargets)
+ case "darwin_universal_common_first":
+ archTargets := filterMultilibTargets(targets, "lib64")
+ reverseSliceInPlace(archTargets)
+ buildTargets = append(getCommonTargets(targets), archTargets...)
default:
return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
multilib)
diff --git a/apex/apex.go b/apex/apex.go
index bb9207d..1e7ce7f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2015,6 +2015,8 @@
}
} else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
// nothing
+ } else if depTag == android.DarwinUniversalVariantTag {
+ // nothing
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
}
diff --git a/cc/binary.go b/cc/binary.go
index 3f951ec..e839122 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -345,6 +345,12 @@
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-dynamic-linker")
}
+ if ctx.Darwin() && deps.DarwinSecondArchOutput.Valid() {
+ fatOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "pre-fat", fileName)
+ transformDarwinUniversalBinary(ctx, fatOutputFile, outputFile, deps.DarwinSecondArchOutput.Path())
+ }
+
builderFlags := flagsToBuilderFlags(flags)
stripFlags := flagsToStripFlags(flags)
if binary.stripper.NeedsStrip(ctx) {
diff --git a/cc/builder.go b/cc/builder.go
index 7161ccf..8af2255 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -165,6 +165,12 @@
}
}()
+ darwinLipo = pctx.AndroidStaticRule("darwinLipo",
+ blueprint.RuleParams{
+ Command: "${config.MacLipoPath} -create -output $out $in",
+ CommandDeps: []string{"${config.MacLipoPath}"},
+ })
+
_ = pctx.SourcePathVariable("archiveRepackPath", "build/soong/scripts/archive_repack.sh")
// Rule to repack an archive (.a) file with a subset of object files.
@@ -1059,6 +1065,15 @@
})
}
+func transformDarwinUniversalBinary(ctx android.ModuleContext, outputFile android.WritablePath, inputFiles ...android.Path) {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: darwinLipo,
+ Description: "lipo " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: inputFiles,
+ })
+}
+
// Registers build statement to zip one or more coverage files.
func transformCoverageFilesToZip(ctx android.ModuleContext,
inputs Objects, baseName string) android.OptionalPath {
diff --git a/cc/cc.go b/cc/cc.go
index 3bb0d6d..b3b8f8c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -167,6 +167,10 @@
// Path to the dynamic linker binary
DynamicLinker android.OptionalPath
+
+ // For Darwin builds, the path to the second architecture's output that should
+ // be combined with this architectures's output into a FAT MachO file.
+ DarwinSecondArchOutput android.OptionalPath
}
// LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
@@ -2584,6 +2588,11 @@
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+ if depTag == android.DarwinUniversalVariantTag {
+ depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile()
+ return
+ }
+
ccDep, ok := dep.(LinkableInterface)
if !ok {
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 318acb4..526ee52 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -87,6 +87,10 @@
return getMacTools(ctx).arPath
})
+ pctx.VariableFunc("MacLipoPath", func(ctx android.PackageVarContext) string {
+ return getMacTools(ctx).lipoPath
+ })
+
pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
return getMacTools(ctx).stripPath
})
@@ -118,6 +122,7 @@
sdkRoot string
arPath string
+ lipoPath string
stripPath string
toolPath string
}
@@ -157,6 +162,7 @@
macTools.sdkRoot = xcrun("--show-sdk-path")
macTools.arPath = xcrun("--find", "ar")
+ macTools.lipoPath = xcrun("--find", "lipo")
macTools.stripPath = xcrun("--find", "strip")
macTools.toolPath = filepath.Dir(xcrun("--find", "ld"))
})
diff --git a/cc/library.go b/cc/library.go
index e53aac0..a081c7d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1429,6 +1429,12 @@
builderFlags := flagsToBuilderFlags(flags)
+ if ctx.Darwin() && deps.DarwinSecondArchOutput.Valid() {
+ fatOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "pre-fat", fileName)
+ transformDarwinUniversalBinary(ctx, fatOutputFile, outputFile, deps.DarwinSecondArchOutput.Path())
+ }
+
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc")