List of usage examples for com.google.common.collect ImmutableMultimap keySet
@Override
public ImmutableSet<K> keySet()
From source file:com.facebook.buck.apple.project_generator.WorkspaceAndProjectGenerator.java
private void generateProject(final Map<Path, ProjectGenerator> projectGenerators, ListeningExecutorService listeningExecutorService, WorkspaceGenerator workspaceGenerator, ImmutableSet<BuildTarget> targetsInRequiredProjects, ImmutableMultimap.Builder<BuildTarget, PBXTarget> buildTargetToPbxTargetMapBuilder, ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder, final Optional<BuildTarget> targetToBuildWithBuck) throws IOException, InterruptedException { ImmutableMultimap.Builder<Cell, BuildTarget> projectCellToBuildTargetsBuilder = ImmutableMultimap.builder(); for (TargetNode<?, ?> targetNode : projectGraph.getNodes()) { BuildTarget buildTarget = targetNode.getBuildTarget(); projectCellToBuildTargetsBuilder.put(rootCell.getCell(buildTarget), buildTarget); }//w w w .j a va2 s . c o m ImmutableMultimap<Cell, BuildTarget> projectCellToBuildTargets = projectCellToBuildTargetsBuilder.build(); List<ListenableFuture<GenerationResult>> projectGeneratorFutures = new ArrayList<>(); for (final Cell projectCell : projectCellToBuildTargets.keySet()) { ImmutableMultimap.Builder<Path, BuildTarget> projectDirectoryToBuildTargetsBuilder = ImmutableMultimap .builder(); final ImmutableSet<BuildTarget> cellRules = ImmutableSet .copyOf(projectCellToBuildTargets.get(projectCell)); for (BuildTarget buildTarget : cellRules) { projectDirectoryToBuildTargetsBuilder.put(buildTarget.getBasePath(), buildTarget); } ImmutableMultimap<Path, BuildTarget> projectDirectoryToBuildTargets = projectDirectoryToBuildTargetsBuilder .build(); final Path relativeTargetCell = rootCell.getRoot().relativize(projectCell.getRoot()); for (final Path projectDirectory : projectDirectoryToBuildTargets.keySet()) { final ImmutableSet<BuildTarget> rules = filterRulesForProjectDirectory(projectGraph, ImmutableSet.copyOf(projectDirectoryToBuildTargets.get(projectDirectory))); if (Sets.intersection(targetsInRequiredProjects, rules).isEmpty()) { continue; } projectGeneratorFutures.add(listeningExecutorService.submit(() -> { GenerationResult result = generateProjectForDirectory(projectGenerators, targetToBuildWithBuck, projectCell, projectDirectory, rules); // convert the projectPath to relative to the target cell here result = GenerationResult.of(relativeTargetCell.resolve(result.getProjectPath()), result.isProjectGenerated(), result.getRequiredBuildTargets(), result.getBuildTargetToGeneratedTargetMap()); return result; })); } } List<GenerationResult> generationResults; try { generationResults = Futures.allAsList(projectGeneratorFutures).get(); } catch (ExecutionException e) { Throwables.propagateIfInstanceOf(e.getCause(), IOException.class); Throwables.propagateIfPossible(e.getCause()); throw new IllegalStateException("Unexpected exception: ", e); } for (GenerationResult result : generationResults) { if (!result.isProjectGenerated()) { continue; } workspaceGenerator.addFilePath(result.getProjectPath()); processGenerationResult(buildTargetToPbxTargetMapBuilder, targetToProjectPathMapBuilder, result); } }
From source file:com.facebook.buck.apple.WorkspaceAndProjectGenerator.java
public Path generateWorkspaceAndDependentProjects(Map<Path, ProjectGenerator> projectGenerators) throws IOException { LOG.debug("Generating workspace for target %s", workspaceBuildTarget); String workspaceName = XcodeWorkspaceConfigDescription.getWorkspaceNameFromArg(workspaceArguments); Path outputDirectory;/*from w ww. j av a2 s . c o m*/ if (combinedProject) { workspaceName += "-Combined"; outputDirectory = BuildTargets.getGenPath(workspaceBuildTarget, "%s").getParent() .resolve(workspaceName + ".xcodeproj"); } else { outputDirectory = workspaceBuildTarget.getBasePath(); } WorkspaceGenerator workspaceGenerator = new WorkspaceGenerator(projectFilesystem, combinedProject ? "project" : workspaceName, outputDirectory); ImmutableMap.Builder<String, XcodeWorkspaceConfigDescription.Arg> schemeConfigsBuilder = ImmutableMap .builder(); ImmutableSetMultimap.Builder<String, Optional<TargetNode<?>>> schemeNameToSrcTargetNodeBuilder = ImmutableSetMultimap .builder(); ImmutableSetMultimap.Builder<String, TargetNode<?>> buildForTestNodesBuilder = ImmutableSetMultimap .builder(); ImmutableMultimap.Builder<AppleTestBundleParamsKey, TargetNode<AppleTestDescription.Arg>> groupedTestsBuilder = ImmutableMultimap .builder(); ImmutableSetMultimap.Builder<String, TargetNode<AppleTestDescription.Arg>> ungroupedTestsBuilder = ImmutableSetMultimap .builder(); buildWorkspaceSchemes(getTargetToBuildWithBuck(), projectGraph, projectGeneratorOptions.contains(ProjectGenerator.Option.INCLUDE_TESTS), projectGeneratorOptions.contains(ProjectGenerator.Option.INCLUDE_DEPENDENCIES_TESTS), groupableTests, workspaceName, workspaceArguments, schemeConfigsBuilder, schemeNameToSrcTargetNodeBuilder, buildForTestNodesBuilder, groupedTestsBuilder, ungroupedTestsBuilder); ImmutableMap<String, XcodeWorkspaceConfigDescription.Arg> schemeConfigs = schemeConfigsBuilder.build(); ImmutableSetMultimap<String, Optional<TargetNode<?>>> schemeNameToSrcTargetNode = schemeNameToSrcTargetNodeBuilder .build(); ImmutableSetMultimap<String, TargetNode<?>> buildForTestNodes = buildForTestNodesBuilder.build(); ImmutableMultimap<AppleTestBundleParamsKey, TargetNode<AppleTestDescription.Arg>> groupedTests = groupedTestsBuilder .build(); ImmutableSetMultimap<String, TargetNode<AppleTestDescription.Arg>> ungroupedTests = ungroupedTestsBuilder .build(); Iterable<PBXTarget> synthesizedCombinedTestTargets = ImmutableList.of(); ImmutableSet<BuildTarget> targetsInRequiredProjects = FluentIterable .from(Optional.presentInstances(schemeNameToSrcTargetNode.values())) .append(buildForTestNodes.values()).transform(HasBuildTarget.TO_TARGET).toSet(); ImmutableMultimap.Builder<BuildTarget, PBXTarget> buildTargetToPbxTargetMapBuilder = ImmutableMultimap .builder(); ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder(); Optional<BuildTarget> targetToBuildWithBuck = getTargetToBuildWithBuck(); if (combinedProject) { LOG.debug("Generating a combined project"); ProjectGenerator generator = new ProjectGenerator(projectGraph, targetsInRequiredProjects, projectFilesystem, outputDirectory.getParent(), workspaceName, buildFileName, projectGeneratorOptions, targetToBuildWithBuck, buildWithBuckFlags, executableFinder, environment, cxxPlatforms, defaultCxxPlatform, sourcePathResolverForNode, buckEventBus, attemptToDetermineBestCxxPlatform, halideBuckConfig, cxxBuckConfig) .setAdditionalCombinedTestTargets(groupedTests) .setTestsToGenerateAsStaticLibraries(groupableTests); combinedProjectGenerator = Optional.of(generator); generator.createXcodeProjects(); workspaceGenerator.addFilePath(generator.getProjectPath(), Optional.<Path>absent()); requiredBuildTargetsBuilder.addAll(generator.getRequiredBuildTargets()); buildTargetToPbxTargetMapBuilder.putAll(generator.getBuildTargetToGeneratedTargetMap()); for (PBXTarget target : generator.getBuildTargetToGeneratedTargetMap().values()) { targetToProjectPathMapBuilder.put(target, generator.getProjectPath()); } synthesizedCombinedTestTargets = generator.getBuildableCombinedTestTargets(); for (PBXTarget target : synthesizedCombinedTestTargets) { targetToProjectPathMapBuilder.put(target, generator.getProjectPath()); } } else { ImmutableMultimap.Builder<Path, BuildTarget> projectDirectoryToBuildTargetsBuilder = ImmutableMultimap .builder(); for (TargetNode<?> targetNode : projectGraph.getNodes()) { BuildTarget buildTarget = targetNode.getBuildTarget(); projectDirectoryToBuildTargetsBuilder.put(buildTarget.getBasePath(), buildTarget); } ImmutableMultimap<Path, BuildTarget> projectDirectoryToBuildTargets = projectDirectoryToBuildTargetsBuilder .build(); for (Path projectDirectory : projectDirectoryToBuildTargets.keySet()) { final ImmutableSet<BuildTarget> rules = filterRulesForProjectDirectory(projectGraph, ImmutableSet.copyOf(projectDirectoryToBuildTargets.get(projectDirectory))); if (Sets.intersection(targetsInRequiredProjects, rules).isEmpty()) { continue; } ProjectGenerator generator = projectGenerators.get(projectDirectory); if (generator == null) { LOG.debug("Generating project for directory %s with targets %s", projectDirectory, rules); String projectName; if (projectDirectory.getNameCount() == 0) { // If we're generating a project in the root directory, use a generic name. projectName = "Project"; } else { // Otherwise, name the project the same thing as the directory we're in. projectName = projectDirectory.getFileName().toString(); } generator = new ProjectGenerator(projectGraph, rules, projectFilesystem, projectDirectory, projectName, buildFileName, projectGeneratorOptions, Optionals.bind( targetToBuildWithBuck, new Function<BuildTarget, Optional<BuildTarget>>() { @Override public Optional<BuildTarget> apply(BuildTarget input) { return rules.contains(input) ? Optional.of(input) : Optional.<BuildTarget>absent(); } }), buildWithBuckFlags, executableFinder, environment, cxxPlatforms, defaultCxxPlatform, sourcePathResolverForNode, buckEventBus, attemptToDetermineBestCxxPlatform, halideBuckConfig, cxxBuckConfig).setTestsToGenerateAsStaticLibraries(groupableTests); generator.createXcodeProjects(); requiredBuildTargetsBuilder.addAll(generator.getRequiredBuildTargets()); projectGenerators.put(projectDirectory, generator); } else { LOG.debug("Already generated project for target %s, skipping", projectDirectory); } workspaceGenerator.addFilePath(generator.getProjectPath()); buildTargetToPbxTargetMapBuilder.putAll(generator.getBuildTargetToGeneratedTargetMap()); for (PBXTarget target : generator.getBuildTargetToGeneratedTargetMap().values()) { targetToProjectPathMapBuilder.put(target, generator.getProjectPath()); } } if (!groupedTests.isEmpty()) { ProjectGenerator combinedTestsProjectGenerator = new ProjectGenerator(projectGraph, ImmutableSortedSet.<BuildTarget>of(), projectFilesystem, BuildTargets.getGenPath(workspaceBuildTarget, "%s-CombinedTestBundles"), "_CombinedTestBundles", buildFileName, projectGeneratorOptions, Optional.<BuildTarget>absent(), buildWithBuckFlags, executableFinder, environment, cxxPlatforms, defaultCxxPlatform, sourcePathResolverForNode, buckEventBus, attemptToDetermineBestCxxPlatform, halideBuckConfig, cxxBuckConfig); combinedTestsProjectGenerator.setAdditionalCombinedTestTargets(groupedTests).createXcodeProjects(); workspaceGenerator.addFilePath(combinedTestsProjectGenerator.getProjectPath()); requiredBuildTargetsBuilder.addAll(combinedTestsProjectGenerator.getRequiredBuildTargets()); for (PBXTarget target : combinedTestsProjectGenerator.getBuildTargetToGeneratedTargetMap() .values()) { targetToProjectPathMapBuilder.put(target, combinedTestsProjectGenerator.getProjectPath()); } synthesizedCombinedTestTargets = combinedTestsProjectGenerator.getBuildableCombinedTestTargets(); for (PBXTarget target : synthesizedCombinedTestTargets) { targetToProjectPathMapBuilder.put(target, combinedTestsProjectGenerator.getProjectPath()); } this.combinedTestsProjectGenerator = Optional.of(combinedTestsProjectGenerator); } } Path workspacePath = workspaceGenerator.writeWorkspace(); final Multimap<BuildTarget, PBXTarget> buildTargetToTarget = buildTargetToPbxTargetMapBuilder.build(); final Function<BuildTarget, PBXTarget> targetNodeToPBXTargetTransformer = new Function<BuildTarget, PBXTarget>() { @Override public PBXTarget apply(BuildTarget input) { ImmutableList<PBXTarget> targets = ImmutableList.copyOf(buildTargetToTarget.get(input)); if (targets.size() == 1) { return targets.get(0); } // The only reason why a build target would map to more than one project target is if // there are two project targets: one is the usual one, the other is a target that just // shells out to Buck. Preconditions.checkState(targets.size() == 2); PBXTarget first = targets.get(0); PBXTarget second = targets.get(1); Preconditions.checkState(first.getName().endsWith(ProjectGenerator.BUILD_WITH_BUCK_POSTFIX) ^ second.getName().endsWith(ProjectGenerator.BUILD_WITH_BUCK_POSTFIX)); PBXTarget buildWithBuckTarget; PBXTarget buildWithXcodeTarget; if (first.getName().endsWith(ProjectGenerator.BUILD_WITH_BUCK_POSTFIX)) { buildWithBuckTarget = first; buildWithXcodeTarget = second; } else { buildWithXcodeTarget = first; buildWithBuckTarget = second; } return buildWithBuck ? buildWithBuckTarget : buildWithXcodeTarget; } }; writeWorkspaceSchemes(workspaceName, outputDirectory, schemeConfigs, schemeNameToSrcTargetNode, buildForTestNodes, ungroupedTests, targetToProjectPathMapBuilder.build(), synthesizedCombinedTestTargets, new Function<TargetNode<?>, Collection<PBXTarget>>() { @Override public Collection<PBXTarget> apply(TargetNode<?> input) { return buildTargetToTarget.get(input.getBuildTarget()); } }, targetNodeToPBXTargetTransformer); return workspacePath; }
From source file:com.facebook.buck.features.apple.project.WorkspaceAndProjectGenerator.java
private void generateProject(Map<Path, ProjectGenerator> projectGenerators, ListeningExecutorService listeningExecutorService, WorkspaceGenerator workspaceGenerator, ImmutableSet<BuildTarget> targetsInRequiredProjects, ImmutableSetMultimap.Builder<PBXProject, PBXTarget> generatedProjectToPbxTargetsBuilder, ImmutableMap.Builder<BuildTarget, PBXTarget> buildTargetToPbxTargetMapBuilder, ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder) throws IOException, InterruptedException { ImmutableMultimap.Builder<Cell, BuildTarget> projectCellToBuildTargetsBuilder = ImmutableMultimap.builder(); for (TargetNode<?> targetNode : projectGraph.getNodes()) { BuildTarget buildTarget = targetNode.getBuildTarget(); projectCellToBuildTargetsBuilder.put(rootCell.getCell(buildTarget), buildTarget); }//from w ww .j av a2 s .co m ImmutableMultimap<Cell, BuildTarget> projectCellToBuildTargets = projectCellToBuildTargetsBuilder.build(); List<ListenableFuture<GenerationResult>> projectGeneratorFutures = new ArrayList<>(); for (Cell projectCell : projectCellToBuildTargets.keySet()) { ImmutableMultimap.Builder<Path, BuildTarget> projectDirectoryToBuildTargetsBuilder = ImmutableMultimap .builder(); ImmutableSet<BuildTarget> cellRules = ImmutableSet.copyOf(projectCellToBuildTargets.get(projectCell)); for (BuildTarget buildTarget : cellRules) { projectDirectoryToBuildTargetsBuilder.put(buildTarget.getBasePath(), buildTarget); } ImmutableMultimap<Path, BuildTarget> projectDirectoryToBuildTargets = projectDirectoryToBuildTargetsBuilder .build(); Path relativeTargetCell = rootCell.getRoot().relativize(projectCell.getRoot()); for (Path projectDirectory : projectDirectoryToBuildTargets.keySet()) { ImmutableSet<BuildTarget> rules = filterRulesForProjectDirectory(projectGraph, ImmutableSet.copyOf(projectDirectoryToBuildTargets.get(projectDirectory))); if (Sets.intersection(targetsInRequiredProjects, rules).isEmpty()) { continue; } boolean isMainProject = workspaceArguments.getSrcTarget().isPresent() && rules.contains(workspaceArguments.getSrcTarget().get()); projectGeneratorFutures.add(listeningExecutorService.submit(() -> { GenerationResult result = generateProjectForDirectory(projectGenerators, projectCell, projectDirectory, rules, isMainProject, targetsInRequiredProjects); // convert the projectPath to relative to the target cell here result = GenerationResult.of(relativeTargetCell.resolve(result.getProjectPath()), result.isProjectGenerated(), result.getRequiredBuildTargets(), result.getXcconfigPaths(), result.getFilesToCopyInXcode(), result.getBuildTargetToGeneratedTargetMap(), result.getGeneratedProjectToPbxTargets()); return result; })); } } List<GenerationResult> generationResults; try { generationResults = Futures.allAsList(projectGeneratorFutures).get(); } catch (ExecutionException e) { Throwables.throwIfInstanceOf(e.getCause(), IOException.class); Throwables.throwIfUnchecked(e.getCause()); throw new IllegalStateException("Unexpected exception: ", e); } for (GenerationResult result : generationResults) { if (!result.isProjectGenerated()) { continue; } workspaceGenerator.addFilePath(result.getProjectPath()); processGenerationResult(generatedProjectToPbxTargetsBuilder, buildTargetToPbxTargetMapBuilder, targetToProjectPathMapBuilder, result); } }
From source file:com.facebook.buck.android.dalvik.DalvikAwareZipSplitter.java
private DalvikAwareZipSplitter(ProjectFilesystem filesystem, Set<Path> inFiles, Path outPrimary, Path outSecondaryDir, String secondaryPattern, Path outDexStoresDir, long linearAllocLimit, Predicate<String> requiredInPrimaryZip, Set<String> wantedInPrimaryZip, ImmutableSet<String> secondaryHeadSet, ImmutableSet<String> secondaryTailSet, ImmutableMultimap<APKModule, String> additionalDexStoreSets, APKModule rootAPKModule, DexSplitStrategy dexSplitStrategy, Path reportDir) { if (linearAllocLimit <= 0) { throw new HumanReadableException("linear_alloc_hard_limit must be greater than zero."); }//from w w w .j a v a 2s . c o m this.filesystem = filesystem; this.inFiles = ImmutableSet.copyOf(inFiles); this.outPrimary = outPrimary; this.secondaryDexWriter = new MySecondaryDexHelper("secondary", outSecondaryDir, secondaryPattern); this.additionalDexWriters = new HashMap<>(); this.requiredInPrimaryZip = requiredInPrimaryZip; this.wantedInPrimaryZip = ImmutableSet.copyOf(wantedInPrimaryZip); this.secondaryHeadSet = secondaryHeadSet; this.secondaryTailSet = secondaryTailSet; this.classPathToDexStore = additionalDexStoreSets.inverse(); for (APKModule dexStore : additionalDexStoreSets.keySet()) { if (!dexStore.equals(rootAPKModule)) { additionalDexWriters.put(dexStore, new MySecondaryDexHelper(dexStore.getCanaryClassName(), outDexStoresDir.resolve(dexStore.getName()), secondaryPattern)); } } this.rootModule = rootAPKModule; this.reportDir = reportDir; this.dexSplitStrategy = dexSplitStrategy; this.linearAllocLimit = linearAllocLimit; this.dalvikStatsCache = new DalvikStatsCache(); }
From source file:org.prebake.service.tools.ext.JunitHtmlReportGenerator.java
static void generateHtmlReport(Map<String, ?> jsonReport, Path reportDir) throws IOException { // Group tests by packages so we can let users examine the results by // logical groupings. ImmutableMultimap<String, Map<?, ?>> byPackage; List<String> resultTypes; {//from ww w .ja va2s . c o m Set<String> resultTypeSet = Sets.newHashSet(); ImmutableList.Builder<Map<?, ?>> b = ImmutableList.builder(); // We can't trust the jsonReport to have the same structure as the method // above, since a filter could arbitrarily change it. Object tests = jsonReport.get(ReportKey.TESTS); if (tests instanceof Iterable<?>) { for (Object testVal : (Iterable<?>) tests) { if (!(testVal instanceof Map<?, ?>)) { continue; // If filter nulls out elements. } Map<?, ?> test = (Map<?, ?>) testVal; b.add(test); String result = getIfOfType(test, ReportKey.RESULT, String.class); resultTypeSet.add(result); } } byPackage = groupBy(b.build(), new Function<Map<?, ?>, String>() { public String apply(Map<?, ?> test) { String className = getIfOfType(test, ReportKey.CLASS_NAME, String.class); if (className == null) { return null; } int lastDot = className.lastIndexOf('.'); return (lastDot >= 0) ? className.substring(0, lastDot) : ""; } }); String[] resultTypeArr = resultTypeSet.toArray(NO_STRINGS); Arrays.sort(resultTypeArr); resultTypes = ImmutableList.copyOf(resultTypeArr); } Map<String, Integer> summary = Maps.newHashMap(); ImmutableList.Builder<Html> table = ImmutableList.builder(); // Now, call out to create the package groupings, which in turn, // create the class level groupings, which in turn create pages for // individual tests. // As we descend into the test tree, each recursive call updates summary // info. Path outFile = reportDir.resolve("index.html"); mkdirs(outFile.getParent()); String[] packageNames = byPackage.keySet().toArray(NO_STRINGS); Arrays.sort(packageNames); for (String packageName : packageNames) { Collection<Map<?, ?>> tests = byPackage.get(packageName); Map<String, Integer> itemSummary = generateHtmlReportOnePackage(packageName, tests, reportDir.resolve("index"), resultTypes); bagPutAll(itemSummary, summary); table.add(htmlLink("index/" + packageName + PACKAGE_FILE_SUFFIX + ".html", packageName)) .add(htmlSpan("summary", summaryToHtml(itemSummary, resultTypes))); } writeReport(outFile, "JUnit", KEY_VAL, table.build(), summary, jsonReport, resultTypes, "index"); OutputStream out = reportDir.resolve("junit_report.css").newOutputStream(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); try { Resources.copy(Resources.getResource(JunitHtmlReportGenerator.class, "junit_report.css"), out); } finally { out.close(); } }
From source file:com.facebook.buck.apple.project_generator.ProjectGenerator.java
private PBXNativeTarget generateBinaryTarget(PBXProject project, Optional<? extends TargetNode<? extends HasAppleBundleFields, ?>> bundle, TargetNode<? extends CxxLibraryDescription.Arg, ?> targetNode, ProductType productType, String productOutputFormat, Optional<Path> infoPlistOptional, boolean includeFrameworks, ImmutableSet<AppleResourceDescription.Arg> recursiveResources, ImmutableSet<AppleResourceDescription.Arg> directResources, ImmutableSet<AppleAssetCatalogDescription.Arg> recursiveAssetCatalogs, ImmutableSet<AppleAssetCatalogDescription.Arg> directAssetCatalogs, ImmutableSet<AppleWrapperResourceArg> wrapperResources, Optional<Iterable<PBXBuildPhase>> copyFilesPhases, Optional<TargetNode<AppleBundleDescription.Arg, ?>> bundleLoaderNode) throws IOException { LOG.debug("Generating binary target for node %s", targetNode); TargetNode<?, ?> buildTargetNode = bundle.isPresent() ? bundle.get() : targetNode; final BuildTarget buildTarget = buildTargetNode.getBuildTarget(); String buildTargetName = getProductNameForBuildTarget(buildTarget); CxxLibraryDescription.Arg arg = targetNode.getConstructorArg(); NewNativeTargetProjectMutator mutator = new NewNativeTargetProjectMutator(pathRelativizer, sourcePathResolver);// w w w . j ava 2 s . c o m ImmutableSet<SourcePath> exportedHeaders = ImmutableSet.copyOf(getHeaderSourcePaths(arg.exportedHeaders)); ImmutableSet<SourcePath> headers = ImmutableSet.copyOf(getHeaderSourcePaths(arg.headers)); ImmutableMap<CxxSource.Type, ImmutableList<String>> langPreprocessorFlags = targetNode .getConstructorArg().langPreprocessorFlags; mutator.setTargetName(getXcodeTargetName(buildTarget)).setProduct(productType, buildTargetName, Paths.get(String.format(productOutputFormat, buildTargetName))); boolean isFocusedOnTarget = shouldIncludeBuildTargetIntoFocusedProject(focusModules, buildTarget); if (isFocusedOnTarget) { mutator.setLangPreprocessorFlags(langPreprocessorFlags).setPublicHeaders(exportedHeaders) .setPrefixHeader(arg.prefixHeader).setSourcesWithFlags(ImmutableSet.copyOf(arg.srcs)) .setPrivateHeaders(headers).setRecursiveResources(recursiveResources) .setDirectResources(directResources).setWrapperResources(wrapperResources); } if (bundle.isPresent() && isFocusedOnTarget) { HasAppleBundleFields bundleArg = bundle.get().getConstructorArg(); mutator.setInfoPlist(Optional.of(bundleArg.getInfoPlist())); } mutator.setBridgingHeader(arg.bridgingHeader); Optional<TargetNode<AppleNativeTargetDescriptionArg, ?>> appleTargetNode = targetNode .castArg(AppleNativeTargetDescriptionArg.class); if (appleTargetNode.isPresent() && isFocusedOnTarget) { AppleNativeTargetDescriptionArg appleArg = appleTargetNode.get().getConstructorArg(); mutator = mutator.setExtraXcodeSources(ImmutableSet.copyOf(appleArg.extraXcodeSources)); } if (options.contains(Option.CREATE_DIRECTORY_STRUCTURE) && isFocusedOnTarget) { mutator.setTargetGroupPath(StreamSupport.stream(buildTarget.getBasePath().spliterator(), false) .map(Object::toString).collect(MoreCollectors.toImmutableList())); } if (!recursiveAssetCatalogs.isEmpty() && isFocusedOnTarget) { mutator.setRecursiveAssetCatalogs(recursiveAssetCatalogs); } if (!directAssetCatalogs.isEmpty() && isFocusedOnTarget) { mutator.setDirectAssetCatalogs(directAssetCatalogs); } if (includeFrameworks && isFocusedOnTarget) { ImmutableSet.Builder<FrameworkPath> frameworksBuilder = ImmutableSet.builder(); frameworksBuilder.addAll(targetNode.getConstructorArg().frameworks); frameworksBuilder.addAll(targetNode.getConstructorArg().libraries); frameworksBuilder.addAll(collectRecursiveFrameworkDependencies(ImmutableList.of(targetNode))); mutator.setFrameworks(frameworksBuilder.build()); mutator.setArchives(collectRecursiveLibraryDependencies(ImmutableList.of(targetNode))); } // TODO(Task #3772930): Go through all dependencies of the rule // and add any shell script rules here ImmutableList.Builder<TargetNode<?, ?>> preScriptPhases = ImmutableList.builder(); ImmutableList.Builder<TargetNode<?, ?>> postScriptPhases = ImmutableList.builder(); if (bundle.isPresent() && targetNode != bundle.get() && isFocusedOnTarget) { collectBuildScriptDependencies(targetGraph.getAll(bundle.get().getDeclaredDeps()), preScriptPhases, postScriptPhases); } collectBuildScriptDependencies(targetGraph.getAll(targetNode.getDeclaredDeps()), preScriptPhases, postScriptPhases); if (isFocusedOnTarget) { mutator.setPreBuildRunScriptPhasesFromTargetNodes(preScriptPhases.build()); if (copyFilesPhases.isPresent()) { mutator.setCopyFilesPhases(copyFilesPhases.get()); } mutator.setPostBuildRunScriptPhasesFromTargetNodes(postScriptPhases.build()); } NewNativeTargetProjectMutator.Result targetBuilderResult; targetBuilderResult = mutator.buildTargetAndAddToProject(project, isFocusedOnTarget); Optional<PBXGroup> targetGroup = targetBuilderResult.targetGroup; if (isFocusedOnTarget) { SourceTreePath buckFilePath = new SourceTreePath(PBXReference.SourceTree.SOURCE_ROOT, pathRelativizer.outputPathToBuildTargetPath(buildTarget).resolve(buildFileName), Optional.empty()); PBXFileReference buckReference = targetGroup.get() .getOrCreateFileReferenceBySourceTreePath(buckFilePath); buckReference.setExplicitFileType(Optional.of("text.script.python")); } // -- configurations ImmutableMap.Builder<String, String> extraSettingsBuilder = ImmutableMap.builder(); extraSettingsBuilder.put("TARGET_NAME", buildTargetName).put("SRCROOT", pathRelativizer.outputPathToBuildTargetPath(buildTarget).toString()); if (productType == ProductType.UI_TEST && isFocusedOnTarget) { if (bundleLoaderNode.isPresent()) { BuildTarget testTarget = bundleLoaderNode.get().getBuildTarget(); extraSettingsBuilder.put("TEST_TARGET_NAME", getXcodeTargetName(testTarget)); } else { throw new HumanReadableException( "The test rule '%s' is configured with 'is_ui_test' but has no test_host_app", buildTargetName); } } else if (bundleLoaderNode.isPresent() && isFocusedOnTarget) { TargetNode<AppleBundleDescription.Arg, ?> bundleLoader = bundleLoaderNode.get(); String bundleLoaderProductName = getProductNameForBuildTarget(bundleLoader.getBuildTarget()); String bundleLoaderBundleName = bundleLoaderProductName + "." + getExtensionString(bundleLoader.getConstructorArg().getExtension()); // NOTE(grp): This is a hack. We need to support both deep (OS X) and flat (iOS) // style bundles for the bundle loader, but at this point we don't know what platform // the bundle loader (or current target) is going to be built for. However, we can be // sure that it's the same as the target (presumably a test) we're building right now. // // Using that knowledge, we can do build setting tricks to defer choosing the bundle // loader path until Xcode build time, when the platform is known. There's no build // setting that conclusively says whether the current platform uses deep bundles: // that would be too easy. But in the cases we care about (unit test bundles), the // current bundle will have a style matching the style of the bundle loader app, so // we can take advantage of that to do the determination. // // Unfortunately, the build setting for the bundle structure (CONTENTS_FOLDER_PATH) // includes the WRAPPER_NAME, so we can't just interpolate that in. Instead, we have // to use another trick with build setting operations and evaluation. By using the // $(:file) operation, we can extract the last component of the contents path: either // "Contents" or the current bundle name. Then, we can interpolate with that expected // result in the build setting name to conditionally choose a different loader path. // The conditional that decdies which path is used. This is a complex Xcode build setting // expression that expands to one of two values, depending on the last path component of // the CONTENTS_FOLDER_PATH variable. As described above, this will be either "Contents" // for deep bundles or the bundle file name itself for flat bundles. Finally, to santiize // the potentially invalid build setting names from the bundle file name, it converts that // to an identifier. We rely on BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_<bundle file name> // being undefined (and thus expanding to nothing) for the path resolution to work. // // The operations on the CONTENTS_FOLDER_PATH are documented here: // http://codeworkshop.net/posts/xcode-build-setting-transformations String bundleLoaderOutputPathConditional = "$(BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_$(CONTENTS_FOLDER_PATH:file:identifier))"; // If the $(CONTENTS_FOLDER_PATH:file:identifier) expands to this, we add the deep bundle // path into the bundle loader. See above for the case when it will expand to this value. String bundleLoaderOutputPathDeepSetting = "BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_Contents"; String bundleLoaderOutputPathDeepValue = "Contents/MacOS/"; String bundleLoaderOutputPathValue = Joiner.on('/').join(getTargetOutputPath(bundleLoader), bundleLoaderBundleName, bundleLoaderOutputPathConditional, bundleLoaderProductName); extraSettingsBuilder.put(bundleLoaderOutputPathDeepSetting, bundleLoaderOutputPathDeepValue) .put("BUNDLE_LOADER", bundleLoaderOutputPathValue).put("TEST_HOST", "$(BUNDLE_LOADER)"); } if (infoPlistOptional.isPresent()) { Path infoPlistPath = pathRelativizer.outputDirToRootRelative(infoPlistOptional.get()); extraSettingsBuilder.put("INFOPLIST_FILE", infoPlistPath.toString()); } if (arg.bridgingHeader.isPresent()) { Path bridgingHeaderPath = pathRelativizer .outputDirToRootRelative(sourcePathResolver.apply(arg.bridgingHeader.get())); extraSettingsBuilder.put("SWIFT_OBJC_BRIDGING_HEADER", Joiner.on('/').join("$(SRCROOT)", bridgingHeaderPath.toString())); } Optional<String> swiftVersion = swiftBuckConfig.getVersion(); if (swiftVersion.isPresent()) { extraSettingsBuilder.put("SWIFT_VERSION", swiftVersion.get()); } Optional<SourcePath> prefixHeaderOptional = targetNode.getConstructorArg().prefixHeader; if (prefixHeaderOptional.isPresent()) { Path prefixHeaderRelative = sourcePathResolver.apply(prefixHeaderOptional.get()); Path prefixHeaderPath = pathRelativizer.outputDirToRootRelative(prefixHeaderRelative); extraSettingsBuilder.put("GCC_PREFIX_HEADER", prefixHeaderPath.toString()); extraSettingsBuilder.put("GCC_PRECOMPILE_PREFIX_HEADER", "YES"); } extraSettingsBuilder.put("USE_HEADERMAP", "NO"); ImmutableMap.Builder<String, String> defaultSettingsBuilder = ImmutableMap.builder(); defaultSettingsBuilder.put("REPO_ROOT", projectFilesystem.getRootPath().toAbsolutePath().normalize().toString()); defaultSettingsBuilder.put(PRODUCT_NAME, getProductName(buildTargetNode, buildTarget)); if (bundle.isPresent()) { defaultSettingsBuilder.put("WRAPPER_EXTENSION", getExtensionString(bundle.get().getConstructorArg().getExtension())); } // We use BUILT_PRODUCTS_DIR as the root for the everything being built. Target- // specific output is placed within CONFIGURATION_BUILD_DIR, inside BUILT_PRODUCTS_DIR. // That allows Copy Files build phases to reference files in the CONFIGURATION_BUILD_DIR // of other targets by using paths relative to the target-independent BUILT_PRODUCTS_DIR. defaultSettingsBuilder.put("BUILT_PRODUCTS_DIR", // $EFFECTIVE_PLATFORM_NAME starts with a dash, so this expands to something like: // $SYMROOT/Debug-iphonesimulator Joiner.on('/').join("$SYMROOT", "$CONFIGURATION$EFFECTIVE_PLATFORM_NAME")); defaultSettingsBuilder.put("CONFIGURATION_BUILD_DIR", "$BUILT_PRODUCTS_DIR"); boolean nodeIsAppleLibrary = targetNode.getDescription() instanceof AppleLibraryDescription; boolean nodeIsCxxLibrary = targetNode.getDescription() instanceof CxxLibraryDescription; if (!bundle.isPresent() && (nodeIsAppleLibrary || nodeIsCxxLibrary)) { defaultSettingsBuilder.put("EXECUTABLE_PREFIX", "lib"); } ImmutableMap.Builder<String, String> appendConfigsBuilder = ImmutableMap.builder(); if (isFocusedOnTarget) { ImmutableSet<Path> recursiveHeaderSearchPaths = collectRecursiveHeaderSearchPaths(targetNode); ImmutableSet<Path> headerMapBases = recursiveHeaderSearchPaths.isEmpty() ? ImmutableSet.of() : ImmutableSet.of(pathRelativizer .outputDirToRootRelative(buildTargetNode.getFilesystem().getBuckPaths().getBuckOut())); appendConfigsBuilder .put("HEADER_SEARCH_PATHS", Joiner.on(' ').join(Iterables.concat(recursiveHeaderSearchPaths, headerMapBases))) .put("LIBRARY_SEARCH_PATHS", Joiner.on(' ').join(collectRecursiveLibrarySearchPaths(ImmutableSet.of(targetNode)))) .put("FRAMEWORK_SEARCH_PATHS", Joiner.on(' ') .join(collectRecursiveFrameworkSearchPaths(ImmutableList.of(targetNode)))); Iterable<String> otherCFlags = Iterables.concat(cxxBuckConfig.getFlags("cflags").orElse(DEFAULT_CFLAGS), collectRecursiveExportedPreprocessorFlags(ImmutableList.of(targetNode)), targetNode.getConstructorArg().compilerFlags, targetNode.getConstructorArg().preprocessorFlags); Iterable<String> otherCxxFlags = Iterables.concat( cxxBuckConfig.getFlags("cxxflags").orElse(DEFAULT_CXXFLAGS), collectRecursiveExportedPreprocessorFlags(ImmutableList.of(targetNode)), targetNode.getConstructorArg().compilerFlags, targetNode.getConstructorArg().preprocessorFlags); Iterable<String> otherLdFlags = Iterables.concat(targetNode.getConstructorArg().linkerFlags, collectRecursiveExportedLinkerFlags(ImmutableList.of(targetNode))); appendConfigsBuilder .put("OTHER_CFLAGS", Joiner.on(' ').join(Iterables.transform(otherCFlags, Escaper.BASH_ESCAPER))) .put("OTHER_CPLUSPLUSFLAGS", Joiner.on(' ').join(Iterables.transform(otherCxxFlags, Escaper.BASH_ESCAPER))) .put("OTHER_LDFLAGS", Joiner.on(' ').join(Iterables.transform(otherLdFlags, Escaper.BASH_ESCAPER))); ImmutableMultimap.Builder<String, ImmutableList<String>> platformFlagsBuilder = ImmutableMultimap .builder(); for (Pair<Pattern, ImmutableList<String>> flags : Iterables.concat( targetNode.getConstructorArg().platformCompilerFlags.getPatternsAndValues(), targetNode.getConstructorArg().platformPreprocessorFlags.getPatternsAndValues(), collectRecursiveExportedPlatformPreprocessorFlags(ImmutableList.of(targetNode)))) { String sdk = flags.getFirst().pattern().replaceAll("[*.]", ""); platformFlagsBuilder.put(sdk, flags.getSecond()); } ImmutableMultimap<String, ImmutableList<String>> platformFlags = platformFlagsBuilder.build(); for (String sdk : platformFlags.keySet()) { appendConfigsBuilder.put(String.format("OTHER_CFLAGS[sdk=*%s*]", sdk), Joiner.on(' ') .join(Iterables.transform( Iterables.concat(otherCFlags, Iterables.concat(platformFlags.get(sdk))), Escaper.BASH_ESCAPER))) .put(String.format("OTHER_CPLUSPLUSFLAGS[sdk=*%s*]", sdk), Joiner.on(' ') .join(Iterables.transform( Iterables.concat(otherCxxFlags, Iterables.concat(platformFlags.get(sdk))), Escaper.BASH_ESCAPER))); } ImmutableMultimap.Builder<String, ImmutableList<String>> platformLinkerFlagsBuilder = ImmutableMultimap .builder(); for (Pair<Pattern, ImmutableList<String>> flags : Iterables.concat( targetNode.getConstructorArg().platformLinkerFlags.getPatternsAndValues(), collectRecursiveExportedPlatformLinkerFlags(ImmutableList.of(targetNode)))) { String sdk = flags.getFirst().pattern().replaceAll("[*.]", ""); platformLinkerFlagsBuilder.put(sdk, flags.getSecond()); } ImmutableMultimap<String, ImmutableList<String>> platformLinkerFlags = platformLinkerFlagsBuilder .build(); for (String sdk : platformLinkerFlags.keySet()) { appendConfigsBuilder .put(String.format("OTHER_LDFLAGS[sdk=*%s*]", sdk), Joiner.on( ' ').join( Iterables .transform( Iterables.concat(otherLdFlags, Iterables.concat( platformLinkerFlags.get(sdk))), Escaper.BASH_ESCAPER))); } } PBXNativeTarget target = targetBuilderResult.target; if (isFocusedOnTarget) { ImmutableMap<String, String> appendedConfig = appendConfigsBuilder.build(); Optional<ImmutableSortedMap<String, ImmutableMap<String, String>>> configs = getXcodeBuildConfigurationsForTargetNode( targetNode, appendedConfig); setTargetBuildConfigurations(getConfigurationNameToXcconfigPath(buildTarget), target, project.getMainGroup(), configs.get(), extraSettingsBuilder.build(), defaultSettingsBuilder.build(), appendedConfig); } // -- phases boolean headerMapDisabled = options.contains(Option.DISABLE_HEADER_MAPS); createHeaderSymlinkTree(sourcePathResolver, getPublicCxxHeaders(targetNode), getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PUBLIC), arg.xcodePublicHeadersSymlinks.orElse(true) || headerMapDisabled); if (isFocusedOnTarget) { createHeaderSymlinkTree(sourcePathResolver, getPrivateCxxHeaders(targetNode), getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PRIVATE), arg.xcodePrivateHeadersSymlinks.orElse(true) || headerMapDisabled); } if (appleTargetNode.isPresent() && isFocusedOnTarget) { // Use Core Data models from immediate dependencies only. addCoreDataModelsIntoTarget(appleTargetNode.get(), targetGroup.get()); addSceneKitAssetsIntoTarget(appleTargetNode.get(), targetGroup.get()); } return target; }
From source file:com.facebook.buck.android.NonPreDexedDexBuildable.java
/** * Create dex artifacts for all of the individual directories of compiled .class files (or the * obfuscated jar files if proguard is used). If split dex is used, multiple dex artifacts will be * produced.//w w w . j a va 2 s .c o m */ @VisibleForTesting void addDexingSteps(Set<Path> classpathEntriesToDex, Supplier<ImmutableMap<String, HashCode>> classNamesToHashesSupplier, Consumer<Path> secondaryDexDirectoriesConsumer, ImmutableList.Builder<Step> steps, Path primaryDexPath, Optional<SourcePath> dexReorderToolFile, Optional<SourcePath> dexReorderDataDumpFile, ImmutableMultimap<APKModule, Path> additionalDexStoreToJarPathMap, BuildContext buildContext) { SourcePathResolver resolver = buildContext.getSourcePathResolver(); Supplier<Set<Path>> primaryInputsToDex; Optional<Path> secondaryDexDir; Optional<Supplier<Multimap<Path, Path>>> secondaryOutputToInputs; Path secondaryDexParentDir = getSecondaryDexRoot().resolve("__secondary_dex__/"); Path additionalDexParentDir = getSecondaryDexRoot().resolve("__additional_dex__/"); Path additionalDexAssetsDir = additionalDexParentDir.resolve("assets"); Optional<ImmutableSet<Path>> additionalDexDirs; if (shouldSplitDex) { Optional<Path> proguardFullConfigFile = Optional.empty(); Optional<Path> proguardMappingFile = Optional.empty(); if (shouldProguard) { proguardFullConfigFile = Optional.of(getProguardConfigDir().resolve("configuration.txt")); proguardMappingFile = Optional.of(getProguardConfigDir().resolve("mapping.txt")); } // DexLibLoader expects that metadata.txt and secondary jar files are under this dir // in assets. // Intermediate directory holding the primary split-zip jar. Path splitZipDir = getBinPath("__split_zip__"); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), splitZipDir))); Path primaryJarPath = splitZipDir.resolve("primary.jar"); Path secondaryJarMetaDirParent = getSecondaryDexRoot().resolve("secondary_meta"); Path secondaryJarMetaDir = secondaryJarMetaDirParent.resolve(AndroidBinary.SECONDARY_DEX_SUBDIR); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryJarMetaDir))); Path secondaryJarMeta = secondaryJarMetaDir.resolve("metadata.txt"); // Intermediate directory holding _ONLY_ the secondary split-zip jar files. This is // important because SmartDexingCommand will try to dx every entry in this directory. It // does this because it's impossible to know what outputs split-zip will generate until it // runs. Path secondaryZipDir = getBinPath("__secondary_zip__"); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryZipDir))); // Intermediate directory holding the directories holding _ONLY_ the additional split-zip // jar files that are intended for that dex store. Path additionalDexStoresZipDir = getBinPath("__dex_stores_zip__"); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), additionalDexStoresZipDir))); for (APKModule dexStore : additionalDexStoreToJarPathMap.keySet()) { steps.addAll(MakeCleanDirectoryStep .of(BuildCellRelativePath.fromCellRelativePath(buildContext.getBuildCellRootPath(), getProjectFilesystem(), additionalDexStoresZipDir.resolve(dexStore.getName())))); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryJarMetaDirParent.resolve("assets").resolve(dexStore.getName())))); } // Run the split-zip command which is responsible for dividing the large set of input // classpaths into a more compact set of jar files such that no one jar file when dexed will // yield a dex artifact too large for dexopt or the dx method limit to handle. Path zipSplitReportDir = getBinPath("__split_zip_report__"); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), zipSplitReportDir))); SplitZipStep splitZipCommand = new SplitZipStep(getProjectFilesystem(), classpathEntriesToDex, secondaryJarMeta, primaryJarPath, secondaryZipDir, "secondary-%d.jar", secondaryJarMetaDirParent, additionalDexStoresZipDir, proguardFullConfigFile, proguardMappingFile, skipProguard, dexSplitMode, dexSplitMode.getPrimaryDexScenarioFile().map(resolver::getAbsolutePath), dexSplitMode.getPrimaryDexClassesFile().map(resolver::getAbsolutePath), dexSplitMode.getSecondaryDexHeadClassesFile().map(resolver::getAbsolutePath), dexSplitMode.getSecondaryDexTailClassesFile().map(resolver::getAbsolutePath), additionalDexStoreToJarPathMap, apkModuleMap, rootAPKModule, zipSplitReportDir); steps.add(splitZipCommand); // Add the secondary dex directory that has yet to be created, but will be by the // smart dexing command. Smart dex will handle "cleaning" this directory properly. if (reorderClassesIntraDex) { secondaryDexDir = Optional.of(secondaryDexParentDir.resolve(SMART_DEX_SECONDARY_DEX_SUBDIR)); Path intraDexReorderSecondaryDexDir = secondaryDexParentDir .resolve(AndroidBinary.SECONDARY_DEX_SUBDIR); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryDexDir.get()))); steps.addAll(MakeCleanDirectoryStep .of(BuildCellRelativePath.fromCellRelativePath(buildContext.getBuildCellRootPath(), getProjectFilesystem(), intraDexReorderSecondaryDexDir))); } else { secondaryDexDir = Optional.of(secondaryDexParentDir.resolve(AndroidBinary.SECONDARY_DEX_SUBDIR)); steps.add(MkdirStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryDexDir.get()))); } if (additionalDexStoreToJarPathMap.isEmpty()) { additionalDexDirs = Optional.empty(); } else { ImmutableSet.Builder<Path> builder = ImmutableSet.builder(); for (APKModule dexStore : additionalDexStoreToJarPathMap.keySet()) { Path dexStorePath = additionalDexAssetsDir.resolve(dexStore.getName()); builder.add(dexStorePath); steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath( buildContext.getBuildCellRootPath(), getProjectFilesystem(), dexStorePath))); } additionalDexDirs = Optional.of(builder.build()); } if (dexSplitMode.getDexStore() == DexStore.RAW) { secondaryDexDirectoriesConsumer.accept(secondaryDexDir.get()); } else { secondaryDexDirectoriesConsumer.accept(secondaryJarMetaDirParent); secondaryDexDirectoriesConsumer.accept(secondaryDexParentDir); } if (additionalDexDirs.isPresent()) { secondaryDexDirectoriesConsumer.accept(additionalDexParentDir); } // Adjust smart-dex inputs for the split-zip case. primaryInputsToDex = Suppliers.ofInstance(ImmutableSet.of(primaryJarPath)); Supplier<Multimap<Path, Path>> secondaryOutputToInputsMap = splitZipCommand .getOutputToInputsMapSupplier(secondaryDexDir.get(), additionalDexAssetsDir); secondaryOutputToInputs = Optional.of(secondaryOutputToInputsMap); } else { // Simple case where our inputs are the natural classpath directories and we don't have // to worry about secondary jar/dex files. primaryInputsToDex = Suppliers.ofInstance(classpathEntriesToDex); secondaryDexDir = Optional.empty(); secondaryOutputToInputs = Optional.empty(); } HashInputJarsToDexStep hashInputJarsToDexStep = new HashInputJarsToDexStep(getProjectFilesystem(), primaryInputsToDex, secondaryOutputToInputs, classNamesToHashesSupplier); steps.add(hashInputJarsToDexStep); // Stores checksum information from each invocation to intelligently decide when dx needs // to be re-run. Path successDir = getBinPath("__smart_dex__/.success"); steps.add(MkdirStep.of(BuildCellRelativePath.fromCellRelativePath(buildContext.getBuildCellRootPath(), getProjectFilesystem(), successDir))); // Add the smart dexing tool that is capable of avoiding the external dx invocation(s) if // it can be shown that the inputs have not changed. It also parallelizes dx invocations // where applicable. // // Note that by not specifying the number of threads this command will use it will select an // optimal default regardless of the value of --num-threads. This decision was made with the // assumption that --num-threads specifies the threading of build rule execution and does not // directly apply to the internal threading/parallelization details of various build commands // being executed. For example, aapt is internally threaded by default when preprocessing // images. EnumSet<DxStep.Option> dxOptions = shouldProguard ? EnumSet.of(DxStep.Option.NO_LOCALS) : EnumSet.of(DxStep.Option.NO_OPTIMIZE); Path selectedPrimaryDexPath = primaryDexPath; if (reorderClassesIntraDex) { String primaryDexFileName = primaryDexPath.getFileName().toString(); String smartDexPrimaryDexFileName = "smart-dex-" + primaryDexFileName; selectedPrimaryDexPath = Paths .get(primaryDexPath.toString().replace(primaryDexFileName, smartDexPrimaryDexFileName)); } SmartDexingStep smartDexingCommand = new SmartDexingStep(androidPlatformTarget, buildContext, getProjectFilesystem(), selectedPrimaryDexPath, primaryInputsToDex, secondaryDexDir, secondaryOutputToInputs, hashInputJarsToDexStep, successDir, dxOptions, dxExecutorService, xzCompressionLevel, dxMaxHeapSize, dexTool, desugarInterfaceMethods, true, Optional.of(additionalJarsForProguardAndDesugar.stream() .map(input -> buildContext.getSourcePathResolver().getAbsolutePath(input)) .collect(ImmutableSet.toImmutableSet()))); steps.add(smartDexingCommand); if (reorderClassesIntraDex) { IntraDexReorderStep intraDexReorderStep = new IntraDexReorderStep(buildContext, getProjectFilesystem(), resolver.getAbsolutePath(dexReorderToolFile.get()), resolver.getAbsolutePath(dexReorderDataDumpFile.get()), getBuildTarget(), selectedPrimaryDexPath, primaryDexPath, secondaryOutputToInputs, SMART_DEX_SECONDARY_DEX_SUBDIR, AndroidBinary.SECONDARY_DEX_SUBDIR); steps.add(intraDexReorderStep); } }
From source file:com.facebook.buck.features.apple.project.ProjectGenerator.java
private PBXNativeTarget generateBinaryTarget(PBXProject project, Optional<? extends TargetNode<? extends HasAppleBundleFields>> bundle, TargetNode<? extends CxxLibraryDescription.CommonArg> targetNode, ProductType productType, String productOutputFormat, Optional<Path> infoPlistOptional, boolean includeFrameworks, ImmutableSet<AppleResourceDescriptionArg> recursiveResources, ImmutableSet<AppleResourceDescriptionArg> directResources, ImmutableSet<AppleAssetCatalogDescriptionArg> recursiveAssetCatalogs, ImmutableSet<AppleAssetCatalogDescriptionArg> directAssetCatalogs, ImmutableSet<AppleWrapperResourceArg> wrapperResources, Optional<Iterable<PBXBuildPhase>> copyFilesPhases, Optional<TargetNode<AppleBundleDescriptionArg>> bundleLoaderNode) throws IOException { LOG.debug("Generating binary target for node %s", targetNode); TargetNode<?> buildTargetNode = bundle.isPresent() ? bundle.get() : targetNode; BuildTarget buildTarget = buildTargetNode.getBuildTarget(); boolean containsSwiftCode = projGenerationStateCache.targetContainsSwiftSourceCode(targetNode); String buildTargetName = getProductNameForBuildTargetNode(buildTargetNode); CxxLibraryDescription.CommonArg arg = targetNode.getConstructorArg(); NewNativeTargetProjectMutator mutator = new NewNativeTargetProjectMutator(pathRelativizer, this::resolveSourcePath); // Both exported headers and exported platform headers will be put into the symlink tree // exported platform headers will be excluded and then included by platform ImmutableSet.Builder<SourcePath> exportedHeadersBuilder = ImmutableSet.builder(); exportedHeadersBuilder.addAll(getHeaderSourcePaths(arg.getExportedHeaders())); PatternMatchedCollection<SourceSortedSet> exportedPlatformHeaders = arg.getExportedPlatformHeaders(); for (SourceSortedSet headersSet : exportedPlatformHeaders.getValues()) { exportedHeadersBuilder.addAll(getHeaderSourcePaths(headersSet)); }//from w w w .j a v a 2 s . c o m ImmutableSet<SourcePath> exportedHeaders = exportedHeadersBuilder.build(); ImmutableSet.Builder<SourcePath> headersBuilder = ImmutableSet.builder(); headersBuilder.addAll(getHeaderSourcePaths(arg.getHeaders())); for (SourceSortedSet headersSet : arg.getPlatformHeaders().getValues()) { headersBuilder.addAll(getHeaderSourcePaths(headersSet)); } ImmutableSet<SourcePath> headers = headersBuilder.build(); ImmutableMap<CxxSource.Type, ImmutableList<StringWithMacros>> langPreprocessorFlags = targetNode .getConstructorArg().getLangPreprocessorFlags(); boolean isFocusedOnTarget = focusModules.isFocusedOn(buildTarget); Optional<String> swiftVersion = getSwiftVersionForTargetNode(targetNode); boolean hasSwiftVersionArg = swiftVersion.isPresent(); if (!swiftVersion.isPresent()) { swiftVersion = swiftBuckConfig.getVersion(); } mutator.setTargetName(getXcodeTargetName(buildTarget)).setProduct(productType, buildTargetName, Paths.get(String.format(productOutputFormat, buildTargetName))); boolean isModularAppleLibrary = isModularAppleLibrary(targetNode) && isFocusedOnTarget; mutator.setFrameworkHeadersEnabled(isModularAppleLibrary); ImmutableMap.Builder<String, String> swiftDepsSettingsBuilder = ImmutableMap.builder(); ImmutableList.Builder<String> swiftDebugLinkerFlagsBuilder = ImmutableList.builder(); ImmutableMap.Builder<String, String> extraSettingsBuilder = ImmutableMap.builder(); ImmutableMap.Builder<String, String> defaultSettingsBuilder = ImmutableMap.builder(); ImmutableList<Pair<Pattern, SourceSortedSet>> platformHeaders = arg.getPlatformHeaders() .getPatternsAndValues(); ImmutableList.Builder<Pair<Pattern, Iterable<SourcePath>>> platformHeadersIterableBuilder = ImmutableList .builder(); for (Pair<Pattern, SourceSortedSet> platformHeader : platformHeaders) { platformHeadersIterableBuilder .add(new Pair<>(platformHeader.getFirst(), getHeaderSourcePaths(platformHeader.getSecond()))); } ImmutableList<Pair<Pattern, SourceSortedSet>> exportedPlatformHeadersPatternsAndValues = exportedPlatformHeaders .getPatternsAndValues(); for (Pair<Pattern, SourceSortedSet> exportedPlatformHeader : exportedPlatformHeadersPatternsAndValues) { platformHeadersIterableBuilder.add(new Pair<>(exportedPlatformHeader.getFirst(), getHeaderSourcePaths(exportedPlatformHeader.getSecond()))); } ImmutableList<Pair<Pattern, Iterable<SourcePath>>> platformHeadersIterable = platformHeadersIterableBuilder .build(); ImmutableList<Pair<Pattern, ImmutableSortedSet<SourceWithFlags>>> platformSources = arg.getPlatformSrcs() .getPatternsAndValues(); ImmutableMap<String, ImmutableSortedSet<String>> platformExcludedSourcesMapping = ProjectGenerator .gatherExcludedSources( appleCxxFlavors.stream().map(f -> applePlatformAndArchitecture(f).getFirst()) .collect(ImmutableSet.toImmutableSet()), platformSources, platformHeadersIterable, outputDirectory, defaultPathResolver); for (Map.Entry<String, ImmutableSortedSet<String>> platformExcludedSources : platformExcludedSourcesMapping .entrySet()) { if (platformExcludedSources.getValue().size() > 0) { extraSettingsBuilder.put(platformExcludedSources.getKey(), String.join(" ", platformExcludedSources.getValue())); } } ImmutableSortedSet<SourceWithFlags> nonPlatformSrcs = arg.getSrcs(); ImmutableSortedSet.Builder<SourceWithFlags> allSrcsBuilder = ImmutableSortedSet.naturalOrder(); allSrcsBuilder.addAll(nonPlatformSrcs); for (Pair<Pattern, ImmutableSortedSet<SourceWithFlags>> platformSource : platformSources) { allSrcsBuilder.addAll(platformSource.getSecond()); } ImmutableSortedSet<SourceWithFlags> allSrcs = allSrcsBuilder.build(); if (!options.shouldGenerateHeaderSymlinkTreesOnly()) { if (isFocusedOnTarget) { filesAddedBuilder.addAll( allSrcs.stream().map(s -> s.getSourcePath()).collect(ImmutableList.toImmutableList())); mutator.setLangPreprocessorFlags(ImmutableMap.copyOf( Maps.transformValues(langPreprocessorFlags, f -> convertStringWithMacros(targetNode, f)))) .setPublicHeaders(exportedHeaders).setPrefixHeader(getPrefixHeaderSourcePath(arg)) .setSourcesWithFlags(ImmutableSet.copyOf(allSrcs)).setPrivateHeaders(headers) .setRecursiveResources(recursiveResources).setDirectResources(directResources) .setWrapperResources(wrapperResources) .setExtraXcodeSources(ImmutableSet.copyOf(arg.getExtraXcodeSources())) .setExtraXcodeFiles(ImmutableSet.copyOf(arg.getExtraXcodeFiles())); } if (bundle.isPresent() && isFocusedOnTarget) { HasAppleBundleFields bundleArg = bundle.get().getConstructorArg(); mutator.setInfoPlist(Optional.of(bundleArg.getInfoPlist())); } mutator.setBridgingHeader(arg.getBridgingHeader()); if (options.shouldCreateDirectoryStructure() && isFocusedOnTarget) { mutator.setTargetGroupPath( RichStream.from(buildTarget.getBasePath()).map(Object::toString).toImmutableList()); } if (!recursiveAssetCatalogs.isEmpty() && isFocusedOnTarget) { mutator.setRecursiveAssetCatalogs(recursiveAssetCatalogs); } if (!directAssetCatalogs.isEmpty() && isFocusedOnTarget) { mutator.setDirectAssetCatalogs(directAssetCatalogs); } FluentIterable<TargetNode<?>> depTargetNodes = collectRecursiveLibraryDepTargets(targetNode); if (includeFrameworks && isFocusedOnTarget) { if (!options.shouldAddLinkedLibrariesAsFlags()) { mutator.setFrameworks(getSytemFrameworksLibsForTargetNode(targetNode)); } if (sharedLibraryToBundle.isPresent()) { // Replace target nodes of libraries which are actually constituents of embedded // frameworks to the bundle representing the embedded framework. // This will be converted to a reference to the xcode build product for the embedded // framework rather than the dylib depTargetNodes = swapSharedLibrariesForBundles(depTargetNodes, sharedLibraryToBundle.get()); } ImmutableSet<PBXFileReference> targetNodeDeps = filterRecursiveLibraryDependenciesForLinkerPhase( depTargetNodes); if (isTargetNodeApplicationTestTarget(targetNode, bundleLoaderNode)) { ImmutableSet<PBXFileReference> bundleLoaderDeps = bundleLoaderNode.isPresent() ? collectRecursiveLibraryDependencies(bundleLoaderNode.get()) : ImmutableSet.of(); mutator.setArchives(Sets.difference(targetNodeDeps, bundleLoaderDeps)); } else { mutator.setArchives(targetNodeDeps); } } if (isFocusedOnTarget) { ImmutableSet<TargetNode<?>> swiftDepTargets = filterRecursiveLibraryDepTargetsWithSwiftSources( depTargetNodes); if (!includeFrameworks && !swiftDepTargets.isEmpty()) { // If the current target, which is non-shared (e.g., static lib), depends on other focused // targets which include Swift code, we must ensure those are treated as dependencies so // that Xcode builds the targets in the correct order. Unfortunately, those deps can be // part of other projects which would require cross-project references. // // Thankfully, there's an easy workaround because we can just create a phony copy phase // which depends on the outputs of the deps (i.e., the static libs). The copy phase // will effectively say "Copy libX.a from Products Dir into Products Dir" which is a nop. // To be on the safe side, we're explicitly marking the copy phase as only running for // deployment postprocessing (i.e., "Copy only when installing") and disabling // deployment postprocessing (it's enabled by default for release builds). CopyFilePhaseDestinationSpec.Builder destSpecBuilder = CopyFilePhaseDestinationSpec.builder(); destSpecBuilder.setDestination(PBXCopyFilesBuildPhase.Destination.PRODUCTS); PBXCopyFilesBuildPhase copyFiles = new PBXCopyFilesBuildPhase(destSpecBuilder.build()); copyFiles.setRunOnlyForDeploymentPostprocessing(Optional.of(Boolean.TRUE)); copyFiles.setName(Optional.of("Fake Swift Dependencies (Copy Files Phase)")); ImmutableSet<PBXFileReference> swiftDepsFileRefs = targetNodesSetToPBXFileReference( swiftDepTargets); for (PBXFileReference fileRef : swiftDepsFileRefs) { PBXBuildFile buildFile = new PBXBuildFile(fileRef); copyFiles.getFiles().add(buildFile); } swiftDepsSettingsBuilder.put("DEPLOYMENT_POSTPROCESSING", "NO"); mutator.setSwiftDependenciesBuildPhase(copyFiles); } if (includeFrameworks && !swiftDepTargets.isEmpty() && shouldEmbedSwiftRuntimeInBundleTarget(bundle) && swiftBuckConfig.getProjectEmbedRuntime()) { // This is a binary that transitively depends on a library that uses Swift. We must ensure // that the Swift runtime is bundled. swiftDepsSettingsBuilder.put("ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES"); } if (includeFrameworks && !swiftDepTargets.isEmpty() && swiftBuckConfig.getProjectAddASTPaths()) { for (TargetNode<?> swiftNode : swiftDepTargets) { String swiftModulePath = String.format( "${BUILT_PRODUCTS_DIR}/%s.swiftmodule/${CURRENT_ARCH}.swiftmodule", getModuleName(swiftNode)); swiftDebugLinkerFlagsBuilder.add("-Xlinker"); swiftDebugLinkerFlagsBuilder.add("-add_ast_path"); swiftDebugLinkerFlagsBuilder.add("-Xlinker"); swiftDebugLinkerFlagsBuilder.add(swiftModulePath); } } } // TODO(Task #3772930): Go through all dependencies of the rule // and add any shell script rules here ImmutableList.Builder<TargetNode<?>> preScriptPhasesBuilder = ImmutableList.builder(); ImmutableList.Builder<TargetNode<?>> postScriptPhasesBuilder = ImmutableList.builder(); if (bundle.isPresent() && targetNode != bundle.get() && isFocusedOnTarget) { collectBuildScriptDependencies(targetGraph.getAll(bundle.get().getDeclaredDeps()), preScriptPhasesBuilder, postScriptPhasesBuilder); } collectBuildScriptDependencies(targetGraph.getAll(targetNode.getDeclaredDeps()), preScriptPhasesBuilder, postScriptPhasesBuilder); if (isFocusedOnTarget) { ImmutableList<TargetNode<?>> preScriptPhases = preScriptPhasesBuilder.build(); ImmutableList<TargetNode<?>> postScriptPhases = postScriptPhasesBuilder.build(); mutator.setPreBuildRunScriptPhasesFromTargetNodes(preScriptPhases, actionGraphBuilderForNode::apply); if (copyFilesPhases.isPresent()) { mutator.setCopyFilesPhases(copyFilesPhases.get()); } mutator.setPostBuildRunScriptPhasesFromTargetNodes(postScriptPhases, actionGraphBuilderForNode::apply); ImmutableList<TargetNode<?>> scriptPhases = Stream .concat(preScriptPhases.stream(), postScriptPhases.stream()) .collect(ImmutableList.toImmutableList()); mutator.collectFilesToCopyInXcode(filesToCopyInXcodeBuilder, scriptPhases, projectCell, actionGraphBuilderForNode::apply); } } NewNativeTargetProjectMutator.Result targetBuilderResult = mutator.buildTargetAndAddToProject(project, isFocusedOnTarget); PBXNativeTarget target = targetBuilderResult.target; Optional<PBXGroup> targetGroup = targetBuilderResult.targetGroup; extraSettingsBuilder.putAll(swiftDepsSettingsBuilder.build()); setAppIconSettings(recursiveAssetCatalogs, directAssetCatalogs, buildTarget, defaultSettingsBuilder); setLaunchImageSettings(recursiveAssetCatalogs, directAssetCatalogs, buildTarget, defaultSettingsBuilder); ImmutableSortedMap<Path, SourcePath> publicCxxHeaders = getPublicCxxHeaders(targetNode); if (isModularAppleLibrary(targetNode) && isFrameworkProductType(productType)) { // Modular frameworks should not include Buck-generated hmaps as they break the VFS overlay // that's generated by Xcode and consequently, all headers part of a framework's umbrella // header fail the modularity test, as they're expected to be mapped by the VFS layer under // $BUILT_PRODUCTS_DIR/Module.framework/Versions/A/Headers. publicCxxHeaders = ImmutableSortedMap.of(); } if (!options.shouldGenerateHeaderSymlinkTreesOnly()) { if (isFocusedOnTarget) { SourceTreePath buckFilePath = new SourceTreePath(PBXReference.SourceTree.SOURCE_ROOT, pathRelativizer.outputPathToBuildTargetPath(buildTarget).resolve(buildFileName), Optional.empty()); PBXFileReference buckReference = targetGroup.get() .getOrCreateFileReferenceBySourceTreePath(buckFilePath); buckReference.setExplicitFileType(Optional.of("text.script.python")); } // Watch dependencies need to have explicit target dependencies setup in order for Xcode to // build them properly within the IDE. It is unable to match the implicit dependency because // of the different in flavor between the targets (iphoneos vs watchos). if (bundle.isPresent() && isFocusedOnTarget) { collectProjectTargetWatchDependencies(targetNode.getBuildTarget().getFlavorPostfix(), target, targetGraph.getAll(bundle.get().getExtraDeps())); } // -- configurations extraSettingsBuilder.put("TARGET_NAME", buildTargetName).put("SRCROOT", pathRelativizer.outputPathToBuildTargetPath(buildTarget).toString()); if (productType == ProductTypes.UI_TEST && isFocusedOnTarget) { if (bundleLoaderNode.isPresent()) { BuildTarget testTarget = bundleLoaderNode.get().getBuildTarget(); extraSettingsBuilder.put("TEST_TARGET_NAME", getXcodeTargetName(testTarget)); addPBXTargetDependency(target, testTarget); } else { throw new HumanReadableException( "The test rule '%s' is configured with 'is_ui_test' but has no test_host_app", buildTargetName); } } else if (bundleLoaderNode.isPresent() && isFocusedOnTarget) { TargetNode<AppleBundleDescriptionArg> bundleLoader = bundleLoaderNode.get(); String bundleLoaderProductName = getProductName(bundleLoader); String bundleLoaderBundleName = bundleLoaderProductName + "." + getExtensionString(bundleLoader.getConstructorArg().getExtension()); // NOTE(grp): This is a hack. We need to support both deep (OS X) and flat (iOS) // style bundles for the bundle loader, but at this point we don't know what platform // the bundle loader (or current target) is going to be built for. However, we can be // sure that it's the same as the target (presumably a test) we're building right now. // // Using that knowledge, we can do build setting tricks to defer choosing the bundle // loader path until Xcode build time, when the platform is known. There's no build // setting that conclusively says whether the current platform uses deep bundles: // that would be too easy. But in the cases we care about (unit test bundles), the // current bundle will have a style matching the style of the bundle loader app, so // we can take advantage of that to do the determination. // // Unfortunately, the build setting for the bundle structure (CONTENTS_FOLDER_PATH) // includes the WRAPPER_NAME, so we can't just interpolate that in. Instead, we have // to use another trick with build setting operations and evaluation. By using the // $(:file) operation, we can extract the last component of the contents path: either // "Contents" or the current bundle name. Then, we can interpolate with that expected // result in the build setting name to conditionally choose a different loader path. // The conditional that decides which path is used. This is a complex Xcode build setting // expression that expands to one of two values, depending on the last path component of // the CONTENTS_FOLDER_PATH variable. As described above, this will be either "Contents" // for deep bundles or the bundle file name itself for flat bundles. Finally, to santiize // the potentially invalid build setting names from the bundle file name, it converts that // to an identifier. We rely on BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_<bundle file name> // being undefined (and thus expanding to nothing) for the path resolution to work. // // The operations on the CONTENTS_FOLDER_PATH are documented here: // http://codeworkshop.net/posts/xcode-build-setting-transformations String bundleLoaderOutputPathConditional = "$(BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_$(CONTENTS_FOLDER_PATH:file:identifier))"; // If the $(CONTENTS_FOLDER_PATH:file:identifier) expands to this, we add the deep bundle // path into the bundle loader. See above for the case when it will expand to this value. extraSettingsBuilder.put("BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_Contents", Joiner.on('/').join(getTargetOutputPath(bundleLoader), bundleLoaderBundleName, "Contents/MacOS", bundleLoaderProductName)); extraSettingsBuilder.put( "BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_" + getProductName(bundle.get()) + "_" + getExtensionString(bundle.get().getConstructorArg().getExtension()), Joiner.on('/').join(getTargetOutputPath(bundleLoader), bundleLoaderBundleName, bundleLoaderProductName)); extraSettingsBuilder.put("BUNDLE_LOADER", bundleLoaderOutputPathConditional).put("TEST_HOST", "$(BUNDLE_LOADER)"); addPBXTargetDependency(target, bundleLoader.getBuildTarget()); } if (infoPlistOptional.isPresent()) { Path infoPlistPath = pathRelativizer.outputDirToRootRelative(infoPlistOptional.get()); extraSettingsBuilder.put("INFOPLIST_FILE", infoPlistPath.toString()); } if (arg.getBridgingHeader().isPresent()) { Path bridgingHeaderPath = pathRelativizer .outputDirToRootRelative(resolveSourcePath(arg.getBridgingHeader().get())); extraSettingsBuilder.put("SWIFT_OBJC_BRIDGING_HEADER", Joiner.on('/').join("$(SRCROOT)", bridgingHeaderPath.toString())); } swiftVersion.ifPresent(s -> extraSettingsBuilder.put("SWIFT_VERSION", s)); swiftVersion.ifPresent(s -> extraSettingsBuilder.put("PRODUCT_MODULE_NAME", getModuleName(targetNode))); if (hasSwiftVersionArg && containsSwiftCode && isFocusedOnTarget) { extraSettingsBuilder.put("SWIFT_OBJC_INTERFACE_HEADER_NAME", getSwiftObjCGeneratedHeaderName(buildTargetNode)); if (swiftBuckConfig.getProjectWMO()) { // We must disable "Index While Building" as there's a bug in the LLVM infra which // makes the compilation fail. extraSettingsBuilder.put("COMPILER_INDEX_STORE_ENABLE", "NO"); // This is a hidden Xcode setting which is needed for two reasons: // - Stops Xcode adding .o files for each Swift compilation unit to dependency db // which is used during linking (which will fail with WMO). // - Turns on WMO itself. // // Note that setting SWIFT_OPTIMIZATION_LEVEL (which is public) to '-Owholemodule' // ends up crashing the Swift compiler for some reason while this doesn't. extraSettingsBuilder.put("SWIFT_WHOLE_MODULE_OPTIMIZATION", "YES"); } } Optional<SourcePath> prefixHeaderOptional = getPrefixHeaderSourcePath(targetNode.getConstructorArg()); if (prefixHeaderOptional.isPresent()) { Path prefixHeaderRelative = resolveSourcePath(prefixHeaderOptional.get()); Path prefixHeaderPath = pathRelativizer.outputDirToRootRelative(prefixHeaderRelative); extraSettingsBuilder.put("GCC_PREFIX_HEADER", prefixHeaderPath.toString()); extraSettingsBuilder.put("GCC_PRECOMPILE_PREFIX_HEADER", "YES"); } boolean shouldSetUseHeadermap = false; if (isModularAppleLibrary) { extraSettingsBuilder.put("CLANG_ENABLE_MODULES", "YES"); extraSettingsBuilder.put("DEFINES_MODULE", "YES"); if (isFrameworkProductType(productType)) { // Modular frameworks need to have both USE_HEADERMAP enabled so that Xcode generates // .framework VFS overlays, in modular libraries we handle this in buck shouldSetUseHeadermap = true; } } extraSettingsBuilder.put("USE_HEADERMAP", shouldSetUseHeadermap ? "YES" : "NO"); defaultSettingsBuilder.put("REPO_ROOT", projectFilesystem.getRootPath().toAbsolutePath().normalize().toString()); if (hasSwiftVersionArg && containsSwiftCode && isFocusedOnTarget) { // We need to be able to control the directory where Xcode places the derived sources, so // that the Obj-C Generated Header can be included in the header map and imported through // a framework-style import like <Module/Module-Swift.h> Path derivedSourcesDir = getDerivedSourcesDirectoryForBuildTarget(buildTarget, projectFilesystem); Path derivedSourceDirRelativeToProjectRoot = pathRelativizer .outputDirToRootRelative(derivedSourcesDir); defaultSettingsBuilder.put("DERIVED_FILE_DIR", derivedSourceDirRelativeToProjectRoot.toString()); } defaultSettingsBuilder.put(PRODUCT_NAME, getProductName(buildTargetNode)); bundle.ifPresent(bundleNode -> defaultSettingsBuilder.put("WRAPPER_EXTENSION", getExtensionString(bundleNode.getConstructorArg().getExtension()))); // We use BUILT_PRODUCTS_DIR as the root for the everything being built. Target- // specific output is placed within CONFIGURATION_BUILD_DIR, inside BUILT_PRODUCTS_DIR. // That allows Copy Files build phases to reference files in the CONFIGURATION_BUILD_DIR // of other targets by using paths relative to the target-independent BUILT_PRODUCTS_DIR. defaultSettingsBuilder.put("BUILT_PRODUCTS_DIR", // $EFFECTIVE_PLATFORM_NAME starts with a dash, so this expands to something like: // $SYMROOT/Debug-iphonesimulator Joiner.on('/').join("$SYMROOT", "$CONFIGURATION$EFFECTIVE_PLATFORM_NAME")); defaultSettingsBuilder.put("CONFIGURATION_BUILD_DIR", "$BUILT_PRODUCTS_DIR"); boolean nodeIsAppleLibrary = targetNode.getDescription() instanceof AppleLibraryDescription; boolean nodeIsCxxLibrary = targetNode.getDescription() instanceof CxxLibraryDescription; if (!bundle.isPresent() && (nodeIsAppleLibrary || nodeIsCxxLibrary)) { defaultSettingsBuilder.put("EXECUTABLE_PREFIX", "lib"); } if (isFocusedOnTarget) { ImmutableSet<Path> recursiveHeaderSearchPaths = collectRecursiveHeaderSearchPaths(targetNode); ImmutableSet<Path> headerMapBases = collectRecursiveHeaderMapBases(targetNode); ImmutableMap.Builder<String, String> appendConfigsBuilder = ImmutableMap.builder(); appendConfigsBuilder.putAll(getFrameworkAndLibrarySearchPathConfigs(targetNode, includeFrameworks)); appendConfigsBuilder.put("HEADER_SEARCH_PATHS", Joiner.on(' ').join(Iterables.concat(recursiveHeaderSearchPaths, headerMapBases))); if (hasSwiftVersionArg && containsSwiftCode && isFocusedOnTarget) { ImmutableSet<Path> swiftIncludePaths = collectRecursiveSwiftIncludePaths(targetNode); Stream<String> allValues = Streams.concat(Stream.of("$BUILT_PRODUCTS_DIR"), Streams .stream(swiftIncludePaths).map((path) -> path.toString()).map(Escaper.BASH_ESCAPER)); appendConfigsBuilder.put("SWIFT_INCLUDE_PATHS", allValues.collect(Collectors.joining(" "))); } ImmutableList.Builder<String> targetSpecificSwiftFlags = ImmutableList.builder(); Optional<TargetNode<SwiftCommonArg>> swiftTargetNode = TargetNodes.castArg(targetNode, SwiftCommonArg.class); targetSpecificSwiftFlags.addAll(swiftTargetNode.map( x -> convertStringWithMacros(targetNode, x.getConstructorArg().getSwiftCompilerFlags())) .orElse(ImmutableList.of())); if (containsSwiftCode && isModularAppleLibrary && publicCxxHeaders.size() > 0) { targetSpecificSwiftFlags.addAll(collectModularTargetSpecificSwiftFlags(targetNode)); } ImmutableList<String> testingOverlay = getFlagsForExcludesForModulesUnderTests(targetNode); Iterable<String> otherSwiftFlags = Iterables.concat( swiftBuckConfig.getCompilerFlags().orElse(DEFAULT_SWIFTFLAGS), targetSpecificSwiftFlags.build()); Iterable<String> otherCFlags = ImmutableList.<String>builder() .addAll(cxxBuckConfig.getCflags().orElse(DEFAULT_CFLAGS)) .addAll(cxxBuckConfig.getCppflags().orElse(DEFAULT_CPPFLAGS)) .addAll(convertStringWithMacros(targetNode, collectRecursiveExportedPreprocessorFlags(targetNode))) .addAll(convertStringWithMacros(targetNode, targetNode.getConstructorArg().getCompilerFlags())) .addAll(convertStringWithMacros(targetNode, targetNode.getConstructorArg().getPreprocessorFlags())) .addAll(convertStringWithMacros(targetNode, collectRecursiveSystemPreprocessorFlags(targetNode))) .addAll(testingOverlay).build(); Iterable<String> otherCxxFlags = ImmutableList.<String>builder() .addAll(cxxBuckConfig.getCxxflags().orElse(DEFAULT_CXXFLAGS)) .addAll(cxxBuckConfig.getCxxppflags().orElse(DEFAULT_CXXPPFLAGS)) .addAll(convertStringWithMacros(targetNode, collectRecursiveExportedPreprocessorFlags(targetNode))) .addAll(convertStringWithMacros(targetNode, targetNode.getConstructorArg().getCompilerFlags())) .addAll(convertStringWithMacros(targetNode, targetNode.getConstructorArg().getPreprocessorFlags())) .addAll(convertStringWithMacros(targetNode, collectRecursiveSystemPreprocessorFlags(targetNode))) .addAll(testingOverlay).build(); appendConfigsBuilder .put("OTHER_SWIFT_FLAGS", Streams.stream(otherSwiftFlags).map(Escaper.BASH_ESCAPER) .collect(Collectors.joining(" "))) .put("OTHER_CFLAGS", Streams.stream(otherCFlags).map(Escaper.BASH_ESCAPER) .collect(Collectors.joining(" "))) .put("OTHER_CPLUSPLUSFLAGS", Streams.stream(otherCxxFlags).map(Escaper.BASH_ESCAPER) .collect(Collectors.joining(" "))); Iterable<String> otherLdFlags = ImmutableList.<String>builder() .addAll(cxxBuckConfig.getLdflags().orElse(DEFAULT_LDFLAGS)) .addAll(appleConfig.linkAllObjC() ? ImmutableList.of("-ObjC") : ImmutableList.of()) .addAll(convertStringWithMacros(targetNode, Iterables.concat(targetNode.getConstructorArg().getLinkerFlags(), collectRecursiveExportedLinkerFlags(targetNode)))) .addAll(swiftDebugLinkerFlagsBuilder.build()).build(); updateOtherLinkerFlagsForOptions(targetNode, bundleLoaderNode, appendConfigsBuilder, otherLdFlags); ImmutableMultimap<String, ImmutableList<String>> platformFlags = convertPlatformFlags(targetNode, Iterables.concat( ImmutableList.of(targetNode.getConstructorArg().getPlatformCompilerFlags()), ImmutableList.of(targetNode.getConstructorArg().getPlatformPreprocessorFlags()), collectRecursiveExportedPlatformPreprocessorFlags(targetNode))); for (String platform : platformFlags.keySet()) { appendConfigsBuilder.put(generateConfigKey("OTHER_CFLAGS", platform), Streams.stream(Iterables.transform( Iterables.concat(otherCFlags, Iterables.concat(platformFlags.get(platform))), Escaper.BASH_ESCAPER::apply)).collect( Collectors.joining(" "))) .put(generateConfigKey("OTHER_CPLUSPLUSFLAGS", platform), Streams.stream(Iterables.transform( Iterables.concat(otherCxxFlags, Iterables.concat(platformFlags.get(platform))), Escaper.BASH_ESCAPER::apply)).collect(Collectors.joining(" "))); } ImmutableMultimap<String, ImmutableList<String>> platformLinkerFlags = convertPlatformFlags( targetNode, Iterables.concat(ImmutableList.of(targetNode.getConstructorArg().getPlatformLinkerFlags()), collectRecursiveExportedPlatformLinkerFlags(targetNode))); for (String platform : platformLinkerFlags.keySet()) { appendConfigsBuilder .put(generateConfigKey("OTHER_LDFLAGS", platform), Streams.stream( Iterables .transform( Iterables.concat(otherLdFlags, Iterables.concat( platformLinkerFlags.get(platform))), Escaper.BASH_ESCAPER::apply)) .collect(Collectors.joining(" "))); } ImmutableMap<String, String> appendedConfig = appendConfigsBuilder.build(); Optional<ImmutableSortedMap<String, ImmutableMap<String, String>>> configs = getXcodeBuildConfigurationsForTargetNode( targetNode); setTargetBuildConfigurations(buildTarget, target, project.getMainGroup(), configs.get(), getTargetCxxBuildConfigurationForTargetNode(targetNode, appendedConfig), extraSettingsBuilder.build(), defaultSettingsBuilder.build(), appendedConfig); } } Optional<String> moduleName = isModularAppleLibrary ? Optional.of(getModuleName(targetNode)) : Optional.empty(); // -- phases createHeaderSymlinkTree(publicCxxHeaders, getSwiftPublicHeaderMapEntriesForTarget(targetNode), moduleName, getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PUBLIC), arg.getXcodePublicHeadersSymlinks().orElse(cxxBuckConfig.getPublicHeadersSymlinksEnabled()) || !options.shouldUseHeaderMaps() || isModularAppleLibrary, !shouldMergeHeaderMaps(), options.shouldGenerateMissingUmbrellaHeader()); if (isFocusedOnTarget) { createHeaderSymlinkTree(getPrivateCxxHeaders(targetNode), ImmutableMap.of(), // private interfaces never have a modulemap Optional.empty(), getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PRIVATE), arg.getXcodePrivateHeadersSymlinks().orElse(cxxBuckConfig.getPrivateHeadersSymlinksEnabled()) || !options.shouldUseHeaderMaps(), options.shouldUseHeaderMaps(), options.shouldGenerateMissingUmbrellaHeader()); } Optional<TargetNode<AppleNativeTargetDescriptionArg>> appleTargetNode = TargetNodes.castArg(targetNode, AppleNativeTargetDescriptionArg.class); if (appleTargetNode.isPresent() && isFocusedOnTarget && !options.shouldGenerateHeaderSymlinkTreesOnly()) { // Use Core Data models from immediate dependencies only. addCoreDataModelsIntoTarget(appleTargetNode.get(), targetGroup.get()); addSceneKitAssetsIntoTarget(appleTargetNode.get(), targetGroup.get()); } if (bundle.isPresent() && isFocusedOnTarget && !options.shouldGenerateHeaderSymlinkTreesOnly()) { addEntitlementsPlistIntoTarget(bundle.get(), targetGroup.get()); } return target; }