List of usage examples for com.google.common.collect ImmutableList stream
default Stream<E> stream()
From source file:com.facebook.buck.rules.CachingBuildRuleBuilder.java
ListenableFuture<BuildResult> build() { final AtomicReference<Long> outputSize = Atomics.newReference(); ListenableFuture<List<BuildResult>> depResults = Futures.immediateFuture(Collections.emptyList()); // If we're performing a deep build, guarantee that all dependencies will *always* get // materialized locally if (buildMode == CachingBuildEngine.BuildMode.DEEP || buildMode == CachingBuildEngine.BuildMode.POPULATE_FROM_REMOTE_CACHE) { depResults = buildRuleBuilderDelegate.getDepResults(rule, buildContext, executionContext); }/*from w ww. ja v a2s .com*/ ListenableFuture<BuildResult> buildResult = Futures.transformAsync(depResults, input -> buildOrFetchFromCache(), serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.SCHEDULING_MORE_WORK_RESOURCE_AMOUNTS)); // Check immediately (without posting a new task) for a failure so that we can short-circuit // pending work. Use .catchingAsync() instead of .catching() so that we can propagate unchecked // exceptions. buildResult = Futures.catchingAsync(buildResult, Throwable.class, throwable -> { Preconditions.checkNotNull(throwable); buildRuleBuilderDelegate.setFirstFailure(throwable); Throwables.throwIfInstanceOf(throwable, Exception.class); throw new RuntimeException(throwable); }); buildResult = Futures.transform(buildResult, (result) -> { buildRuleBuilderDelegate.markRuleAsUsed(rule, buildContext.getEventBus()); return result; }, MoreExecutors.directExecutor()); // Setup a callback to handle either the cached or built locally cases. AsyncFunction<BuildResult, BuildResult> callback = input -> { // If we weren't successful, exit now. if (input.getStatus() != BuildRuleStatus.SUCCESS) { return Futures.immediateFuture(input); } try (Scope scope = LeafEvents.scope(buildContext.getEventBus(), "finalizing_build_rule")) { // We shouldn't see any build fail result at this point. BuildRuleSuccessType success = Preconditions.checkNotNull(input.getSuccess()); // If we didn't build the rule locally, reload the recorded paths from the build // metadata. if (success != BuildRuleSuccessType.BUILT_LOCALLY) { try { for (String str : onDiskBuildInfo.getValuesOrThrow(BuildInfo.MetadataKey.RECORDED_PATHS)) { buildInfoRecorder.recordArtifact(Paths.get(str)); } } catch (IOException e) { LOG.error(e, "Failed to read RECORDED_PATHS for %s", rule); throw e; } } // Try get the output size now that all outputs have been recorded. if (success == BuildRuleSuccessType.BUILT_LOCALLY) { outputSize.set(buildInfoRecorder.getOutputSize()); } // If the success type means the rule has potentially changed it's outputs... if (success.outputsHaveChanged()) { // The build has succeeded, whether we've fetched from cache, or built locally. // So run the post-build steps. if (rule instanceof HasPostBuildSteps) { executePostBuildSteps( ((HasPostBuildSteps) rule).getPostBuildSteps(buildContext.getBuildContext())); } // Invalidate any cached hashes for the output paths, since we've updated them. for (Path path : buildInfoRecorder.getRecordedPaths()) { fileHashCache.invalidate(rule.getProjectFilesystem().resolve(path)); } } if (SupportsInputBasedRuleKey.isSupported(rule) && success == BuildRuleSuccessType.BUILT_LOCALLY && !buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY) .isPresent()) { // Doing this here is probably not strictly necessary, however in the case of // pipelined rules built locally we will never do an input-based cache check. // That check would have written the key to metadata, and there are some asserts // during cache upload that try to ensure they are present. Optional<RuleKey> inputRuleKey = calculateInputBasedRuleKey(buildContext.getEventBus()); if (inputRuleKey.isPresent()) { buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY, inputRuleKey.get().toString()); } } // If this rule uses dep files and we built locally, make sure we store the new dep file // list and re-calculate the dep file rule key. if (useDependencyFileRuleKey() && success == BuildRuleSuccessType.BUILT_LOCALLY) { // Query the rule for the actual inputs it used. ImmutableList<SourcePath> inputs = ((SupportsDependencyFileRuleKey) rule) .getInputsAfterBuildingLocally(buildContext.getBuildContext(), executionContext.getCellPathResolver()); // Record the inputs into our metadata for next time. // TODO(#9117006): We don't support a way to serlialize `SourcePath`s to the cache, // so need to use DependencyFileEntry's instead and recover them on deserialization. ImmutableList<String> inputStrings = inputs.stream() .map(inputString -> DependencyFileEntry.fromSourcePath(inputString, pathResolver)) .map(MoreFunctions.toJsonFunction()).collect(MoreCollectors.toImmutableList()); buildInfoRecorder.addMetadata(BuildInfo.MetadataKey.DEP_FILE, inputStrings); // Re-calculate and store the depfile rule key for next time. Optional<RuleKeyAndInputs> depFileRuleKeyAndInputs = calculateDepFileRuleKey( Optional.of(inputStrings), /* allowMissingInputs */ false); if (depFileRuleKeyAndInputs.isPresent()) { RuleKey depFileRuleKey = depFileRuleKeyAndInputs.get().getRuleKey(); buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY, depFileRuleKey.toString()); // Push an updated manifest to the cache. if (useManifestCaching()) { Optional<RuleKeyAndInputs> manifestKey = calculateManifestKey( buildContext.getEventBus()); if (manifestKey.isPresent()) { buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.MANIFEST_KEY, manifestKey.get().getRuleKey().toString()); updateAndStoreManifest(depFileRuleKeyAndInputs.get().getRuleKey(), depFileRuleKeyAndInputs.get().getInputs(), manifestKey.get(), buildContext.getArtifactCache()); } } } } // If this rule was built locally, grab and record the output hashes in the build // metadata so that cache hits avoid re-hashing file contents. Since we use output // hashes for input-based rule keys and for detecting non-determinism, we would spend // a lot of time re-hashing output paths -- potentially in serialized in a single step. // So, do the hashing here to distribute the workload across several threads and cache // the results. // // Also, since hashing outputs can potentially be expensive, we avoid doing this for // rules that are marked as uncacheable. The rationale here is that they are likely not // cached due to the sheer size which would be costly to hash or builtin non-determinism // in the rule which somewhat defeats the purpose of logging the hash. if (success == BuildRuleSuccessType.BUILT_LOCALLY && shouldUploadToCache(success, Preconditions.checkNotNull(outputSize.get()))) { ImmutableSortedMap.Builder<String, String> outputHashes = ImmutableSortedMap.naturalOrder(); for (Path path : buildInfoRecorder.getOutputPaths()) { outputHashes.put(path.toString(), fileHashCache.get(rule.getProjectFilesystem().resolve(path)).toString()); } buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.RECORDED_PATH_HASHES, outputHashes.build()); } // If this rule was fetched from cache, seed the file hash cache with the recorded // output hashes from the build metadata. Since outputs which have been changed have // already been invalidated above, this is purely a best-effort optimization -- if the // the output hashes weren't recorded in the cache we do nothing. if (success != BuildRuleSuccessType.BUILT_LOCALLY && success.outputsHaveChanged()) { Optional<ImmutableMap<String, String>> hashes = onDiskBuildInfo .getBuildMap(BuildInfo.MetadataKey.RECORDED_PATH_HASHES); // We only seed after first verifying the recorded path hashes. This prevents the // optimization, but is useful to keep in place for a while to verify this optimization // is causing issues. if (hashes.isPresent() && verifyRecordedPathHashes(rule.getBuildTarget(), rule.getProjectFilesystem(), hashes.get())) { // Seed the cache with the hashes. for (Map.Entry<String, String> ent : hashes.get().entrySet()) { Path path = rule.getProjectFilesystem().getPath(ent.getKey()); HashCode hashCode = HashCode.fromString(ent.getValue()); fileHashCache.set(rule.getProjectFilesystem().resolve(path), hashCode); } } } // Make sure the origin field is filled in. BuildId buildId = buildContext.getBuildId(); if (success == BuildRuleSuccessType.BUILT_LOCALLY) { buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.ORIGIN_BUILD_ID, buildId.toString()); } else if (success.outputsHaveChanged()) { Preconditions.checkState( buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.ORIGIN_BUILD_ID) .isPresent(), "Cache hits must populate the %s field (%s)", BuildInfo.MetadataKey.ORIGIN_BUILD_ID, success); } // Make sure that all of the local files have the same values they would as if the // rule had been built locally. buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.TARGET, rule.getBuildTarget().toString()); buildInfoRecorder.addMetadata(BuildInfo.MetadataKey.RECORDED_PATHS, buildInfoRecorder.getRecordedPaths().stream().map(Object::toString) .collect(MoreCollectors.toImmutableList())); if (success.shouldWriteRecordedMetadataToDiskAfterBuilding()) { try { boolean clearExistingMetadata = success.shouldClearAndOverwriteMetadataOnDisk(); buildInfoRecorder.writeMetadataToDisk(clearExistingMetadata); } catch (IOException e) { throw new IOException(String.format("Failed to write metadata to disk for %s.", rule), e); } } // Give the rule a chance to populate its internal data structures now that all of // the files should be in a valid state. try { if (rule instanceof InitializableFromDisk) { doInitializeFromDisk((InitializableFromDisk<?>) rule); } } catch (IOException e) { throw new IOException( String.format("Error initializing %s from disk: %s.", rule, e.getMessage()), e); } } return Futures.immediateFuture(input); }; buildResult = Futures.transformAsync(buildResult, ruleAsyncFunction(buildContext.getEventBus(), callback), serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS)); buildResult = Futures.catchingAsync(buildResult, Throwable.class, thrown -> { LOG.debug(thrown, "Building rule [%s] failed.", rule.getBuildTarget()); if (consoleLogBuildFailuresInline) { buildContext.getEventBus().post(ConsoleEvent.severe(getErrorMessageIncludingBuildRule(thrown))); } thrown = maybeAttachBuildRuleNameToException(thrown); recordFailureAndCleanUp(thrown); return Futures.immediateFuture(BuildResult.failure(rule, thrown)); }); // Do things that need to happen after either success or failure, but don't block the dependents // while doing so: buildRuleBuilderDelegate .addAsyncCallback(MoreFutures.addListenableCallback(buildResult, new FutureCallback<BuildResult>() { private void uploadToCache(BuildRuleSuccessType success) { // Collect up all the rule keys we have index the artifact in the cache with. Set<RuleKey> ruleKeys = new HashSet<>(); // If the rule key has changed (and is not already in the cache), we need to push // the artifact to cache using the new key. ruleKeys.add(ruleKeyFactories.getDefaultRuleKeyFactory().build(rule)); // If the input-based rule key has changed, we need to push the artifact to cache // using the new key. if (SupportsInputBasedRuleKey.isSupported(rule)) { Optional<RuleKey> calculatedRuleKey = calculateInputBasedRuleKey( buildContext.getEventBus()); Optional<RuleKey> onDiskRuleKey = onDiskBuildInfo .getRuleKey(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY); Optional<RuleKey> metaDataRuleKey = buildInfoRecorder .getBuildMetadataFor(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY) .map(RuleKey::new); Preconditions.checkState(calculatedRuleKey.equals(onDiskRuleKey), "%s (%s): %s: invalid on-disk input-based rule key: %s != %s", rule.getBuildTarget(), rule.getType(), success, calculatedRuleKey, onDiskRuleKey); Preconditions.checkState(calculatedRuleKey.equals(metaDataRuleKey), "%s: %s: invalid meta-data input-based rule key: %s != %s", rule.getBuildTarget(), success, calculatedRuleKey, metaDataRuleKey); if (calculatedRuleKey.isPresent()) { ruleKeys.add(calculatedRuleKey.get()); } } // If the manifest-based rule key has changed, we need to push the artifact to cache // using the new key. if (useManifestCaching()) { Optional<RuleKey> onDiskRuleKey = onDiskBuildInfo .getRuleKey(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY); Optional<RuleKey> metaDataRuleKey = buildInfoRecorder .getBuildMetadataFor(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY).map(RuleKey::new); Preconditions.checkState(onDiskRuleKey.equals(metaDataRuleKey), "%s: %s: inconsistent meta-data and on-disk dep-file rule key: %s != %s", rule.getBuildTarget(), success, onDiskRuleKey, metaDataRuleKey); if (onDiskRuleKey.isPresent()) { ruleKeys.add(onDiskRuleKey.get()); } } // Do the actual upload. try { // Verify that the recorded path hashes are accurate. Optional<String> recordedPathHashes = buildInfoRecorder .getBuildMetadataFor(BuildInfo.MetadataKey.RECORDED_PATH_HASHES); if (recordedPathHashes.isPresent() && !verifyRecordedPathHashes(rule.getBuildTarget(), rule.getProjectFilesystem(), recordedPathHashes.get())) { return; } // Push to cache. buildInfoRecorder.performUploadToArtifactCache(ImmutableSet.copyOf(ruleKeys), buildContext.getArtifactCache(), buildContext.getEventBus()); } catch (Throwable t) { buildContext.getEventBus().post( ThrowableConsoleEvent.create(t, "Error uploading to cache for %s.", rule)); } } private void handleResult(BuildResult input) { Optional<Long> outputSize = Optional.empty(); Optional<HashCode> outputHash = Optional.empty(); Optional<BuildRuleSuccessType> successType = Optional.empty(); boolean shouldUploadToCache = false; BuildRuleEvent.Resumed resumedEvent = BuildRuleEvent.resumed(rule, buildRuleDurationTracker, ruleKeyFactories.getDefaultRuleKeyFactory()); LOG.verbose(resumedEvent.toString()); buildContext.getEventBus().post(resumedEvent); if (input.getStatus() == BuildRuleStatus.SUCCESS) { BuildRuleSuccessType success = Preconditions.checkNotNull(input.getSuccess()); successType = Optional.of(success); // Try get the output size. if (success == BuildRuleSuccessType.BUILT_LOCALLY || success.shouldUploadResultingArtifact()) { try { outputSize = Optional.of(buildInfoRecorder.getOutputSize()); } catch (IOException e) { buildContext.getEventBus().post(ThrowableConsoleEvent.create(e, "Error getting output size for %s.", rule)); } } // Compute it's output hash for logging/tracing purposes, as this artifact will // be consumed by other builds. if (outputSize.isPresent() && shouldHashOutputs(success, outputSize.get())) { try { outputHash = Optional.of(buildInfoRecorder.getOutputHash(fileHashCache)); } catch (IOException e) { buildContext.getEventBus().post(ThrowableConsoleEvent.create(e, "Error getting output hash for %s.", rule)); } } // Determine if this is rule is cacheable. shouldUploadToCache = outputSize.isPresent() && shouldUploadToCache(success, outputSize.get()); // Upload it to the cache. if (shouldUploadToCache) { uploadToCache(success); } } boolean failureOrBuiltLocally = input.getStatus() == BuildRuleStatus.FAIL || input.getSuccess() == BuildRuleSuccessType.BUILT_LOCALLY; // Log the result to the event bus. BuildRuleEvent.Finished finished = BuildRuleEvent.finished(resumedEvent, getBuildRuleKeys(), input.getStatus(), input.getCacheResult(), onDiskBuildInfo.getBuildValue(BuildInfo.MetadataKey.ORIGIN_BUILD_ID) .map(BuildId::new), successType, shouldUploadToCache, outputHash, outputSize, getBuildRuleDiagnosticData(failureOrBuiltLocally)); LOG.verbose(finished.toString()); buildContext.getEventBus().post(finished); } @Override public void onSuccess(BuildResult input) { handleResult(input); // Reset interrupted flag once failure has been recorded. if (input.getFailure() instanceof InterruptedException) { Threads.interruptCurrentThread(); } } @Override public void onFailure(@Nonnull Throwable thrown) { throw new AssertionError("Dead code"); } }, serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS))); return buildResult; }
From source file:com.google.errorprone.bugpatterns.CatchFail.java
Optional<Fix> deleteFix(TryTree tree, ImmutableList<CatchTree> catchBlocks, VisitorState state) { SuggestedFix.Builder fix = SuggestedFix.builder(); if (tree.getFinallyBlock() != null || catchBlocks.size() < tree.getCatches().size()) { // If the try statement has a finally region, or other catch blocks, delete only the // unnecessary blocks. catchBlocks.forEach(fix::delete); } else {/*from w w w . java2 s. co m*/ // The try statement has no finally region and all catch blocks are unnecessary. Replace it // with the try statements, deleting all catches. List<? extends StatementTree> tryStatements = tree.getBlock().getStatements(); // If the try block is empty, all of the catches are dead, so just delete the whole try and // don't modify the signature of the method if (tryStatements.isEmpty()) { return Optional.of(fix.delete(tree).build()); } else { String source = state.getSourceCode().toString(); // Replace the full region to work around a GJF partial formatting bug that prevents it from // re-indenting unchanged lines. This means that fixes may overlap, but that's (hopefully) // unlikely. // TODO(b/24140798): emit more precise replacements if GJF is fixed fix.replace(tree, source.substring(((JCTree) tryStatements.get(0)).getStartPosition(), state.getEndPosition(Iterables.getLast(tryStatements)))); } } MethodTree enclosing = findEnclosing(state.getPath()); if (enclosing == null) { // There isn't an enclosing method, possibly because we're in a lambda or initializer block. return Optional.empty(); } if (isExpectedExceptionTest(ASTHelpers.getSymbol(enclosing), state)) { // Replacing the original exception with fail() may break badly-structured expected-exception // tests, so don't use that fix for methods annotated with @Test(expected=...). return Optional.empty(); } // Fix up the enclosing method's throws declaration to include the new thrown exception types. Collection<Type> thrownTypes = ASTHelpers.getSymbol(enclosing).getThrownTypes(); Types types = state.getTypes(); // Find all types in the deleted catch blocks that are not already in the throws declaration. ImmutableList<Type> toThrow = catchBlocks.stream().map(c -> ASTHelpers.getType(c.getParameter())) // convert multi-catch to a list of component types .flatMap(t -> t instanceof UnionClassType ? ImmutableList.copyOf(((UnionClassType) t).getAlternativeTypes()).stream() : Stream.of(t)) .filter(t -> thrownTypes.stream().noneMatch(x -> types.isAssignable(t, x))) .collect(toImmutableList()); if (!toThrow.isEmpty()) { if (!JUnitMatchers.TEST_CASE.matches(enclosing, state)) { // Don't add throws declarations to methods that don't look like test cases, since it may // not be a safe local refactoring. return Optional.empty(); } String throwsString = toThrow.stream().map(t -> SuggestedFixes.qualifyType(state, fix, t)).distinct() .collect(joining(", ")); if (enclosing.getThrows().isEmpty()) { // Add a new throws declaration. fix.prefixWith(enclosing.getBody(), "throws " + throwsString); } else { // Append to an existing throws declaration. fix.postfixWith(Iterables.getLast(enclosing.getThrows()), ", " + throwsString); } } return Optional.of(fix.build()); }
From source file:com.google.gerrit.server.update.NoteDbBatchUpdate.java
static void execute(ImmutableList<NoteDbBatchUpdate> updates, BatchUpdateListener listener, @Nullable RequestId requestId, boolean dryrun) throws UpdateException, RestApiException { if (updates.isEmpty()) { return;//from www . jav a 2s . co m } setRequestIds(updates, requestId); try { List<CheckedFuture<?, IOException>> indexFutures = new ArrayList<>(); List<ChangesHandle> handles = new ArrayList<>(updates.size()); Order order = getOrder(updates, listener); try { switch (order) { case REPO_BEFORE_DB: for (NoteDbBatchUpdate u : updates) { u.executeUpdateRepo(); } listener.afterUpdateRepos(); for (NoteDbBatchUpdate u : updates) { handles.add(u.executeChangeOps(dryrun)); } for (ChangesHandle h : handles) { h.execute(); indexFutures.addAll(h.startIndexFutures()); } listener.afterUpdateRefs(); listener.afterUpdateChanges(); break; case DB_BEFORE_REPO: // Call updateChange for each op before updateRepo, but defer executing the // NoteDbUpdateManager until after calling updateRepo. They share an inserter and // BatchRefUpdate, so it will all execute as a single batch. But we have to let // NoteDbUpdateManager actually execute the update, since it has to interleave it // properly with All-Users updates. // // TODO(dborowitz): This may still result in multiple updates to All-Users, but that's // currently not a big deal because multi-change batches generally aren't affecting // drafts anyway. for (NoteDbBatchUpdate u : updates) { handles.add(u.executeChangeOps(dryrun)); } for (NoteDbBatchUpdate u : updates) { u.executeUpdateRepo(); } for (ChangesHandle h : handles) { // TODO(dborowitz): This isn't quite good enough: in theory updateRepo may want to // see the results of change meta commands, but they aren't actually added to the // BatchUpdate until the body of execute. To fix this, execute needs to be split up // into a method that returns a BatchRefUpdate before execution. Not a big deal at the // moment, because this order is only used for deleting changes, and those updateRepo // implementations definitely don't need to observe the updated change meta refs. h.execute(); indexFutures.addAll(h.startIndexFutures()); } break; default: throw new IllegalStateException("invalid execution order: " + order); } } finally { for (ChangesHandle h : handles) { h.close(); } } ChangeIndexer.allAsList(indexFutures).get(); // Fire ref update events only after all mutations are finished, since callers may assume a // patch set ref being created means the change was created, or a branch advancing meaning // some changes were closed. updates.stream().filter(u -> u.batchRefUpdate != null) .forEach(u -> u.gitRefUpdated.fire(u.project, u.batchRefUpdate, u.getAccount().orElse(null))); if (!dryrun) { for (NoteDbBatchUpdate u : updates) { u.executePostOps(); } } } catch (Exception e) { wrapAndThrowException(e); } }
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 . co 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; }