in src/com/facebook/buck/android/AndroidNativeLibsPackageableGraphEnhancer.java [170:412]
public AndroidNativeLibsGraphEnhancementResult enhance(
AndroidPackageableCollection packageableCollection) {
ImmutableMultimap<APKModule, NativeLinkableGroup> nativeLinkableGroups =
packageableCollection.getNativeLinkables();
ImmutableMultimap<APKModule, NativeLinkableGroup> nativeLinkableGroupsAssets =
packageableCollection.getNativeLinkablesAssets();
// TODO(cjhopman): The linkables handling is much more complex and we probably should split it
// out into its own function.
boolean hasLinkables =
!(nativeLinkableGroups.isEmpty() && nativeLinkableGroupsAssets.isEmpty());
boolean hasNativeLibDirs =
!(packageableCollection.getNativeLibsDirectories().isEmpty()
&& packageableCollection.getNativeLibAssetsDirectories().isEmpty()
&& packageableCollection.getNativeLibsDirectoriesForSystemLoader().isEmpty());
boolean hasNativeCode = hasLinkables || hasNativeLibDirs;
if (!hasNativeCode) {
return ImmutableAndroidNativeLibsGraphEnhancementResult.of(
Optional.empty(),
Optional.of(ImmutableSortedSet.of()),
Optional.empty(),
Optional.empty(),
Optional.empty());
}
ImmutableMap<TargetCpuType, NdkCxxPlatform> nativePlatforms = ImmutableMap.of();
if (hasLinkables) {
NdkCxxPlatformsProvider ndkCxxPlatformsProvider =
toolchainProvider.getByName(
NdkCxxPlatformsProvider.DEFAULT_NAME,
originalBuildTarget.getTargetConfiguration(),
NdkCxxPlatformsProvider.class);
nativePlatforms = ndkCxxPlatformsProvider.getResolvedNdkCxxPlatforms(graphBuilder);
if (nativePlatforms.isEmpty()) {
throw new HumanReadableException(
"No native platforms detected. Probably Android NDK is not configured properly.");
}
}
Iterable<TargetCpuType> filteredLinkablePlatforms =
hasLinkables ? getFilteredPlatforms(nativePlatforms, cpuFilters) : ImmutableList.of();
ImmutableMap.Builder<TargetCpuType, NativeLinkableEnhancementResult> nativeLinkablesBuilder =
ImmutableMap.builder();
for (TargetCpuType cpuType : filteredLinkablePlatforms) {
nativeLinkablesBuilder.put(
cpuType,
expandLinkableGroups(
nativePlatforms.get(cpuType).getCxxPlatform(),
nativeLinkableGroups,
nativeLinkableGroupsAssets));
}
ImmutableMap<TargetCpuType, NativeLinkableEnhancementResult> nativeLinkables =
nativeLinkablesBuilder.build();
ImmutableSortedMap<String, String> sonameMapping = null;
ImmutableSortedMap<String, ImmutableSortedSet<String>> sharedObjectTargets = null;
if (nativeLibraryMergeMap.isPresent()
&& !nativeLibraryMergeMap.get().isEmpty()
&& !nativePlatforms.isEmpty()) {
NativeLibraryMergeEnhancer.NativeLibraryMergeEnhancementResult enhancement =
NativeLibraryMergeEnhancer.enhance(
cellPathResolver,
cxxBuckConfig,
graphBuilder,
originalBuildTarget,
projectFilesystem,
nativePlatforms,
nativeLibraryMergeMap.get(),
nativeLibraryMergeGlue,
nativeLibraryMergeLocalizedSymbols,
nativeLinkables);
nativeLinkables = enhancement.getMergedLinkables();
sonameMapping = enhancement.getSonameMapping();
sharedObjectTargets = enhancement.getSharedObjectTargets();
}
// Iterate over all the {@link AndroidNativeLinkable}s from the collector and grab the shared
// libraries for all the {@link TargetCpuType}s that we care about. We deposit them into a map
// of CPU type and SONAME to the shared library path, which the {@link CopyNativeLibraries}
// rule will use to compose the destination name.
ImmutableMap.Builder<APKModule, CopyNativeLibraries> moduleMappedCopyNativeLibriesBuilder =
ImmutableMap.builder();
boolean hasCopyNativeLibraries = false;
// Make sure we process the root module last so that we know if any of the module contain
// libraries that depend on a non-system runtime and add it to the root module if needed.
ImmutableSet<APKModule> apkModules =
FluentIterable.from(apkModuleGraph.getAPKModules())
.filter(input -> !input.isRootModule())
.append(apkModuleGraph.getRootAPKModule())
.toSet();
ImmutableMap.Builder<AndroidLinkableMetadata, SourcePath> nativeLinkableLibsBuilder =
ImmutableMap.builder();
ImmutableMap.Builder<AndroidLinkableMetadata, SourcePath> nativeLinkableLibsAssetsBuilder =
ImmutableMap.builder();
BiConsumer<AndroidLinkableMetadata, BuildTarget> duplicateReporter =
new BiConsumer<AndroidLinkableMetadata, BuildTarget>() {
Map<AndroidLinkableMetadata, BuildTarget> nativeLinkableLibsMap = new HashMap<>();
@Override
public void accept(AndroidLinkableMetadata metadata, BuildTarget buildTarget) {
BuildTarget existing = nativeLinkableLibsMap.putIfAbsent(metadata, buildTarget);
if (existing != null && existing != buildTarget) {
throw new HumanReadableException(
"Two libraries in the dependencies have the same output filename: %s:\n"
+ "Those libraries are %s and %s",
metadata.getSoName(), buildTarget, existing);
}
}
};
for (TargetCpuType targetCpuType : filteredLinkablePlatforms) {
getNativeLinkableMetadata(
nativeLinkables.get(targetCpuType).getNativeLinkables(),
nativeLinkableLibsBuilder,
duplicateReporter,
targetCpuType);
getNativeLinkableMetadata(
nativeLinkables.get(targetCpuType).getNativeLinkableAssets(),
nativeLinkableLibsAssetsBuilder,
duplicateReporter,
targetCpuType);
}
// Adds a cxxruntime linkable to the nativeLinkableLibsBuilder for every platform that needs it.
ImmutableMap<AndroidLinkableMetadata, SourcePath> nativeLinkableLibsAssets =
nativeLinkableLibsAssetsBuilder.build();
addCxxRuntimeLinkables(nativePlatforms, nativeLinkableLibsBuilder, nativeLinkableLibsAssets);
ImmutableMap<AndroidLinkableMetadata, SourcePath> nativeLinkableLibs =
nativeLinkableLibsBuilder.build();
if (relinkerMode == RelinkerMode.ENABLED
&& (!nativeLinkableLibs.isEmpty() || !nativeLinkableLibsAssets.isEmpty())) {
NativeRelinker relinker =
new NativeRelinker(
originalBuildTarget,
projectFilesystem,
cellPathResolver,
graphBuilder.getSourcePathResolver(),
graphBuilder,
cxxBuckConfig,
nativePlatforms,
nativeLinkableLibs,
nativeLinkableLibsAssets,
relinkerWhitelist);
nativeLinkableLibs = relinker.getRelinkedLibs();
nativeLinkableLibsAssets = relinker.getRelinkedLibsAssets();
for (BuildRule rule : relinker.getRules()) {
graphBuilder.addToIndex(rule);
}
}
ImmutableMap<StripLinkable, CopyNativeLibraries.StrippedObjectDescription> strippedLibsMap =
generateStripRules(nativePlatforms, nativeLinkableLibs);
ImmutableMap<StripLinkable, CopyNativeLibraries.StrippedObjectDescription>
strippedLibsAssetsMap = generateStripRules(nativePlatforms, nativeLinkableLibsAssets);
ImmutableSortedSet<SourcePath> unstrippedLibraries =
RichStream.from(nativeLinkableLibs.values())
.concat(nativeLinkableLibsAssets.values().stream())
.toImmutableSortedSet(Ordering.natural());
Optional<CopyNativeLibraries> nativeLibrariesForPrimaryApk = Optional.empty();
for (APKModule module : apkModules) {
ImmutableMap<StripLinkable, CopyNativeLibraries.StrippedObjectDescription>
filteredStrippedLibsMap =
ImmutableMap.copyOf(
FluentIterable.from(strippedLibsMap.entrySet())
.filter(entry -> module.equals(entry.getValue().getApkModule())));
ImmutableMap<StripLinkable, CopyNativeLibraries.StrippedObjectDescription>
filteredStrippedLibsAssetsMap =
ImmutableMap.copyOf(
FluentIterable.from(strippedLibsAssetsMap.entrySet())
.filter(entry -> module.equals(entry.getValue().getApkModule())));
ImmutableCollection<SourcePath> nativeLibsDirectories =
packageableCollection.getNativeLibsDirectories().get(module);
ImmutableCollection<SourcePath> nativeLibsAssetsDirectories =
packageableCollection.getNativeLibAssetsDirectories().get(module);
// Handle native libs which need to go into the primary APK and skip exopackage/optimization
ImmutableCollection<SourcePath> nativeLibsDirectoriesForPrimaryDexModule =
module.isRootModule()
? packageableCollection.getNativeLibsDirectoriesForSystemLoader()
: ImmutableList.of();
if (module.isRootModule() && !nativeLibsDirectoriesForPrimaryDexModule.isEmpty()) {
nativeLibrariesForPrimaryApk =
Optional.of(
createCopyNativeLibraries(
module,
ImmutableMap.of(),
ImmutableMap.of(),
nativeLibsDirectoriesForPrimaryDexModule,
ImmutableList.of(),
"_for_primary_apk"));
}
if (filteredStrippedLibsMap.isEmpty()
&& filteredStrippedLibsAssetsMap.isEmpty()
&& nativeLibsDirectories.isEmpty()
&& nativeLibsAssetsDirectories.isEmpty()) {
continue;
}
moduleMappedCopyNativeLibriesBuilder.put(
module,
createCopyNativeLibraries(
module,
filteredStrippedLibsMap,
filteredStrippedLibsAssetsMap,
nativeLibsDirectories,
nativeLibsAssetsDirectories,
""));
hasCopyNativeLibraries = true;
}
Optional<ImmutableMap<APKModule, CopyNativeLibraries>> copyNativeLibraries =
hasCopyNativeLibraries
? Optional.of(moduleMappedCopyNativeLibriesBuilder.build())
: Optional.empty();
return ImmutableAndroidNativeLibsGraphEnhancementResult.of(
copyNativeLibraries,
Optional.of(unstrippedLibraries),
Optional.ofNullable(sonameMapping),
Optional.ofNullable(sharedObjectTargets),
nativeLibrariesForPrimaryApk);
}