in src/com/facebook/buck/android/toolchain/ndk/impl/NdkCxxPlatforms.java [446:681]
static UnresolvedNdkCxxPlatform build(
CxxBuckConfig config,
AndroidBuckConfig androidConfig,
ProjectFilesystem filesystem,
Flavor flavor,
Platform platform,
Path ndkRoot,
NdkCxxPlatformTargetConfiguration targetConfiguration,
NdkCxxRuntime cxxRuntime,
NdkCxxRuntimeType runtimeType,
ExecutableFinder executableFinder,
boolean strictToolchainPaths) {
String ndkVersion = readVersion(ndkRoot);
if (getNdkMajorVersion(ndkVersion) > 17
&& cxxRuntime != NdkCxxRuntime.LIBCXX
&& cxxRuntime != NdkCxxRuntime.SYSTEM) {
throw new HumanReadableException(
"C++ runtime %s was removed in Android NDK 18.\n"
+ "Detected Android NDK version is %s.\n"
+ "Configuration needs to be changed in order to build with the current Android NDK",
cxxRuntime.toString(), ndkVersion);
}
// Create a version string to use when generating rule keys via the NDK tools we'll generate
// below. This will be used in lieu of hashing the contents of the tools, so that builds from
// different host platforms (which produce identical output) will share the cache with one
// another.
NdkCompilerType compilerType = targetConfiguration.getCompiler().getType();
String version =
Joiner.on('-')
.join(
ImmutableList.of(
readVersion(ndkRoot),
targetConfiguration.getToolchain(),
targetConfiguration.getTargetAppPlatform(),
compilerType,
targetConfiguration.getCompiler().getVersion(),
targetConfiguration.getCompiler().getGccVersion(),
cxxRuntime));
Host host = getHost(platform);
NdkCxxToolchainPaths toolchainPaths =
new NdkCxxToolchainPaths(
filesystem,
ndkRoot,
targetConfiguration,
host.toString(),
cxxRuntime,
strictToolchainPaths,
getUseUnifiedHeaders(androidConfig, ndkVersion));
// Sanitized paths will have magic placeholders for parts of the paths that
// are machine/host-specific. See comments on ANDROID_NDK_ROOT and
// BUILD_HOST_SUBST above.
NdkCxxToolchainPaths sanitizedPaths = toolchainPaths.getSanitizedPaths();
// Build up the map of paths that must be sanitized.
ImmutableBiMap.Builder<Path, String> sanitizePathsBuilder = ImmutableBiMap.builder();
sanitizePathsBuilder.put(
toolchainPaths.getNdkToolRoot(),
PathFormatter.pathWithUnixSeparators(sanitizedPaths.getNdkToolRoot()));
if (compilerType != NdkCompilerType.GCC) {
sanitizePathsBuilder.put(
toolchainPaths.getNdkGccToolRoot(),
PathFormatter.pathWithUnixSeparators(sanitizedPaths.getNdkGccToolRoot()));
}
sanitizePathsBuilder.put(ndkRoot, AndroidNdkConstants.ANDROID_NDK_ROOT);
CxxToolProvider.Type type =
compilerType == NdkCompilerType.CLANG
? CxxToolProvider.Type.CLANG
: CxxToolProvider.Type.GCC;
ToolProvider ccTool =
new ConstantToolProvider(
getCTool(toolchainPaths, compilerType.cc, version, executableFinder));
ToolProvider cxxTool =
new ConstantToolProvider(
getCTool(toolchainPaths, compilerType.cxx, version, executableFinder));
CompilerProvider cc =
new CompilerProvider(
ccTool, () -> type, ToolType.CC, config.getUseDetailedUntrackedHeaderMessages(), true);
PreprocessorProvider cpp = new PreprocessorProvider(ccTool, type, ToolType.CPP, true);
CompilerProvider cxx =
new CompilerProvider(
cxxTool,
() -> type,
ToolType.CXX,
config.getUseDetailedUntrackedHeaderMessages(),
true);
PreprocessorProvider cxxpp = new PreprocessorProvider(cxxTool, type, ToolType.CXXPP, true);
Optional<SharedLibraryInterfaceParams.Type> sharedLibType = config.getSharedLibraryInterfaces();
Optional<SharedLibraryInterfaceParams> sharedLibParams = Optional.empty();
if (sharedLibType.isPresent()
&& sharedLibType.get() != SharedLibraryInterfaceParams.Type.DISABLED) {
sharedLibParams =
Optional.of(
ElfSharedLibraryInterfaceParams.of(
new ConstantToolProvider(
getGccTool(toolchainPaths, "objcopy", version, executableFinder)),
ImmutableList.of(),
sharedLibType.get() == SharedLibraryInterfaceParams.Type.DEFINED_ONLY));
}
CxxPlatform.Builder cxxPlatformBuilder = CxxPlatform.builder();
ImmutableBiMap<Path, String> sanitizePaths = sanitizePathsBuilder.build();
PrefixMapDebugPathSanitizer compilerDebugPathSanitizer =
new PrefixMapDebugPathSanitizer(".", sanitizePaths, true);
cxxPlatformBuilder
.setFlavor(flavor)
.setAs(cc)
.addAllAsflags(StringArg.from(getAsflags(targetConfiguration, toolchainPaths)))
.setAspp(cpp)
.setCc(cc)
.addAllCflags(
StringArg.from(
getCCompilationFlags(targetConfiguration, toolchainPaths, androidConfig)))
.setCpp(cpp)
.addAllCppflags(
StringArg.from(
getCPreprocessorFlags(targetConfiguration, toolchainPaths, androidConfig)))
.setCxx(cxx)
.addAllCxxflags(
StringArg.from(
getCxxCompilationFlags(targetConfiguration, toolchainPaths, androidConfig)))
.setCxxpp(cxxpp)
.addAllCxxppflags(
StringArg.from(
getCxxPreprocessorFlags(targetConfiguration, toolchainPaths, androidConfig)))
.setLd(
new DefaultLinkerProvider(
LinkerProvider.Type.GNU,
new ConstantToolProvider(
getCcLinkTool(
targetConfiguration,
toolchainPaths,
compilerType.cxx,
version,
cxxRuntime,
executableFinder)),
config.shouldCacheLinks()))
.addAllLdflags(StringArg.from(getLdFlags(targetConfiguration, androidConfig)))
.setStrip(getGccTool(toolchainPaths, "strip", version, executableFinder))
.setSymbolNameTool(
new PosixNmSymbolNameTool(
new ConstantToolProvider(
getGccTool(toolchainPaths, "nm", version, executableFinder))))
.setAr(
ArchiverProvider.from(
new GnuArchiver(getGccTool(toolchainPaths, "ar", version, executableFinder))))
.setArchiveContents(config.getArchiveContents().orElse(ArchiveContents.NORMAL))
.setRanlib(
new ConstantToolProvider(
getGccTool(toolchainPaths, "ranlib", version, executableFinder)))
// NDK builds are cross compiled, so the header is the same regardless of the host platform.
.setCompilerDebugPathSanitizer(compilerDebugPathSanitizer)
.setSharedLibraryExtension("so")
.setSharedLibraryVersionedExtensionFormat("so.%s")
.setStaticLibraryExtension("a")
.setObjectFileExtension("o")
.setSharedLibraryInterfaceParams(sharedLibParams)
.setPublicHeadersSymlinksEnabled(config.getPublicHeadersSymlinksEnabled())
.setPrivateHeadersSymlinksEnabled(config.getPrivateHeadersSymlinksEnabled())
.setFilepathLengthLimited(config.getFilepathLengthLimited());
// Add the NDK root path to the white-list so that headers from the NDK won't trigger the
// verification warnings. Ideally, long-term, we'd model NDK libs/headers via automatically
// generated nodes/descriptions so that they wouldn't need to special case it here.
HeaderVerification headerVerification = config.getHeaderVerificationOrIgnore();
try {
headerVerification =
headerVerification.withPlatformWhitelist(
ImmutableList.of(
"^"
+ Pattern.quote(ndkRoot.toRealPath().toString() + File.separatorChar)
+ ".*"));
} catch (IOException e) {
LOG.warn(e, "NDK path could not be resolved: %s", ndkRoot);
}
cxxPlatformBuilder.setHeaderVerification(headerVerification);
LOG.debug("NDK root: %s", ndkRoot.toString());
LOG.debug(
"Headers verification platform whitelist: %s", headerVerification.getPlatformWhitelist());
if (cxxRuntime != NdkCxxRuntime.SYSTEM) {
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.SHARED, StringArg.of("-l" + cxxRuntime.sharedName));
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-l" + cxxRuntime.staticName));
if (getNdkMajorVersion(ndkVersion) >= 12 && cxxRuntime == NdkCxxRuntime.LIBCXX) {
if (getNdkMajorVersion(ndkVersion) < 17
|| targetConfiguration.getTargetArchAbi() == NdkTargetArchAbi.ARMEABI_V7A
|| targetConfiguration.getTargetArchAbi() == NdkTargetArchAbi.X86) {
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-landroid_support"));
}
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-lc++abi"));
if (targetConfiguration.getTargetArchAbi() == NdkTargetArchAbi.ARMEABI_V7A) {
// libc++abi on 32-bit ARM depends on the LLVM unwinder; if not explicitly
// included here, clang++ would resolve references to _Unwind_RaiseException
// and related symbols with implementations provided by libgcc.a, which is
// not ABI-compatible with libc++ (and would most likely result in crashes
// when throwing exceptions).
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-lunwind"));
// Don't export symbols from libunwind and libgcc in the linked binary.
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-Wl,--exclude-libs,libunwind.a"));
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-Wl,--exclude-libs,libgcc.a"));
}
if (targetConfiguration.getTargetArchAbi() == NdkTargetArchAbi.ARMEABI) {
cxxPlatformBuilder.putRuntimeLdflags(
Linker.LinkableDepType.STATIC, StringArg.of("-latomic"));
}
}
}
CxxPlatform cxxPlatform = cxxPlatformBuilder.build();
NdkCxxPlatform.Builder builder = NdkCxxPlatform.builder();
builder
.setCxxPlatform(cxxPlatform)
.setCxxRuntime(cxxRuntime)
.setObjdump(getGccTool(toolchainPaths, "objdump", version, executableFinder));
if ((cxxRuntime != NdkCxxRuntime.SYSTEM) && (runtimeType != NdkCxxRuntimeType.STATIC)) {
builder.setCxxSharedRuntimePath(
PathSourcePath.of(
filesystem,
toolchainPaths.getCxxRuntimeLibsDirectory().resolve(cxxRuntime.getSoname())));
}
return StaticUnresolvedNdkCxxPlatform.of(builder.build());
}