diff options
Diffstat (limited to 'src/main')
8 files changed, 569 insertions, 2203 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java index b8c796e5ca..1612857639 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java @@ -23,7 +23,6 @@ import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions; import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.ApplePlatform; import com.google.devtools.build.lib.rules.cpp.CppOptions; -import com.google.devtools.build.lib.rules.objc.ObjcCommandLineOptions.ObjcCrosstoolMode; /** * Transition that produces a configuration that causes c++ toolchain selection to use the @@ -88,8 +87,7 @@ public class AppleCrosstoolTransition implements PatchTransition { * Returns true if the given options imply use of AppleCrosstoolTransition for all apple targets. */ public static boolean appleCrosstoolTransitionIsAppliedForAllObjc(BuildOptions options) { - return (options.get(AppleCommandLineOptions.class).enableAppleCrosstoolTransition - || options.get(ObjcCommandLineOptions.class).objcCrosstoolMode != ObjcCrosstoolMode.OFF); + return options.get(AppleCommandLineOptions.class).enableAppleCrosstoolTransition; } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java index 7a9282e7ce..7a843735b5 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java @@ -14,16 +14,24 @@ package com.google.devtools.build.lib.rules.objc; +import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet; import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates; import static com.google.devtools.build.lib.rules.cpp.Link.LINK_LIBRARY_FILETYPES; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_DIR; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_SEARCH_PATH_ONLY; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LINK_INPUTS; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_DYLIB; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_FRAMEWORK; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_DIR; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.COMPILABLE_SRCS_TYPE; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.HEADERS; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.NON_ARC_SRCS_TYPE; @@ -31,6 +39,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.PRECOMPIL import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SRCS_TYPE; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.STRIP; import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.util.Comparator.naturalOrder; import static java.util.stream.Collectors.toCollection; import com.google.common.annotations.VisibleForTesting; @@ -40,11 +49,14 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.google.common.collect.Streams; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ParameterFile; @@ -69,26 +81,45 @@ import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions.AppleBitcodeMode; import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.ApplePlatform; import com.google.devtools.build.lib.rules.apple.ApplePlatform.PlatformType; import com.google.devtools.build.lib.rules.apple.AppleToolchain; import com.google.devtools.build.lib.rules.apple.XcodeConfig; import com.google.devtools.build.lib.rules.apple.XcodeConfigProvider; +import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper; +import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info; import com.google.devtools.build.lib.rules.cpp.CcToolchain; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.CollidingProvidesException; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension; import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; +import com.google.devtools.build.lib.rules.cpp.CppCompileAction; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration; import com.google.devtools.build.lib.rules.cpp.CppFileTypes; import com.google.devtools.build.lib.rules.cpp.CppHelper; +import com.google.devtools.build.lib.rules.cpp.CppLinkAction; +import com.google.devtools.build.lib.rules.cpp.CppLinkActionBuilder; import com.google.devtools.build.lib.rules.cpp.CppModuleMap; import com.google.devtools.build.lib.rules.cpp.CppModuleMapAction; +import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; import com.google.devtools.build.lib.rules.cpp.FdoSupportProvider; +import com.google.devtools.build.lib.rules.cpp.FeatureSpecification; +import com.google.devtools.build.lib.rules.cpp.IncludeProcessing; +import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness; +import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; +import com.google.devtools.build.lib.rules.cpp.NoProcessing; +import com.google.devtools.build.lib.rules.cpp.PrecompiledFiles; import com.google.devtools.build.lib.rules.cpp.UmbrellaHeaderAction; -import com.google.devtools.build.lib.rules.objc.ObjcCommandLineOptions.ObjcCrosstoolMode; +import com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag; +import com.google.devtools.build.lib.rules.objc.ObjcVariablesExtension.VariableCategory; import com.google.devtools.build.lib.util.FileTypeSet; import com.google.devtools.build.lib.util.Pair; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -109,7 +140,7 @@ import javax.annotation.Nullable; * * <p>Methods on this class can be called in any order without impacting the result. */ -public abstract class CompilationSupport { +public class CompilationSupport { @VisibleForTesting static final String OBJC_MODULE_CACHE_DIR_NAME = "_objc_module_cache"; @@ -146,12 +177,63 @@ public abstract class CompilationSupport { ImmutableList.of( "-fexceptions", "-fasm-blocks", "-fobjc-abi-version=2", "-fobjc-legacy-dispatch"); + /** + * Frameworks implicitly linked to iOS, watchOS, and tvOS binaries when using legacy compilation. + */ + @VisibleForTesting + static final ImmutableList<SdkFramework> AUTOMATIC_SDK_FRAMEWORKS = + ImmutableList.of(new SdkFramework("Foundation"), new SdkFramework("UIKit")); + private static final String FRAMEWORK_SUFFIX = ".framework"; /** Selects cc libraries that have alwayslink=1. */ - protected static final Predicate<Artifact> ALWAYS_LINKED_CC_LIBRARY = + private static final Predicate<Artifact> ALWAYS_LINKED_CC_LIBRARY = input -> LINK_LIBRARY_FILETYPES.matches(input.getFilename()); + private static final String OBJC_MODULE_FEATURE_NAME = "use_objc_modules"; + private static final String NO_ENABLE_MODULES_FEATURE_NAME = "no_enable_modules"; + private static final String DEAD_STRIP_FEATURE_NAME = "dead_strip"; + + /** + * Enabled if this target's rule is not a test rule. Binary stripping should not be applied in the + * link step. TODO(b/36562173): Replace this behavior with a condition on bundle creation. + * + * <p>Note that the crosstool does not support feature negation in FlagSet.with_feature, which is + * the mechanism used to condition linker arguments here. Therefore, we expose + * "is_not_test_target" instead of the more intuitive "is_test_target". + */ + private static final String IS_NOT_TEST_TARGET_FEATURE_NAME = "is_not_test_target"; + + /** Enabled if this target generates debug symbols in a dSYM file. */ + private static final String GENERATE_DSYM_FILE_FEATURE_NAME = "generate_dsym_file"; + + /** + * Enabled if this target does not generate debug symbols. + * + * <p>Note that the crosstool does not support feature negation in FlagSet.with_feature, which is + * the mechanism used to condition linker arguments here. Therefore, we expose + * "no_generate_debug_symbols" in addition to "generate_dsym_file" + */ + private static final String NO_GENERATE_DEBUG_SYMBOLS_FEATURE_NAME = "no_generate_debug_symbols"; + + private static final String GENERATE_LINKMAP_FEATURE_NAME = "generate_linkmap"; + + /** Enabled if this target has objc sources in its transitive closure. */ + private static final String CONTAINS_OBJC = "contains_objc_sources"; + + private static final ImmutableList<String> ACTIVATED_ACTIONS = + ImmutableList.of( + "objc-compile", + "objc++-compile", + "objc-archive", + "objc-fully-link", + "objc-executable", + "objc++-executable", + "assemble", + "preprocess-assemble", + "c-compile", + "c++-compile"); + /** * Returns the location of the xcrunwrapper tool. */ @@ -165,7 +247,7 @@ public abstract class CompilationSupport { public static final FilesToRunProvider libtool(RuleContext ruleContext) { return ruleContext.getExecutablePrerequisite(ObjcRuleClasses.LIBTOOL_ATTRIBUTE, Mode.HOST); } - + /** * Files which can be instrumented along with the attributes in which they may occur and the * attributes along which they are propagated from dependencies (via @@ -186,6 +268,222 @@ public abstract class CompilationSupport { public static final SafeImplicitOutputsFunction FULLY_LINKED_LIB = fromTemplates("%{name}_fully_linked.a"); + private static ImmutableList<Artifact> getObjFiles( + CompilationArtifacts compilationArtifacts, IntermediateArtifacts intermediateArtifacts) { + ImmutableList.Builder<Artifact> result = new ImmutableList.Builder<>(); + for (Artifact sourceFile : compilationArtifacts.getSrcs()) { + result.add(intermediateArtifacts.objFile(sourceFile)); + } + for (Artifact nonArcSourceFile : compilationArtifacts.getNonArcSrcs()) { + result.add(intermediateArtifacts.objFile(nonArcSourceFile)); + } + result.addAll(compilationArtifacts.getPrecompiledSrcs()); + return result.build(); + } + + private IncludeProcessing createIncludeProcessing( + Iterable<Artifact> privateHdrs, ObjcProvider objcProvider, @Nullable Artifact pchHdr) { + if (isHeaderThinningEnabled()) { + Iterable<Artifact> potentialInputs = + Iterables.concat( + privateHdrs, + objcProvider.get(HEADER), + objcProvider.get(STATIC_FRAMEWORK_FILE), + objcProvider.get(DYNAMIC_FRAMEWORK_FILE)); + if (pchHdr != null) { + potentialInputs = Iterables.concat(potentialInputs, ImmutableList.of(pchHdr)); + } + return new HeaderThinning(potentialInputs); + } else { + return new NoProcessing(); + } + } + + private CcLibraryHelper createCcLibraryHelper( + ObjcProvider objcProvider, + CompilationArtifacts compilationArtifacts, + VariablesExtension extension, + ExtraCompileArgs extraCompileArgs, + CcToolchainProvider ccToolchain, + FdoSupportProvider fdoSupport, + Iterable<PathFragment> priorityHeaders) { + PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext); + Collection<Artifact> arcSources = ImmutableSortedSet.copyOf(compilationArtifacts.getSrcs()); + Collection<Artifact> nonArcSources = + ImmutableSortedSet.copyOf(compilationArtifacts.getNonArcSrcs()); + Collection<Artifact> privateHdrs = + ImmutableSortedSet.copyOf(compilationArtifacts.getPrivateHdrs()); + Collection<Artifact> publicHdrs = + Stream.concat( + Streams.stream(attributes.hdrs()), + Streams.stream(compilationArtifacts.getAdditionalHdrs())) + .collect(toImmutableSortedSet(naturalOrder())); + Artifact pchHdr = getPchFile().orNull(); + ObjcCppSemantics semantics = createObjcCppSemantics(objcProvider, privateHdrs, pchHdr); + CcLibraryHelper result = + new CcLibraryHelper( + ruleContext, + semantics, + getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider), + CcLibraryHelper.SourceCategory.CC_AND_OBJC, + ccToolchain, + fdoSupport, + buildConfiguration) + .addSources(arcSources, ImmutableMap.of("objc_arc", "")) + .addSources(nonArcSources, ImmutableMap.of("no_objc_arc", "")) + .addSources(privateHdrs) + .addDefines(objcProvider.get(DEFINE)) + .enableCompileProviders() + .addPublicHeaders(publicHdrs) + .addPrecompiledFiles(precompiledFiles) + .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)) + // Not all our dependencies need to export cpp information. + // For example, objc_proto_library can depend on a proto_library rule that does not + // generate C++ protos. + .setCheckDepsGenerateCpp(false) + .setCopts( + ImmutableList.<String>builder() + .addAll(getCompileRuleCopts()) + .addAll( + ruleContext + .getFragment(ObjcConfiguration.class) + .getCoptsForCompilationMode()) + .addAll(extraCompileArgs) + .build()) + .addIncludeDirs(priorityHeaders) + .addIncludeDirs(objcProvider.get(INCLUDE)) + .addSystemIncludeDirs(objcProvider.get(INCLUDE_SYSTEM)) + .setCppModuleMap(intermediateArtifacts.moduleMap()) + .setLinkedArtifactNameSuffix(intermediateArtifacts.archiveFileNameSuffix()) + .setPropagateModuleMapToCompileAction(false) + .setNeverLink(true) + .addVariableExtension(extension); + + if (pchHdr != null) { + result.addNonModuleMapHeader(pchHdr); + } + if (!useDeps) { + result.doNotUseDeps(); + } + if (getCustomModuleMap(ruleContext).isPresent()) { + result.doNotGenerateModuleMap(); + } + return result; + } + + private ObjcCppSemantics createObjcCppSemantics( + ObjcProvider objcProvider, Collection<Artifact> privateHdrs, Artifact pchHdr) { + return new ObjcCppSemantics( + objcProvider, + createIncludeProcessing(privateHdrs, objcProvider, pchHdr), + ruleContext.getFragment(ObjcConfiguration.class), + isHeaderThinningEnabled(), + intermediateArtifacts, + buildConfiguration); + } + + private FeatureConfiguration getFeatureConfiguration( + RuleContext ruleContext, + CcToolchainProvider ccToolchain, + BuildConfiguration configuration, + ObjcProvider objcProvider) { + boolean isHost = ruleContext.getConfiguration().isHostConfiguration(); + ImmutableSet.Builder<String> activatedCrosstoolSelectables = + ImmutableSet.<String>builder() + .addAll(ccToolchain.getFeatures().getDefaultFeatures()) + .addAll(ACTIVATED_ACTIONS) + .addAll( + ruleContext + .getFragment(AppleConfiguration.class) + .getBitcodeMode() + .getFeatureNames()) + // We create a module map by default to allow for Swift interop. + .add(CppRuleClasses.MODULE_MAPS) + .add(CppRuleClasses.COMPILE_ALL_MODULES) + .add(CppRuleClasses.EXCLUDE_PRIVATE_HEADERS_IN_MODULE_MAPS) + .add(CppRuleClasses.ONLY_DOTH_HEADERS_IN_MODULE_MAPS) + .add(CppRuleClasses.COMPILE_ACTION_FLAGS_IN_FLAG_SET) + .add(CppRuleClasses.DEPENDENCY_FILE) + .add(CppRuleClasses.INCLUDE_PATHS) + .add(isHost ? "host" : "nonhost") + .add(configuration.getCompilationMode().toString()); + + if (configuration.getFragment(ObjcConfiguration.class).moduleMapsEnabled() + && !getCustomModuleMap(ruleContext).isPresent()) { + activatedCrosstoolSelectables.add(OBJC_MODULE_FEATURE_NAME); + } + if (!CompilationAttributes.Builder.fromRuleContext(ruleContext).build().enableModules()) { + activatedCrosstoolSelectables.add(NO_ENABLE_MODULES_FEATURE_NAME); + } + if (configuration.getFragment(ObjcConfiguration.class).shouldStripBinary()) { + activatedCrosstoolSelectables.add(DEAD_STRIP_FEATURE_NAME); + } + if (getPchFile().isPresent()) { + activatedCrosstoolSelectables.add("pch"); + } + if (!isTestRule) { + activatedCrosstoolSelectables.add(IS_NOT_TEST_TARGET_FEATURE_NAME); + } + if (configuration.getFragment(ObjcConfiguration.class).generateDsym()) { + activatedCrosstoolSelectables.add(GENERATE_DSYM_FILE_FEATURE_NAME); + } else { + activatedCrosstoolSelectables.add(NO_GENERATE_DEBUG_SYMBOLS_FEATURE_NAME); + } + if (configuration.getFragment(ObjcConfiguration.class).generateLinkmap()) { + activatedCrosstoolSelectables.add(GENERATE_LINKMAP_FEATURE_NAME); + } + AppleBitcodeMode bitcodeMode = + configuration.getFragment(AppleConfiguration.class).getBitcodeMode(); + if (bitcodeMode != AppleBitcodeMode.NONE) { + activatedCrosstoolSelectables.addAll(bitcodeMode.getFeatureNames()); + } + if (objcProvider.is(Flag.USES_OBJC)) { + activatedCrosstoolSelectables.add(CONTAINS_OBJC); + } + + activatedCrosstoolSelectables.addAll(ruleContext.getFeatures()); + try { + return configuration + .getFragment(CppConfiguration.class) + .getFeatures() + .getFeatureConfiguration( + FeatureSpecification.create( + activatedCrosstoolSelectables.build(), ImmutableSet.<String>of())); + } catch (CollidingProvidesException e) { + ruleContext.ruleError(e.getMessage()); + return FeatureConfiguration.EMPTY; + } + } + + private void registerHeaderScanningActions( + Info info, ObjcProvider objcProvider, CompilationArtifacts compilationArtifacts) { + // PIC is not used for Obj-C builds, if that changes this method will need to change + if (!isHeaderThinningEnabled() + || info.getCcCompilationOutputs().getObjectFiles(false).isEmpty()) { + return; + } + + ImmutableList.Builder<ObjcHeaderThinningInfo> headerThinningInfos = ImmutableList.builder(); + AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment(); + for (Artifact objectFile : info.getCcCompilationOutputs().getObjectFiles(false)) { + ActionAnalysisMetadata generatingAction = + analysisEnvironment.getLocalGeneratingAction(objectFile); + if (generatingAction instanceof CppCompileAction) { + CppCompileAction action = (CppCompileAction) generatingAction; + Artifact sourceFile = action.getSourceFile(); + if (!sourceFile.isTreeArtifact() + && SOURCES_FOR_HEADER_THINNING.matches(sourceFile.getFilename())) { + headerThinningInfos.add( + new ObjcHeaderThinningInfo( + sourceFile, + intermediateArtifacts.headersListFile(sourceFile), + action.getCompilerOptions())); + } + } + } + registerHeaderScanningActions(headerThinningInfos.build(), objcProvider, compilationArtifacts); + } + /** * Iterable wrapper providing strong type safety for arguments to binary linking. */ @@ -225,7 +523,7 @@ public abstract class CompilationSupport { * Set of {@link com.google.devtools.build.lib.util.FileType} of source artifacts that are * compatible with header thinning. */ - protected static final FileTypeSet SOURCES_FOR_HEADER_THINNING = + private static final FileTypeSet SOURCES_FOR_HEADER_THINNING = FileTypeSet.of( CppFileTypes.OBJC_SOURCE, CppFileTypes.OBJCPP_SOURCE, @@ -295,17 +593,17 @@ public abstract class CompilationSupport { .build(); } - protected final RuleContext ruleContext; - protected final BuildConfiguration buildConfiguration; - protected final ObjcConfiguration objcConfiguration; - protected final AppleConfiguration appleConfiguration; - protected final CompilationAttributes attributes; - protected final IntermediateArtifacts intermediateArtifacts; - protected final boolean useDeps; - protected final Map<String, NestedSet<Artifact>> outputGroupCollector; - protected final CcToolchainProvider toolchain; - protected final boolean isTestRule; - protected final boolean usePch; + private final RuleContext ruleContext; + private final BuildConfiguration buildConfiguration; + private final ObjcConfiguration objcConfiguration; + private final AppleConfiguration appleConfiguration; + private final CompilationAttributes attributes; + private final IntermediateArtifacts intermediateArtifacts; + private final boolean useDeps; + private final Map<String, NestedSet<Artifact>> outputGroupCollector; + private final CcToolchainProvider toolchain; + private final boolean isTestRule; + private final boolean usePch; /** * Creates a new compilation support for the given rule and build configuration. @@ -320,7 +618,7 @@ public abstract class CompilationSupport { * artifacts with different output prefixes, multiple archives can be compiled for the same rule * context. */ - protected CompilationSupport( + private CompilationSupport( RuleContext ruleContext, BuildConfiguration buildConfiguration, IntermediateArtifacts intermediateArtifacts, @@ -362,7 +660,6 @@ public abstract class CompilationSupport { private CompilationAttributes compilationAttributes; private boolean useDeps = true; private Map<String, NestedSet<Artifact>> outputGroupCollector; - private boolean isObjcLibrary = false; private CcToolchainProvider toolchain; private boolean isTestRule = false; private boolean usePch = true; @@ -410,15 +707,6 @@ public abstract class CompilationSupport { } /** - * Indicates that this CompilationSupport is for use in an objc_library target. This will cause - * CrosstoolCompilationSupport to be used if --experimental_objc_crosstool=library - */ - public Builder setIsObjcLibrary() { - this.isObjcLibrary = true; - return this; - } - - /** * Indicates that this CompilationSupport is for use in a test rule. */ public Builder setIsTestRule() { @@ -450,11 +738,7 @@ public abstract class CompilationSupport { return this; } - /** - * Returns a {@link CompilationSupport} instance. This is either a {@link - * CrosstoolCompilationSupport} or {@link LegacyCompilationSupport} depending on the value of - * --experimental_objc_crosstool. - */ + /** Returns a {@link CompilationSupport} instance. */ public CompilationSupport build() { Preconditions.checkNotNull(ruleContext, "CompilationSupport is missing RuleContext"); @@ -475,32 +759,16 @@ public abstract class CompilationSupport { outputGroupCollector = new TreeMap<>(); } - ObjcCrosstoolMode objcCrosstoolMode = - buildConfiguration.getFragment(ObjcConfiguration.class).getObjcCrosstoolMode(); - if (objcCrosstoolMode == ObjcCrosstoolMode.ALL - || (isObjcLibrary && objcCrosstoolMode == ObjcCrosstoolMode.LIBRARY)) { - return new CrosstoolCompilationSupport( - ruleContext, - buildConfiguration, - intermediateArtifacts, - compilationAttributes, - useDeps, - outputGroupCollector, - toolchain, - isTestRule, - usePch); - } else { - return new LegacyCompilationSupport( - ruleContext, - buildConfiguration, - intermediateArtifacts, - compilationAttributes, - useDeps, - outputGroupCollector, - toolchain, - isTestRule, - usePch); - } + return new CompilationSupport( + ruleContext, + buildConfiguration, + intermediateArtifacts, + compilationAttributes, + useDeps, + outputGroupCollector, + toolchain, + isTestRule, + usePch); } } @@ -588,7 +856,7 @@ public abstract class CompilationSupport { return registerCompileAndArchiveActions( common, extraCompileArgs, ImmutableList.<PathFragment>of()); } - + /** * Registers an action to create an archive artifact by fully (statically) linking all transitive * dependencies of this rule. @@ -607,30 +875,6 @@ public abstract class CompilationSupport { /** * Registers an action to create an archive artifact by fully (statically) linking all transitive - * dependencies of this rule. - * - * @param objcProvider provides all compiling and linking information to create this artifact - * @param outputArchive the output artifact for this action - * @param ccToolchain the cpp toolchain provider, may be null - * @param fdoSupport the cpp FDO support provider, may be null - */ - public CompilationSupport registerFullyLinkAction( - ObjcProvider objcProvider, Artifact outputArchive, @Nullable CcToolchainProvider ccToolchain, - @Nullable FdoSupportProvider fdoSupport) throws InterruptedException { - ImmutableList<Artifact> inputArtifacts = ImmutableList.<Artifact>builder() - .addAll(objcProvider.getObjcLibraries()) - .addAll(objcProvider.get(IMPORTED_LIBRARY)) - .addAll(objcProvider.getCcLibraries()).build(); - return registerFullyLinkAction( - objcProvider, - inputArtifacts, - outputArchive, - ccToolchain, - fdoSupport); - } - - /** - * Registers an action to create an archive artifact by fully (statically) linking all transitive * dependencies of this rule *except* for dependencies given in {@code avoidsDeps}. * * @param objcProvider provides all compiling and linking information to create this artifact @@ -652,17 +896,13 @@ public abstract class CompilationSupport { .addAll(objcProvider.getObjcLibraries()) .addAll(objcProvider.get(IMPORTED_LIBRARY)) .addAll(objcProvider.getCcLibraries()).build(); - - Iterable<Artifact> inputArtifacts = Iterables.filter(depsArtifacts, - Predicates.not(Predicates.in(avoidsDepsArtifacts.build()))); return registerFullyLinkAction( objcProvider, - inputArtifacts, outputArchive, toolchain, maybeGetFdoSupport()); } - + /** * Returns a provider that collects this target's instrumented sources as well as those of its * dependencies. @@ -764,11 +1004,63 @@ public abstract class CompilationSupport { * @return this compilation support * @throws RuleErrorException for invalid crosstool files */ - abstract CompilationSupport registerCompileAndArchiveActions( - CompilationArtifacts compilationArtifacts, ObjcProvider objcProvider, - ExtraCompileArgs extraCompileArgs, Iterable<PathFragment> priorityHeaders, - @Nullable CcToolchainProvider ccToolchain, @Nullable FdoSupportProvider fdoSupport) - throws RuleErrorException, InterruptedException; + CompilationSupport registerCompileAndArchiveActions( + CompilationArtifacts compilationArtifacts, + ObjcProvider objcProvider, + ExtraCompileArgs extraCompileArgs, + Iterable<PathFragment> priorityHeaders, + @Nullable CcToolchainProvider ccToolchain, + @Nullable FdoSupportProvider fdoSupport) + throws RuleErrorException, InterruptedException { + Preconditions.checkNotNull(ccToolchain); + Preconditions.checkNotNull(fdoSupport); + ObjcVariablesExtension.Builder extension = + new ObjcVariablesExtension.Builder() + .setRuleContext(ruleContext) + .setObjcProvider(objcProvider) + .setCompilationArtifacts(compilationArtifacts) + .setIntermediateArtifacts(intermediateArtifacts) + .setConfiguration(buildConfiguration); + CcLibraryHelper helper; + + if (compilationArtifacts.getArchive().isPresent()) { + Artifact objList = intermediateArtifacts.archiveObjList(); + + // TODO(b/30783125): Signal the need for this action in the CROSSTOOL. + registerObjFilelistAction(getObjFiles(compilationArtifacts, intermediateArtifacts), objList); + + extension.addVariableCategory(VariableCategory.ARCHIVE_VARIABLES); + + helper = + createCcLibraryHelper( + objcProvider, + compilationArtifacts, + extension.build(), + extraCompileArgs, + ccToolchain, + fdoSupport, + priorityHeaders) + .setLinkType(LinkTargetType.OBJC_ARCHIVE) + .addLinkActionInput(objList); + } else { + helper = + createCcLibraryHelper( + objcProvider, + compilationArtifacts, + extension.build(), + extraCompileArgs, + ccToolchain, + fdoSupport, + priorityHeaders); + } + + Info info = helper.build(); + outputGroupCollector.putAll(info.getOutputGroups()); + + registerHeaderScanningActions(info, objcProvider, compilationArtifacts); + + return this; + } /** * Registers all actions necessary to compile this rule's sources and archive them. @@ -793,9 +1085,17 @@ public abstract class CompilationSupport { } return this; } + + private StrippingType getStrippingType(ExtraLinkArgs extraLinkArgs) { + return Iterables.contains(extraLinkArgs, "-dynamiclib") + ? StrippingType.DYNAMIC_LIB + : StrippingType.DEFAULT; + } + /** - * Registers any actions necessary to link this rule and its dependencies. Manually sets the - * toolchain. + * Registers any actions necessary to link this rule and its dependencies. Automatically infers + * the toolchain from the configuration of this CompilationSupport - if a different toolchain is + * required, use the custom toolchain override. * * <p>Dsym bundle is generated if {@link ObjcConfiguration#generateDsym()} is set. * @@ -810,10 +1110,9 @@ public abstract class CompilationSupport { * @param extraLinkArgs any additional arguments to pass to the linker * @param extraLinkInputs any additional input artifacts to pass to the link action * @param dsymOutputType the file type of the dSYM bundle to be generated - * @param toolchain the CROSSTOOL-derived toolchain for use in linking * @return this compilation support */ - abstract CompilationSupport registerLinkActions( + CompilationSupport registerLinkActions( ObjcProvider objcProvider, J2ObjcMappingFileProvider j2ObjcMappingFileProvider, J2ObjcEntryClassProvider j2ObjcEntryClassProvider, @@ -821,7 +1120,103 @@ public abstract class CompilationSupport { Iterable<Artifact> extraLinkInputs, DsymOutputType dsymOutputType, CcToolchainProvider toolchain) - throws InterruptedException; + throws InterruptedException { + Iterable<Artifact> prunedJ2ObjcArchives = + computeAndStripPrunedJ2ObjcArchives( + j2ObjcEntryClassProvider, j2ObjcMappingFileProvider, objcProvider); + ImmutableList<Artifact> bazelBuiltLibraries = + Iterables.isEmpty(prunedJ2ObjcArchives) + ? objcProvider.getObjcLibraries() + : substituteJ2ObjcPrunedLibraries(objcProvider); + + Artifact inputFileList = intermediateArtifacts.linkerObjList(); + ImmutableSet<Artifact> forceLinkArtifacts = getForceLoadArtifacts(objcProvider); + + Iterable<Artifact> objFiles = + Iterables.concat( + bazelBuiltLibraries, objcProvider.get(IMPORTED_LIBRARY), objcProvider.getCcLibraries()); + // Clang loads archives specified in filelists and also specified as -force_load twice, + // resulting in duplicate symbol errors unless they are deduped. + objFiles = Iterables.filter(objFiles, Predicates.not(Predicates.in(forceLinkArtifacts))); + + registerObjFilelistAction(objFiles, inputFileList); + + LinkTargetType linkType = + (objcProvider.is(Flag.USES_CPP)) + ? LinkTargetType.OBJCPP_EXECUTABLE + : LinkTargetType.OBJC_EXECUTABLE; + + ObjcVariablesExtension.Builder extensionBuilder = + new ObjcVariablesExtension.Builder() + .setRuleContext(ruleContext) + .setObjcProvider(objcProvider) + .setConfiguration(buildConfiguration) + .setIntermediateArtifacts(intermediateArtifacts) + .setFrameworkNames(frameworkNames(objcProvider)) + .setLibraryNames(libraryNames(objcProvider)) + .setForceLoadArtifacts(getForceLoadArtifacts(objcProvider)) + .setAttributeLinkopts(attributes.linkopts()) + .addVariableCategory(VariableCategory.EXECUTABLE_LINKING_VARIABLES); + + Artifact binaryToLink = getBinaryToLink(); + FdoSupportProvider fdoSupport = + CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext); + CppLinkActionBuilder executableLinkAction = + new CppLinkActionBuilder( + ruleContext, + binaryToLink, + toolchain, + fdoSupport, + getFeatureConfiguration(ruleContext, toolchain, buildConfiguration, objcProvider), + createObjcCppSemantics( + objcProvider, /* privateHdrs= */ ImmutableList.of(), /* pchHdr= */ null)) + .setMnemonic("ObjcLink") + .addActionInputs(bazelBuiltLibraries) + .addActionInputs(objcProvider.getCcLibraries()) + .addTransitiveActionInputs(objcProvider.get(IMPORTED_LIBRARY)) + .addTransitiveActionInputs(objcProvider.get(STATIC_FRAMEWORK_FILE)) + .addTransitiveActionInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE)) + .addTransitiveActionInputs(objcProvider.get(LINK_INPUTS)) + .setCrosstoolInputs(toolchain.getLink()) + .addActionInputs(prunedJ2ObjcArchives) + .addActionInputs(extraLinkInputs) + .addActionInput(inputFileList) + .setLinkType(linkType) + .setLinkStaticness(LinkStaticness.FULLY_STATIC) + .addLinkopts(ImmutableList.copyOf(extraLinkArgs)); + + if (objcConfiguration.generateDsym()) { + Artifact dsymBundleZip = intermediateArtifacts.tempDsymBundleZip(dsymOutputType); + extensionBuilder + .setDsymBundleZip(dsymBundleZip) + .addVariableCategory(VariableCategory.DSYM_VARIABLES); + registerDsymActions(dsymOutputType); + executableLinkAction.addActionOutput(dsymBundleZip); + } + + if (objcConfiguration.generateLinkmap()) { + Artifact linkmap = intermediateArtifacts.linkmap(); + extensionBuilder.setLinkmap(linkmap).addVariableCategory(VariableCategory.LINKMAP_VARIABLES); + executableLinkAction.addActionOutput(linkmap); + } + + if (appleConfiguration.getBitcodeMode() == AppleBitcodeMode.EMBEDDED) { + Artifact bitcodeSymbolMap = intermediateArtifacts.bitcodeSymbolMap(); + extensionBuilder + .setBitcodeSymbolMap(bitcodeSymbolMap) + .addVariableCategory(VariableCategory.BITCODE_VARIABLES); + executableLinkAction.addActionOutput(bitcodeSymbolMap); + } + + executableLinkAction.addVariablesExtension(extensionBuilder.build()); + ruleContext.registerAction(executableLinkAction.build()); + + if (objcConfiguration.shouldStripBinary()) { + registerBinaryStripAction(binaryToLink, getStrippingType(extraLinkArgs)); + } + + return this; + } /** * Registers any actions necessary to link this rule and its dependencies. Automatically infers @@ -865,7 +1260,7 @@ public abstract class CompilationSupport { * Returns the copts for the compile action in the current rule context (using a combination of * the rule's "copts" attribute as well as the current configuration copts). */ - protected Iterable<String> getCompileRuleCopts() { + private Iterable<String> getCompileRuleCopts() { List<String> copts = Stream.concat(objcConfiguration.getCopts().stream(), attributes.copts().stream()) .collect(toCollection(ArrayList::new)); @@ -898,7 +1293,7 @@ public abstract class CompilationSupport { * Registers an action that writes given set of object files to the given objList. This objList is * suitable to signal symbols to archive in a libtool archiving invocation. */ - protected CompilationSupport registerObjFilelistAction( + private CompilationSupport registerObjFilelistAction( Iterable<Artifact> objFiles, Artifact objList) { ImmutableSet<Artifact> dedupedObjFiles = ImmutableSet.copyOf(objFiles); CustomCommandLine.Builder objFilesToLinkParam = new CustomCommandLine.Builder(); @@ -925,22 +1320,62 @@ public abstract class CompilationSupport { ISO_8859_1)); return this; } - + /** * Registers an action to create an archive artifact by fully (statically) linking all transitive * dependencies of this rule. * * @param objcProvider provides all compiling and linking information to create this artifact - * @param inputArtifacts inputs for this action * @param outputArchive the output artifact for this action * @param ccToolchain the cpp toolchain provider, may be null * @param fdoSupport the cpp FDO support provider, may be null * @return this {@link CompilationSupport} instance */ - protected abstract CompilationSupport registerFullyLinkAction( - ObjcProvider objcProvider, Iterable<Artifact> inputArtifacts, Artifact outputArchive, - @Nullable CcToolchainProvider ccToolchain, @Nullable FdoSupportProvider fdoSupport) - throws InterruptedException; + CompilationSupport registerFullyLinkAction( + ObjcProvider objcProvider, + Artifact outputArchive, + @Nullable CcToolchainProvider ccToolchain, + @Nullable FdoSupportProvider fdoSupport) + throws InterruptedException { + Preconditions.checkNotNull(ccToolchain); + Preconditions.checkNotNull(fdoSupport); + PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName()); + String libraryIdentifier = + ruleContext + .getPackageDirectory() + .getRelative(labelName.replaceName("lib" + labelName.getBaseName())) + .getPathString(); + ObjcVariablesExtension extension = + new ObjcVariablesExtension.Builder() + .setRuleContext(ruleContext) + .setObjcProvider(objcProvider) + .setConfiguration(buildConfiguration) + .setIntermediateArtifacts(intermediateArtifacts) + .setFullyLinkArchive(outputArchive) + .addVariableCategory(VariableCategory.FULLY_LINK_VARIABLES) + .build(); + CppLinkAction fullyLinkAction = + new CppLinkActionBuilder( + ruleContext, + outputArchive, + ccToolchain, + fdoSupport, + getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider), + createObjcCppSemantics( + objcProvider, /* privateHdrs= */ ImmutableList.of(), /* pchHdr= */ null)) + .addActionInputs(objcProvider.getObjcLibraries()) + .addActionInputs(objcProvider.getCcLibraries()) + .addActionInputs(objcProvider.get(IMPORTED_LIBRARY).toSet()) + .setCrosstoolInputs(ccToolchain.getLink()) + .setLinkType(LinkTargetType.OBJC_FULLY_LINKED_ARCHIVE) + .setLinkStaticness(LinkStaticness.FULLY_STATIC) + .setLibraryIdentifier(libraryIdentifier) + .addVariablesExtension(extension) + .build(); + ruleContext.registerAction(fullyLinkAction); + + return this; + } private PathFragment removeSuffix(PathFragment path, String suffix) { String name = path.getBaseName(); @@ -949,7 +1384,7 @@ public abstract class CompilationSupport { return path.replaceName(name.substring(0, name.length() - suffix.length())); } - protected CompilationSupport registerDsymActions(DsymOutputType dsymOutputType) { + private CompilationSupport registerDsymActions(DsymOutputType dsymOutputType) { Artifact tempDsymBundleZip = intermediateArtifacts.tempDsymBundleZip(dsymOutputType); Artifact linkedBinary = objcConfiguration.shouldStripBinary() @@ -993,7 +1428,7 @@ public abstract class CompilationSupport { return this; } - /** + /** * Returns all framework names to pass to the linker using {@code -framework} flags. For a * framework in the directory foo/bar.framework, the name is "bar". Each framework is found * without using the full path by means of the framework search paths. Search paths are added by @@ -1003,7 +1438,7 @@ public abstract class CompilationSupport { * paths, but this is imposed on us by clang. clang does not support passing the full path to the * framework, so Bazel cannot do it either. */ - protected Set<String> frameworkNames(ObjcProvider provider) { + private Set<String> frameworkNames(ObjcProvider provider) { Set<String> names = new LinkedHashSet<>(); Iterables.addAll(names, SdkFramework.names(provider.get(SDK_FRAMEWORK))); for (PathFragment frameworkDir : @@ -1018,11 +1453,9 @@ public abstract class CompilationSupport { } return names; } - - /** - * Returns libraries that should be passed to the linker. - */ - protected ImmutableList<String> libraryNames(ObjcProvider objcProvider) { + + /** Returns libraries that should be passed to the linker. */ + private ImmutableList<String> libraryNames(ObjcProvider objcProvider) { ImmutableList.Builder<String> args = new ImmutableList.Builder<>(); for (String dylib : objcProvider.get(SDK_DYLIB)) { if (dylib.startsWith("lib")) { @@ -1034,11 +1467,9 @@ public abstract class CompilationSupport { } return args.build(); } - - /** - * Returns libraries that should be passed into the linker with {@code -force_load}. - */ - protected ImmutableSet<Artifact> getForceLoadArtifacts(ObjcProvider objcProvider) { + + /** Returns libraries that should be passed into the linker with {@code -force_load}. */ + private ImmutableSet<Artifact> getForceLoadArtifacts(ObjcProvider objcProvider) { ImmutableList<Artifact> ccLibraries = objcProvider.getCcLibraries(); Iterable<Artifact> ccLibrariesToForceLoad = Iterables.filter(ccLibraries, ALWAYS_LINKED_CC_LIBRARY); @@ -1050,18 +1481,16 @@ public abstract class CompilationSupport { } /** Returns pruned J2Objc archives for this target. */ - protected ImmutableList<Artifact> j2objcPrunedLibraries(ObjcProvider objcProvider) { + private ImmutableList<Artifact> j2objcPrunedLibraries(ObjcProvider objcProvider) { ImmutableList.Builder<Artifact> j2objcPrunedLibraryBuilder = ImmutableList.builder(); for (Artifact j2objcLibrary : objcProvider.get(ObjcProvider.J2OBJC_LIBRARY)) { j2objcPrunedLibraryBuilder.add(intermediateArtifacts.j2objcPrunedArchive(j2objcLibrary)); } return j2objcPrunedLibraryBuilder.build(); } - - /** - * Returns true if this build should strip J2Objc dead code. - */ - protected boolean stripJ2ObjcDeadCode(J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { + + /** Returns true if this build should strip J2Objc dead code. */ + private boolean stripJ2ObjcDeadCode(J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { J2ObjcConfiguration j2objcConfiguration = buildConfiguration.getFragment(J2ObjcConfiguration.class); // Only perform J2ObjC dead code stripping if flag --j2objc_dead_code_removal is specified and @@ -1070,10 +1499,8 @@ public abstract class CompilationSupport { && !j2ObjcEntryClassProvider.getEntryClasses().isEmpty(); } - /** - * Registers actions to perform J2Objc dead code removal. - */ - protected void registerJ2ObjcDeadCodeRemovalActions( + /** Registers actions to perform J2Objc dead code removal. */ + private void registerJ2ObjcDeadCodeRemovalActions( ObjcProvider objcProvider, J2ObjcMappingFileProvider j2ObjcMappingFileProvider, J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { @@ -1146,9 +1573,9 @@ public abstract class CompilationSupport { .build(ruleContext)); } } - + /** Returns archives arising from j2objc transpilation after dead code removal. */ - protected Iterable<Artifact> computeAndStripPrunedJ2ObjcArchives( + private Iterable<Artifact> computeAndStripPrunedJ2ObjcArchives( J2ObjcEntryClassProvider j2ObjcEntryClassProvider, J2ObjcMappingFileProvider j2ObjcMappingFileProvider, ObjcProvider objcProvider) { @@ -1165,7 +1592,7 @@ public abstract class CompilationSupport { * Returns a nested set of Bazel-built ObjC libraries with all unpruned J2ObjC libraries * substituted with pruned ones. */ - protected ImmutableList<Artifact> substituteJ2ObjcPrunedLibraries(ObjcProvider objcProvider) { + private ImmutableList<Artifact> substituteJ2ObjcPrunedLibraries(ObjcProvider objcProvider) { ImmutableList.Builder<Artifact> libraries = new ImmutableList.Builder<>(); Set<Artifact> unprunedJ2ObjcLibs = objcProvider.get(ObjcProvider.J2OBJC_LIBRARY).toSet(); @@ -1180,9 +1607,9 @@ public abstract class CompilationSupport { } return libraries.build(); } - + /** Returns the artifact that should be the outcome of this build's link action */ - protected Artifact getBinaryToLink() { + private Artifact getBinaryToLink() { // When compilation_mode=opt and objc_enable_binary_stripping are specified, the unstripped // binary containing debug symbols is generated by the linker, which also needs the debug @@ -1205,7 +1632,7 @@ public abstract class CompilationSupport { } /** Signals if stripping should include options for dynamic libraries. */ - protected enum StrippingType { + private enum StrippingType { DEFAULT, DYNAMIC_LIB } @@ -1213,7 +1640,7 @@ public abstract class CompilationSupport { * Registers an action that uses the 'strip' tool to perform binary stripping on the given binary * subject to the given {@link StrippingType}. */ - protected void registerBinaryStripAction(Artifact binaryToLink, StrippingType strippingType) { + private void registerBinaryStripAction(Artifact binaryToLink, StrippingType strippingType) { final ImmutableList<String> stripArgs; if (isTestRule) { // For test targets, only debug symbols are stripped off, since /usr/bin/strip is not able @@ -1261,7 +1688,7 @@ public abstract class CompilationSupport { return this; } - protected Optional<Artifact> getPchFile() { + private Optional<Artifact> getPchFile() { if (!usePch) { return Optional.absent(); } @@ -1326,7 +1753,7 @@ public abstract class CompilationSupport { } /** Holds information about Objective-C compile actions that require header thinning. */ - protected static final class ObjcHeaderThinningInfo { + private static final class ObjcHeaderThinningInfo { /** Source file for compile action. */ public final Artifact sourceFile; /** headers_list file for compile action. */ @@ -1351,7 +1778,7 @@ public abstract class CompilationSupport { * Returns true when ObjC header thinning is enabled via configuration and an a valid * header_scanner executable target is provided. */ - protected boolean isHeaderThinningEnabled() { + private boolean isHeaderThinningEnabled() { if (objcConfiguration.useExperimentalHeaderThinning() && ruleContext.isAttrDefined(ObjcRuleClasses.HEADER_SCANNER_ATTRIBUTE, BuildType.LABEL)) { FilesToRunProvider tool = getHeaderThinningToolExecutable(); @@ -1362,7 +1789,7 @@ public abstract class CompilationSupport { return false; } - protected FilesToRunProvider getHeaderThinningToolExecutable() { + private FilesToRunProvider getHeaderThinningToolExecutable() { return ruleContext .getPrerequisite(ObjcRuleClasses.HEADER_SCANNER_ATTRIBUTE, Mode.HOST) .getProvider(FilesToRunProvider.class); @@ -1379,7 +1806,7 @@ public abstract class CompilationSupport { * being distributed so they don't contribute to the critical path. The partition size is * configurable so that it can be tuned. */ - protected void registerHeaderScanningActions( + private void registerHeaderScanningActions( ImmutableList<ObjcHeaderThinningInfo> headerThinningInfo, ObjcProvider objcProvider, CompilationArtifacts compilationArtifacts) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java deleted file mode 100644 index 958e025f68..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright 2016 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.devtools.build.lib.rules.objc; - -import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LINK_INPUTS; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_FILE; -import static java.util.Comparator.naturalOrder; - -import com.google.common.base.Preconditions; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Streams; -import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.AnalysisEnvironment; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.config.BuildConfiguration; -import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions.AppleBitcodeMode; -import com.google.devtools.build.lib.rules.apple.AppleConfiguration; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info; -import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.CollidingProvidesException; -import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; -import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension; -import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; -import com.google.devtools.build.lib.rules.cpp.CppCompileAction; -import com.google.devtools.build.lib.rules.cpp.CppConfiguration; -import com.google.devtools.build.lib.rules.cpp.CppHelper; -import com.google.devtools.build.lib.rules.cpp.CppLinkAction; -import com.google.devtools.build.lib.rules.cpp.CppLinkActionBuilder; -import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; -import com.google.devtools.build.lib.rules.cpp.FdoSupportProvider; -import com.google.devtools.build.lib.rules.cpp.FeatureSpecification; -import com.google.devtools.build.lib.rules.cpp.IncludeProcessing; -import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness; -import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; -import com.google.devtools.build.lib.rules.cpp.NoProcessing; -import com.google.devtools.build.lib.rules.cpp.PrecompiledFiles; -import com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag; -import com.google.devtools.build.lib.rules.objc.ObjcVariablesExtension.VariableCategory; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.Collection; -import java.util.Map; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -/** - * Constructs command lines for objc compilation, archiving, and linking. Uses the crosstool - * infrastructure to register {@link CppCompileAction} and {@link CppLinkAction} instances, making - * use of a provided toolchain. - */ -// TODO(b/65163377): Remove LegacyCompilationSupport and use only this implementation. -public class CrosstoolCompilationSupport extends CompilationSupport { - - private static final String OBJC_MODULE_FEATURE_NAME = "use_objc_modules"; - private static final String NO_ENABLE_MODULES_FEATURE_NAME = "no_enable_modules"; - private static final String DEAD_STRIP_FEATURE_NAME = "dead_strip"; - /** - * Enabled if this target's rule is not a test rule. Binary stripping should not be applied in - * the link step. TODO(b/36562173): Replace this behavior with a condition on bundle creation. - * - * <p>Note that the crosstool does not support feature negation in FlagSet.with_feature, which - * is the mechanism used to condition linker arguments here. Therefore, we expose - * "is_not_test_target" instead of the more intuitive "is_test_target". - */ - private static final String IS_NOT_TEST_TARGET_FEATURE_NAME = "is_not_test_target"; - /** Enabled if this target generates debug symbols in a dSYM file. */ - private static final String GENERATE_DSYM_FILE_FEATURE_NAME = "generate_dsym_file"; - /** - * Enabled if this target does not generate debug symbols. - * - * <p>Note that the crosstool does not support feature negation in FlagSet.with_feature, which is - * the mechanism used to condition linker arguments here. Therefore, we expose - * "no_generate_debug_symbols" in addition to "generate_dsym_file" - */ - private static final String NO_GENERATE_DEBUG_SYMBOLS_FEATURE_NAME = "no_generate_debug_symbols"; - - private static final String GENERATE_LINKMAP_FEATURE_NAME = "generate_linkmap"; - - /** Enabled if this target has objc sources in its transitive closure. */ - private static final String CONTAINS_OBJC = "contains_objc_sources"; - - private static final ImmutableList<String> ACTIVATED_ACTIONS = - ImmutableList.of( - "objc-compile", - "objc++-compile", - "objc-archive", - "objc-fully-link", - "objc-executable", - "objc++-executable", - "assemble", - "preprocess-assemble", - "c-compile", - "c++-compile"); - - /** - * Creates a new CompilationSupport instance that uses the c++ rule backend - * - * @param ruleContext the RuleContext for the calling target - * @param outputGroupCollector a map that will be updated with output groups produced by compile - * action generation. - */ - public CrosstoolCompilationSupport( - RuleContext ruleContext, Map<String, NestedSet<Artifact>> outputGroupCollector) { - this( - ruleContext, - ruleContext.getConfiguration(), - ObjcRuleClasses.intermediateArtifacts(ruleContext), - CompilationAttributes.Builder.fromRuleContext(ruleContext).build(), - /*useDeps=*/ true, - outputGroupCollector, - null, - /*isTestRule=*/ false, - /*usePch=*/ true); - } - - /** - * Creates a new CompilationSupport instance that uses the c++ rule backend - * - * @param ruleContext the RuleContext for the calling target - * @param buildConfiguration the configuration for the calling target - * @param intermediateArtifacts IntermediateArtifacts for deriving artifact paths - * @param compilationAttributes attributes of the calling target - * @param useDeps true if deps should be used - * @param toolchain if not null overrides the default toolchain from the ruleContext. - * @param usePch true if pch should be used - */ - public CrosstoolCompilationSupport( - RuleContext ruleContext, - BuildConfiguration buildConfiguration, - IntermediateArtifacts intermediateArtifacts, - CompilationAttributes compilationAttributes, - boolean useDeps, - Map<String, NestedSet<Artifact>> outputGroupCollector, - CcToolchainProvider toolchain, - boolean isTestRule, - boolean usePch) { - super( - ruleContext, - buildConfiguration, - intermediateArtifacts, - compilationAttributes, - useDeps, - outputGroupCollector, - toolchain, - isTestRule, - usePch); - } - - @Override - CompilationSupport registerCompileAndArchiveActions( - CompilationArtifacts compilationArtifacts, - ObjcProvider objcProvider, ExtraCompileArgs extraCompileArgs, - Iterable<PathFragment> priorityHeaders, - @Nullable CcToolchainProvider ccToolchain, - @Nullable FdoSupportProvider fdoSupport) throws RuleErrorException, InterruptedException { - Preconditions.checkNotNull(ccToolchain); - Preconditions.checkNotNull(fdoSupport); - ObjcVariablesExtension.Builder extension = - new ObjcVariablesExtension.Builder() - .setRuleContext(ruleContext) - .setObjcProvider(objcProvider) - .setCompilationArtifacts(compilationArtifacts) - .setIntermediateArtifacts(intermediateArtifacts) - .setConfiguration(buildConfiguration); - CcLibraryHelper helper; - - if (compilationArtifacts.getArchive().isPresent()) { - Artifact objList = intermediateArtifacts.archiveObjList(); - - // TODO(b/30783125): Signal the need for this action in the CROSSTOOL. - registerObjFilelistAction(getObjFiles(compilationArtifacts, intermediateArtifacts), objList); - - extension.addVariableCategory(VariableCategory.ARCHIVE_VARIABLES); - - helper = - createCcLibraryHelper( - objcProvider, - compilationArtifacts, - extension.build(), - extraCompileArgs, - ccToolchain, - fdoSupport, - priorityHeaders) - .setLinkType(LinkTargetType.OBJC_ARCHIVE) - .addLinkActionInput(objList); - } else { - helper = - createCcLibraryHelper( - objcProvider, - compilationArtifacts, - extension.build(), - extraCompileArgs, - ccToolchain, - fdoSupport, - priorityHeaders); - } - - Info info = helper.build(); - outputGroupCollector.putAll(info.getOutputGroups()); - - registerHeaderScanningActions(info, objcProvider, compilationArtifacts); - - return this; - } - - @Override - protected CompilationSupport registerFullyLinkAction( - ObjcProvider objcProvider, Iterable<Artifact> inputArtifacts, Artifact outputArchive, - @Nullable CcToolchainProvider ccToolchain, @Nullable FdoSupportProvider fdoSupport) - throws InterruptedException { - Preconditions.checkNotNull(ccToolchain); - Preconditions.checkNotNull(fdoSupport); - PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName()); - String libraryIdentifier = - ruleContext - .getPackageDirectory() - .getRelative(labelName.replaceName("lib" + labelName.getBaseName())) - .getPathString(); - ObjcVariablesExtension extension = - new ObjcVariablesExtension.Builder() - .setRuleContext(ruleContext) - .setObjcProvider(objcProvider) - .setConfiguration(buildConfiguration) - .setIntermediateArtifacts(intermediateArtifacts) - .setFullyLinkArchive(outputArchive) - .addVariableCategory(VariableCategory.FULLY_LINK_VARIABLES) - .build(); - CppLinkAction fullyLinkAction = - new CppLinkActionBuilder( - ruleContext, - outputArchive, - ccToolchain, - fdoSupport, - getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider), - createObjcCppSemantics( - objcProvider, /* privateHdrs= */ ImmutableList.of(), /* pchHdr= */ null)) - .addActionInputs(objcProvider.getObjcLibraries()) - .addActionInputs(objcProvider.getCcLibraries()) - .addActionInputs(objcProvider.get(IMPORTED_LIBRARY).toSet()) - .setCrosstoolInputs(ccToolchain.getLink()) - .setLinkType(LinkTargetType.OBJC_FULLY_LINKED_ARCHIVE) - .setLinkStaticness(LinkStaticness.FULLY_STATIC) - .setLibraryIdentifier(libraryIdentifier) - .addVariablesExtension(extension) - .build(); - ruleContext.registerAction(fullyLinkAction); - - return this; - } - - private StrippingType getStrippingType(ExtraLinkArgs extraLinkArgs) { - return Iterables.contains(extraLinkArgs, "-dynamiclib") - ? StrippingType.DYNAMIC_LIB - : StrippingType.DEFAULT; - } - - @Override - CompilationSupport registerLinkActions( - ObjcProvider objcProvider, - J2ObjcMappingFileProvider j2ObjcMappingFileProvider, - J2ObjcEntryClassProvider j2ObjcEntryClassProvider, - ExtraLinkArgs extraLinkArgs, - Iterable<Artifact> extraLinkInputs, - DsymOutputType dsymOutputType, - CcToolchainProvider toolchain) - throws InterruptedException { - Iterable<Artifact> prunedJ2ObjcArchives = - computeAndStripPrunedJ2ObjcArchives( - j2ObjcEntryClassProvider, j2ObjcMappingFileProvider, objcProvider); - ImmutableList<Artifact> bazelBuiltLibraries = - Iterables.isEmpty(prunedJ2ObjcArchives) - ? objcProvider.getObjcLibraries() - : substituteJ2ObjcPrunedLibraries(objcProvider); - - Artifact inputFileList = intermediateArtifacts.linkerObjList(); - ImmutableSet<Artifact> forceLinkArtifacts = getForceLoadArtifacts(objcProvider); - - Iterable<Artifact> objFiles = - Iterables.concat( - bazelBuiltLibraries, objcProvider.get(IMPORTED_LIBRARY), objcProvider.getCcLibraries()); - // Clang loads archives specified in filelists and also specified as -force_load twice, - // resulting in duplicate symbol errors unless they are deduped. - objFiles = Iterables.filter(objFiles, Predicates.not(Predicates.in(forceLinkArtifacts))); - - registerObjFilelistAction(objFiles, inputFileList); - - LinkTargetType linkType = (objcProvider.is(Flag.USES_CPP)) - ? LinkTargetType.OBJCPP_EXECUTABLE - : LinkTargetType.OBJC_EXECUTABLE; - - ObjcVariablesExtension.Builder extensionBuilder = - new ObjcVariablesExtension.Builder() - .setRuleContext(ruleContext) - .setObjcProvider(objcProvider) - .setConfiguration(buildConfiguration) - .setIntermediateArtifacts(intermediateArtifacts) - .setFrameworkNames(frameworkNames(objcProvider)) - .setLibraryNames(libraryNames(objcProvider)) - .setForceLoadArtifacts(getForceLoadArtifacts(objcProvider)) - .setAttributeLinkopts(attributes.linkopts()) - .addVariableCategory(VariableCategory.EXECUTABLE_LINKING_VARIABLES); - - Artifact binaryToLink = getBinaryToLink(); - FdoSupportProvider fdoSupport = - CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext); - CppLinkActionBuilder executableLinkAction = - new CppLinkActionBuilder( - ruleContext, - binaryToLink, - toolchain, - fdoSupport, - getFeatureConfiguration(ruleContext, toolchain, buildConfiguration, objcProvider), - createObjcCppSemantics( - objcProvider, /* privateHdrs= */ ImmutableList.of(), /* pchHdr= */ null)) - .setMnemonic("ObjcLink") - .addActionInputs(bazelBuiltLibraries) - .addActionInputs(objcProvider.getCcLibraries()) - .addTransitiveActionInputs(objcProvider.get(IMPORTED_LIBRARY)) - .addTransitiveActionInputs(objcProvider.get(STATIC_FRAMEWORK_FILE)) - .addTransitiveActionInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE)) - .addTransitiveActionInputs(objcProvider.get(LINK_INPUTS)) - .setCrosstoolInputs(toolchain.getLink()) - .addActionInputs(prunedJ2ObjcArchives) - .addActionInputs(extraLinkInputs) - .addActionInput(inputFileList) - .setLinkType(linkType) - .setLinkStaticness(LinkStaticness.FULLY_STATIC) - .addLinkopts(ImmutableList.copyOf(extraLinkArgs)); - - if (objcConfiguration.generateDsym()) { - Artifact dsymBundleZip = intermediateArtifacts.tempDsymBundleZip(dsymOutputType); - extensionBuilder - .setDsymBundleZip(dsymBundleZip) - .addVariableCategory(VariableCategory.DSYM_VARIABLES); - registerDsymActions(dsymOutputType); - executableLinkAction.addActionOutput(dsymBundleZip); - } - - if (objcConfiguration.generateLinkmap()) { - Artifact linkmap = intermediateArtifacts.linkmap(); - extensionBuilder - .setLinkmap(linkmap) - .addVariableCategory(VariableCategory.LINKMAP_VARIABLES); - executableLinkAction.addActionOutput(linkmap); - } - - if (appleConfiguration.getBitcodeMode() == AppleBitcodeMode.EMBEDDED) { - Artifact bitcodeSymbolMap = intermediateArtifacts.bitcodeSymbolMap(); - extensionBuilder - .setBitcodeSymbolMap(bitcodeSymbolMap) - .addVariableCategory(VariableCategory.BITCODE_VARIABLES); - executableLinkAction.addActionOutput(bitcodeSymbolMap); - } - - executableLinkAction.addVariablesExtension(extensionBuilder.build()); - ruleContext.registerAction(executableLinkAction.build()); - - if (objcConfiguration.shouldStripBinary()) { - registerBinaryStripAction(binaryToLink, getStrippingType(extraLinkArgs)); - } - - return this; - } - - private IncludeProcessing createIncludeProcessing( - Iterable<Artifact> privateHdrs, ObjcProvider objcProvider, @Nullable Artifact pchHdr) { - if (isHeaderThinningEnabled()) { - Iterable<Artifact> potentialInputs = - Iterables.concat( - privateHdrs, - objcProvider.get(HEADER), - objcProvider.get(STATIC_FRAMEWORK_FILE), - objcProvider.get(DYNAMIC_FRAMEWORK_FILE)); - if (pchHdr != null) { - potentialInputs = Iterables.concat(potentialInputs, ImmutableList.of(pchHdr)); - } - return new HeaderThinning(potentialInputs); - } else { - return new NoProcessing(); - } - } - - private CcLibraryHelper createCcLibraryHelper( - ObjcProvider objcProvider, - CompilationArtifacts compilationArtifacts, - VariablesExtension extension, - ExtraCompileArgs extraCompileArgs, - CcToolchainProvider ccToolchain, - FdoSupportProvider fdoSupport, - Iterable<PathFragment> priorityHeaders) { - PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext); - Collection<Artifact> arcSources = ImmutableSortedSet.copyOf(compilationArtifacts.getSrcs()); - Collection<Artifact> nonArcSources = - ImmutableSortedSet.copyOf(compilationArtifacts.getNonArcSrcs()); - Collection<Artifact> privateHdrs = - ImmutableSortedSet.copyOf(compilationArtifacts.getPrivateHdrs()); - Collection<Artifact> publicHdrs = - Stream.concat( - Streams.stream(attributes.hdrs()), - Streams.stream(compilationArtifacts.getAdditionalHdrs())) - .collect(toImmutableSortedSet(naturalOrder())); - Artifact pchHdr = getPchFile().orNull(); - ObjcCppSemantics semantics = createObjcCppSemantics(objcProvider, privateHdrs, pchHdr); - CcLibraryHelper result = - new CcLibraryHelper( - ruleContext, - semantics, - getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider), - CcLibraryHelper.SourceCategory.CC_AND_OBJC, - ccToolchain, - fdoSupport, - buildConfiguration) - .addSources(arcSources, ImmutableMap.of("objc_arc", "")) - .addSources(nonArcSources, ImmutableMap.of("no_objc_arc", "")) - .addSources(privateHdrs) - .addDefines(objcProvider.get(DEFINE)) - .enableCompileProviders() - .addPublicHeaders(publicHdrs) - .addPrecompiledFiles(precompiledFiles) - .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)) - // Not all our dependencies need to export cpp information. - // For example, objc_proto_library can depend on a proto_library rule that does not - // generate C++ protos. - .setCheckDepsGenerateCpp(false) - .setCopts( - ImmutableList.<String>builder() - .addAll(getCompileRuleCopts()) - .addAll( - ruleContext - .getFragment(ObjcConfiguration.class) - .getCoptsForCompilationMode()) - .addAll(extraCompileArgs) - .build()) - .addIncludeDirs(priorityHeaders) - .addIncludeDirs(objcProvider.get(INCLUDE)) - .addSystemIncludeDirs(objcProvider.get(INCLUDE_SYSTEM)) - .setCppModuleMap(intermediateArtifacts.moduleMap()) - .setLinkedArtifactNameSuffix(intermediateArtifacts.archiveFileNameSuffix()) - .setPropagateModuleMapToCompileAction(false) - .setNeverLink(true) - .addVariableExtension(extension); - - if (pchHdr != null) { - result.addNonModuleMapHeader(pchHdr); - } - if (!useDeps) { - result.doNotUseDeps(); - } - if (getCustomModuleMap(ruleContext).isPresent()) { - result.doNotGenerateModuleMap(); - } - return result; - } - - private ObjcCppSemantics createObjcCppSemantics( - ObjcProvider objcProvider, Collection<Artifact> privateHdrs, Artifact pchHdr) { - return new ObjcCppSemantics( - objcProvider, - createIncludeProcessing(privateHdrs, objcProvider, pchHdr), - ruleContext.getFragment(ObjcConfiguration.class), - isHeaderThinningEnabled(), - intermediateArtifacts, - buildConfiguration); - } - - private FeatureConfiguration getFeatureConfiguration( - RuleContext ruleContext, - CcToolchainProvider ccToolchain, - BuildConfiguration configuration, - ObjcProvider objcProvider) { - boolean isHost = ruleContext.getConfiguration().isHostConfiguration(); - ImmutableSet.Builder<String> activatedCrosstoolSelectables = - ImmutableSet.<String>builder() - .addAll(ccToolchain.getFeatures().getDefaultFeatures()) - .addAll(ACTIVATED_ACTIONS) - .addAll( - ruleContext - .getFragment(AppleConfiguration.class) - .getBitcodeMode() - .getFeatureNames()) - // We create a module map by default to allow for Swift interop. - .add(CppRuleClasses.MODULE_MAPS) - .add(CppRuleClasses.COMPILE_ALL_MODULES) - .add(CppRuleClasses.EXCLUDE_PRIVATE_HEADERS_IN_MODULE_MAPS) - .add(CppRuleClasses.ONLY_DOTH_HEADERS_IN_MODULE_MAPS) - .add(CppRuleClasses.COMPILE_ACTION_FLAGS_IN_FLAG_SET) - .add(CppRuleClasses.DEPENDENCY_FILE) - .add(CppRuleClasses.INCLUDE_PATHS) - .add(isHost ? "host" : "nonhost") - .add(configuration.getCompilationMode().toString()); - - if (configuration.getFragment(ObjcConfiguration.class).moduleMapsEnabled() - && !getCustomModuleMap(ruleContext).isPresent()) { - activatedCrosstoolSelectables.add(OBJC_MODULE_FEATURE_NAME); - } - if (!CompilationAttributes.Builder.fromRuleContext(ruleContext).build().enableModules()) { - activatedCrosstoolSelectables.add(NO_ENABLE_MODULES_FEATURE_NAME); - } - if (configuration.getFragment(ObjcConfiguration.class).shouldStripBinary()) { - activatedCrosstoolSelectables.add(DEAD_STRIP_FEATURE_NAME); - } - if (getPchFile().isPresent()) { - activatedCrosstoolSelectables.add("pch"); - } - if (!isTestRule) { - activatedCrosstoolSelectables.add(IS_NOT_TEST_TARGET_FEATURE_NAME); - } - if (configuration.getFragment(ObjcConfiguration.class).generateDsym()) { - activatedCrosstoolSelectables.add(GENERATE_DSYM_FILE_FEATURE_NAME); - } else { - activatedCrosstoolSelectables.add(NO_GENERATE_DEBUG_SYMBOLS_FEATURE_NAME); - } - if (configuration.getFragment(ObjcConfiguration.class).generateLinkmap()) { - activatedCrosstoolSelectables.add(GENERATE_LINKMAP_FEATURE_NAME); - } - AppleBitcodeMode bitcodeMode = - configuration.getFragment(AppleConfiguration.class).getBitcodeMode(); - if (bitcodeMode != AppleBitcodeMode.NONE) { - activatedCrosstoolSelectables.addAll(bitcodeMode.getFeatureNames()); - } - if (objcProvider.is(Flag.USES_OBJC)) { - activatedCrosstoolSelectables.add(CONTAINS_OBJC); - } - - activatedCrosstoolSelectables.addAll(ruleContext.getFeatures()); - try { - return configuration - .getFragment(CppConfiguration.class) - .getFeatures() - .getFeatureConfiguration( - FeatureSpecification.create( - activatedCrosstoolSelectables.build(), ImmutableSet.<String>of())); - } catch (CollidingProvidesException e) { - ruleContext.ruleError(e.getMessage()); - return FeatureConfiguration.EMPTY; - } - } - - private static ImmutableList<Artifact> getObjFiles( - CompilationArtifacts compilationArtifacts, IntermediateArtifacts intermediateArtifacts) { - ImmutableList.Builder<Artifact> result = new ImmutableList.Builder<>(); - for (Artifact sourceFile : compilationArtifacts.getSrcs()) { - result.add(intermediateArtifacts.objFile(sourceFile)); - } - for (Artifact nonArcSourceFile : compilationArtifacts.getNonArcSrcs()) { - result.add(intermediateArtifacts.objFile(nonArcSourceFile)); - } - result.addAll(compilationArtifacts.getPrecompiledSrcs()); - return result.build(); - } - - private void registerHeaderScanningActions( - Info info, ObjcProvider objcProvider, CompilationArtifacts compilationArtifacts) { - // PIC is not used for Obj-C builds, if that changes this method will need to change - if (!isHeaderThinningEnabled() - || info.getCcCompilationOutputs().getObjectFiles(false).isEmpty()) { - return; - } - - ImmutableList.Builder<ObjcHeaderThinningInfo> headerThinningInfos = ImmutableList.builder(); - AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment(); - for (Artifact objectFile : info.getCcCompilationOutputs().getObjectFiles(false)) { - ActionAnalysisMetadata generatingAction = - analysisEnvironment.getLocalGeneratingAction(objectFile); - if (generatingAction instanceof CppCompileAction) { - CppCompileAction action = (CppCompileAction) generatingAction; - Artifact sourceFile = action.getSourceFile(); - if (!sourceFile.isTreeArtifact() - && SOURCES_FOR_HEADER_THINNING.matches(sourceFile.getFilename())) { - headerThinningInfos.add( - new ObjcHeaderThinningInfo( - sourceFile, - intermediateArtifacts.headersListFile(sourceFile), - action.getCompilerOptions())); - } - } - } - registerHeaderScanningActions(headerThinningInfos.build(), objcProvider, compilationArtifacts); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java deleted file mode 100644 index e6d502c5f9..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java +++ /dev/null @@ -1,917 +0,0 @@ -// Copyright 2016 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.devtools.build.lib.rules.objc; - -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LINK_INPUTS; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MODULE_MAP; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_FILE; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.WEAK_SDK_FRAMEWORK; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG_PLUSPLUS; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.COMPILABLE_SRCS_TYPE; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.DSYMUTIL; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.HEADERS; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.NON_ARC_SRCS_TYPE; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.PRECOMPILED_SRCS_TYPE; -import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SRCS_TYPE; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; -import com.google.common.base.Optional; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; -import com.google.devtools.build.lib.actions.CommandLineExpansionException; -import com.google.devtools.build.lib.analysis.OutputGroupProvider; -import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.actions.CommandLine; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; -import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate; -import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate.OutputPathMapper; -import com.google.devtools.build.lib.analysis.config.BuildConfiguration; -import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.collect.nestedset.Order; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions; -import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions.AppleBitcodeMode; -import com.google.devtools.build.lib.rules.apple.AppleConfiguration; -import com.google.devtools.build.lib.rules.apple.ApplePlatform; -import com.google.devtools.build.lib.rules.apple.AppleToolchain; -import com.google.devtools.build.lib.rules.apple.DottedVersion; -import com.google.devtools.build.lib.rules.apple.XcodeConfig; -import com.google.devtools.build.lib.rules.apple.XcodeConfigProvider; -import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; -import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile; -import com.google.devtools.build.lib.rules.cpp.CppModuleMap; -import com.google.devtools.build.lib.rules.cpp.FdoSupportProvider; -import com.google.devtools.build.lib.vfs.FileSystemUtils; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nullable; - -/** - * Constructs command lines for objc compilation, archiving, and linking. Uses hard-coded - * command line templates. - */ -// TODO(b/65163377): Remove this implementation. -public class LegacyCompilationSupport extends CompilationSupport { - - /** - * Frameworks implicitly linked to iOS, watchOS, and tvOS binaries when using legacy compilation. - */ - @VisibleForTesting - static final ImmutableList<SdkFramework> AUTOMATIC_SDK_FRAMEWORKS = - ImmutableList.of(new SdkFramework("Foundation"), new SdkFramework("UIKit")); - - /** - * A mapper that maps input ObjC source {@link Artifact.TreeFileArtifact}s to output object file - * {@link Artifact.TreeFileArtifact}s. - */ - private static final OutputPathMapper COMPILE_ACTION_TEMPLATE_OUTPUT_PATH_MAPPER = - new OutputPathMapper() { - @Override - public PathFragment parentRelativeOutputPath(TreeFileArtifact inputTreeFileArtifact) { - return FileSystemUtils.replaceExtension( - inputTreeFileArtifact.getParentRelativePath(), ".o"); - } - }; - - /** - * Returns information about the given rule's compilation artifacts. Dependencies specified in the - * current rule's attributes are obtained via {@code ruleContext}. Output locations are determined - * using the given {@code intermediateArtifacts} object. The fact that these are distinct objects - * allows the caller to generate compilation actions pertaining to a configuration separate from - * the current rule's configuration. - */ - static CompilationArtifacts compilationArtifacts( - RuleContext ruleContext, IntermediateArtifacts intermediateArtifacts) { - PrerequisiteArtifacts srcs = - ruleContext.getPrerequisiteArtifacts("srcs", Mode.TARGET).errorsForNonMatching(SRCS_TYPE); - return new CompilationArtifacts.Builder() - .addSrcs(srcs.filter(COMPILABLE_SRCS_TYPE).list()) - .addNonArcSrcs( - ruleContext - .getPrerequisiteArtifacts("non_arc_srcs", Mode.TARGET) - .errorsForNonMatching(NON_ARC_SRCS_TYPE) - .list()) - .addPrivateHdrs(srcs.filter(HEADERS).list()) - .addPrecompiledSrcs(srcs.filter(PRECOMPILED_SRCS_TYPE).list()) - .setIntermediateArtifacts(intermediateArtifacts) - .build(); - } - - /** - * Creates a new legacy compilation support for the given rule and build configuration. - * - * <p>All actions will be created under the given build configuration, which may be different than - * the current rule context configuration. - * - * <p>The compilation and linking flags will be retrieved from the given compilation attributes. - * The names of the generated artifacts will be retrieved from the given intermediate artifacts. - * - * <p>By instantiating multiple compilation supports for the same rule but with intermediate - * artifacts with different output prefixes, multiple archives can be compiled for the same rule - * context. - */ - LegacyCompilationSupport( - RuleContext ruleContext, - BuildConfiguration buildConfiguration, - IntermediateArtifacts intermediateArtifacts, - CompilationAttributes compilationAttributes, - boolean useDeps, - Map<String, NestedSet<Artifact>> outputGroupCollector, - CcToolchainProvider toolchain, - boolean isTestRule, - boolean usePch) { - super( - ruleContext, - buildConfiguration, - intermediateArtifacts, - compilationAttributes, - useDeps, - outputGroupCollector, - toolchain, - isTestRule, - usePch); - } - - @Override - CompilationSupport registerCompileAndArchiveActions( - CompilationArtifacts compilationArtifacts, ObjcProvider objcProvider, - ExtraCompileArgs extraCompileArgs, Iterable<PathFragment> priorityHeaders, - @Nullable CcToolchainProvider ccToolchain, @Nullable FdoSupportProvider fdoSupport) { - registerGenerateModuleMapAction(compilationArtifacts); - Optional<CppModuleMap> moduleMap; - if (objcConfiguration.moduleMapsEnabled()) { - moduleMap = Optional.of(intermediateArtifacts.moduleMap()); - } else { - moduleMap = Optional.absent(); - } - registerCompileAndArchiveActions( - compilationArtifacts, - objcProvider, - extraCompileArgs, - priorityHeaders, - moduleMap); - return this; - } - - /** - * Creates actions to compile each source file individually, and link all the compiled object - * files into a single archive library. - */ - private void registerCompileAndArchiveActions( - CompilationArtifacts compilationArtifacts, - ObjcProvider objcProvider, - ExtraCompileArgs extraCompileArgs, - Iterable<PathFragment> priorityHeaders, - Optional<CppModuleMap> moduleMap) { - ImmutableList.Builder<Artifact> objFilesBuilder = ImmutableList.builder(); - ImmutableList.Builder<ObjcHeaderThinningInfo> objcHeaderThinningInfos = ImmutableList.builder(); - - for (Artifact sourceFile : compilationArtifacts.getSrcs()) { - Artifact objFile = intermediateArtifacts.objFile(sourceFile); - objFilesBuilder.add(objFile); - - if (objFile.isTreeArtifact()) { - registerCompileActionTemplate( - sourceFile, - objFile, - objcProvider, - priorityHeaders, - moduleMap, - compilationArtifacts, - Iterables.concat(extraCompileArgs, ImmutableList.of("-fobjc-arc"))); - } else { - ObjcHeaderThinningInfo objcHeaderThinningInfo = - registerCompileAction( - sourceFile, - objFile, - objcProvider, - priorityHeaders, - moduleMap, - compilationArtifacts, - Iterables.concat(extraCompileArgs, ImmutableList.of("-fobjc-arc"))); - if (objcHeaderThinningInfo != null) { - objcHeaderThinningInfos.add(objcHeaderThinningInfo); - } - } - } - for (Artifact nonArcSourceFile : compilationArtifacts.getNonArcSrcs()) { - Artifact objFile = intermediateArtifacts.objFile(nonArcSourceFile); - objFilesBuilder.add(objFile); - if (objFile.isTreeArtifact()) { - registerCompileActionTemplate( - nonArcSourceFile, - objFile, - objcProvider, - priorityHeaders, - moduleMap, - compilationArtifacts, - Iterables.concat(extraCompileArgs, ImmutableList.of("-fno-objc-arc"))); - } else { - ObjcHeaderThinningInfo objcHeaderThinningInfo = - registerCompileAction( - nonArcSourceFile, - objFile, - objcProvider, - priorityHeaders, - moduleMap, - compilationArtifacts, - Iterables.concat(extraCompileArgs, ImmutableList.of("-fno-objc-arc"))); - if (objcHeaderThinningInfo != null) { - objcHeaderThinningInfos.add(objcHeaderThinningInfo); - } - } - } - - objFilesBuilder.addAll(compilationArtifacts.getPrecompiledSrcs()); - - ImmutableList<Artifact> objFiles = objFilesBuilder.build(); - outputGroupCollector.put( - OutputGroupProvider.FILES_TO_COMPILE, - NestedSetBuilder.<Artifact>stableOrder().addAll(objFiles).build()); - - for (Artifact archive : compilationArtifacts.getArchive().asSet()) { - registerArchiveActions(objFiles, archive); - } - - registerHeaderScanningActions( - objcHeaderThinningInfos.build(), objcProvider, compilationArtifacts); - } - - private CustomCommandLine compileActionCommandLine( - Artifact sourceFile, - Artifact objFile, - ObjcProvider objcProvider, - Iterable<PathFragment> priorityHeaders, - Optional<CppModuleMap> moduleMap, - Optional<Artifact> pchFile, - Optional<Artifact> dotdFile, - Iterable<String> otherFlags, - boolean collectCodeCoverage, - boolean isCPlusPlusSource) { - CustomCommandLine.Builder commandLine = new CustomCommandLine.Builder().add(CLANG); - - if (isCPlusPlusSource) { - commandLine.add("-stdlib=libc++"); - commandLine.add("-std=gnu++11"); - } - - // The linker needs full debug symbol information to perform binary dead-code stripping. - if (objcConfiguration.shouldStripBinary()) { - commandLine.add("-g"); - } - - ImmutableList<String> coverageFlags = ImmutableList.of(); - if (collectCodeCoverage) { - if (buildConfiguration.isLLVMCoverageMapFormatEnabled()) { - coverageFlags = CLANG_LLVM_COVERAGE_FLAGS; - } else { - coverageFlags = CLANG_GCOV_COVERAGE_FLAGS; - } - } - - commandLine - .addAll(ImmutableList.copyOf(compileFlagsForClang(appleConfiguration))) - .addAll( - commonLinkAndCompileFlagsForClang(objcProvider, objcConfiguration, appleConfiguration)) - .addAll(objcConfiguration.getCoptsForCompilationMode()) - .addPaths( - VectorArg.addBefore("-iquote") - .each(ObjcCommon.userHeaderSearchPaths(objcProvider, buildConfiguration))) - .addExecPaths(VectorArg.addBefore("-include").each(pchFile.asSet())) - .addPaths(VectorArg.addBefore("-I").each(ImmutableList.copyOf(priorityHeaders))) - .addPaths(VectorArg.addBefore("-I").each(objcProvider.get(INCLUDE))) - .addPaths(VectorArg.addBefore("-isystem").each(objcProvider.get(INCLUDE_SYSTEM))) - .addAll(ImmutableList.copyOf(otherFlags)) - .addAll(VectorArg.format("-D%s").each(objcProvider.get(DEFINE))) - .addAll(coverageFlags) - .addAll(ImmutableList.copyOf(getCompileRuleCopts())); - - // Add input source file arguments - commandLine.add("-c"); - if (sourceFile.isTreeArtifact()) { - commandLine.addPlaceholderTreeArtifactExecPath(sourceFile); - } else { - commandLine.addPath(sourceFile.getExecPath()); - } - - // Add output object file arguments. - commandLine.add("-o"); - if (objFile.isTreeArtifact()) { - commandLine.addPlaceholderTreeArtifactExecPath(objFile); - } else { - commandLine.addPath(objFile.getExecPath()); - } - - // Add Dotd file arguments. - if (dotdFile.isPresent()) { - commandLine.add("-MD").addExecPath("-MF", dotdFile.get()); - } - - // Add module map arguments. - if (moduleMap.isPresent() && !getCustomModuleMap(ruleContext).isPresent()) { - // If modules are enabled for the rule, -fmodules is added to the copts already. (This implies - // module map usage). Otherwise, we need to pass -fmodule-maps. - if (!attributes.enableModules()) { - commandLine.add("-fmodule-maps"); - } - // -fmodule-map-file only loads the module in Xcode 7, so we add the module maps's directory - // to the include path instead. - // TODO(bazel-team): Use -fmodule-map-file when Xcode 6 support is dropped. - commandLine - .add("-iquote") - .addPath(moduleMap.get().getArtifact().getExecPath().getParentDirectory()) - .addFormatted("-fmodule-name=%s", moduleMap.get().getName()); - } - - return commandLine.build(); - } - - @Nullable - private ObjcHeaderThinningInfo registerCompileAction( - Artifact sourceFile, - Artifact objFile, - ObjcProvider objcProvider, - Iterable<PathFragment> priorityHeaders, - Optional<CppModuleMap> moduleMap, - CompilationArtifacts compilationArtifacts, - Iterable<String> otherFlags) { - boolean isCPlusPlusSource = ObjcRuleClasses.CPP_SOURCES.matches(sourceFile.getExecPath()); - boolean runCodeCoverage = - buildConfiguration.isCodeCoverageEnabled() && ObjcRuleClasses.isInstrumentable(sourceFile); - DotdFile dotdFile = intermediateArtifacts.dotdFile(sourceFile); - - CustomCommandLine commandLine = - compileActionCommandLine( - sourceFile, - objFile, - objcProvider, - priorityHeaders, - moduleMap, - getPchFile(), - Optional.of(dotdFile.artifact()), - otherFlags, - runCodeCoverage, - isCPlusPlusSource); - - Optional<Artifact> gcnoFile = Optional.absent(); - if (runCodeCoverage && !buildConfiguration.isLLVMCoverageMapFormatEnabled()) { - gcnoFile = Optional.of(intermediateArtifacts.gcnoFile(sourceFile)); - } - - NestedSet<Artifact> moduleMapInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER); - if (objcConfiguration.moduleMapsEnabled()) { - moduleMapInputs = objcProvider.get(MODULE_MAP); - } - - // TODO(bazel-team): Remove private headers from inputs once they're added to the provider. - ObjcCompileAction.Builder compileBuilder = - ObjcCompileAction.Builder.createObjcCompileActionBuilderWithAppleEnv( - XcodeConfigProvider.fromRuleContext(ruleContext), - appleConfiguration.getSingleArchPlatform()) - .setDotdPruningPlan(objcConfiguration.getDotdPruningPlan()) - .setSourceFile(sourceFile) - .addTransitiveHeaders(objcProvider.get(HEADER)) - .addHeaders(compilationArtifacts.getPrivateHdrs()) - .addTransitiveMandatoryInputs(moduleMapInputs) - .addTransitiveMandatoryInputs(objcProvider.get(STATIC_FRAMEWORK_FILE)) - .addTransitiveMandatoryInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE)) - .setDotdFile(dotdFile) - .addMandatoryInputs(getPchFile().asSet()); - - Artifact headersListFile = null; - if (isHeaderThinningEnabled() - && SOURCES_FOR_HEADER_THINNING.matches(sourceFile.getFilename())) { - headersListFile = intermediateArtifacts.headersListFile(sourceFile); - compileBuilder.setHeadersListFile(headersListFile); - } - - ruleContext.registerAction( - compileBuilder - .setMnemonic("ObjcCompile") - .setExecutable(xcrunwrapper(ruleContext)) - .addCommandLine(commandLine) - .addOutput(objFile) - .addOutputs(gcnoFile.asSet()) - .addOutput(dotdFile.artifact()) - .build(ruleContext)); - - return headersListFile == null - ? null - : new ObjcHeaderThinningInfo( - sourceFile, headersListFile, ImmutableList.copyOf(commandLine.arguments())); - } - - /** - * Registers a SpawnActionTemplate to compile the source file tree artifact, {@code sourceFiles}, - * which can contain multiple concrete source files unknown at analysis time. At execution time, - * the SpawnActionTemplate will register one ObjcCompile action for each individual source file - * under {@code sourceFiles}. - * - * <p>Note that this method currently does not support code coverage and sources other than ObjC - * sources. - * - * @param sourceFiles tree artifact containing source files to compile - * @param objFiles tree artifact containing object files compiled from {@code sourceFiles} - * @param objcProvider ObjcProvider instance for this invocation - * @param priorityHeaders priority headers to be included before the dependency headers - * @param moduleMap the module map generated from the associated headers - * @param compilationArtifacts the CompilationArtifacts instance for this invocation - * @param otherFlags extra compilation flags to add to the compile action command line - */ - private void registerCompileActionTemplate( - Artifact sourceFiles, - Artifact objFiles, - ObjcProvider objcProvider, - Iterable<PathFragment> priorityHeaders, - Optional<CppModuleMap> moduleMap, - CompilationArtifacts compilationArtifacts, - Iterable<String> otherFlags) { - CustomCommandLine commandLine = - compileActionCommandLine( - sourceFiles, - objFiles, - objcProvider, - priorityHeaders, - moduleMap, - getPchFile(), - Optional.<Artifact>absent(), - otherFlags, - /* collectCodeCoverage= */ false, - /* isCPlusPlusSource=*/ false); - - AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); - ApplePlatform platform = appleConfiguration.getSingleArchPlatform(); - - NestedSet<Artifact> moduleMapInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER); - if (objcConfiguration.moduleMapsEnabled()) { - moduleMapInputs = objcProvider.get(MODULE_MAP); - } - - ruleContext.registerAction( - new SpawnActionTemplate.Builder(sourceFiles, objFiles) - .setMnemonics("ObjcCompileActionTemplate", "ObjcCompile") - .setExecutable(xcrunwrapper(ruleContext)) - .setCommandLineTemplate(commandLine) - .setEnvironment( - ObjcRuleClasses.appleToolchainEnvironment( - XcodeConfigProvider.fromRuleContext(ruleContext), platform)) - .setExecutionInfo(ObjcRuleClasses.darwinActionExecutionRequirement()) - .setOutputPathMapper(COMPILE_ACTION_TEMPLATE_OUTPUT_PATH_MAPPER) - .addCommonTransitiveInputs(objcProvider.get(HEADER)) - .addCommonTransitiveInputs(moduleMapInputs) - .addCommonInputs(compilationArtifacts.getPrivateHdrs()) - .addCommonTransitiveInputs(objcProvider.get(STATIC_FRAMEWORK_FILE)) - .addCommonTransitiveInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE)) - .addCommonInputs(getPchFile().asSet()) - .build(ruleContext.getActionOwner())); - } - - private void registerArchiveActions(List<Artifact> objFiles, Artifact archive) { - Artifact objList = intermediateArtifacts.archiveObjList(); - registerObjFilelistAction(objFiles, objList); - registerArchiveAction(objFiles, archive); - } - - private void registerArchiveAction( - Iterable<Artifact> objFiles, - Artifact archive) { - Artifact objList = intermediateArtifacts.archiveObjList(); - ruleContext.registerAction( - ObjcRuleClasses.spawnAppleEnvActionBuilder( - XcodeConfigProvider.fromRuleContext(ruleContext), - appleConfiguration.getSingleArchPlatform()) - .setMnemonic("ObjcLink") - .setExecutable(libtool(ruleContext)) - .addCommandLine( - new CustomCommandLine.Builder() - .add("-static") - .addExecPath("-filelist", objList) - .add("-arch_only", appleConfiguration.getSingleArchitecture()) - .add("-syslibroot", AppleToolchain.sdkDir()) - .addExecPath("-o", archive) - .build()) - .addInputs(objFiles) - .addInput(objList) - .addOutput(archive) - .build(ruleContext)); - } - - @Override - protected CompilationSupport registerFullyLinkAction( - ObjcProvider objcProvider, Iterable<Artifact> inputArtifacts, Artifact outputArchive, - @Nullable CcToolchainProvider ccToolchain, @Nullable FdoSupportProvider fdoSupport) { - ruleContext.registerAction( - ObjcRuleClasses.spawnAppleEnvActionBuilder( - XcodeConfigProvider.fromRuleContext(ruleContext), - appleConfiguration.getSingleArchPlatform()) - .setMnemonic("ObjcLink") - .setExecutable(libtool(ruleContext)) - .addCommandLine( - new CustomCommandLine.Builder() - .add("-static") - .add("-arch_only", appleConfiguration.getSingleArchitecture()) - .add("-syslibroot", AppleToolchain.sdkDir()) - .addExecPath("-o", outputArchive) - .addExecPaths(ImmutableList.copyOf(inputArtifacts)) - .build()) - .addInputs(inputArtifacts) - .addOutput(outputArchive) - .build(ruleContext)); - return this; - } - - @Override - CompilationSupport registerLinkActions( - ObjcProvider objcProvider, - J2ObjcMappingFileProvider j2ObjcMappingFileProvider, - J2ObjcEntryClassProvider j2ObjcEntryClassProvider, - ExtraLinkArgs extraLinkArgs, - Iterable<Artifact> extraLinkInputs, - DsymOutputType dsymOutputType, - CcToolchainProvider toolchain) { - Optional<Artifact> dsymBundleZip; - Optional<Artifact> linkmap; - Optional<Artifact> bitcodeSymbolMap; - if (objcConfiguration.generateDsym()) { - registerDsymActions(dsymOutputType); - dsymBundleZip = Optional.of(intermediateArtifacts.tempDsymBundleZip(dsymOutputType)); - } else { - dsymBundleZip = Optional.absent(); - } - - Iterable<Artifact> prunedJ2ObjcArchives = - computeAndStripPrunedJ2ObjcArchives( - j2ObjcEntryClassProvider, j2ObjcMappingFileProvider, objcProvider); - - if (objcConfiguration.generateLinkmap()) { - linkmap = Optional.of(intermediateArtifacts.linkmap()); - } else { - linkmap = Optional.absent(); - } - - if (appleConfiguration.getBitcodeMode() == AppleBitcodeMode.EMBEDDED) { - bitcodeSymbolMap = Optional.of(intermediateArtifacts.bitcodeSymbolMap()); - } else { - bitcodeSymbolMap = Optional.absent(); - } - - registerLinkAction( - objcProvider, - extraLinkArgs, - extraLinkInputs, - dsymBundleZip, - prunedJ2ObjcArchives, - linkmap, - bitcodeSymbolMap); - return this; - } - - private StrippingType getStrippingType(CommandLine commandLine) { - try { - return Iterables.contains(commandLine.arguments(), "-dynamiclib") - ? StrippingType.DYNAMIC_LIB - : StrippingType.DEFAULT; - } catch (CommandLineExpansionException e) { - // This can't actually happen, because the command lines used by this class do - // not throw. This class is slated for deletion, so throwing an assertion is good enough. - throw new AssertionError("Cannot fail to expand command line but did.", e); - } - } - - private void registerLinkAction( - ObjcProvider objcProvider, - ExtraLinkArgs extraLinkArgs, - Iterable<Artifact> extraLinkInputs, - Optional<Artifact> dsymBundleZip, - Iterable<Artifact> prunedJ2ObjcArchives, - Optional<Artifact> linkmap, - Optional<Artifact> bitcodeSymbolMap) { - Artifact binaryToLink = getBinaryToLink(); - - ImmutableList<Artifact> objcLibraries = objcProvider.getObjcLibraries(); - ImmutableList<Artifact> ccLibraries = objcProvider.getCcLibraries(); - ImmutableList<Artifact> bazelBuiltLibraries = Iterables.isEmpty(prunedJ2ObjcArchives) - ? objcLibraries : substituteJ2ObjcPrunedLibraries(objcProvider); - CommandLine commandLine = - linkCommandLine( - extraLinkArgs, - objcProvider, - binaryToLink, - dsymBundleZip, - ccLibraries, - bazelBuiltLibraries, - linkmap, - bitcodeSymbolMap); - ruleContext.registerAction( - ObjcRuleClasses.spawnAppleEnvActionBuilder( - XcodeConfigProvider.fromRuleContext(ruleContext), - appleConfiguration.getSingleArchPlatform()) - .setMnemonic("ObjcLink") - .setShellCommand(ImmutableList.of("/bin/bash", "-c")) - .addCommandLine(new SingleArgCommandLine(commandLine)) - .addOutput(binaryToLink) - .addOutputs(dsymBundleZip.asSet()) - .addOutputs(linkmap.asSet()) - .addOutputs(bitcodeSymbolMap.asSet()) - .addInputs(bazelBuiltLibraries) - .addTransitiveInputs(objcProvider.get(IMPORTED_LIBRARY)) - .addTransitiveInputs(objcProvider.get(STATIC_FRAMEWORK_FILE)) - .addTransitiveInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE)) - .addTransitiveInputs(objcProvider.get(LINK_INPUTS)) - .addInputs(ccLibraries) - .addInputs(extraLinkInputs) - .addInputs(prunedJ2ObjcArchives) - .addInput(intermediateArtifacts.linkerObjList()) - .addInput(xcrunwrapper(ruleContext).getExecutable()) - .build(ruleContext)); - - if (objcConfiguration.shouldStripBinary()) { - registerBinaryStripAction(binaryToLink, getStrippingType(commandLine)); - } - } - - @Override - protected Set<String> frameworkNames(ObjcProvider objcProvider) { - Set<String> names = new LinkedHashSet<>(); - Iterables.addAll(names, SdkFramework.names(AUTOMATIC_SDK_FRAMEWORKS)); - names.addAll(super.frameworkNames(objcProvider)); - return names; - } - - private CommandLine linkCommandLine( - ExtraLinkArgs extraLinkArgs, - ObjcProvider objcProvider, - Artifact linkedBinary, - Optional<Artifact> dsymBundleZip, - Iterable<Artifact> ccLibraries, - Iterable<Artifact> bazelBuiltLibraries, - Optional<Artifact> linkmap, - Optional<Artifact> bitcodeSymbolMap) { - ImmutableList<String> libraryNames = libraryNames(objcProvider); - - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder() - .addPath(xcrunwrapper(ruleContext).getExecutable().getExecPath()); - if (objcProvider.is(USES_CPP)) { - commandLine - .add(CLANG_PLUSPLUS) - .add("-stdlib=libc++") - .add("-std=gnu++11"); - } else { - commandLine.add(CLANG); - } - - // TODO(b/36562173): Replace the "!isTestRule" condition with the presence of "-bundle" in - // the command line. - if (objcConfiguration.shouldStripBinary() && !isTestRule) { - commandLine.add("-dead_strip").add("-no_dead_strip_inits_and_terms"); - } - - Iterable<Artifact> ccLibrariesToForceLoad = - Iterables.filter(ccLibraries, ALWAYS_LINKED_CC_LIBRARY); - - ImmutableSet<Artifact> forceLinkArtifacts = ImmutableSet.<Artifact>builder() - .addAll(objcProvider.get(FORCE_LOAD_LIBRARY)) - .addAll(ccLibrariesToForceLoad).build(); - - Artifact inputFileList = intermediateArtifacts.linkerObjList(); - Iterable<Artifact> objFiles = - Iterables.concat(bazelBuiltLibraries, objcProvider.get(IMPORTED_LIBRARY), ccLibraries); - // Clang loads archives specified in filelists and also specified as -force_load twice, - // resulting in duplicate symbol errors unless they are deduped. - objFiles = Iterables.filter(objFiles, Predicates.not(Predicates.in(forceLinkArtifacts))); - - registerObjFilelistAction(objFiles, inputFileList); - - commandLine.add("-filelist", inputFileList.getExecPathString()); - - AppleBitcodeMode bitcodeMode = appleConfiguration.getBitcodeMode(); - commandLine.addAll(bitcodeMode.getCompileAndLinkFlags()); - - if (bitcodeMode == AppleBitcodeMode.EMBEDDED) { - commandLine.add("-Xlinker").add("-bitcode_verify"); - commandLine.add("-Xlinker").add("-bitcode_hide_symbols"); - commandLine - .add("-Xlinker") - .add("-bitcode_symbol_map") - .add("-Xlinker") - .addExecPath(bitcodeSymbolMap.get()); - } - - commandLine - .addAll( - commonLinkAndCompileFlagsForClang(objcProvider, objcConfiguration, appleConfiguration)) - .add("-Xlinker") - .add("-objc_abi_version") - .add("-Xlinker") - .add("2") - // Set the rpath so that at runtime dylibs can be loaded from the bundle root's "Frameworks" - // directory. - .add("-Xlinker") - .add("-rpath") - .add("-Xlinker") - .add("@executable_path/Frameworks") - .add("-fobjc-link-runtime") - .addAll(DEFAULT_LINKER_FLAGS) - .addAll(VectorArg.addBefore("-framework").each(frameworkNames(objcProvider))) - .addAll( - VectorArg.addBefore("-weak_framework") - .each(SdkFramework.names(objcProvider.get(WEAK_SDK_FRAMEWORK)))) - .addAll(VectorArg.format("-l%s").each(libraryNames)) - .addExecPath("-o", linkedBinary) - .addExecPaths(VectorArg.addBefore("-force_load").each(forceLinkArtifacts)) - .addAll(ImmutableList.copyOf(extraLinkArgs)) - .addAll(objcProvider.get(ObjcProvider.LINKOPT)); - - if (buildConfiguration.isCodeCoverageEnabled()) { - if (buildConfiguration.isLLVMCoverageMapFormatEnabled()) { - commandLine.addAll(LINKER_LLVM_COVERAGE_FLAGS); - } else { - commandLine.addAll(LINKER_COVERAGE_FLAGS); - } - } - - for (String linkopt : attributes.linkopts()) { - commandLine.addFormatted("-Wl,%s", linkopt); - } - - if (linkmap.isPresent()) { - commandLine.add("-Xlinker -map").addPath("-Xlinker ", linkmap.get().getExecPath()); - } - - // Call to dsymutil for debug symbol generation must happen in the link action. - // All debug symbol information is encoded in object files inside archive files. To generate - // the debug symbol bundle, dsymutil will look inside the linked binary for the encoded - // absolute paths to archive files, which are only valid in the link action. - if (dsymBundleZip.isPresent()) { - PathFragment dsymPath = FileSystemUtils.removeExtension(dsymBundleZip.get().getExecPath()); - commandLine - .add("&&") - .addPath(xcrunwrapper(ruleContext).getExecutable().getExecPath()) - .add(DSYMUTIL) - .addExecPath(linkedBinary) - .addPath("-o", dsymPath) - .addDynamicString( - "&& zipped_bundle=${PWD}/" + dsymBundleZip.get().getShellEscapedExecPathString()) - .addDynamicString("&& cd " + dsymPath) - .add("&& /usr/bin/zip -q -r \"${zipped_bundle}\" ."); - } - - return commandLine.build(); - } - - /** - * Command line that converts its input's arg array to a single input. - * - * <p>Required as a hack to the link command line because that may contain two commands, which are - * then passed to {@code /bin/bash -c}, and accordingly need to be a single argument. - */ - @Immutable // if original is immutable - private static final class SingleArgCommandLine extends CommandLine { - private final CommandLine original; - - private SingleArgCommandLine(CommandLine original) { - this.original = original; - } - - @Override - public Iterable<String> arguments() throws CommandLineExpansionException { - return ImmutableList.of(Joiner.on(' ').join(original.arguments())); - } - } - - /** - * This method is necessary because - * {@link XcodeConfig#getMinimumOsForPlatformType(RuleContext, ApplePlatform.PlatformType)} uses - * the configuration of whichever rule it was called from; however, we are interested in the - * minimum versions for the dependencies here, which are possibly behind a configuration - * transition. - * - * <p>It's kosher to reach into {@link }AppleConfiguration} this way because we don't touch - * anything that may be tainted by data from BUILD files, only the options, which are directly - * passed into the configuration loader. - */ - private DottedVersion getExplicitMinimumOsVersion( - AppleConfiguration configuration, ApplePlatform.PlatformType platformType) { - AppleCommandLineOptions options = configuration.getOptions(); - switch (platformType) { - case IOS: - return options.iosMinimumOs; - case WATCHOS: - return options.watchosMinimumOs; - case TVOS: - return options.tvosMinimumOs; - case MACOS: - return options.macosMinimumOs; - default: - throw new IllegalStateException("Unhandled platform type: " + platformType); - } - } - - /** Returns a list of clang flags used for all link and compile actions executed through clang. */ - private ImmutableList<String> commonLinkAndCompileFlagsForClang( - ObjcProvider provider, - ObjcConfiguration objcConfiguration, - AppleConfiguration appleConfiguration) { - ImmutableList.Builder<String> builder = new ImmutableList.Builder<>(); - ApplePlatform platform = appleConfiguration.getSingleArchPlatform(); - String minOSVersionArg; - switch (platform) { - case IOS_SIMULATOR: - minOSVersionArg = "-mios-simulator-version-min"; - break; - case IOS_DEVICE: - minOSVersionArg = "-miphoneos-version-min"; - break; - case WATCHOS_SIMULATOR: - minOSVersionArg = "-mwatchos-simulator-version-min"; - break; - case WATCHOS_DEVICE: - minOSVersionArg = "-mwatchos-version-min"; - break; - case TVOS_SIMULATOR: - minOSVersionArg = "-mtvos-simulator-version-min"; - break; - case TVOS_DEVICE: - minOSVersionArg = "-mtvos-version-min"; - break; - default: - throw new IllegalArgumentException("Unhandled platform " + platform); - } - DottedVersion minOSVersion = - getExplicitMinimumOsVersion(appleConfiguration, platform.getType()); - if (minOSVersion == null) { - minOSVersion = XcodeConfig.getMinimumOsForPlatformType(ruleContext, platform.getType()); - } - builder.add(minOSVersionArg + "=" + minOSVersion); - - if (objcConfiguration.generateDsym()) { - builder.add("-g"); - } - - return builder - .add("-arch", appleConfiguration.getSingleArchitecture()) - .add("-isysroot", AppleToolchain.sdkDir()) - // TODO(bazel-team): Pass framework search paths to Xcodegen. - .addAll(commonFrameworkFlags(provider, ruleContext, platform)) - .build(); - } - - private static Iterable<String> compileFlagsForClang(AppleConfiguration configuration) { - return Iterables.concat( - AppleToolchain.DEFAULT_WARNINGS.values(), - platformSpecificCompileFlagsForClang(configuration), - configuration.getBitcodeMode().getCompileAndLinkFlags(), - DEFAULT_COMPILER_FLAGS - ); - } - - private static List<String> platformSpecificCompileFlagsForClang( - AppleConfiguration configuration) { - switch (configuration.getSingleArchPlatform()) { - case IOS_DEVICE: - case WATCHOS_DEVICE: - case TVOS_DEVICE: - return ImmutableList.of(); - case IOS_SIMULATOR: - case WATCHOS_SIMULATOR: - case TVOS_SIMULATOR: - return SIMULATOR_COMPILE_FLAGS; - default: - throw new AssertionError(); - } - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java index 176840b2f9..ec50abc4b7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java @@ -20,7 +20,6 @@ import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.rules.apple.DottedVersion; import com.google.devtools.build.lib.rules.apple.DottedVersionConverter; import com.google.devtools.common.options.Converters.CommaSeparatedOptionListConverter; -import com.google.devtools.common.options.EnumConverter; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionDocumentationCategory; import com.google.devtools.common.options.OptionEffectTag; @@ -239,38 +238,6 @@ public class ObjcCommandLineOptions extends FragmentOptions { ) public boolean deviceDebugEntitlements; - /** Specifies the circumstances under which a CROSSTOOL is used for objc in this configuration. */ - public enum ObjcCrosstoolMode { - /** The CROSSTOOL is used for all objc compile, archive, and link actions. */ - ALL, - - /** - * The CROSSTOOL is used for all objc compile and archive actions originating from an - * objc_library target. - */ - LIBRARY, - - /** The CROSSTOOL is not used for any objc action. */ - OFF - } - - /** Converter for {@link ObjcCrosstoolMode}. */ - public static class ObjcCrosstoolUsageConverter extends EnumConverter<ObjcCrosstoolMode> { - public ObjcCrosstoolUsageConverter() { - super(ObjcCrosstoolMode.class, "objc crosstool mode"); - } - } - - @Option( - name = "experimental_objc_crosstool", - defaultValue = "all", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = {OptionEffectTag.CHANGES_INPUTS}, - metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE}, - converter = ObjcCrosstoolUsageConverter.class - ) - public ObjcCrosstoolMode objcCrosstoolMode; - @Option( name = "objc_use_dotd_pruning", defaultValue = "true", diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java deleted file mode 100644 index 0e179314a2..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2016 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.devtools.build.lib.rules.objc; - -import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.devtools.build.lib.actions.ActionEnvironment; -import com.google.devtools.build.lib.actions.ActionExecutionContext; -import com.google.devtools.build.lib.actions.ActionExecutionException; -import com.google.devtools.build.lib.actions.ActionInput; -import com.google.devtools.build.lib.actions.ActionOwner; -import com.google.devtools.build.lib.actions.ActionResult; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.ArtifactResolver; -import com.google.devtools.build.lib.actions.CommandLineExpansionException; -import com.google.devtools.build.lib.actions.ExecException; -import com.google.devtools.build.lib.actions.ResourceSet; -import com.google.devtools.build.lib.actions.RunfilesSupplier; -import com.google.devtools.build.lib.actions.Spawn; -import com.google.devtools.build.lib.actions.extra.SpawnInfo; -import com.google.devtools.build.lib.analysis.actions.CommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.collect.nestedset.Order; -import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible; -import com.google.devtools.build.lib.profiler.Profiler; -import com.google.devtools.build.lib.profiler.ProfilerTask; -import com.google.devtools.build.lib.rules.apple.ApplePlatform; -import com.google.devtools.build.lib.rules.apple.XcodeConfigProvider; -import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile; -import com.google.devtools.build.lib.rules.cpp.CppFileTypes; -import com.google.devtools.build.lib.rules.cpp.HeaderDiscovery; -import com.google.devtools.build.lib.rules.cpp.IncludeScanningContext; -import com.google.devtools.build.lib.util.DependencySet; -import com.google.devtools.build.lib.util.Fingerprint; -import com.google.devtools.build.lib.vfs.Path; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * An action that compiles objc or objc++ source. - * - * <p>We don't use a plain SpawnAction here because we implement .d input pruning, which requires - * post-execution filtering of input artifacts. - * - * <p>Additionally the header thinning feature is implemented here which, like .d input pruning, - * reduces the action inputs to just the required set of headers for improved performance. Unlike - * dotd it does so via the discoverInputs mechanism before execution. - * - * <p>We don't use a CppCompileAction because the ObjcCompileAction uses custom logic instead of the - * CROSSTOOL to construct its command line. - */ -public class ObjcCompileAction extends SpawnAction { - - /** - * A spawn that provides all headers to sandboxed execution to allow pruned headers to be - * re-introduced into action inputs. - */ - public class ObjcCompileActionSpawn extends ActionSpawn { - - public ObjcCompileActionSpawn(ImmutableList<String> arguments, Map<String, String> clientEnv) { - super(arguments, clientEnv); - } - - @Override - public Iterable<? extends ActionInput> getInputFiles() { - ImmutableList.Builder<ActionInput> listBuilder = - ImmutableList.<ActionInput>builder().addAll(super.getInputFiles()); - // Normally discoveredInputs should not be null when this is called, however that may occur if - // the extra action feature is used - if (discoveredInputs != null) { - listBuilder.addAll(discoveredInputs); - } - return listBuilder.build(); - } - } - - private final DotdFile dotdFile; - private final Artifact sourceFile; - private final NestedSet<Artifact> mandatoryInputs; - private final HeaderDiscovery.DotdPruningMode dotdPruningPlan; - private final NestedSet<Artifact> headers; - private final Artifact headersListFile; - - private Iterable<Artifact> discoveredInputs; - - private static final String GUID = "a00d5bac-a72c-4f0f-99a7-d5fdc6072137"; - - private ObjcCompileAction( - ActionOwner owner, - Iterable<Artifact> tools, - Iterable<Artifact> inputs, - Iterable<Artifact> outputs, - ResourceSet resourceSet, - CommandLine argv, - boolean isShellCommand, - ActionEnvironment env, - ImmutableMap<String, String> executionInfo, - CharSequence progressMessage, - RunfilesSupplier runfilesSupplier, - String mnemonic, - boolean executeUnconditionally, - ExtraActionInfoSupplier<?> extraActionInfoSupplier, - DotdFile dotdFile, - Artifact sourceFile, - NestedSet<Artifact> mandatoryInputs, - HeaderDiscovery.DotdPruningMode dotdPruningPlan, - NestedSet<Artifact> headers, - @Nullable Artifact headersListFile) { - super( - owner, - tools, - headersListFile == null ? inputs : mandatoryInputs, - outputs, - resourceSet, - argv, - isShellCommand, - env, - executionInfo, - progressMessage, - runfilesSupplier, - mnemonic, - executeUnconditionally, - extraActionInfoSupplier); - - this.dotdFile = dotdFile; - this.sourceFile = sourceFile; - this.mandatoryInputs = mandatoryInputs; - this.dotdPruningPlan = dotdPruningPlan; - this.headers = headers; - this.headersListFile = headersListFile; - } - - private Iterable<Artifact> filterHeaderFiles() { - ImmutableList.Builder<Artifact> inputs = ImmutableList.<Artifact>builder(); - - for (Artifact headerArtifact : headers) { - if (CppFileTypes.OBJC_HEADER.matches(headerArtifact.getFilename()) - // C++ headers can be extensionless - || (!headerArtifact.isFileset() && headerArtifact.getExtension().isEmpty())) { - inputs.add(headerArtifact); - } - } - return inputs.build(); - } - - /** Returns the DotdPruningPlan for this compile */ - @VisibleForTesting - public HeaderDiscovery.DotdPruningMode getDotdPruningPlan() { - return dotdPruningPlan; - } - - @Override - public final Spawn getSpawn(Map<String, String> clientEnv) { - try { - return new ObjcCompileActionSpawn( - ImmutableList.copyOf(getCommandLine().arguments()), clientEnv); - } catch (CommandLineExpansionException e) { - throw new AssertionError("ObjcCompileAction command line expansion cannot fail"); - } - } - - @Override - public boolean discoversInputs() { - return true; - } - - @Override - public synchronized Iterable<Artifact> discoverInputs( - ActionExecutionContext actionExecutionContext) - throws ActionExecutionException, InterruptedException { - if (headersListFile != null) { - try { - discoveredInputs = - HeaderThinning.findRequiredHeaderInputs( - sourceFile, headersListFile, getAllowedDerivedInputsMap(false)); - } catch (ExecException e) { - throw e.toActionExecutionException( - "Header thinning of rule '" + getOwner().getLabel() + "'", - actionExecutionContext.getVerboseFailures(), - this); - } - } else { - discoveredInputs = filterHeaderFiles(); - } - return discoveredInputs; - } - - @Override - public ImmutableSet<Artifact> getMandatoryOutputs() { - return ImmutableSet.of(dotdFile.artifact()); - } - - @Override - public ActionResult execute(ActionExecutionContext actionExecutionContext) - throws ActionExecutionException, InterruptedException { - ActionResult actionResult = super.execute(actionExecutionContext); - - if (dotdPruningPlan == HeaderDiscovery.DotdPruningMode.USE) { - IncludeScanningContext scanningContext = - actionExecutionContext.getContext(IncludeScanningContext.class); - NestedSet<Artifact> discoveredInputs = - discoverInputsFromDotdFiles( - actionExecutionContext.getExecRoot(), scanningContext.getArtifactResolver()); - - updateActionInputs(discoveredInputs); - } else { - // TODO(lberki): This is awkward, but necessary since updateInputs() must be called when - // input discovery is in effect. I *think* it's possible to avoid setting discoversInputs() - // to true if the header list file is null and then we'd not need to have this here, but I - // haven't quite managed to get that right yet. - updateActionInputs(getInputs()); - } - - return actionResult; - } - - @VisibleForTesting - public NestedSet<Artifact> discoverInputsFromDotdFiles( - Path execRoot, ArtifactResolver artifactResolver) throws ActionExecutionException { - if (dotdFile == null) { - return NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER); - } - return new HeaderDiscovery.Builder() - .setAction(this) - .setSourceFile(sourceFile) - .setDependencies(processDepset(execRoot).getDependencies()) - .setPermittedSystemIncludePrefixes(ImmutableList.<Path>of()) - .setAllowedDerivedinputsMap(getAllowedDerivedInputsMap(true)) - .build() - .discoverInputsFromDependencies(execRoot, artifactResolver); - } - - private DependencySet processDepset(Path execRoot) throws ActionExecutionException { - try { - DependencySet depSet = new DependencySet(execRoot); - return depSet.read(dotdFile.getPath()); - } catch (IOException e) { - // Some kind of IO or parse exception--wrap & rethrow it to stop the build. - throw new ActionExecutionException("error while parsing .d file", e, this, false); - } - } - - /** - * Returns a map of input and header artifacts for this action. - * - * @param excludeSourceArtifacts If true artifacts where {@link Artifact#isSourceArtifact()} is - * true are excluded from the map - */ - private Map<PathFragment, Artifact> getAllowedDerivedInputsMap(boolean excludeSourceArtifacts) { - // LinkedHashMap required here as it is not guaranteed that entries are unique and to preserve - // insertion order - Map<PathFragment, Artifact> allowedDerivedInputMap = new LinkedHashMap<>(); - for (Artifact artifact : Iterables.concat(mandatoryInputs, headers)) { - if (!excludeSourceArtifacts || !artifact.isSourceArtifact()) { - allowedDerivedInputMap.put(artifact.getExecPath(), artifact); - } - } - return allowedDerivedInputMap; - } - - @Override - public Iterable<Artifact> getAllowedDerivedInputs() { - return getAllowedDerivedInputsMap(true).values(); - } - - /** - * Recalculates this action's live input collection, including sources, middlemen. - * - * @throws ActionExecutionException iff any errors happen during update. - */ - @VisibleForTesting // productionVisibility = Visibility.PRIVATE - @ThreadCompatible - final void updateActionInputs(Iterable<Artifact> discoveredInputs) - throws ActionExecutionException { - Profiler.instance().startTask(ProfilerTask.ACTION_UPDATE, this); - try { - updateInputs(Iterables.concat(mandatoryInputs, discoveredInputs)); - } finally { - Profiler.instance().completeTask(ProfilerTask.ACTION_UPDATE); - } - } - - @Override - protected SpawnInfo getExtraActionSpawnInfo() { - SpawnInfo.Builder info = null; - try { - info = SpawnInfo.newBuilder(super.getExtraActionSpawnInfo()); - } catch (CommandLineExpansionException e) { - throw new AssertionError("ObjcCompileAction command line expansion cannot fail"); - } - if (!inputsDiscovered()) { - for (Artifact headerArtifact : filterHeaderFiles()) { - // As in SpawnAction#getExtraActionSpawnInfo explicitly ignore middleman artifacts here. - if (!headerArtifact.isMiddlemanArtifact()) { - info.addInputFile(headerArtifact.getExecPathString()); - } - } - } - return info.build(); - } - - @Override - public String computeKey() { - Fingerprint f = new Fingerprint(); - f.addString(GUID); - try { - f.addString(super.computeKey()); - } catch (CommandLineExpansionException e) { - throw new AssertionError("ObjcCompileAction command line expansion cannot fail"); - } - f.addBoolean(dotdFile == null || dotdFile.artifact() == null); - f.addBoolean(dotdPruningPlan == HeaderDiscovery.DotdPruningMode.USE); - f.addBoolean(headersListFile == null); - if (dotdFile != null) { - f.addPath(dotdFile.getSafeExecPath()); - } - return f.hexDigestAndReset(); - } - - /** A Builder for ObjcCompileAction */ - public static class Builder extends SpawnAction.Builder { - - private DotdFile dotdFile; - private Artifact sourceFile; - private Artifact headersListFile; - private final NestedSetBuilder<Artifact> mandatoryInputs = new NestedSetBuilder<>(STABLE_ORDER); - private HeaderDiscovery.DotdPruningMode dotdPruningPlan; - private final NestedSetBuilder<Artifact> headers = NestedSetBuilder.stableOrder(); - - /** - * Creates a new compile action builder with apple environment variables set that are typically - * needed by the apple toolchain. - */ - public static ObjcCompileAction.Builder createObjcCompileActionBuilderWithAppleEnv( - XcodeConfigProvider xcodeConfigProvider, ApplePlatform targetPlatform) { - return (Builder) - new ObjcCompileAction.Builder() - .setExecutionInfo(ObjcRuleClasses.darwinActionExecutionRequirement()) - .setEnvironment( - ObjcRuleClasses.appleToolchainEnvironment(xcodeConfigProvider, targetPlatform)); - } - - @Override - public Builder addTools(Iterable<Artifact> artifacts) { - super.addTools(artifacts); - mandatoryInputs.addAll(artifacts); - return this; - } - - @Override - public Builder addTransitiveTools(NestedSet<Artifact> artifacts) { - super.addTransitiveTools(artifacts); - mandatoryInputs.addTransitive(artifacts); - return this; - } - - /** Sets a .d file that will used to prune input headers */ - public Builder setDotdFile(DotdFile dotdFile) { - Preconditions.checkNotNull(dotdFile); - this.dotdFile = dotdFile; - return this; - } - - /** - * Sets a .headers_list file that is generated for the header thinning feature. File is used to - * discover required inputs to compile action and update action inputs. - */ - public Builder setHeadersListFile(Artifact headersListFile) { - Preconditions.checkNotNull(headersListFile); - this.headersListFile = headersListFile; - this.addMandatoryInput(headersListFile); - return this; - } - - /** Sets the source file that is being compiled in this action */ - public Builder setSourceFile(Artifact sourceFile) { - Preconditions.checkNotNull(sourceFile); - this.sourceFile = sourceFile; - this.mandatoryInputs.add(sourceFile); - this.addInput(sourceFile); - return this; - } - - /** Add an input that cannot be pruned */ - public Builder addMandatoryInput(Artifact input) { - Preconditions.checkNotNull(input); - this.mandatoryInputs.add(input); - this.addInput(input); - return this; - } - - /** Add inputs that cannot be pruned */ - public Builder addMandatoryInputs(Iterable<Artifact> input) { - Preconditions.checkNotNull(input); - this.mandatoryInputs.addAll(input); - this.addInputs(input); - return this; - } - - /** Add inputs that cannot be pruned */ - public Builder addTransitiveMandatoryInputs(NestedSet<Artifact> input) { - Preconditions.checkNotNull(input); - this.mandatoryInputs.addTransitive(input); - this.addTransitiveInputs(input); - return this; - } - - /** Indicates that this compile action should perform .d pruning */ - public Builder setDotdPruningPlan(HeaderDiscovery.DotdPruningMode dotdPruningPlan) { - Preconditions.checkNotNull(dotdPruningPlan); - this.dotdPruningPlan = dotdPruningPlan; - return this; - } - - /** Adds to the set of all possible headers that could be required by this compile action. */ - public Builder addTransitiveHeaders(NestedSet<Artifact> headers) { - this.headers.addTransitive(Preconditions.checkNotNull(headers)); - this.addTransitiveInputs(headers); - return this; - } - - /** Adds to the set of all possible headers that could be required by this compile action. */ - public Builder addHeaders(Iterable<Artifact> headers) { - this.headers.addAll(Preconditions.checkNotNull(headers)); - this.addInputs(headers); - return this; - } - - @Override - protected SpawnAction createSpawnAction( - ActionOwner owner, - NestedSet<Artifact> tools, - NestedSet<Artifact> inputsAndTools, - ImmutableList<Artifact> outputs, - ResourceSet resourceSet, - CommandLine actualCommandLine, - boolean isShellCommand, - ActionEnvironment env, - ImmutableMap<String, String> executionInfo, - CharSequence progressMessage, - RunfilesSupplier runfilesSupplier, - String mnemonic) { - return new ObjcCompileAction( - owner, - tools, - inputsAndTools, - outputs, - resourceSet, - actualCommandLine, - isShellCommand, - // TODO(#3320): This is missing the inherited action env from --action_env. - ActionEnvironment.create(env.getFixedEnv()), - executionInfo, - progressMessage, - runfilesSupplier, - mnemonic, - executeUnconditionally, - extraActionInfoSupplier, - dotdFile, - sourceFile, - mandatoryInputs.build(), - dotdPruningPlan, - headers.build(), - headersListFile); - } - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java index b3f0f6abd4..c57592226f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java @@ -23,7 +23,6 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.rules.apple.ApplePlatform.PlatformType; import com.google.devtools.build.lib.rules.apple.DottedVersion; import com.google.devtools.build.lib.rules.cpp.HeaderDiscovery; -import com.google.devtools.build.lib.rules.objc.ObjcCommandLineOptions.ObjcCrosstoolMode; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; @@ -70,7 +69,6 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { private final boolean debugWithGlibcxx; @Nullable private final Label extraEntitlements; private final boolean deviceDebugEntitlements; - private final ObjcCrosstoolMode objcCrosstoolMode; private final boolean enableAppleBinaryNativeProtos; private final HeaderDiscovery.DotdPruningMode dotdPruningPlan; private final boolean experimentalHeaderThinning; @@ -103,7 +101,6 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { this.debugWithGlibcxx = objcOptions.debugWithGlibcxx; this.extraEntitlements = objcOptions.extraEntitlements; this.deviceDebugEntitlements = objcOptions.deviceDebugEntitlements; - this.objcCrosstoolMode = objcOptions.objcCrosstoolMode; this.enableAppleBinaryNativeProtos = objcOptions.enableAppleBinaryNativeProtos; this.dotdPruningPlan = objcOptions.useDotdPruning @@ -290,14 +287,6 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { return deviceDebugEntitlements && compilationMode != CompilationMode.OPT; } - /** - * Returns an {@link ObjcCrosstoolMode} that specifies the circumstances under which a - * CROSSTOOL is used for objc in this configuration. - */ - public ObjcCrosstoolMode getObjcCrosstoolMode() { - return objcCrosstoolMode; - } - /** Returns true if apple_binary targets should generate and link Objc protos. */ @SkylarkCallable(name = "enable_apple_binary_native_protos", structField = true, doc = "Returns whether apple_binary should generate and link protos natively.") diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java index be449de555..7ad60f0c46 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java @@ -71,7 +71,6 @@ public class ObjcLibrary implements RuleConfiguredTargetFactory { new CompilationSupport.Builder() .setRuleContext(ruleContext) .setOutputGroupCollector(outputGroupCollector) - .setIsObjcLibrary() .build(); compilationSupport |