diff options
author | 2018-02-08 01:42:23 -0800 | |
---|---|---|
committer | 2018-02-08 01:44:21 -0800 | |
commit | 8a96fe9bc1472656cecc420df881181340b82a40 (patch) | |
tree | 176a8d459dc3a8224fea3a5dc62975e0170b91b9 /src | |
parent | e7541262293977598ad96d9eb7a83b439eedd634 (diff) |
C++: Split C++ library into two classes, compilation and linking
These will be separate calls in the Skylark API.
RELNOTES:none
PiperOrigin-RevId: 184961734
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java | 25 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java | 28 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java (renamed from src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java) | 902 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java | 26 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java | 22 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java | 30 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java | 706 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java | 2 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java | 52 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java | 274 |
10 files changed, 1091 insertions, 976 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java index d72d44d015..61f6c2a18c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java @@ -48,7 +48,7 @@ import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.rules.apple.ApplePlatform; import com.google.devtools.build.lib.rules.cpp.CcCommon.CcFlagsSupplier; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.DynamicMode; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool; @@ -212,14 +212,15 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory { return null; } - CcLibraryHelper compilationHelper = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + CcCompilationHelper compilationHelper = + new CcCompilationHelper( + ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) .fromCommon(common) .addSources(common.getSources()) .addDeps(ImmutableList.of(CppHelper.mallocForTarget(ruleContext))) .setFake(fake) .addPrecompiledFiles(precompiledFiles); - Info.CompilationInfo compilationInfo = compilationHelper.compile(); + CompilationInfo compilationInfo = compilationHelper.compile(); CppCompilationContext cppCompilationContext = compilationInfo.getCppCompilationContext(); CcCompilationOutputs ccCompilationOutputs = compilationInfo.getCcCompilationOutputs(); @@ -232,11 +233,11 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory { && cppConfiguration.getLinkCompileOutputSeparately() && linkStaticness == LinkStaticness.DYNAMIC; // When linking the object files directly into the resulting binary, we do not need - // library-level link outputs; thus, we do not let CcLibraryHelper produce link outputs + // library-level link outputs; thus, we do not let CcCompilationHelper produce link outputs // (either shared object files or archives) for a non-library link type [*], and add // the object files explicitly in determineLinkerArguments. // - // When linking the object files into their own library, we want CcLibraryHelper to + // When linking the object files into their own library, we want CcCompilationHelper to // take care of creating the library link outputs for us, so we need to set the link // type to STATIC_LIBRARY. // @@ -245,8 +246,14 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory { // output matching a shared object, for example cc_binary(name="foo.so", ...) on linux. CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY; if (linkCompileOutputSeparately) { - CcLibraryHelper linkingHelper = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + CcLinkingHelper linkingHelper = + new CcLinkingHelper( + ruleContext, + semantics, + featureConfiguration, + ccToolchain, + fdoSupport, + ruleContext.getConfiguration()) .fromCommon(common) .addDeps(ImmutableList.of(CppHelper.mallocForTarget(ruleContext))) .setFake(fake) @@ -868,7 +875,7 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory { instrumentedObjectFiles, !TargetUtils.isTestRule(ruleContext.getRule()) && !fake); NestedSet<Artifact> headerTokens = - CcLibraryHelper.collectHeaderTokens(ruleContext, ccCompilationOutputs); + CcCompilationHelper.collectHeaderTokens(ruleContext, ccCompilationOutputs); NestedSet<Artifact> filesToCompile = ccCompilationOutputs.getFilesToCompile( cppConfiguration.isLipoContextCollector(), diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java index 07e2ca9408..8d599be1f1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java @@ -43,7 +43,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.rules.apple.ApplePlatform; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.SourceCategory; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.SourceCategory; 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; @@ -60,6 +60,7 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.TreeMap; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.annotation.Nullable; @@ -149,6 +150,31 @@ public final class CcCommon { } /** + * Merges a list of output groups into one. The sets for each entry with a given key are merged. + */ + public static Map<String, NestedSet<Artifact>> mergeOutputGroups( + ImmutableList<Map<String, NestedSet<Artifact>>> outputGroups) { + Map<String, NestedSetBuilder<Artifact>> mergedOutputGroupsBuilder = new TreeMap<>(); + + for (Map<String, NestedSet<Artifact>> outputGroup : outputGroups) { + for (Map.Entry<String, NestedSet<Artifact>> entryOutputGroup : outputGroup.entrySet()) { + String key = entryOutputGroup.getKey(); + mergedOutputGroupsBuilder.computeIfAbsent( + key, (String k) -> NestedSetBuilder.compileOrder()); + mergedOutputGroupsBuilder.get(key).addTransitive(entryOutputGroup.getValue()); + } + } + + Map<String, NestedSet<Artifact>> mergedOutputGroups = new TreeMap<>(); + for (Map.Entry<String, NestedSetBuilder<Artifact>> entryOutputGroupBuilder : + mergedOutputGroupsBuilder.entrySet()) { + mergedOutputGroups.put( + entryOutputGroupBuilder.getKey(), entryOutputGroupBuilder.getValue().build()); + } + return mergedOutputGroups; + } + + /** * Returns our own linkopts from the rule attribute. This determines linker * options to use when building this target and anything that depends on it. */ diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java index e898aa4820..d6464d1340 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.rules.cpp; -import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toCollection; import com.google.common.base.Function; @@ -22,20 +21,13 @@ import com.google.common.base.Optional; 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.ImmutableSetMultimap; import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; -import com.google.common.collect.Streams; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.AnalysisUtils; -import com.google.devtools.build.lib.analysis.FileProvider; import com.google.devtools.build.lib.analysis.LanguageDependentFragment; import com.google.devtools.build.lib.analysis.OutputGroupInfo; import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap; import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder; @@ -52,9 +44,6 @@ import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter; 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.CppConfiguration.HeadersCheckingMode; -import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; -import com.google.devtools.build.lib.rules.cpp.Link.Staticness; -import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.util.FileTypeSet; import com.google.devtools.build.lib.util.Pair; @@ -70,33 +59,24 @@ import java.util.TreeMap; import javax.annotation.Nullable; /** - * A class to create C/C++ compile and link actions in a way that is consistent with cc_library. - * Rules that generate source files and emulate cc_library on top of that should use this class - * instead of the lower-level APIs in CppHelper and CppModel. + * A class to create C/C++ compile actions in a way that is consistent with cc_library. Rules that + * generate source files and emulate cc_library on top of that should use this class instead of the + * lower-level APIs in CppHelper and CppModel. * * <p>Rules that want to use this class are required to have implicit dependencies on the toolchain, * the STL, the lipo context, and so on. Optionally, they can also have copts, and malloc * attributes, but note that these require explicit calls to the corresponding setter methods. - * TODO(plf): Split this class in two, one for compilation and other for linking. */ -public final class CcLibraryHelper { - /** - * Similar to {@code OutputGroupInfo.HIDDEN_TOP_LEVEL}, but specific to header token files. - */ +public final class CcCompilationHelper { + /** Similar to {@code OutputGroupInfo.HIDDEN_TOP_LEVEL}, but specific to header token files. */ public static final String HIDDEN_HEADER_TOKENS = OutputGroupInfo.HIDDEN_OUTPUT_GROUP_PREFIX + "hidden_header_tokens" + OutputGroupInfo.INTERNAL_SUFFIX; - /** A string constant for the name of archive library(.a, .lo) output group. */ - public static final String ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME = "archive"; - - /** A string constant for the name of dynamic library output group. */ - public static final String DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME = "dynamic_library"; - /** - * A group of source file types and action names for builds controlled by CcLibraryHelper. - * Determines what file types CcLibraryHelper considers sources and what action configs are + * A group of source file types and action names for builds controlled by CcCompilationHelper. + * Determines what file types CcCompilationHelper considers sources and what action configs are * configured in the CROSSTOOL. */ public enum SourceCategory { @@ -124,150 +104,42 @@ public final class CcLibraryHelper { this.sourceTypeSet = sourceTypeSet; } - /** - * Returns the set of file types that are valid for this category. - */ + /** Returns the set of file types that are valid for this category. */ public FileTypeSet getSourceTypes() { return sourceTypeSet; } } /** Function for extracting module maps from CppCompilationDependencies. */ - public static final Function<TransitiveInfoCollection, CppModuleMap> CPP_DEPS_TO_MODULES = + private static final Function<TransitiveInfoCollection, CppModuleMap> CPP_DEPS_TO_MODULES = dep -> { CppCompilationContext context = dep.getProvider(CppCompilationContext.class); return context == null ? null : context.getCppModuleMap(); }; - /** - * Contains the providers as well as the compilation and linking outputs, and the compilation - * context. TODO(plf): Remove outer class Info. - */ - public static final class Info { - private final TransitiveInfoProviderMapBuilder providers; - private final ImmutableMap<String, NestedSet<Artifact>> outputGroups; + /** Contains the providers as well as the compilation outputs, and the compilation context. */ + public static final class CompilationInfo { + private final TransitiveInfoProviderMap providers; + private final Map<String, NestedSet<Artifact>> outputGroups; private final CcCompilationOutputs compilationOutputs; - private final CcLinkingOutputs linkingOutputsExcludingPrecompiledLibraries; private final CppCompilationContext context; - /** Contains the providers as well as the compilation outputs, and the compilation context. */ - public static final class CompilationInfo { - private final TransitiveInfoProviderMap providers; - private final Map<String, NestedSet<Artifact>> outputGroups; - private final CcCompilationOutputs compilationOutputs; - private final CppCompilationContext context; - - private CompilationInfo( - TransitiveInfoProviderMap providers, - Map<String, NestedSet<Artifact>> outputGroups, - CcCompilationOutputs compilationOutputs, - CppCompilationContext context) { - this.providers = providers; - this.outputGroups = outputGroups; - this.compilationOutputs = compilationOutputs; - this.context = context; - } - - public TransitiveInfoProviderMap getProviders() { - return providers; - } - - public Map<String, NestedSet<Artifact>> getOutputGroups() { - return outputGroups; - } - - public CcCompilationOutputs getCcCompilationOutputs() { - return compilationOutputs; - } - - public CppCompilationContext getCppCompilationContext() { - return context; - } - } - - /** Contains the providers as well as the linking outputs. */ - public static final class LinkingInfo { - private final TransitiveInfoProviderMap providers; - private final Map<String, NestedSet<Artifact>> outputGroups; - private final CcLinkingOutputs linkingOutputs; - private final CcLinkingOutputs linkingOutputsExcludingPrecompiledLibraries; - - private LinkingInfo( - TransitiveInfoProviderMap providers, - Map<String, NestedSet<Artifact>> outputGroups, - CcLinkingOutputs linkingOutputs, - CcLinkingOutputs linkingOutputsExcludingPrecompiledLibraries) { - this.providers = providers; - this.outputGroups = outputGroups; - this.linkingOutputs = linkingOutputs; - this.linkingOutputsExcludingPrecompiledLibraries = - linkingOutputsExcludingPrecompiledLibraries; - } - - public TransitiveInfoProviderMap getProviders() { - return providers; - } - - public Map<String, NestedSet<Artifact>> getOutputGroups() { - return outputGroups; - } - - public CcLinkingOutputs getCcLinkingOutputs() { - return linkingOutputs; - } - - /** - * Returns the linking outputs before adding the pre-compiled libraries. Avoid using this - - * pre-compiled and locally compiled libraries should be treated identically. This method only - * exists for backwards compatibility. - */ - public CcLinkingOutputs getCcLinkingOutputsExcludingPrecompiledLibraries() { - return linkingOutputsExcludingPrecompiledLibraries; - } - - /** - * Adds the static, pic-static libraries to the given builder. If addDynamicLibraries - * parameter is true, it also adds dynamic(both compile-time and execution-time) libraries. - */ - public void addLinkingOutputsTo( - NestedSetBuilder<Artifact> filesBuilder, boolean addDynamicLibraries) { - filesBuilder - .addAll(LinkerInputs.toLibraryArtifacts(linkingOutputs.getStaticLibraries())) - .addAll(LinkerInputs.toLibraryArtifacts(linkingOutputs.getPicStaticLibraries())); - if (addDynamicLibraries) { - filesBuilder - .addAll(LinkerInputs.toNonSolibArtifacts(linkingOutputs.getDynamicLibraries())) - .addAll( - LinkerInputs.toNonSolibArtifacts(linkingOutputs.getExecutionDynamicLibraries())); - } - } - - public void addLinkingOutputsTo(NestedSetBuilder<Artifact> filesBuilder) { - addLinkingOutputsTo(filesBuilder, true); - } - } - - public Info(CompilationInfo compilationInfo, LinkingInfo linkingInfo) { - this.providers = - new TransitiveInfoProviderMapBuilder() - .addAll(compilationInfo.getProviders()) - .addAll(linkingInfo.getProviders()); - this.outputGroups = - ImmutableMap.copyOf( - Iterables.concat( - compilationInfo.getOutputGroups().entrySet(), - linkingInfo.getOutputGroups().entrySet())); - this.compilationOutputs = compilationInfo.getCcCompilationOutputs(); - this.linkingOutputsExcludingPrecompiledLibraries = - linkingInfo.getCcLinkingOutputsExcludingPrecompiledLibraries(); - this.context = compilationInfo.getCppCompilationContext(); + private CompilationInfo( + TransitiveInfoProviderMap providers, + Map<String, NestedSet<Artifact>> outputGroups, + CcCompilationOutputs compilationOutputs, + CppCompilationContext context) { + this.providers = providers; + this.outputGroups = outputGroups; + this.compilationOutputs = compilationOutputs; + this.context = context; } public TransitiveInfoProviderMap getProviders() { - return providers.build(); + return providers; } - public ImmutableMap<String, NestedSet<Artifact>> getOutputGroups() { + public Map<String, NestedSet<Artifact>> getOutputGroups() { return outputGroups; } @@ -275,43 +147,9 @@ public final class CcLibraryHelper { return compilationOutputs; } - /** - * Returns the linking outputs before adding the pre-compiled libraries. Avoid using this - - * pre-compiled and locally compiled libraries should be treated identically. This method only - * exists for backwards compatibility. - */ - public CcLinkingOutputs getCcLinkingOutputsExcludingPrecompiledLibraries() { - return linkingOutputsExcludingPrecompiledLibraries; - } - public CppCompilationContext getCppCompilationContext() { return context; } - - /** - * Merges a list of output groups into one. The sets for each entry with a given key are merged. - */ - public static Map<String, NestedSet<Artifact>> mergeOutputGroups( - Map<String, NestedSet<Artifact>>... outputGroups) { - Map<String, NestedSetBuilder<Artifact>> mergedOutputGroupsBuilder = new TreeMap<>(); - - for (Map<String, NestedSet<Artifact>> outputGroup : outputGroups) { - for (Map.Entry<String, NestedSet<Artifact>> entryOutputGroup : outputGroup.entrySet()) { - String key = entryOutputGroup.getKey(); - mergedOutputGroupsBuilder.computeIfAbsent( - key, (String k) -> NestedSetBuilder.compileOrder()); - mergedOutputGroupsBuilder.get(key).addTransitive(entryOutputGroup.getValue()); - } - } - - Map<String, NestedSet<Artifact>> mergedOutputGroups = new TreeMap<>(); - for (Map.Entry<String, NestedSetBuilder<Artifact>> entryOutputGroupBuilder : - mergedOutputGroupsBuilder.entrySet()) { - mergedOutputGroups.put( - entryOutputGroupBuilder.getKey(), entryOutputGroupBuilder.getValue().build()); - } - return mergedOutputGroups; - } } private final RuleContext ruleContext; @@ -330,86 +168,72 @@ public final class CcLibraryHelper { private final Set<CppSource> compilationUnitSources = new LinkedHashSet<>(); private final List<Artifact> objectFiles = new ArrayList<>(); private final List<Artifact> picObjectFiles = new ArrayList<>(); - private final List<Artifact> nonCodeLinkerInputs = new ArrayList<>(); private ImmutableList<String> copts = ImmutableList.of(); - private final List<String> linkopts = new ArrayList<>(); private CoptsFilter coptsFilter = CoptsFilter.alwaysPasses(); private final Set<String> defines = new LinkedHashSet<>(); private final List<TransitiveInfoCollection> deps = new ArrayList<>(); private final List<CppCompilationContext> depContexts = new ArrayList<>(); - private final NestedSetBuilder<Artifact> linkstamps = NestedSetBuilder.stableOrder(); private final List<PathFragment> looseIncludeDirs = new ArrayList<>(); private final List<PathFragment> systemIncludeDirs = new ArrayList<>(); private final List<PathFragment> includeDirs = new ArrayList<>(); - private final List<Artifact> linkActionInputs = new ArrayList<>(); - @Nullable private Artifact dynamicLibrary; - private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY; private HeadersCheckingMode headersCheckingMode = HeadersCheckingMode.LOOSE; - private boolean neverlink; private boolean fake; - private final List<LibraryToLink> staticLibraries = new ArrayList<>(); - private final List<LibraryToLink> picStaticLibraries = new ArrayList<>(); - private final List<LibraryToLink> dynamicLibraries = new ArrayList<>(); - private final List<LibraryToLink> executionDynamicLibraries = new ArrayList<>(); - - private boolean emitLinkActions = true; - private boolean emitLinkActionsIfEmpty; - private boolean emitCcNativeLibrariesProvider; - private boolean emitCcSpecificLinkParamsProvider; - private boolean emitInterfaceSharedObjects; - private boolean createDynamicLibrary = true; - private boolean createStaticLibraries = true; private boolean checkDepsGenerateCpp = true; private boolean emitCompileProviders; private final SourceCategory sourceCategory; - private List<VariablesExtension> variablesExtensions = new ArrayList<>(); + private final List<VariablesExtension> variablesExtensions = new ArrayList<>(); @Nullable private CppModuleMap cppModuleMap; private boolean propagateModuleMapToCompileAction = true; private final FeatureConfiguration featureConfiguration; - private CcToolchainProvider ccToolchain; + private final CcToolchainProvider ccToolchain; private final FdoSupportProvider fdoSupport; - private String linkedArtifactNameSuffix = ""; private boolean useDeps = true; private boolean generateModuleMap = true; private String purpose = null; private boolean generateNoPic = true; /** - * Creates a CcLibraryHelper. + * Creates a CcCompilationHelper. * - * @param ruleContext the RuleContext for the rule being built - * @param semantics CppSemantics for the build - * @param featureConfiguration activated features and action configs for the build - * @param sourceCatagory the candidate source types for the build + * @param ruleContext the RuleContext for the rule being built + * @param semantics CppSemantics for the build + * @param featureConfiguration activated features and action configs for the build + * @param sourceCatagory the candidate source types for the build * @param ccToolchain the C++ toolchain provider for the build * @param fdoSupport the C++ FDO optimization support provider for the build */ - public CcLibraryHelper( + public CcCompilationHelper( RuleContext ruleContext, CppSemantics semantics, FeatureConfiguration featureConfiguration, SourceCategory sourceCatagory, CcToolchainProvider ccToolchain, FdoSupportProvider fdoSupport) { - this(ruleContext, semantics, featureConfiguration, sourceCatagory, ccToolchain, fdoSupport, + this( + ruleContext, + semantics, + featureConfiguration, + sourceCatagory, + ccToolchain, + fdoSupport, ruleContext.getConfiguration()); } /** - * Creates a CcLibraryHelper that outputs artifacts in a given configuration. + * Creates a CcCompilationHelper that outputs artifacts in a given configuration. * - * @param ruleContext the RuleContext for the rule being built - * @param semantics CppSemantics for the build - * @param featureConfiguration activated features and action configs for the build - * @param sourceCatagory the candidate source types for the build + * @param ruleContext the RuleContext for the rule being built + * @param semantics CppSemantics for the build + * @param featureConfiguration activated features and action configs for the build + * @param sourceCatagory the candidate source types for the build * @param ccToolchain the C++ toolchain provider for the build * @param fdoSupport the C++ FDO optimization support provider for the build * @param configuration the configuration that gives the directory of output artifacts */ - public CcLibraryHelper( + public CcCompilationHelper( RuleContext ruleContext, CppSemantics semantics, FeatureConfiguration featureConfiguration, @@ -427,7 +251,7 @@ public final class CcLibraryHelper { } /** - * Creates a CcLibraryHelper for cpp source files. + * Creates a CcCompilationHelper for cpp source files. * * @param ruleContext the RuleContext for the rule being built * @param semantics CppSemantics for the build @@ -435,19 +259,21 @@ public final class CcLibraryHelper { * @param ccToolchain the C++ toolchain provider for the build * @param fdoSupport the C++ FDO optimization support provider for the build */ - public CcLibraryHelper( - RuleContext ruleContext, CppSemantics semantics, FeatureConfiguration featureConfiguration, - CcToolchainProvider ccToolchain, FdoSupportProvider fdoSupport) { + public CcCompilationHelper( + RuleContext ruleContext, + CppSemantics semantics, + FeatureConfiguration featureConfiguration, + CcToolchainProvider ccToolchain, + FdoSupportProvider fdoSupport) { this(ruleContext, semantics, featureConfiguration, SourceCategory.CC, ccToolchain, fdoSupport); } /** Sets fields that overlap for cc_library and cc_binary rules. */ - public CcLibraryHelper fromCommon(CcCommon common) { + public CcCompilationHelper fromCommon(CcCommon common) { setCopts(common.getCopts()); addDefines(common.getDefines()); addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)); addLooseIncludeDirs(common.getLooseIncludeDirs()); - addNonCodeLinkerInputs(common.getLinkerScripts()); addSystemIncludeDirs(common.getSystemIncludeDirs()); setCoptsFilter(common.getCoptsFilter()); setHeadersCheckingMode(semantics.determineHeadersCheckingMode(ruleContext)); @@ -459,7 +285,7 @@ public final class CcLibraryHelper { * rules. They may be parsed/preprocessed or compiled into a header module depending on the * configuration. */ - public CcLibraryHelper addPublicHeaders(Collection<Artifact> headers) { + public CcCompilationHelper addPublicHeaders(Collection<Artifact> headers) { for (Artifact header : headers) { addHeader(header, ruleContext.getLabel()); } @@ -471,7 +297,7 @@ public final class CcLibraryHelper { * rules. They may be parsed/preprocessed or compiled into a header module depending on the * configuration. */ - public CcLibraryHelper addPublicHeaders(Artifact... headers) { + public CcCompilationHelper addPublicHeaders(Artifact... headers) { addPublicHeaders(Arrays.asList(headers)); return this; } @@ -481,7 +307,7 @@ public final class CcLibraryHelper { * rules. They may be parsed/preprocessed or compiled into a header module depending on the * configuration. */ - public CcLibraryHelper addPublicHeaders(Iterable<Pair<Artifact, Label>> headers) { + public CcCompilationHelper addPublicHeaders(Iterable<Pair<Artifact, Label>> headers) { for (Pair<Artifact, Label> header : headers) { addHeader(header.first, header.second); } @@ -492,7 +318,7 @@ public final class CcLibraryHelper { * Add the corresponding files as public header files, i.e., these files will not be compiled, but * are made visible as includes to dependent rules in module maps. */ - public CcLibraryHelper addAdditionalExportedHeaders( + public CcCompilationHelper addAdditionalExportedHeaders( Iterable<PathFragment> additionalExportedHeaders) { Iterables.addAll(this.additionalExportedHeaders, additionalExportedHeaders); return this; @@ -502,7 +328,7 @@ public final class CcLibraryHelper { * Add the corresponding files as public textual header files. These files will not be compiled * into a target's header module, but will be made visible as textual includes to dependent rules. */ - public CcLibraryHelper addPublicTextualHeaders(Iterable<Artifact> textualHeaders) { + public CcCompilationHelper addPublicTextualHeaders(Iterable<Artifact> textualHeaders) { Iterables.addAll(this.publicTextualHeaders, textualHeaders); for (Artifact header : textualHeaders) { this.additionalExportedHeaders.add(header.getExecPath()); @@ -515,7 +341,7 @@ public final class CcLibraryHelper { * will not be compiled, but also not made visible as includes to dependent rules. The given build * variables will be added to those used for compiling this source. */ - public CcLibraryHelper addSources(Collection<Artifact> sources) { + public CcCompilationHelper addSources(Collection<Artifact> sources) { for (Artifact source : sources) { addSource(source, ruleContext.getLabel()); } @@ -526,7 +352,7 @@ public final class CcLibraryHelper { * Add the corresponding files as source files. These may also be header files, in which case they * will not be compiled, but also not made visible as includes to dependent rules. */ - public CcLibraryHelper addSources(Iterable<Pair<Artifact, Label>> sources) { + public CcCompilationHelper addSources(Iterable<Pair<Artifact, Label>> sources) { for (Pair<Artifact, Label> source : sources) { addSource(source.first, source.second); } @@ -537,12 +363,12 @@ public final class CcLibraryHelper { * Add the corresponding files as source files. These may also be header files, in which case they * will not be compiled, but also not made visible as includes to dependent rules. */ - public CcLibraryHelper addSources(Artifact... sources) { + public CcCompilationHelper addSources(Artifact... sources) { return addSources(Arrays.asList(sources)); } /** Add the corresponding files as non-header, non-source input files. */ - public CcLibraryHelper addAdditionalInputs(Collection<Artifact> inputs) { + public CcCompilationHelper addAdditionalInputs(Collection<Artifact> inputs) { Iterables.addAll(additionalInputs, inputs); return this; } @@ -564,7 +390,7 @@ public final class CcLibraryHelper { } /** Adds a header to {@code publicHeaders}, but not to this target's module map. */ - public CcLibraryHelper addNonModuleMapHeader(Artifact header) { + public CcCompilationHelper addNonModuleMapHeader(Artifact header) { Preconditions.checkNotNull(header); nonModuleMapHeaders.add(header); return this; @@ -574,7 +400,7 @@ public final class CcLibraryHelper { * Adds a source to {@code compilationUnitSources} if it is a compiled file type (including * parsed/preprocessed header) and to {@code privateHeaders} if it is a header. */ - private CcLibraryHelper addSource(Artifact source, Label label) { + private void addSource(Artifact source, Label label) { Preconditions.checkNotNull(featureConfiguration); boolean isHeader = CppFileTypes.CPP_HEADER.matches(source.getExecPath()); boolean isTextualInclude = CppFileTypes.CPP_TEXTUAL_INCLUDE.matches(source.getExecPath()); @@ -586,7 +412,7 @@ public final class CcLibraryHelper { privateHeaders.add(source); } if (isTextualInclude || !isCompiledSource || (isHeader && !shouldProcessHeaders())) { - return this; + return; } boolean isClifInputProto = CppFileTypes.CLIF_INPUT_PROTO.matches(source.getExecPathString()); CppSource.Type type; @@ -598,7 +424,6 @@ public final class CcLibraryHelper { type = CppSource.Type.SOURCE; } compilationUnitSources.add(CppSource.create(source, label, type)); - return this; } private boolean shouldProcessHeaders() { @@ -626,7 +451,7 @@ public final class CcLibraryHelper { * here, if {@code --start_end_lib} is enabled, but instead at any binary that transitively * depends on the current rule. */ - public CcLibraryHelper addObjectFiles(Iterable<Artifact> objectFiles) { + public CcCompilationHelper addObjectFiles(Iterable<Artifact> objectFiles) { for (Artifact objectFile : objectFiles) { Preconditions.checkArgument(Link.OBJECT_FILETYPES.matches(objectFile.getFilename())); } @@ -640,7 +465,7 @@ public final class CcLibraryHelper { * here, if {@code --start_end_lib} is enabled, but instead at any binary that transitively * depends on the current rule. */ - public CcLibraryHelper addPicObjectFiles(Iterable<Artifact> picObjectFiles) { + public CcCompilationHelper addPicObjectFiles(Iterable<Artifact> picObjectFiles) { for (Artifact objectFile : objectFiles) { Preconditions.checkArgument(Link.OBJECT_FILETYPES.matches(objectFile.getFilename())); } @@ -648,115 +473,44 @@ public final class CcLibraryHelper { return this; } - /** - * Adds the corresponding non-code files as linker inputs. - */ - public CcLibraryHelper addNonCodeLinkerInputs(Iterable<Artifact> nonCodeLinkerInputs) { - for (Artifact nonCodeLinkerInput : nonCodeLinkerInputs) { - String basename = nonCodeLinkerInput.getFilename(); - Preconditions.checkArgument(!Link.OBJECT_FILETYPES.matches(basename)); - Preconditions.checkArgument(!Link.ARCHIVE_LIBRARY_FILETYPES.matches(basename)); - Preconditions.checkArgument(!Link.SHARED_LIBRARY_FILETYPES.matches(basename)); - this.nonCodeLinkerInputs.add(nonCodeLinkerInput); - } - - return this; - } - - /** - * Add the corresponding files as static libraries into the linker outputs (i.e., after the linker - * action) - this makes them available for linking to binary rules that depend on this rule. - */ - public CcLibraryHelper addStaticLibraries(Iterable<LibraryToLink> libraries) { - Iterables.addAll(staticLibraries, libraries); - return this; - } - - /** - * Add the corresponding files as static libraries into the linker outputs (i.e., after the linker - * action) - this makes them available for linking to binary rules that depend on this rule. - */ - public CcLibraryHelper addPicStaticLibraries(Iterable<LibraryToLink> libraries) { - Iterables.addAll(picStaticLibraries, libraries); - return this; - } - - /** - * Add the corresponding files as dynamic libraries into the linker outputs (i.e., after the - * linker action) - this makes them available for linking to binary rules that depend on this - * rule. - */ - public CcLibraryHelper addDynamicLibraries(Iterable<LibraryToLink> libraries) { - Iterables.addAll(dynamicLibraries, libraries); - return this; - } - - /** Add the corresponding files as dynamic libraries required at runtime */ - public CcLibraryHelper addExecutionDynamicLibraries(Iterable<LibraryToLink> libraries) { - Iterables.addAll(executionDynamicLibraries, libraries); - return this; - } - - public CcLibraryHelper setCopts(ImmutableList<String> copts) { + public CcCompilationHelper setCopts(ImmutableList<String> copts) { this.copts = Preconditions.checkNotNull(copts); return this; } /** Sets a pattern that is used to filter copts; set to {@code null} for no filtering. */ - public CcLibraryHelper setCoptsFilter(CoptsFilter coptsFilter) { + private void setCoptsFilter(CoptsFilter coptsFilter) { this.coptsFilter = Preconditions.checkNotNull(coptsFilter); - return this; } - /** - * Adds the given options as linker options to the link command. - */ - public CcLibraryHelper addLinkopts(Iterable<String> linkopts) { - Iterables.addAll(this.linkopts, linkopts); - return this; - } - - /** - * Adds the given defines to the compiler command line. - */ - public CcLibraryHelper addDefines(Iterable<String> defines) { + /** Adds the given defines to the compiler command line. */ + public CcCompilationHelper addDefines(Iterable<String> defines) { Iterables.addAll(this.defines, defines); return this; } /** - * Adds the given targets as dependencies - this can include explicit dependencies on other - * rules (like from a "deps" attribute) and also implicit dependencies on runtime libraries. + * Adds the given targets as dependencies - this can include explicit dependencies on other rules + * (like from a "deps" attribute) and also implicit dependencies on runtime libraries. */ - public CcLibraryHelper addDeps(Iterable<? extends TransitiveInfoCollection> deps) { + public CcCompilationHelper addDeps(Iterable<? extends TransitiveInfoCollection> deps) { for (TransitiveInfoCollection dep : deps) { this.deps.add(dep); } return this; } - public CcLibraryHelper addDepContext(CppCompilationContext dep) { + public CcCompilationHelper addDepContext(CppCompilationContext dep) { this.depContexts.add(Preconditions.checkNotNull(dep)); return this; } /** - * Adds the given linkstamps. Note that linkstamps are usually not compiled at the library level, - * but only in the dependent binary rules. - */ - public CcLibraryHelper addLinkstamps(Iterable<? extends TransitiveInfoCollection> linkstamps) { - for (TransitiveInfoCollection linkstamp : linkstamps) { - this.linkstamps.addTransitive(linkstamp.getProvider(FileProvider.class).getFilesToBuild()); - } - return this; - } - - /** * Adds the given precompiled files to this helper. Shared and static libraries are added as * compilation prerequisites, and object files are added as pic or non-pic object files * respectively. */ - public CcLibraryHelper addPrecompiledFiles(PrecompiledFiles precompiledFiles) { + public CcCompilationHelper addPrecompiledFiles(PrecompiledFiles precompiledFiles) { addObjectFiles(precompiledFiles.getObjectFiles(false)); addPicObjectFiles(precompiledFiles.getObjectFiles(true)); return this; @@ -767,112 +521,50 @@ public final class CcLibraryHelper { * referenced when headers checking is {@link HeadersCheckingMode#LOOSE} or {@link * HeadersCheckingMode#WARN}. */ - public CcLibraryHelper addLooseIncludeDirs(Iterable<PathFragment> looseIncludeDirs) { + private void addLooseIncludeDirs(Iterable<PathFragment> looseIncludeDirs) { Iterables.addAll(this.looseIncludeDirs, looseIncludeDirs); - return this; } /** * Adds the given directories to the system include directories (they are passed with {@code * "-isystem"} to the compiler); these are also passed to dependent rules. */ - public CcLibraryHelper addSystemIncludeDirs(Iterable<PathFragment> systemIncludeDirs) { + public CcCompilationHelper addSystemIncludeDirs(Iterable<PathFragment> systemIncludeDirs) { Iterables.addAll(this.systemIncludeDirs, systemIncludeDirs); return this; } /** - * Adds the given directories to the include directories (they are passed with {@code "-I"} to - * the compiler); these are also passed to dependent rules. + * Adds the given directories to the include directories (they are passed with {@code "-I"} to the + * compiler); these are also passed to dependent rules. */ - public CcLibraryHelper addIncludeDirs(Iterable<PathFragment> includeDirs) { + public CcCompilationHelper addIncludeDirs(Iterable<PathFragment> includeDirs) { Iterables.addAll(this.includeDirs, includeDirs); return this; } - /** Adds the given artifact to the input of any generated link actions. */ - public CcLibraryHelper addLinkActionInput(Artifact input) { - Preconditions.checkNotNull(input); - this.linkActionInputs.add(input); - return this; - } - - /** - * Adds a variableExtension to template the crosstool. - */ - public CcLibraryHelper addVariableExtension(VariablesExtension variableExtension) { + /** Adds a variableExtension to template the crosstool. */ + public CcCompilationHelper addVariableExtension(VariablesExtension variableExtension) { Preconditions.checkNotNull(variableExtension); this.variablesExtensions.add(variableExtension); return this; } - /** - * Sets a module map artifact for this build. - */ - public CcLibraryHelper setCppModuleMap(CppModuleMap cppModuleMap) { + /** Sets a module map artifact for this build. */ + public CcCompilationHelper setCppModuleMap(CppModuleMap cppModuleMap) { Preconditions.checkNotNull(cppModuleMap); this.cppModuleMap = cppModuleMap; return this; } - /** - * Signals that this target's module map should not be an input to c++ compile actions. - */ - public CcLibraryHelper setPropagateModuleMapToCompileAction(boolean propagatesModuleMap) { + /** Signals that this target's module map should not be an input to c++ compile actions. */ + public CcCompilationHelper setPropagateModuleMapToCompileAction(boolean propagatesModuleMap) { this.propagateModuleMapToCompileAction = propagatesModuleMap; return this; } - /** - * Overrides the path for the generated dynamic library - this should only be called if the - * dynamic library is an implicit or explicit output of the rule, i.e., if it is accessible by - * name from other rules in the same package. Set to {@code null} to use the default computation. - */ - public CcLibraryHelper setDynamicLibrary(@Nullable Artifact dynamicLibrary) { - this.dynamicLibrary = dynamicLibrary; - return this; - } - - /** - * Marks the output of this rule as alwayslink, i.e., the corresponding symbols will be retained - * by the linker even if they are not otherwise used. This is useful for libraries that register - * themselves somewhere during initialization. - * - * <p>This only sets the link type (see {@link #setStaticLinkType}), either to a static library or - * to an alwayslink static library (blaze uses a different file extension to signal alwayslink to - * downstream code). - */ - public CcLibraryHelper setAlwayslink(boolean alwayslink) { - linkType = alwayslink - ? LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY - : LinkTargetType.STATIC_LIBRARY; - return this; - } - - /** - * Directly set the link type. This can be used instead of {@link #setAlwayslink}. Setting - * anything other than a static link causes this class to skip the link action creation. - */ - public CcLibraryHelper setStaticLinkType(LinkTargetType linkType) { - Preconditions.checkNotNull(linkType); - Preconditions.checkState(linkType.staticness() == Staticness.STATIC); - this.linkType = linkType; - return this; - } - - /** - * Marks the resulting code as neverlink, i.e., the code will not be linked into dependent - * libraries or binaries - the header files are still available. - */ - public CcLibraryHelper setNeverLink(boolean neverlink) { - this.neverlink = neverlink; - return this; - } - - /** - * Sets the given headers checking mode. The default is {@link HeadersCheckingMode#LOOSE}. - */ - public CcLibraryHelper setHeadersCheckingMode(HeadersCheckingMode headersCheckingMode) { + /** Sets the given headers checking mode. The default is {@link HeadersCheckingMode#LOOSE}. */ + public CcCompilationHelper setHeadersCheckingMode(HeadersCheckingMode headersCheckingMode) { this.headersCheckingMode = Preconditions.checkNotNull(headersCheckingMode); return this; } @@ -883,125 +575,48 @@ public final class CcLibraryHelper { * used for non-compilation tests. Unfortunately, the design is problematic, so please don't add * any further uses. */ - public CcLibraryHelper setFake(boolean fake) { + public CcCompilationHelper setFake(boolean fake) { this.fake = fake; return this; } - /* - * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule - * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may - * generate the same linked artifact and therefore lead to artifact conflicts. This method - * provides a way to avoid this artifact conflict by allowing different callers acting on the same - * rule to provide a suffix that will be used to scope their own linked artifacts. - */ - public CcLibraryHelper setLinkedArtifactNameSuffix(String suffix) { - this.linkedArtifactNameSuffix = Preconditions.checkNotNull(suffix); - return this; - } - - /** - * This adds the {@link CcNativeLibraryProvider} to the providers created by this class. - */ - public CcLibraryHelper enableCcNativeLibrariesProvider() { - this.emitCcNativeLibrariesProvider = true; - return this; - } - - /** - * This adds the {@link CcSpecificLinkParamsProvider} to the providers created by this class. - * Otherwise the result will contain an instance of {@link CcLinkParamsInfo}. - */ - public CcLibraryHelper enableCcSpecificLinkParamsProvider() { - this.emitCcSpecificLinkParamsProvider = true; - return this; - } - - public CcLibraryHelper setEmitLinkActions(boolean emitLinkActions) { - this.emitLinkActions = emitLinkActions; - return this; - } - - /** - * Enables or disables generation of link actions if there are no object files. Some rules declare - * a <code>.a</code> or <code>.so</code> implicit output, which requires that these files are - * created even if there are no object files, so be careful when calling this. - * - * <p>This is disabled by default. - */ - public CcLibraryHelper setGenerateLinkActionsIfEmpty(boolean emitLinkActionsIfEmpty) { - this.emitLinkActionsIfEmpty = emitLinkActionsIfEmpty; - return this; - } - - /** - * Enables the optional generation of interface dynamic libraries - this is only used when the - * linker generates a dynamic library, and only if the crosstool supports it. The default is not - * to generate interface dynamic libraries. - */ - public CcLibraryHelper enableInterfaceSharedObjects() { - this.emitInterfaceSharedObjects = true; - return this; - } - - /** - * This enables or disables the generation of a dynamic library link action. The default is to - * generate a dynamic library. Note that the selection between dynamic or static linking is - * performed at the binary rule level. - */ - public CcLibraryHelper setCreateDynamicLibrary(boolean emitDynamicLibrary) { - this.createDynamicLibrary = emitDynamicLibrary; - return this; - } - - /** When createStaticLibraries is true, there are no actions created for static libraries. */ - public CcLibraryHelper setCreateStaticLibraries(boolean emitStaticLibraries) { - this.createStaticLibraries = emitStaticLibraries; - return this; - } - - public CcLibraryHelper setNeverlink(boolean neverlink) { - this.neverlink = neverlink; - return this; - } - /** * Disables checking that the deps actually are C++ rules. By default, the {@link #compile} method * uses {@link LanguageDependentFragment.Checker#depSupportsLanguage} to check that all deps * provide C++ providers. */ - public CcLibraryHelper setCheckDepsGenerateCpp(boolean checkDepsGenerateCpp) { + public CcCompilationHelper setCheckDepsGenerateCpp(boolean checkDepsGenerateCpp) { this.checkDepsGenerateCpp = checkDepsGenerateCpp; return this; } /** - * Enables the output of the {@code files_to_compile} and {@code compilation_prerequisites} - * output groups. + * Enables the output of the {@code files_to_compile} and {@code compilation_prerequisites} output + * groups. */ // TODO(bazel-team): We probably need to adjust this for the multi-language rules. - public CcLibraryHelper enableCompileProviders() { + public CcCompilationHelper enableCompileProviders() { this.emitCompileProviders = true; return this; } /** - * Causes actions generated from this CcLibraryHelper not to use build semantics (includes, + * Causes actions generated from this CcCompilationHelper not to use build semantics (includes, * headers, srcs) from dependencies. */ - public CcLibraryHelper doNotUseDeps() { + public CcCompilationHelper doNotUseDeps() { this.useDeps = false; return this; } /** non-PIC actions won't be generated. */ - public CcLibraryHelper setGenerateNoPic(boolean generateNoPic) { + public CcCompilationHelper setGenerateNoPic(boolean generateNoPic) { this.generateNoPic = generateNoPic; return this; } /** Adds mandatory inputs for the compilation action. */ - public CcLibraryHelper addCompilationMandatoryInputs( + public CcCompilationHelper addCompilationMandatoryInputs( Collection<Artifact> compilationMandatoryInputs) { this.compilationMandatoryInputs.addAll(compilationMandatoryInputs); return this; @@ -1010,7 +625,7 @@ public final class CcLibraryHelper { /** Adds additional includes to be scanned. */ // TODO(plf): This is only needed for CLIF. Investigate whether this is strictly necessary or // there is a way to avoid include scanning for CLIF rules. - public CcLibraryHelper addAditionalIncludeScanningRoots( + public CcCompilationHelper addAditionalIncludeScanningRoots( Collection<Artifact> additionalIncludeScanningRoots) { this.additionalIncludeScanningRoots.addAll(additionalIncludeScanningRoots); return this; @@ -1021,7 +636,7 @@ public final class CcLibraryHelper { * * @throws RuleErrorException */ - public Info.CompilationInfo compile() throws RuleErrorException { + public CompilationInfo compile() throws RuleErrorException { if (checkDepsGenerateCpp) { for (LanguageDependentFragment dep : AnalysisUtils.getProviders(deps, LanguageDependentFragment.class)) { @@ -1085,223 +700,23 @@ public final class CcLibraryHelper { CcCommon.collectCompilationPrerequisites(ruleContext, cppCompilationContext)); } - return new Info.CompilationInfo( - providers.build(), outputGroups, ccOutputs, cppCompilationContext); + return new CompilationInfo(providers.build(), outputGroups, ccOutputs, cppCompilationContext); } - /** - * Create the C++ link actions, and the corresponding linking related providers. - * - * @throws RuleErrorException - */ - public Info.LinkingInfo link( - CcCompilationOutputs ccOutputs, CppCompilationContext cppCompilationContext) - throws RuleErrorException, InterruptedException { - Preconditions.checkNotNull(ccOutputs); - Preconditions.checkNotNull(cppCompilationContext); - - if (checkDepsGenerateCpp) { - for (LanguageDependentFragment dep : - AnalysisUtils.getProviders(deps, LanguageDependentFragment.class)) { - LanguageDependentFragment.Checker.depSupportsLanguage( - ruleContext, dep, CppRuleClasses.LANGUAGE, "deps"); - } - } - - CppModel model = initializeCppModel(); - model.setContext(cppCompilationContext); - - // Create link actions (only if there are object files or if explicitly requested). - CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY; - if (emitLinkActions && (emitLinkActionsIfEmpty || !ccOutputs.isEmpty())) { - // On some systems, the linker gives an error message if there are no input files. Even with - // the check above, this can still happen if there is a .nopic.o or .o files in srcs, but no - // other files. To fix that, we'd have to check for each link action individually. - // - // An additional pre-existing issue is that the header check tokens are dropped if we don't - // generate any link actions, effectively disabling header checking in some cases. - if (linkType.staticness() == Staticness.STATIC) { - // TODO(bazel-team): This can't create the link action for a cc_binary yet. - ccLinkingOutputs = model.createCcLinkActions(ccOutputs, nonCodeLinkerInputs); - } - } - CcLinkingOutputs originalLinkingOutputs = ccLinkingOutputs; - if (!(staticLibraries.isEmpty() - && picStaticLibraries.isEmpty() - && dynamicLibraries.isEmpty() - && executionDynamicLibraries.isEmpty())) { - - CcLinkingOutputs.Builder newOutputsBuilder = new CcLinkingOutputs.Builder(); - if (!ccOutputs.isEmpty()) { - // Add the linked outputs of this rule iff we had anything to put in them, but then - // make sure we're not colliding with some library added from the inputs. - newOutputsBuilder.merge(originalLinkingOutputs); - ImmutableSetMultimap<String, LibraryToLink> precompiledLibraryMap = - CcLinkingOutputs.getLibrariesByIdentifier( - Iterables.concat( - staticLibraries, picStaticLibraries, - dynamicLibraries, executionDynamicLibraries)); - ImmutableSetMultimap<String, LibraryToLink> linkedLibraryMap = - originalLinkingOutputs.getLibrariesByIdentifier(); - for (String matchingIdentifier : - Sets.intersection(precompiledLibraryMap.keySet(), linkedLibraryMap.keySet())) { - Iterable<Artifact> matchingInputLibs = - LinkerInputs.toNonSolibArtifacts(precompiledLibraryMap.get(matchingIdentifier)); - Iterable<Artifact> matchingOutputLibs = - LinkerInputs.toNonSolibArtifacts(linkedLibraryMap.get(matchingIdentifier)); - ruleContext.ruleError( - "Can't put " - + Streams.stream(matchingInputLibs) - .map(Artifact::getFilename) - .collect(joining(", ")) - + " into the srcs of a " - + ruleContext.getRuleClassNameForLogging() - + " with the same name (" - + ruleContext.getRule().getName() - + ") which also contains other code or objects to link; it shares a name with " - + Streams.stream(matchingOutputLibs) - .map(Artifact::getFilename) - .collect(joining(", ")) - + " (output compiled and linked from the non-library sources of this rule), " - + "which could cause confusion"); - } - } - - // Merge the pre-compiled libraries (static & dynamic) into the linker outputs. - ccLinkingOutputs = - newOutputsBuilder - .addStaticLibraries(staticLibraries) - .addPicStaticLibraries(picStaticLibraries) - .addDynamicLibraries(dynamicLibraries) - .addExecutionDynamicLibraries(executionDynamicLibraries) - .build(); - } - - Runfiles cppStaticRunfiles = collectCppRunfiles(ccLinkingOutputs, true); - Runfiles cppSharedRunfiles = collectCppRunfiles(ccLinkingOutputs, false); - - // By very careful when adding new providers here - it can potentially affect a lot of rules. - // We should consider merging most of these providers into a single provider. - TransitiveInfoProviderMapBuilder providers = - new TransitiveInfoProviderMapBuilder() - .add(new CppRunfilesProvider(cppStaticRunfiles, cppSharedRunfiles)); - - Map<String, NestedSet<Artifact>> outputGroups = new TreeMap<>(); - - if (shouldAddLinkerOutputArtifacts(ruleContext, ccOutputs)) { - addLinkerOutputArtifacts(outputGroups, ccOutputs); - } - - // TODO(bazel-team): Maybe we can infer these from other data at the places where they are - // used. - if (emitCcNativeLibrariesProvider) { - providers.add(new CcNativeLibraryProvider(collectNativeCcLibraries(ccLinkingOutputs))); - } - providers.put( - CcExecutionDynamicLibrariesProvider.class, - collectExecutionDynamicLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries())); - - CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class); - boolean forcePic = cppConfiguration.forcePic(); - if (emitCcSpecificLinkParamsProvider) { - providers.add( - new CcSpecificLinkParamsProvider( - createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic))); - } else { - providers.put( - new CcLinkParamsInfo( - createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic))); - } - return new Info.LinkingInfo( - providers.build(), outputGroups, ccLinkingOutputs, originalLinkingOutputs); - } - - /** - * Returns true if the appropriate attributes for linker output artifacts are defined, and either - * the compile action produces object files or the build is configured to produce an archive or - * dynamic library even in the absence of object files. - */ - private boolean shouldAddLinkerOutputArtifacts( - RuleContext ruleContext, CcCompilationOutputs ccOutputs) { - return (ruleContext.attributes().has("alwayslink", Type.BOOLEAN) - && ruleContext.attributes().has("linkstatic", Type.BOOLEAN) - && (emitLinkActionsIfEmpty || !ccOutputs.isEmpty())); - } - - /** - * Adds linker output artifacts to the given map, to be registered on the configured target as - * output groups. - */ - private void addLinkerOutputArtifacts(Map<String, NestedSet<Artifact>> outputGroups, - CcCompilationOutputs ccOutputs) { - NestedSetBuilder<Artifact> archiveFile = new NestedSetBuilder<>(Order.STABLE_ORDER); - NestedSetBuilder<Artifact> dynamicLibrary = new NestedSetBuilder<>(Order.STABLE_ORDER); - - if (ruleContext.attributes().get("alwayslink", Type.BOOLEAN)) { - archiveFile.add( - CppHelper.getLinuxLinkedArtifact( - ruleContext, - configuration, - Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY, - linkedArtifactNameSuffix)); - } else { - archiveFile.add( - CppHelper.getLinuxLinkedArtifact( - ruleContext, - configuration, - Link.LinkTargetType.STATIC_LIBRARY, - linkedArtifactNameSuffix)); - } - - if (!ruleContext.attributes().get("linkstatic", Type.BOOLEAN) - && !ccOutputs.isEmpty()) { - dynamicLibrary.add( - CppHelper.getLinuxLinkedArtifact( - ruleContext, - configuration, - Link.LinkTargetType.DYNAMIC_LIBRARY, - linkedArtifactNameSuffix)); - - if (CppHelper.useInterfaceSharedObjects(ccToolchain.getCppConfiguration(), ccToolchain) - && emitInterfaceSharedObjects) { - dynamicLibrary.add( - CppHelper.getLinuxLinkedArtifact( - ruleContext, - configuration, - LinkTargetType.INTERFACE_DYNAMIC_LIBRARY, - linkedArtifactNameSuffix)); - } - } - - outputGroups.put(ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME, archiveFile.build()); - outputGroups.put(DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME, dynamicLibrary.build()); - } - - /** - * Creates the C/C++ compilation action creator. - */ + /** Creates the C/C++ compilation action creator. */ private CppModel initializeCppModel() { return new CppModel( ruleContext, semantics, ccToolchain, fdoSupport, configuration, copts, coptsFilter) .addCompilationUnitSources(compilationUnitSources) - .setLinkTargetType(linkType) - .setNeverLink(neverlink) - .addLinkActionInputs(linkActionInputs) .addCompilationMandatoryInputs(compilationMandatoryInputs) .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots) .setFake(fake) .setGenerateNoPic(generateNoPic) - .setAllowInterfaceSharedObjects(emitInterfaceSharedObjects) - .setCreateDynamicLibrary(createDynamicLibrary) - .setCreateStaticLibraries(createStaticLibraries) // Note: this doesn't actually save the temps, it just makes the CppModel use the // configurations --save_temps setting to decide whether to actually save the temps. .setSaveTemps(true) - .setDynamicLibrary(dynamicLibrary) - .addLinkopts(linkopts) .setFeatureConfiguration(featureConfiguration) - .addVariablesExtension(variablesExtensions) - .setLinkedArtifactNameSuffix(linkedArtifactNameSuffix); + .addVariablesExtension(variablesExtensions); } @Immutable @@ -1319,16 +734,16 @@ public final class CcLibraryHelper { this.virtualIncludePath = virtualIncludePath; } - public ImmutableList<Artifact> getHeaders() { + private ImmutableList<Artifact> getHeaders() { return headers; } - public ImmutableList<Artifact> getModuleMapHeaders() { + private ImmutableList<Artifact> getModuleMapHeaders() { return moduleMapHeaders; } @Nullable - public PathFragment getVirtualIncludePath() { + private PathFragment getVirtualIncludePath() { return virtualIncludePath; } } @@ -1352,8 +767,13 @@ public final class CcLibraryHelper { stripPrefix = PathFragment.create(ruleContext.attributes().get("strip_include_prefix", Type.STRING)); if (stripPrefix.isAbsolute()) { - stripPrefix = ruleContext.getLabel().getPackageIdentifier().getRepository().getSourceRoot() - .getRelative(stripPrefix.toRelative()); + stripPrefix = + ruleContext + .getLabel() + .getPackageIdentifier() + .getRepository() + .getSourceRoot() + .getRelative(stripPrefix.toRelative()); } else { stripPrefix = ruleContext.getPackageDirectory().getRelative(stripPrefix); } @@ -1372,8 +792,7 @@ public final class CcLibraryHelper { } if (stripPrefix.containsUplevelReferences()) { - ruleContext.attributeError("strip_include_prefix", - "should not contain uplevel references"); + ruleContext.attributeError("strip_include_prefix", "should not contain uplevel references"); } if (prefix != null && prefix.containsUplevelReferences()) { @@ -1392,9 +811,10 @@ public final class CcLibraryHelper { for (Artifact originalHeader : publicHeaders) { if (!originalHeader.getRootRelativePath().startsWith(stripPrefix)) { - ruleContext.ruleError(String.format( - "header '%s' is not under the specified strip prefix '%s'", - originalHeader.getExecPathString(), stripPrefix.getPathString())); + ruleContext.ruleError( + String.format( + "header '%s' is not under the specified strip prefix '%s'", + originalHeader.getExecPathString(), stripPrefix.getPathString())); continue; } @@ -1443,7 +863,7 @@ public final class CcLibraryHelper { /** * Create context for cc compile action from generated inputs. * - * TODO(plf): Try to pull out CppCompilationContext building out of this class. + * <p>TODO(plf): Try to pull out CppCompilationContext building out of this class. */ private CppCompilationContext initializeCppCompilationContext(CppModel model) { CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext); @@ -1568,8 +988,8 @@ public final class CcLibraryHelper { return contextBuilder.build(); } - private UmbrellaHeaderAction createUmbrellaHeaderAction(Artifact umbrellaHeader, - PublicHeaders publicHeaders) { + private UmbrellaHeaderAction createUmbrellaHeaderAction( + Artifact umbrellaHeader, PublicHeaders publicHeaders) { return new UmbrellaHeaderAction( ruleContext.getActionOwner(), umbrellaHeader, @@ -1627,9 +1047,8 @@ public final class CcLibraryHelper { RuleContext ruleContext, CcCompilationOutputs ccCompilationOutputs) { NestedSetBuilder<Artifact> headerTokens = NestedSetBuilder.stableOrder(); for (OutputGroupInfo dep : - ruleContext.getPrerequisites( - "deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) { - headerTokens.addTransitive(dep.getOutputGroup(CcLibraryHelper.HIDDEN_HEADER_TOKENS)); + ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) { + headerTokens.addTransitive(dep.getOutputGroup(CcCompilationHelper.HIDDEN_HEADER_TOKENS)); } if (ruleContext.getFragment(CppConfiguration.class).processHeadersInDependencies()) { headerTokens.addAll(ccCompilationOutputs.getHeaderTokenFiles()); @@ -1663,73 +1082,6 @@ public final class CcLibraryHelper { return new TransitiveLipoInfoProvider(scannableBuilder.build()); } - private Runfiles collectCppRunfiles( - CcLinkingOutputs ccLinkingOutputs, boolean linkingStatically) { - Runfiles.Builder builder = new Runfiles.Builder( - ruleContext.getWorkspaceName(), ruleContext.getConfiguration().legacyExternalRunfiles()); - builder.addTargets(deps, RunfilesProvider.DEFAULT_RUNFILES); - builder.addTargets(deps, CppRunfilesProvider.runfilesFunction(linkingStatically)); - // Add the shared libraries to the runfiles. - builder.addArtifacts(ccLinkingOutputs.getLibrariesForRunfiles(linkingStatically)); - return builder.build(); - } - - private CcLinkParamsStore createCcLinkParamsStore( - final CcLinkingOutputs ccLinkingOutputs, final CppCompilationContext cppCompilationContext, - final boolean forcePic) { - return new CcLinkParamsStore() { - @Override - protected void collect( - CcLinkParams.Builder builder, boolean linkingStatically, boolean linkShared) { - builder.addLinkstamps(linkstamps.build(), cppCompilationContext); - builder.addTransitiveTargets( - deps, CcLinkParamsInfo.TO_LINK_PARAMS, CcSpecificLinkParamsProvider.TO_LINK_PARAMS); - if (!neverlink) { - builder.addLibraries( - ccLinkingOutputs.getPreferredLibraries( - linkingStatically, /*preferPic=*/ linkShared || forcePic)); - if (!linkingStatically - || (ccLinkingOutputs.getStaticLibraries().isEmpty() - && ccLinkingOutputs.getPicStaticLibraries().isEmpty())) { - builder.addExecutionDynamicLibraries( - LinkerInputs.toLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries())); - } - builder.addLinkOpts(linkopts); - builder.addNonCodeInputs(nonCodeLinkerInputs); - } - } - }; - } - - private NestedSet<LinkerInput> collectNativeCcLibraries(CcLinkingOutputs ccLinkingOutputs) { - NestedSetBuilder<LinkerInput> result = NestedSetBuilder.linkOrder(); - result.addAll(ccLinkingOutputs.getDynamicLibraries()); - for (CcNativeLibraryProvider dep : - AnalysisUtils.getProviders(deps, CcNativeLibraryProvider.class)) { - result.addTransitive(dep.getTransitiveCcNativeLibraries()); - } - - return result.build(); - } - - private CcExecutionDynamicLibrariesProvider collectExecutionDynamicLibraryArtifacts( - List<LibraryToLink> executionDynamicLibraries) { - Iterable<Artifact> artifacts = LinkerInputs.toLibraryArtifacts(executionDynamicLibraries); - if (!Iterables.isEmpty(artifacts)) { - return new CcExecutionDynamicLibrariesProvider( - NestedSetBuilder.wrap(Order.STABLE_ORDER, artifacts)); - } - - NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder(); - for (CcExecutionDynamicLibrariesProvider dep : - AnalysisUtils.getProviders(deps, CcExecutionDynamicLibrariesProvider.class)) { - builder.addTransitive(dep.getExecutionDynamicLibraryArtifacts()); - } - return builder.isEmpty() - ? CcExecutionDynamicLibrariesProvider.EMPTY - : new CcExecutionDynamicLibrariesProvider(builder.build()); - } - private NestedSet<Artifact> getTemps(CcCompilationOutputs compilationOutputs) { return ruleContext.getFragment(CppConfiguration.class).isLipoContextCollector() ? NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER) @@ -1740,10 +1092,8 @@ public final class CcLibraryHelper { this.additionalCppModuleMaps.add(Preconditions.checkNotNull(cppModuleMap)); } - /** - * Don't generate a module map for this target if a custom module map is provided. - */ - public CcLibraryHelper doNotGenerateModuleMap() { + /** Don't generate a module map for this target if a custom module map is provided. */ + public CcCompilationHelper doNotGenerateModuleMap() { generateModuleMap = false; return this; } @@ -1755,7 +1105,7 @@ public final class CcLibraryHelper { * @param purpose must be a string which is suitable for use as a filename. A single rule may have * many middlemen with distinct purposes. */ - public CcLibraryHelper setPurpose(@Nullable String purpose) { + public CcCompilationHelper setPurpose(@Nullable String purpose) { this.purpose = purpose; return this; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java index f5e9f9dea5..b70ace4aea 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java @@ -23,7 +23,8 @@ import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo; +import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode; import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; @@ -62,7 +63,7 @@ public abstract class CcImport implements RuleConfiguredTargetFactory { "'shared_library' should be specified when 'system_provided' is false"); } - // Create CcLibraryHelper + // Create CcCompilationHelper CcToolchainProvider ccToolchain = CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext); FeatureConfiguration featureConfiguration = @@ -72,8 +73,9 @@ public abstract class CcImport implements RuleConfiguredTargetFactory { // Add headers to compilation step. final CcCommon common = new CcCommon(ruleContext); - Info.CompilationInfo compilationInfo = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + CompilationInfo compilationInfo = + new CcCompilationHelper( + ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) .addPublicHeaders(common.getHeaders()) .setHeadersCheckingMode(HeadersCheckingMode.STRICT) .compile(); @@ -90,8 +92,14 @@ public abstract class CcImport implements RuleConfiguredTargetFactory { .getRelative(labelName.replaceName("lib" + labelName.getBaseName())) .getPathString(); - CcLibraryHelper linkingHelper = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport); + CcLinkingHelper linkingHelper = + new CcLinkingHelper( + ruleContext, + semantics, + featureConfiguration, + ccToolchain, + fdoSupport, + ruleContext.getConfiguration()); if (staticLibrary != null) { if (CppFileTypes.PIC_ARCHIVE.matches(staticLibrary.getPath())) { @@ -159,7 +167,7 @@ public abstract class CcImport implements RuleConfiguredTargetFactory { linkingHelper.addDynamicLibraries(dynamicLibraryList); } - Info.LinkingInfo linkingInfo = + LinkingInfo linkingInfo = linkingHelper.link( compilationInfo.getCcCompilationOutputs(), compilationInfo.getCppCompilationContext()); @@ -168,8 +176,8 @@ public abstract class CcImport implements RuleConfiguredTargetFactory { .addProviders(linkingInfo.getProviders()) .addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider()) .addOutputGroups( - Info.mergeOutputGroups( - compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups())) + CcCommon.mergeOutputGroups( + ImmutableList.of(compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups()))) .addProvider(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java index ad05f41707..a844ef6375 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java @@ -26,7 +26,8 @@ import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo; +import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.Path; @@ -130,14 +131,21 @@ public abstract class CcIncLibrary implements RuleConfiguredTargetFactory { new CreateIncSymlinkAction(ruleContext.getActionOwner(), virtualArtifactMap, includeRoot)); FdoSupportProvider fdoSupport = CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext); - Info.CompilationInfo compilationInfo = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + CompilationInfo compilationInfo = + new CcCompilationHelper( + ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) .addIncludeDirs(Arrays.asList(includePath)) .addPublicHeaders(virtualArtifactMap.keySet()) .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)) .compile(); - Info.LinkingInfo linkingInfo = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + LinkingInfo linkingInfo = + new CcLinkingHelper( + ruleContext, + semantics, + featureConfiguration, + ccToolchain, + fdoSupport, + ruleContext.getConfiguration()) .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)) .link( compilationInfo.getCcCompilationOutputs(), @@ -154,8 +162,8 @@ public abstract class CcIncLibrary implements RuleConfiguredTargetFactory { .addProviders(linkingInfo.getProviders()) .addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider()) .addOutputGroups( - Info.mergeOutputGroups( - compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups())) + CcCommon.mergeOutputGroups( + ImmutableList.of(compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups()))) .add(InstrumentedFilesProvider.class, instrumentedFilesProvider) .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)) .build(); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java index 963414ae86..d07dd05769 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java @@ -37,7 +37,8 @@ import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.ImplicitOutputsFunction; import com.google.devtools.build.lib.packages.RawAttributeMapper; import com.google.devtools.build.lib.rules.cpp.CcCommon.CcFlagsSupplier; -import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo; +import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; @@ -132,16 +133,23 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory { return; } - CcLibraryHelper compilationHelper = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + CcCompilationHelper compilationHelper = + new CcCompilationHelper( + ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) .fromCommon(common) .addSources(common.getSources()) .addPublicHeaders(common.getHeaders()) .enableCompileProviders() .addPrecompiledFiles(precompiledFiles); - CcLibraryHelper linkingHelper = - new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport) + CcLinkingHelper linkingHelper = + new CcLinkingHelper( + ruleContext, + semantics, + featureConfiguration, + ccToolchain, + fdoSupport, + ruleContext.getConfiguration()) .fromCommon(common) .addLinkopts(common.getLinkopts()) .enableCcNativeLibrariesProvider() @@ -272,8 +280,8 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory { linkingHelper.addDynamicLibraries(dynamicLibraries); linkingHelper.addExecutionDynamicLibraries(dynamicLibraries); - Info.CompilationInfo compilationInfo = compilationHelper.compile(); - Info.LinkingInfo linkingInfo = + CompilationInfo compilationInfo = compilationHelper.compile(); + LinkingInfo linkingInfo = linkingHelper.link( compilationInfo.getCcCompilationOutputs(), compilationInfo.getCppCompilationContext()); @@ -322,8 +330,8 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory { .addProviders(linkingInfo.getProviders()) .addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider()) .addOutputGroups( - Info.mergeOutputGroups( - compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups())) + CcCommon.mergeOutputGroups( + ImmutableList.of(compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups()))) .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider) .addProvider( RunfilesProvider.class, RunfilesProvider.withData(staticRunfiles, sharedRunfiles)) @@ -335,8 +343,8 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory { collectHiddenTopLevelArtifacts( ruleContext, ccToolchain, compilationInfo.getCcCompilationOutputs())) .addOutputGroup( - CcLibraryHelper.HIDDEN_HEADER_TOKENS, - CcLibraryHelper.collectHeaderTokens( + CcCompilationHelper.HIDDEN_HEADER_TOKENS, + CcCompilationHelper.collectHeaderTokens( ruleContext, compilationInfo.getCcCompilationOutputs())); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java new file mode 100644 index 0000000000..77dc80f562 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java @@ -0,0 +1,706 @@ +// Copyright 2014 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.cpp; + +import static java.util.stream.Collectors.joining; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import com.google.common.collect.Streams; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.AnalysisUtils; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.LanguageDependentFragment; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.Runfiles; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap; +import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder; +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.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter; +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.Link.LinkTargetType; +import com.google.devtools.build.lib.rules.cpp.Link.Staticness; +import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; +import com.google.devtools.build.lib.syntax.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import javax.annotation.Nullable; + +/** + * A class to create C/C++ link actions in a way that is consistent with cc_library. Rules that + * generate source files and emulate cc_library on top of that should use this class instead of the + * lower-level APIs in CppHelper and CppModel. + * + * <p>Rules that want to use this class are required to have implicit dependencies on the toolchain, + * the STL, the lipo context, and so on. Optionally, they can also have copts, and malloc + * attributes, but note that these require explicit calls to the corresponding setter methods. + */ +public final class CcLinkingHelper { + + /** A string constant for the name of archive library(.a, .lo) output group. */ + public static final String ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME = "archive"; + + /** A string constant for the name of dynamic library output group. */ + public static final String DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME = "dynamic_library"; + + /** Contains the providers as well as the linking outputs. */ + public static final class LinkingInfo { + private final TransitiveInfoProviderMap providers; + private final Map<String, NestedSet<Artifact>> outputGroups; + private final CcLinkingOutputs linkingOutputs; + private final CcLinkingOutputs linkingOutputsExcludingPrecompiledLibraries; + + private LinkingInfo( + TransitiveInfoProviderMap providers, + Map<String, NestedSet<Artifact>> outputGroups, + CcLinkingOutputs linkingOutputs, + CcLinkingOutputs linkingOutputsExcludingPrecompiledLibraries) { + this.providers = providers; + this.outputGroups = outputGroups; + this.linkingOutputs = linkingOutputs; + this.linkingOutputsExcludingPrecompiledLibraries = + linkingOutputsExcludingPrecompiledLibraries; + } + + public TransitiveInfoProviderMap getProviders() { + return providers; + } + + public Map<String, NestedSet<Artifact>> getOutputGroups() { + return outputGroups; + } + + public CcLinkingOutputs getCcLinkingOutputs() { + return linkingOutputs; + } + + /** + * Returns the linking outputs before adding the pre-compiled libraries. Avoid using this - + * pre-compiled and locally compiled libraries should be treated identically. This method only + * exists for backwards compatibility. + */ + public CcLinkingOutputs getCcLinkingOutputsExcludingPrecompiledLibraries() { + return linkingOutputsExcludingPrecompiledLibraries; + } + + /** + * Adds the static, pic-static libraries to the given builder. If addDynamicLibraries parameter + * is true, it also adds dynamic(both compile-time and execution-time) libraries. + */ + public void addLinkingOutputsTo( + NestedSetBuilder<Artifact> filesBuilder, boolean addDynamicLibraries) { + filesBuilder + .addAll(LinkerInputs.toLibraryArtifacts(linkingOutputs.getStaticLibraries())) + .addAll(LinkerInputs.toLibraryArtifacts(linkingOutputs.getPicStaticLibraries())); + if (addDynamicLibraries) { + filesBuilder + .addAll(LinkerInputs.toNonSolibArtifacts(linkingOutputs.getDynamicLibraries())) + .addAll( + LinkerInputs.toNonSolibArtifacts(linkingOutputs.getExecutionDynamicLibraries())); + } + } + + public void addLinkingOutputsTo(NestedSetBuilder<Artifact> filesBuilder) { + addLinkingOutputsTo(filesBuilder, true); + } + } + + private final RuleContext ruleContext; + private final CppSemantics semantics; + private final BuildConfiguration configuration; + + private final List<Artifact> nonCodeLinkerInputs = new ArrayList<>(); + private final List<String> linkopts = new ArrayList<>(); + private final List<TransitiveInfoCollection> deps = new ArrayList<>(); + private final NestedSetBuilder<Artifact> linkstamps = NestedSetBuilder.stableOrder(); + private final List<Artifact> linkActionInputs = new ArrayList<>(); + + @Nullable private Artifact dynamicLibrary; + private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY; + private boolean neverlink; + private boolean fake; + + private final List<LibraryToLink> staticLibraries = new ArrayList<>(); + private final List<LibraryToLink> picStaticLibraries = new ArrayList<>(); + private final List<LibraryToLink> dynamicLibraries = new ArrayList<>(); + private final List<LibraryToLink> executionDynamicLibraries = new ArrayList<>(); + + private boolean checkDepsGenerateCpp = true; + private boolean emitLinkActionsIfEmpty; + private boolean emitCcNativeLibrariesProvider; + private boolean emitCcSpecificLinkParamsProvider; + private boolean emitInterfaceSharedObjects; + private boolean createDynamicLibrary = true; + private boolean createStaticLibraries = true; + private final List<VariablesExtension> variablesExtensions = new ArrayList<>(); + + private final FeatureConfiguration featureConfiguration; + private final CcToolchainProvider ccToolchain; + private final FdoSupportProvider fdoSupport; + private String linkedArtifactNameSuffix = ""; + + /** + * Creates a CcLinkingHelper that outputs artifacts in a given configuration. + * + * @param ruleContext the RuleContext for the rule being built + * @param semantics CppSemantics for the build + * @param featureConfiguration activated features and action configs for the build + * @param ccToolchain the C++ toolchain provider for the build + * @param fdoSupport the C++ FDO optimization support provider for the build + * @param configuration the configuration that gives the directory of output artifacts + */ + public CcLinkingHelper( + RuleContext ruleContext, + CppSemantics semantics, + FeatureConfiguration featureConfiguration, + CcToolchainProvider ccToolchain, + FdoSupportProvider fdoSupport, + BuildConfiguration configuration) { + this.ruleContext = Preconditions.checkNotNull(ruleContext); + this.semantics = Preconditions.checkNotNull(semantics); + this.featureConfiguration = Preconditions.checkNotNull(featureConfiguration); + this.ccToolchain = Preconditions.checkNotNull(ccToolchain); + this.fdoSupport = Preconditions.checkNotNull(fdoSupport); + this.configuration = Preconditions.checkNotNull(configuration); + } + + /** Sets fields that overlap for cc_library and cc_binary rules. */ + public CcLinkingHelper fromCommon(CcCommon common) { + addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)); + addNonCodeLinkerInputs(common.getLinkerScripts()); + return this; + } + + /** Adds the corresponding non-code files as linker inputs. */ + public void addNonCodeLinkerInputs(Iterable<Artifact> nonCodeLinkerInputs) { + for (Artifact nonCodeLinkerInput : nonCodeLinkerInputs) { + String basename = nonCodeLinkerInput.getFilename(); + Preconditions.checkArgument(!Link.OBJECT_FILETYPES.matches(basename)); + Preconditions.checkArgument(!Link.ARCHIVE_LIBRARY_FILETYPES.matches(basename)); + Preconditions.checkArgument(!Link.SHARED_LIBRARY_FILETYPES.matches(basename)); + this.nonCodeLinkerInputs.add(nonCodeLinkerInput); + } + } + + /** + * Add the corresponding files as static libraries into the linker outputs (i.e., after the linker + * action) - this makes them available for linking to binary rules that depend on this rule. + */ + public CcLinkingHelper addStaticLibraries(Iterable<LibraryToLink> libraries) { + Iterables.addAll(staticLibraries, libraries); + return this; + } + + /** + * Add the corresponding files as static libraries into the linker outputs (i.e., after the linker + * action) - this makes them available for linking to binary rules that depend on this rule. + */ + public CcLinkingHelper addPicStaticLibraries(Iterable<LibraryToLink> libraries) { + Iterables.addAll(picStaticLibraries, libraries); + return this; + } + + /** + * Add the corresponding files as dynamic libraries into the linker outputs (i.e., after the + * linker action) - this makes them available for linking to binary rules that depend on this + * rule. + */ + public CcLinkingHelper addDynamicLibraries(Iterable<LibraryToLink> libraries) { + Iterables.addAll(dynamicLibraries, libraries); + return this; + } + + /** Add the corresponding files as dynamic libraries required at runtime */ + public CcLinkingHelper addExecutionDynamicLibraries(Iterable<LibraryToLink> libraries) { + Iterables.addAll(executionDynamicLibraries, libraries); + return this; + } + + /** Adds the given options as linker options to the link command. */ + public CcLinkingHelper addLinkopts(Iterable<String> linkopts) { + Iterables.addAll(this.linkopts, linkopts); + return this; + } + + /** + * Adds the given targets as dependencies - this can include explicit dependencies on other rules + * (like from a "deps" attribute) and also implicit dependencies on runtime libraries. + */ + public CcLinkingHelper addDeps(Iterable<? extends TransitiveInfoCollection> deps) { + for (TransitiveInfoCollection dep : deps) { + this.deps.add(dep); + } + return this; + } + + /** + * Adds the given linkstamps. Note that linkstamps are usually not compiled at the library level, + * but only in the dependent binary rules. + */ + public CcLinkingHelper addLinkstamps(Iterable<? extends TransitiveInfoCollection> linkstamps) { + for (TransitiveInfoCollection linkstamp : linkstamps) { + this.linkstamps.addTransitive(linkstamp.getProvider(FileProvider.class).getFilesToBuild()); + } + return this; + } + + /** Adds the given artifact to the input of any generated link actions. */ + public CcLinkingHelper addLinkActionInput(Artifact input) { + Preconditions.checkNotNull(input); + this.linkActionInputs.add(input); + return this; + } + + /** Adds a variableExtension to template the crosstool. */ + public CcLinkingHelper addVariableExtension(VariablesExtension variableExtension) { + Preconditions.checkNotNull(variableExtension); + this.variablesExtensions.add(variableExtension); + return this; + } + + /** + * Overrides the path for the generated dynamic library - this should only be called if the + * dynamic library is an implicit or explicit output of the rule, i.e., if it is accessible by + * name from other rules in the same package. Set to {@code null} to use the default computation. + */ + public CcLinkingHelper setDynamicLibrary(@Nullable Artifact dynamicLibrary) { + this.dynamicLibrary = dynamicLibrary; + return this; + } + + /** + * Marks the output of this rule as alwayslink, i.e., the corresponding symbols will be retained + * by the linker even if they are not otherwise used. This is useful for libraries that register + * themselves somewhere during initialization. + * + * <p>This only sets the link type (see {@link #setStaticLinkType}), either to a static library or + * to an alwayslink static library (blaze uses a different file extension to signal alwayslink to + * downstream code). + */ + public CcLinkingHelper setAlwayslink(boolean alwayslink) { + linkType = + alwayslink ? LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY : LinkTargetType.STATIC_LIBRARY; + return this; + } + + /** + * Directly set the link type. This can be used instead of {@link #setAlwayslink}. Setting + * anything other than a static link causes this class to skip the link action creation. + */ + public CcLinkingHelper setStaticLinkType(LinkTargetType linkType) { + Preconditions.checkNotNull(linkType); + Preconditions.checkState(linkType.staticness() == Staticness.STATIC); + this.linkType = linkType; + return this; + } + + /** + * Marks the resulting code as neverlink, i.e., the code will not be linked into dependent + * libraries or binaries - the header files are still available. + */ + public CcLinkingHelper setNeverLink(boolean neverlink) { + this.neverlink = neverlink; + return this; + } + + /** + * Disables checking that the deps actually are C++ rules. By default, the {@link #link} method + * uses {@link LanguageDependentFragment.Checker#depSupportsLanguage} to check that all deps + * provide C++ providers. + */ + public CcLinkingHelper setCheckDepsGenerateCpp(boolean checkDepsGenerateCpp) { + this.checkDepsGenerateCpp = checkDepsGenerateCpp; + return this; + } + + /** + * Marks the resulting code as fake, i.e., the code will not actually be compiled or linked, but + * instead, the compile command is written to a file and added to the runfiles. This is currently + * used for non-compilation tests. Unfortunately, the design is problematic, so please don't add + * any further uses. + */ + public CcLinkingHelper setFake(boolean fake) { + this.fake = fake; + return this; + } + + /* + * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule + * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may + * generate the same linked artifact and therefore lead to artifact conflicts. This method + * provides a way to avoid this artifact conflict by allowing different callers acting on the same + * rule to provide a suffix that will be used to scope their own linked artifacts. + */ + public CcLinkingHelper setLinkedArtifactNameSuffix(String suffix) { + this.linkedArtifactNameSuffix = Preconditions.checkNotNull(suffix); + return this; + } + + /** This adds the {@link CcNativeLibraryProvider} to the providers created by this class. */ + public CcLinkingHelper enableCcNativeLibrariesProvider() { + this.emitCcNativeLibrariesProvider = true; + return this; + } + + /** + * This adds the {@link CcSpecificLinkParamsProvider} to the providers created by this class. + * Otherwise the result will contain an instance of {@link CcLinkParamsInfo}. + */ + public CcLinkingHelper enableCcSpecificLinkParamsProvider() { + this.emitCcSpecificLinkParamsProvider = true; + return this; + } + + /** + * Enables or disables generation of link actions if there are no object files. Some rules declare + * a <code>.a</code> or <code>.so</code> implicit output, which requires that these files are + * created even if there are no object files, so be careful when calling this. + * + * <p>This is disabled by default. + */ + public CcLinkingHelper setGenerateLinkActionsIfEmpty(boolean emitLinkActionsIfEmpty) { + this.emitLinkActionsIfEmpty = emitLinkActionsIfEmpty; + return this; + } + + /** + * Enables the optional generation of interface dynamic libraries - this is only used when the + * linker generates a dynamic library, and only if the crosstool supports it. The default is not + * to generate interface dynamic libraries. + */ + public CcLinkingHelper enableInterfaceSharedObjects() { + this.emitInterfaceSharedObjects = true; + return this; + } + + /** + * This enables or disables the generation of a dynamic library link action. The default is to + * generate a dynamic library. Note that the selection between dynamic or static linking is + * performed at the binary rule level. + */ + public CcLinkingHelper setCreateDynamicLibrary(boolean emitDynamicLibrary) { + this.createDynamicLibrary = emitDynamicLibrary; + return this; + } + + /** When createStaticLibraries is true, there are no actions created for static libraries. */ + public CcLinkingHelper setCreateStaticLibraries(boolean emitStaticLibraries) { + this.createStaticLibraries = emitStaticLibraries; + return this; + } + + public CcLinkingHelper setNeverlink(boolean neverlink) { + this.neverlink = neverlink; + return this; + } + + /** + * Create the C++ link actions, and the corresponding linking related providers. + * + * @throws RuleErrorException + */ + public LinkingInfo link( + CcCompilationOutputs ccOutputs, CppCompilationContext cppCompilationContext) + throws RuleErrorException, InterruptedException { + Preconditions.checkNotNull(ccOutputs); + Preconditions.checkNotNull(cppCompilationContext); + + if (checkDepsGenerateCpp) { + for (LanguageDependentFragment dep : + AnalysisUtils.getProviders(deps, LanguageDependentFragment.class)) { + LanguageDependentFragment.Checker.depSupportsLanguage( + ruleContext, dep, CppRuleClasses.LANGUAGE, "deps"); + } + } + + CppModel model = initializeCppModel(); + model.setContext(cppCompilationContext); + + // Create link actions (only if there are object files or if explicitly requested). + CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY; + if (emitLinkActionsIfEmpty || !ccOutputs.isEmpty()) { + // On some systems, the linker gives an error message if there are no input files. Even with + // the check above, this can still happen if there is a .nopic.o or .o files in srcs, but no + // other files. To fix that, we'd have to check for each link action individually. + // + // An additional pre-existing issue is that the header check tokens are dropped if we don't + // generate any link actions, effectively disabling header checking in some cases. + if (linkType.staticness() == Staticness.STATIC) { + // TODO(bazel-team): This can't create the link action for a cc_binary yet. + ccLinkingOutputs = model.createCcLinkActions(ccOutputs, nonCodeLinkerInputs); + } + } + CcLinkingOutputs originalLinkingOutputs = ccLinkingOutputs; + if (!(staticLibraries.isEmpty() + && picStaticLibraries.isEmpty() + && dynamicLibraries.isEmpty() + && executionDynamicLibraries.isEmpty())) { + + CcLinkingOutputs.Builder newOutputsBuilder = new CcLinkingOutputs.Builder(); + if (!ccOutputs.isEmpty()) { + // Add the linked outputs of this rule iff we had anything to put in them, but then + // make sure we're not colliding with some library added from the inputs. + newOutputsBuilder.merge(originalLinkingOutputs); + ImmutableSetMultimap<String, LibraryToLink> precompiledLibraryMap = + CcLinkingOutputs.getLibrariesByIdentifier( + Iterables.concat( + staticLibraries, picStaticLibraries, + dynamicLibraries, executionDynamicLibraries)); + ImmutableSetMultimap<String, LibraryToLink> linkedLibraryMap = + originalLinkingOutputs.getLibrariesByIdentifier(); + for (String matchingIdentifier : + Sets.intersection(precompiledLibraryMap.keySet(), linkedLibraryMap.keySet())) { + Iterable<Artifact> matchingInputLibs = + LinkerInputs.toNonSolibArtifacts(precompiledLibraryMap.get(matchingIdentifier)); + Iterable<Artifact> matchingOutputLibs = + LinkerInputs.toNonSolibArtifacts(linkedLibraryMap.get(matchingIdentifier)); + ruleContext.ruleError( + "Can't put " + + Streams.stream(matchingInputLibs) + .map(Artifact::getFilename) + .collect(joining(", ")) + + " into the srcs of a " + + ruleContext.getRuleClassNameForLogging() + + " with the same name (" + + ruleContext.getRule().getName() + + ") which also contains other code or objects to link; it shares a name with " + + Streams.stream(matchingOutputLibs) + .map(Artifact::getFilename) + .collect(joining(", ")) + + " (output compiled and linked from the non-library sources of this rule), " + + "which could cause confusion"); + } + } + + // Merge the pre-compiled libraries (static & dynamic) into the linker outputs. + ccLinkingOutputs = + newOutputsBuilder + .addStaticLibraries(staticLibraries) + .addPicStaticLibraries(picStaticLibraries) + .addDynamicLibraries(dynamicLibraries) + .addExecutionDynamicLibraries(executionDynamicLibraries) + .build(); + } + + Runfiles cppStaticRunfiles = collectCppRunfiles(ccLinkingOutputs, true); + Runfiles cppSharedRunfiles = collectCppRunfiles(ccLinkingOutputs, false); + + // By very careful when adding new providers here - it can potentially affect a lot of rules. + // We should consider merging most of these providers into a single provider. + TransitiveInfoProviderMapBuilder providers = + new TransitiveInfoProviderMapBuilder() + .add(new CppRunfilesProvider(cppStaticRunfiles, cppSharedRunfiles)); + + Map<String, NestedSet<Artifact>> outputGroups = new TreeMap<>(); + + if (shouldAddLinkerOutputArtifacts(ruleContext, ccOutputs)) { + addLinkerOutputArtifacts(outputGroups, ccOutputs); + } + + // TODO(bazel-team): Maybe we can infer these from other data at the places where they are + // used. + if (emitCcNativeLibrariesProvider) { + providers.add(new CcNativeLibraryProvider(collectNativeCcLibraries(ccLinkingOutputs))); + } + providers.put( + CcExecutionDynamicLibrariesProvider.class, + collectExecutionDynamicLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries())); + + CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class); + boolean forcePic = cppConfiguration.forcePic(); + if (emitCcSpecificLinkParamsProvider) { + providers.add( + new CcSpecificLinkParamsProvider( + createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic))); + } else { + providers.put( + new CcLinkParamsInfo( + createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic))); + } + return new LinkingInfo( + providers.build(), outputGroups, ccLinkingOutputs, originalLinkingOutputs); + } + + /** + * Returns true if the appropriate attributes for linker output artifacts are defined, and either + * the compile action produces object files or the build is configured to produce an archive or + * dynamic library even in the absence of object files. + */ + private boolean shouldAddLinkerOutputArtifacts( + RuleContext ruleContext, CcCompilationOutputs ccOutputs) { + return (ruleContext.attributes().has("alwayslink", Type.BOOLEAN) + && ruleContext.attributes().has("linkstatic", Type.BOOLEAN) + && (emitLinkActionsIfEmpty || !ccOutputs.isEmpty())); + } + + /** + * Adds linker output artifacts to the given map, to be registered on the configured target as + * output groups. + */ + private void addLinkerOutputArtifacts( + Map<String, NestedSet<Artifact>> outputGroups, CcCompilationOutputs ccOutputs) { + NestedSetBuilder<Artifact> archiveFile = new NestedSetBuilder<>(Order.STABLE_ORDER); + NestedSetBuilder<Artifact> dynamicLibrary = new NestedSetBuilder<>(Order.STABLE_ORDER); + + if (ruleContext.attributes().get("alwayslink", Type.BOOLEAN)) { + archiveFile.add( + CppHelper.getLinuxLinkedArtifact( + ruleContext, + configuration, + Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY, + linkedArtifactNameSuffix)); + } else { + archiveFile.add( + CppHelper.getLinuxLinkedArtifact( + ruleContext, + configuration, + Link.LinkTargetType.STATIC_LIBRARY, + linkedArtifactNameSuffix)); + } + + if (!ruleContext.attributes().get("linkstatic", Type.BOOLEAN) && !ccOutputs.isEmpty()) { + dynamicLibrary.add( + CppHelper.getLinuxLinkedArtifact( + ruleContext, + configuration, + Link.LinkTargetType.DYNAMIC_LIBRARY, + linkedArtifactNameSuffix)); + + if (CppHelper.useInterfaceSharedObjects(ccToolchain.getCppConfiguration(), ccToolchain) + && emitInterfaceSharedObjects) { + dynamicLibrary.add( + CppHelper.getLinuxLinkedArtifact( + ruleContext, + configuration, + LinkTargetType.INTERFACE_DYNAMIC_LIBRARY, + linkedArtifactNameSuffix)); + } + } + + outputGroups.put(ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME, archiveFile.build()); + outputGroups.put(DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME, dynamicLibrary.build()); + } + + /** Creates the C/C++ compilation action creator. */ + private CppModel initializeCppModel() { + // TODO(plf): Split CppModel into compilation and linking and stop passing last two arguments. + return new CppModel( + ruleContext, + semantics, + ccToolchain, + fdoSupport, + configuration, + ImmutableList.of(), + CoptsFilter.alwaysPasses()) + .setLinkTargetType(linkType) + .setNeverLink(neverlink) + .addLinkActionInputs(linkActionInputs) + .setFake(fake) + .setAllowInterfaceSharedObjects(emitInterfaceSharedObjects) + .setCreateDynamicLibrary(createDynamicLibrary) + .setCreateStaticLibraries(createStaticLibraries) + // Note: this doesn't actually save the temps, it just makes the CppModel use the + // configurations --save_temps setting to decide whether to actually save the temps. + .setSaveTemps(true) + .setDynamicLibrary(dynamicLibrary) + .addLinkopts(linkopts) + .setFeatureConfiguration(featureConfiguration) + .addVariablesExtension(variablesExtensions) + .setLinkedArtifactNameSuffix(linkedArtifactNameSuffix); + } + + private Runfiles collectCppRunfiles( + CcLinkingOutputs ccLinkingOutputs, boolean linkingStatically) { + Runfiles.Builder builder = + new Runfiles.Builder( + ruleContext.getWorkspaceName(), + ruleContext.getConfiguration().legacyExternalRunfiles()); + builder.addTargets(deps, RunfilesProvider.DEFAULT_RUNFILES); + builder.addTargets(deps, CppRunfilesProvider.runfilesFunction(linkingStatically)); + // Add the shared libraries to the runfiles. + builder.addArtifacts(ccLinkingOutputs.getLibrariesForRunfiles(linkingStatically)); + return builder.build(); + } + + private CcLinkParamsStore createCcLinkParamsStore( + final CcLinkingOutputs ccLinkingOutputs, + final CppCompilationContext cppCompilationContext, + final boolean forcePic) { + return new CcLinkParamsStore() { + @Override + protected void collect( + CcLinkParams.Builder builder, boolean linkingStatically, boolean linkShared) { + builder.addLinkstamps(linkstamps.build(), cppCompilationContext); + builder.addTransitiveTargets( + deps, CcLinkParamsInfo.TO_LINK_PARAMS, CcSpecificLinkParamsProvider.TO_LINK_PARAMS); + if (!neverlink) { + builder.addLibraries( + ccLinkingOutputs.getPreferredLibraries( + linkingStatically, /*preferPic=*/ linkShared || forcePic)); + if (!linkingStatically + || (ccLinkingOutputs.getStaticLibraries().isEmpty() + && ccLinkingOutputs.getPicStaticLibraries().isEmpty())) { + builder.addExecutionDynamicLibraries( + LinkerInputs.toLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries())); + } + builder.addLinkOpts(linkopts); + builder.addNonCodeInputs(nonCodeLinkerInputs); + } + } + }; + } + + private NestedSet<LinkerInput> collectNativeCcLibraries(CcLinkingOutputs ccLinkingOutputs) { + NestedSetBuilder<LinkerInput> result = NestedSetBuilder.linkOrder(); + result.addAll(ccLinkingOutputs.getDynamicLibraries()); + for (CcNativeLibraryProvider dep : + AnalysisUtils.getProviders(deps, CcNativeLibraryProvider.class)) { + result.addTransitive(dep.getTransitiveCcNativeLibraries()); + } + + return result.build(); + } + + private CcExecutionDynamicLibrariesProvider collectExecutionDynamicLibraryArtifacts( + List<LibraryToLink> executionDynamicLibraries) { + Iterable<Artifact> artifacts = LinkerInputs.toLibraryArtifacts(executionDynamicLibraries); + if (!Iterables.isEmpty(artifacts)) { + return new CcExecutionDynamicLibrariesProvider( + NestedSetBuilder.wrap(Order.STABLE_ORDER, artifacts)); + } + + NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder(); + for (CcExecutionDynamicLibrariesProvider dep : + AnalysisUtils.getProviders(deps, CcExecutionDynamicLibrariesProvider.class)) { + builder.addTransitive(dep.getExecutionDynamicLibraryArtifacts()); + } + return builder.isEmpty() + ? CcExecutionDynamicLibrariesProvider.EMPTY + : new CcExecutionDynamicLibrariesProvider(builder.build()); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java index d3037ff265..247d3ef91f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java @@ -261,7 +261,7 @@ public class CppCompileActionBuilder { } else if (CppFileTypes.CPP_MODULE.matches(sourcePath)) { return CppCompileAction.CPP_MODULE_CODEGEN; } - // CcLibraryHelper ensures CppCompileAction only gets instantiated for supported file types. + // CcCompilationHelper ensures CppCompileAction only gets instantiated for supported file types. throw new IllegalStateException(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java index a3cc7bfacb..2f4e7807e8 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java @@ -28,7 +28,6 @@ import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; import com.google.devtools.build.lib.analysis.OutputGroupInfo; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; -import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap; import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder; import com.google.devtools.build.lib.cmdline.Label; @@ -41,8 +40,10 @@ import com.google.devtools.build.lib.packages.NativeAspectClass; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.rules.cpp.AspectLegalCppSemantics; import com.google.devtools.build.lib.rules.cpp.CcCommon; -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.CcCompilationHelper; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo; +import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper; +import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo; import com.google.devtools.build.lib.rules.cpp.CcToolchain; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; @@ -114,9 +115,7 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu .requireProviders(ProtoSupportDataProvider.class) .add( attr(PROTO_TOOLCHAIN_ATTR, LABEL) - .mandatoryNativeProviders( - ImmutableList.<Class<? extends TransitiveInfoProvider>>of( - ProtoLangToolchainProvider.class)) + .mandatoryNativeProviders(ImmutableList.of(ProtoLangToolchainProvider.class)) .value(PROTO_TOOLCHAIN_LABEL)) .add( attr(CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME, LABEL) @@ -149,7 +148,7 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu FeatureConfiguration featureConfiguration = getFeatureConfiguration(supportData); ProtoConfiguration protoConfiguration = ruleContext.getFragment(ProtoConfiguration.class); - CcLibraryHelper compilationHelper = initializeCompilationHelper(featureConfiguration); + CcCompilationHelper compilationHelper = initializeCompilationHelper(featureConfiguration); // Compute and register files generated by this proto library. Collection<Artifact> outputs = new ArrayList<>(); @@ -190,8 +189,8 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu filesBuilder.addAll(outputs); createProtoCompileAction(supportData, outputs); - Info.CompilationInfo compilationInfo = compilationHelper.compile(); - Info.LinkingInfo linkingInfo = + CompilationInfo compilationInfo = compilationHelper.compile(); + LinkingInfo linkingInfo = initializeLinkingHelper(featureConfiguration) .link( compilationInfo.getCcCompilationOutputs(), @@ -204,8 +203,9 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu .build(); outputGroups = ImmutableMap.copyOf( - Info.mergeOutputGroups( - compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups())); + CcCommon.mergeOutputGroups( + ImmutableList.of( + compilationInfo.getOutputGroups(), linkingInfo.getOutputGroups()))); // On Windows, dynamic library is not built by default, so don't add them to filesToBuild. linkingInfo.addLinkingOutputsTo( filesBuilder, !featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)); @@ -236,9 +236,10 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu return featureConfiguration; } - private CcLibraryHelper initializeCcLibraryHelper(FeatureConfiguration featureConfiguration) { - CcLibraryHelper helper = - new CcLibraryHelper( + private CcCompilationHelper initializeCompilationHelper( + FeatureConfiguration featureConfiguration) { + CcCompilationHelper helper = + new CcCompilationHelper( ruleContext, cppSemantics, featureConfiguration, @@ -253,15 +254,22 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu return helper; } - private CcLibraryHelper initializeCompilationHelper(FeatureConfiguration featureConfiguration) { - return initializeCcLibraryHelper(featureConfiguration); - } - - private CcLibraryHelper initializeLinkingHelper(FeatureConfiguration featureConfiguration) { - CcLibraryHelper helper = - initializeCcLibraryHelper(featureConfiguration) + private CcLinkingHelper initializeLinkingHelper(FeatureConfiguration featureConfiguration) { + CcLinkingHelper helper = + new CcLinkingHelper( + ruleContext, + cppSemantics, + featureConfiguration, + ccToolchain(ruleContext), + CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext), + ruleContext.getConfiguration()) .enableCcSpecificLinkParamsProvider() .enableCcNativeLibrariesProvider(); + TransitiveInfoCollection runtime = getProtoToolchainProvider().runtime(); + if (runtime != null) { + helper.addDeps(ImmutableList.of(runtime)); + } + helper.addDeps(ruleContext.getPrerequisites("deps", TARGET)); // TODO(dougk): Configure output artifact with action_config // once proto compile action is configurable from the crosstool. if (!ccToolchain(ruleContext).supportsDynamicLinker()) { @@ -287,7 +295,7 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu return result.build(); } - private void registerBlacklistedSrcs(SupportData supportData, CcLibraryHelper helper) { + private void registerBlacklistedSrcs(SupportData supportData, CcCompilationHelper helper) { // Hack: This is a proto_library for descriptor.proto or similar. // // The headers of those libraries are precomputed . They are also explicitly part of normal 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 6f574abe67..f768eda0f5 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 @@ -88,9 +88,12 @@ 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.CcCommon; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper; +import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo; import com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs; -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.CcLinkingHelper; +import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo; 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; @@ -301,7 +304,7 @@ public class CompilationSupport { } } - private Info.CompilationInfo compile( + private CompilationInfo compile( ObjcProvider objcProvider, VariablesExtension extension, ExtraCompileArgs extraCompileArgs, @@ -318,12 +321,12 @@ public class CompilationSupport { ObjcCppSemantics semantics, String purpose) throws RuleErrorException, InterruptedException { - CcLibraryHelper result = - new CcLibraryHelper( + CcCompilationHelper result = + new CcCompilationHelper( ruleContext, semantics, getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider), - CcLibraryHelper.SourceCategory.CC_AND_OBJC, + CcCompilationHelper.SourceCategory.CC_AND_OBJC, ccToolchain, fdoSupport, buildConfiguration) @@ -398,7 +401,7 @@ public class CompilationSupport { String purpose = String.format("%s_objc_arc", semantics.getPurpose()); extensionBuilder.setArcEnabled(true); - Info.CompilationInfo objcArcCompilationInfo = + CompilationInfo objcArcCompilationInfo = compile( objcProvider, extensionBuilder.build(), @@ -417,7 +420,7 @@ public class CompilationSupport { purpose = String.format("%s_non_objc_arc", semantics.getPurpose()); extensionBuilder.setArcEnabled(false); - Info.CompilationInfo nonObjcArcCompilationInfo = + CompilationInfo nonObjcArcCompilationInfo = compile( objcProvider, extensionBuilder.build(), @@ -434,23 +437,18 @@ public class CompilationSupport { semantics, purpose); - CcLibraryHelper resultLink = - new CcLibraryHelper( + CcLinkingHelper resultLink = + new CcLinkingHelper( ruleContext, semantics, getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider), - CcLibraryHelper.SourceCategory.CC_AND_OBJC, ccToolchain, fdoSupport, buildConfiguration) - .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) .setLinkedArtifactNameSuffix(intermediateArtifacts.archiveFileNameSuffix()) .setNeverLink(true) + .setCheckDepsGenerateCpp(false) .addVariableExtension(extensionBuilder.build()); if (linkType != null) { @@ -475,15 +473,15 @@ public class CompilationSupport { compilationOutputsBuilder.merge(objcArcCompilationInfo.getCcCompilationOutputs()); compilationOutputsBuilder.merge(nonObjcArcCompilationInfo.getCcCompilationOutputs()); - Info.LinkingInfo linkingInfo = - resultLink.link( - compilationOutputsBuilder.build(), compilationContextBuilder.build()); + LinkingInfo linkingInfo = + resultLink.link(compilationOutputsBuilder.build(), compilationContextBuilder.build()); Map<String, NestedSet<Artifact>> mergedOutputGroups = - Info.mergeOutputGroups( - objcArcCompilationInfo.getOutputGroups(), - nonObjcArcCompilationInfo.getOutputGroups(), - linkingInfo.getOutputGroups()); + CcCommon.mergeOutputGroups( + ImmutableList.of( + objcArcCompilationInfo.getOutputGroups(), + nonObjcArcCompilationInfo.getOutputGroups(), + linkingInfo.getOutputGroups())); return new Pair<>(compilationOutputsBuilder.build(), ImmutableMap.copyOf(mergedOutputGroups)); } @@ -572,36 +570,6 @@ public class CompilationSupport { } } - private void registerHeaderScanningActions( - CcCompilationOutputs ccCompilationOutputs, - ObjcProvider objcProvider, - CompilationArtifacts compilationArtifacts) { - // PIC is not used for Obj-C builds, if that changes this method will need to change - if (!isHeaderThinningEnabled() || ccCompilationOutputs.getObjectFiles(false).isEmpty()) { - return; - } - - ImmutableList.Builder<ObjcHeaderThinningInfo> headerThinningInfos = ImmutableList.builder(); - AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment(); - for (Artifact objectFile : ccCompilationOutputs.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. */ @@ -890,72 +858,6 @@ public class CompilationSupport { } /** - * Registers all actions necessary to compile this rule's sources and archive them. - * - * @param compilationArtifacts collection of artifacts required for the compilation - * @param objcProvider provides all compiling and linking information to register these actions - * @param toolchain the toolchain to be used in determining command lines - * @return this compilation support - * @throws RuleErrorException for invalid crosstool files - */ - CompilationSupport registerCompileAndArchiveActions( - CompilationArtifacts compilationArtifacts, - ObjcProvider objcProvider, - CcToolchainProvider toolchain) - throws RuleErrorException, InterruptedException { - return registerCompileAndArchiveActions( - compilationArtifacts, - objcProvider, - ExtraCompileArgs.NONE, - ImmutableList.<PathFragment>of(), - toolchain, - maybeGetFdoSupport()); - } - - /** - * Registers all actions necessary to compile this rule's sources and archive them. - * - * @param common common information about this rule and its dependencies - * @return this compilation support - * @throws RuleErrorException for invalid crosstool files - */ - CompilationSupport registerCompileAndArchiveActions(ObjcCommon common) - throws RuleErrorException, InterruptedException { - return registerCompileAndArchiveActions( - common, ExtraCompileArgs.NONE, ImmutableList.<PathFragment>of()); - } - - /** - * Registers all actions necessary to compile this rule's sources and archive them. - * - * @param common common information about this rule and its dependencies - * @param priorityHeaders priority headers to be included before the dependency headers - * @return this compilation support - * @throws RuleErrorException for invalid crosstool files - */ - CompilationSupport registerCompileAndArchiveActions( - ObjcCommon common, Iterable<PathFragment> priorityHeaders) - throws RuleErrorException, InterruptedException { - return registerCompileAndArchiveActions(common, ExtraCompileArgs.NONE, priorityHeaders); - } - - /** - * 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 - */ - public CompilationSupport registerFullyLinkAction( - ObjcProvider objcProvider, Artifact outputArchive) throws InterruptedException { - return registerFullyLinkAction( - objcProvider, - outputArchive, - toolchain, - maybeGetFdoSupport()); - } - - /** * Returns a provider that collects this target's instrumented sources as well as those of its * dependencies. * @@ -984,27 +886,6 @@ public class CompilationSupport { } /** - * Registers an action that will generate a clang module map for this target, using the hdrs - * attribute of this rule. - */ - CompilationSupport registerGenerateModuleMapAction(CompilationArtifacts compilationArtifacts) { - // TODO(bazel-team): Include textual headers in the module map when Xcode 6 support is - // dropped. - // TODO(b/32225593): Include private headers in the module map. - Iterable<Artifact> publicHeaders = attributes.hdrs(); - publicHeaders = Iterables.concat(publicHeaders, compilationArtifacts.getAdditionalHdrs()); - CppModuleMap moduleMap = intermediateArtifacts.moduleMap(); - registerGenerateModuleMapAction(moduleMap, publicHeaders); - - Optional<Artifact> umbrellaHeader = moduleMap.getUmbrellaHeader(); - if (umbrellaHeader.isPresent()) { - registerGenerateUmbrellaHeaderAction(umbrellaHeader.get(), publicHeaders); - } - - return this; - } - - /** * Validates compilation-related attributes on this rule. * * @return this compilation support @@ -1049,6 +930,56 @@ public class CompilationSupport { * * @param compilationArtifacts collection of artifacts required for the compilation * @param objcProvider provides all compiling and linking information to register these actions + * @param toolchain the toolchain to be used in determining command lines + * @return this compilation support + * @throws RuleErrorException for invalid crosstool files + */ + CompilationSupport registerCompileAndArchiveActions( + CompilationArtifacts compilationArtifacts, + ObjcProvider objcProvider, + CcToolchainProvider toolchain) + throws RuleErrorException, InterruptedException { + return registerCompileAndArchiveActions( + compilationArtifacts, + objcProvider, + ExtraCompileArgs.NONE, + ImmutableList.<PathFragment>of(), + toolchain, + maybeGetFdoSupport()); + } + + /** + * Registers all actions necessary to compile this rule's sources and archive them. + * + * @param common common information about this rule and its dependencies + * @return this compilation support + * @throws RuleErrorException for invalid crosstool files + */ + CompilationSupport registerCompileAndArchiveActions(ObjcCommon common) + throws RuleErrorException, InterruptedException { + return registerCompileAndArchiveActions( + common, ExtraCompileArgs.NONE, ImmutableList.<PathFragment>of()); + } + + /** + * Registers all actions necessary to compile this rule's sources and archive them. + * + * @param common common information about this rule and its dependencies + * @param priorityHeaders priority headers to be included before the dependency headers + * @return this compilation support + * @throws RuleErrorException for invalid crosstool files + */ + CompilationSupport registerCompileAndArchiveActions( + ObjcCommon common, Iterable<PathFragment> priorityHeaders) + throws RuleErrorException, InterruptedException { + return registerCompileAndArchiveActions(common, ExtraCompileArgs.NONE, priorityHeaders); + } + + /** + * Registers all actions necessary to compile this rule's sources and archive them. + * + * @param compilationArtifacts collection of artifacts required for the compilation + * @param objcProvider provides all compiling and linking information to register these actions * @param extraCompileArgs args to be added to compile actions * @param priorityHeaders priority headers to be included before the dependency headers * @param ccToolchain the cpp toolchain provider, may be null @@ -1381,6 +1312,18 @@ public class CompilationSupport { * * @param objcProvider provides all compiling and linking information to create this artifact * @param outputArchive the output artifact for this action + */ + public CompilationSupport registerFullyLinkAction( + ObjcProvider objcProvider, Artifact outputArchive) throws InterruptedException { + return registerFullyLinkAction(objcProvider, outputArchive, toolchain, maybeGetFdoSupport()); + } + + /** + * 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 * @return this {@link CompilationSupport} instance @@ -1745,6 +1688,27 @@ public class CompilationSupport { } /** + * Registers an action that will generate a clang module map for this target, using the hdrs + * attribute of this rule. + */ + CompilationSupport registerGenerateModuleMapAction(CompilationArtifacts compilationArtifacts) { + // TODO(bazel-team): Include textual headers in the module map when Xcode 6 support is + // dropped. + // TODO(b/32225593): Include private headers in the module map. + Iterable<Artifact> publicHeaders = attributes.hdrs(); + publicHeaders = Iterables.concat(publicHeaders, compilationArtifacts.getAdditionalHdrs()); + CppModuleMap moduleMap = intermediateArtifacts.moduleMap(); + registerGenerateModuleMapAction(moduleMap, publicHeaders); + + Optional<Artifact> umbrellaHeader = moduleMap.getUmbrellaHeader(); + if (umbrellaHeader.isPresent()) { + registerGenerateUmbrellaHeaderAction(umbrellaHeader.get(), publicHeaders); + } + + return this; + } + + /** * Registers an action that will generate a clang module map. * @param moduleMap the module map to generate * @param publicHeaders the headers that should be directly accessible by dependers @@ -1840,6 +1804,36 @@ public class CompilationSupport { .getProvider(FilesToRunProvider.class); } + private void registerHeaderScanningActions( + CcCompilationOutputs ccCompilationOutputs, + ObjcProvider objcProvider, + CompilationArtifacts compilationArtifacts) { + // PIC is not used for Obj-C builds, if that changes this method will need to change + if (!isHeaderThinningEnabled() || ccCompilationOutputs.getObjectFiles(false).isEmpty()) { + return; + } + + ImmutableList.Builder<ObjcHeaderThinningInfo> headerThinningInfos = ImmutableList.builder(); + AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment(); + for (Artifact objectFile : ccCompilationOutputs.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); + } + /** * Creates and registers ObjcHeaderScanning {@link SpawnAction}. Groups all the actions by their * compilation command line arguments and creates a ObjcHeaderScanning action for each unique one. |