in src/com/facebook/buck/apple/toolchain/impl/AppleCxxPlatforms.java [158:516]
public static AppleCxxPlatform buildWithXcodeToolFinder(
ProjectFilesystem filesystem,
AppleSdk targetSdk,
String minVersion,
String targetArchitecture,
AppleSdkPaths sdkPaths,
BuckConfig buckConfig,
XcodeToolFinder xcodeToolFinder,
XcodeBuildVersionCache xcodeBuildVersionCache) {
AppleCxxPlatform.Builder platformBuilder = AppleCxxPlatform.builder();
ImmutableList.Builder<Path> toolSearchPathsBuilder = ImmutableList.builder();
// Search for tools from most specific to least specific.
toolSearchPathsBuilder
.add(sdkPaths.getSdkPath().resolve(USR_BIN))
.add(sdkPaths.getSdkPath().resolve("Developer").resolve(USR_BIN))
.add(sdkPaths.getPlatformPath().resolve("Developer").resolve(USR_BIN));
for (Path toolchainPath : sdkPaths.getToolchainPaths()) {
toolSearchPathsBuilder.add(toolchainPath.resolve(USR_BIN));
}
if (sdkPaths.getDeveloperPath().isPresent()) {
toolSearchPathsBuilder.add(sdkPaths.getDeveloperPath().get().resolve(USR_BIN));
toolSearchPathsBuilder.add(sdkPaths.getDeveloperPath().get().resolve("Tools"));
}
// TODO(beng): Add more and better cflags.
ImmutableList.Builder<String> cflagsBuilder = ImmutableList.builder();
cflagsBuilder.add("-isysroot", sdkPaths.getSdkPath().toString());
cflagsBuilder.add("-arch", targetArchitecture);
cflagsBuilder.add(targetSdk.getApplePlatform().getMinVersionFlagPrefix() + minVersion);
if (targetSdk.getApplePlatform().equals(ApplePlatform.WATCHOS)) {
cflagsBuilder.add("-fembed-bitcode");
}
AppleConfig appleConfig = buckConfig.getView(AppleConfig.class);
// Populate Xcode version keys from Xcode's own Info.plist if available.
Optional<String> xcodeBuildVersion = Optional.empty();
Optional<Path> developerPath = sdkPaths.getDeveloperPath();
if (developerPath.isPresent()) {
Path xcodeBundlePath = developerPath.get().getParent();
if (xcodeBundlePath != null) {
Path xcodeInfoPlistPath = xcodeBundlePath.resolve("Info.plist");
try (InputStream stream = Files.newInputStream(xcodeInfoPlistPath)) {
NSDictionary parsedXcodeInfoPlist = (NSDictionary) PropertyListParser.parse(stream);
NSObject xcodeVersionObject = parsedXcodeInfoPlist.objectForKey("DTXcode");
if (xcodeVersionObject != null) {
Optional<String> xcodeVersion = Optional.of(xcodeVersionObject.toString());
platformBuilder.setXcodeVersion(xcodeVersion);
}
} catch (IOException e) {
LOG.warn(
"Error reading Xcode's info plist %s; ignoring Xcode versions", xcodeInfoPlistPath);
} catch (PropertyListFormatException
| ParseException
| ParserConfigurationException
| SAXException e) {
LOG.warn("Error in parsing %s; ignoring Xcode versions", xcodeInfoPlistPath);
}
}
xcodeBuildVersion = xcodeBuildVersionCache.lookup(developerPath.get());
platformBuilder.setXcodeBuildVersion(xcodeBuildVersion);
LOG.debug("Xcode build version is: " + xcodeBuildVersion.orElse("<absent>"));
}
ImmutableList.Builder<String> versions = ImmutableList.builder();
versions.add(targetSdk.getVersion());
ImmutableList<String> toolchainVersions =
targetSdk.getToolchains().stream()
.map(AppleToolchain::getVersion)
.flatMap(RichStream::from)
.collect(ImmutableList.toImmutableList());
if (toolchainVersions.isEmpty()) {
if (!xcodeBuildVersion.isPresent()) {
throw new HumanReadableException("Failed to read toolchain versions and Xcode version.");
}
versions.add(xcodeBuildVersion.get());
} else {
versions.addAll(toolchainVersions);
}
String version = Joiner.on(':').join(versions.build());
ImmutableList<Path> toolSearchPaths = toolSearchPathsBuilder.build();
Tool clangPath =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "clang", version);
Tool clangXxPath =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "clang++", version);
Tool ar =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "ar", version);
Tool ranlib =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "ranlib", version);
Tool strip =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "strip", version);
Tool nm =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "nm", version);
Tool actool =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "actool", version);
Tool ibtool =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "ibtool", version);
Tool libtool =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "libtool", version);
Tool momc =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "momc", version);
Tool xctest =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "xctest", version);
Tool dsymutil =
getXcodeTool(
filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "dsymutil", version);
// We are seeing a stack overflow in dsymutil during (fat) LTO
// builds. Upstream dsymutil was patched to avoid recursion in the
// offending path in https://reviews.llvm.org/D48899, and
// https://reviews.llvm.org/D45172 mentioned that there is much
// more stack space available when single threaded.
if (appleConfig.shouldWorkAroundDsymutilLTOStackOverflowBug()) {
dsymutil = new CommandTool.Builder(dsymutil).addArg("-num-threads=1").build();
}
Tool lipo =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "lipo", version);
Tool lldb =
getXcodeTool(filesystem, toolSearchPaths, xcodeToolFinder, appleConfig, "lldb", version);
Optional<Path> stubBinaryPath =
targetSdk
.getApplePlatform()
.getStubBinaryPath()
.map(input -> sdkPaths.getSdkPath().resolve(input));
UserFlavor targetFlavor =
UserFlavor.of(
Flavor.replaceInvalidCharacters(targetSdk.getName() + "-" + targetArchitecture),
String.format("SDK: %s, architecture: %s", targetSdk.getName(), targetArchitecture));
CxxBuckConfig config =
appleConfig.useFlavoredCxxSections()
? new CxxBuckConfig(buckConfig, targetFlavor)
: new CxxBuckConfig(buckConfig);
ImmutableBiMap.Builder<Path, String> sanitizerPaths = ImmutableBiMap.builder();
sanitizerPaths.put(sdkPaths.getSdkPath(), "APPLE_SDKROOT");
sanitizerPaths.put(sdkPaths.getPlatformPath(), "APPLE_PLATFORM_DIR");
if (sdkPaths.getDeveloperPath().isPresent()) {
sanitizerPaths.put(sdkPaths.getDeveloperPath().get(), "APPLE_DEVELOPER_DIR");
}
// https://github.com/facebook/buck/pull/1168: add the root cell's absolute path to the quote
// include path, and also force it to be sanitized by all user rule keys.
if (appleConfig.addCellPathToIquotePath()) {
sanitizerPaths.put(filesystem.getRootPath().getPath(), ".");
cflagsBuilder.add("-iquote", filesystem.getRootPath().toString());
}
DebugPathSanitizer compilerDebugPathSanitizer =
new PrefixMapDebugPathSanitizer(
DebugPathSanitizer.getPaddedDir(
".", config.getDebugPathSanitizerLimit(), File.separatorChar),
sanitizerPaths.build());
ImmutableList<String> cflags = cflagsBuilder.build();
ImmutableMap.Builder<String, String> macrosBuilder = ImmutableMap.builder();
macrosBuilder.put("SDKROOT", sdkPaths.getSdkPath().toString());
macrosBuilder.put("PLATFORM_DIR", sdkPaths.getPlatformPath().toString());
macrosBuilder.put("CURRENT_ARCH", targetArchitecture);
if (sdkPaths.getDeveloperPath().isPresent()) {
macrosBuilder.put("DEVELOPER_DIR", sdkPaths.getDeveloperPath().get().toString());
}
ImmutableMap<String, String> macros = macrosBuilder.build();
Optional<String> buildVersion = Optional.empty();
Path platformVersionPlistPath = sdkPaths.getPlatformPath().resolve("version.plist");
try (InputStream versionPlist = Files.newInputStream(platformVersionPlistPath)) {
NSDictionary versionInfo = (NSDictionary) PropertyListParser.parse(versionPlist);
if (versionInfo != null) {
NSObject productBuildVersion = versionInfo.objectForKey("ProductBuildVersion");
if (productBuildVersion != null) {
buildVersion = Optional.of(productBuildVersion.toString());
} else {
LOG.warn(
"In %s, missing ProductBuildVersion. Build version will be unset for this platform.",
platformVersionPlistPath);
}
} else {
LOG.warn(
"Empty version plist in %s. Build version will be unset for this platform.",
platformVersionPlistPath);
}
} catch (NoSuchFileException e) {
LOG.warn(
"%s does not exist. Build version will be unset for this platform.",
platformVersionPlistPath);
} catch (PropertyListFormatException
| SAXException
| ParserConfigurationException
| ParseException
| IOException e) {
// Some other error occurred, print the exception since it may contain error details.
LOG.warn(
e,
"Failed to parse %s. Build version will be unset for this platform.",
platformVersionPlistPath);
}
PreprocessorProvider aspp =
new PreprocessorProvider(
new ConstantToolProvider(clangPath), CxxToolProvider.Type.CLANG, ToolType.ASPP);
CompilerProvider as =
new CompilerProvider(
new ConstantToolProvider(clangPath),
CxxToolProvider.Type.CLANG,
ToolType.AS,
config.getUseDetailedUntrackedHeaderMessages());
PreprocessorProvider cpp =
new PreprocessorProvider(
new ConstantToolProvider(clangPath), CxxToolProvider.Type.CLANG, ToolType.CPP);
CompilerProvider cc =
new CompilerProvider(
new ConstantToolProvider(clangPath),
CxxToolProvider.Type.CLANG,
ToolType.CC,
config.getUseDetailedUntrackedHeaderMessages());
PreprocessorProvider cxxpp =
new PreprocessorProvider(
new ConstantToolProvider(clangXxPath), CxxToolProvider.Type.CLANG, ToolType.CXXPP);
CompilerProvider cxx =
new CompilerProvider(
new ConstantToolProvider(clangXxPath),
CxxToolProvider.Type.CLANG,
ToolType.CXX,
config.getUseDetailedUntrackedHeaderMessages());
ImmutableList.Builder<String> whitelistBuilder = ImmutableList.builder();
whitelistBuilder.add("^" + Pattern.quote(sdkPaths.getSdkPath().toString()) + "\\/.*");
whitelistBuilder.add(
"^"
+ Pattern.quote(sdkPaths.getPlatformPath() + "/Developer/Library/Frameworks")
+ "\\/.*");
for (Path toolchainPath : sdkPaths.getToolchainPaths()) {
LOG.debug("Apple toolchain path: %s", toolchainPath);
try {
whitelistBuilder.add("^" + Pattern.quote(toolchainPath.toRealPath().toString()) + "\\/.*");
} catch (IOException e) {
LOG.warn(e, "Apple toolchain path could not be resolved: %s", toolchainPath);
}
}
HeaderVerification headerVerification =
config.getHeaderVerificationOrIgnore().withPlatformWhitelist(whitelistBuilder.build());
LOG.debug(
"Headers verification platform whitelist: %s", headerVerification.getPlatformWhitelist());
ImmutableList<String> ldFlags =
getLdFlags(targetSdk, filesystem, xcodeToolFinder, toolSearchPaths, appleConfig, version);
ImmutableList<String> combinedLdFlags =
ImmutableList.<String>builder().addAll(cflags).addAll(ldFlags).build();
ImmutableList<Arg> cflagsArgs = ImmutableList.copyOf(StringArg.from(cflags));
CxxPlatform cxxPlatform =
CxxPlatforms.build(
targetFlavor,
Platform.MACOS,
config,
as,
aspp,
cc,
cxx,
cpp,
cxxpp,
new DefaultLinkerProvider(
LinkerProvider.Type.DARWIN,
new ConstantToolProvider(clangXxPath),
config.shouldCacheLinks(),
appleConfig.shouldLinkScrubConcurrently()),
StringArg.from(combinedLdFlags),
ImmutableMultimap.of(),
strip,
ArchiverProvider.from(new BsdArchiver(ar)),
ArchiveContents.NORMAL,
Optional.of(new ConstantToolProvider(ranlib)),
new PosixNmSymbolNameTool(new ConstantToolProvider(nm)),
cflagsArgs,
ImmutableList.of(),
cflagsArgs,
ImmutableList.of(),
cflagsArgs,
ImmutableList.of(),
"dylib",
"%s.dylib",
"a",
"o",
Optional.empty(),
compilerDebugPathSanitizer,
macros,
Optional.empty(),
headerVerification,
config.getPublicHeadersSymlinksEnabled(),
config.getPrivateHeadersSymlinksEnabled(),
PicType.PIC);
ApplePlatform applePlatform = targetSdk.getApplePlatform();
ImmutableList.Builder<Path> swiftOverrideSearchPathBuilder = ImmutableList.builder();
AppleSdkPaths.Builder swiftSdkPathsBuilder = AppleSdkPaths.builder().from(sdkPaths);
Optional<SwiftPlatform> swiftPlatform =
getSwiftPlatform(
SwiftTargetTriple.of(
targetArchitecture,
"apple",
applePlatform.getSwiftName().orElse(applePlatform.getName()),
minVersion,
applePlatform.getIsSimulator()),
version,
targetSdk,
swiftSdkPathsBuilder.build(),
appleConfig.shouldLinkSystemSwift(),
swiftOverrideSearchPathBuilder.addAll(toolSearchPaths).build(),
xcodeToolFinder,
filesystem);
platformBuilder
.setCxxPlatform(cxxPlatform)
.setSwiftPlatform(swiftPlatform)
.setAppleSdk(targetSdk)
.setAppleSdkPaths(sdkPaths)
.setMinVersion(minVersion)
.setBuildVersion(buildVersion)
.setActool(actool)
.setLibtool(libtool)
.setIbtool(ibtool)
.setMomc(momc)
.setCopySceneKitAssets(
getOptionalTool(
"copySceneKitAssets", toolSearchPaths, xcodeToolFinder, version, filesystem))
.setXctest(xctest)
.setDsymutil(dsymutil)
.setLipo(lipo)
.setStubBinary(stubBinaryPath)
.setLldb(lldb)
.setCodesignAllocate(
getOptionalTool(
"codesign_allocate", toolSearchPaths, xcodeToolFinder, version, filesystem))
.setCodesignProvider(appleConfig.getCodesignProvider());
return platformBuilder.build();
}