in src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java [108:496]
public static void init(
CppSemantics semantics,
RuleContext ruleContext,
RuleConfiguredTargetBuilder targetBuilder,
ImmutableList<String> additionalCopts,
PathFragment soFilename,
boolean alwaysLink,
boolean neverLink,
boolean linkStatic,
boolean addDynamicRuntimeInputArtifactsToRunfiles)
throws RuleErrorException, InterruptedException {
semantics.validateDeps(ruleContext);
if (ruleContext.hasErrors()) {
addEmptyRequiredProviders(targetBuilder);
return;
}
CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
if (!cppConfiguration.experimentalCcImplementationDeps()
&& ruleContext.attributes().isAttributeValueExplicitlySpecified("implementation_deps")) {
ruleContext.attributeError(
"implementation_deps", "requires --experimental_cc_implementation_deps");
}
final CcCommon common = new CcCommon(ruleContext);
common.reportInvalidOptions(ruleContext);
CcToolchainProvider ccToolchain = common.getToolchain();
ImmutableMap.Builder<String, String> toolchainMakeVariables = ImmutableMap.builder();
ccToolchain.addGlobalMakeVariables(toolchainMakeVariables);
ruleContext.initConfigurationMakeVariableContext(
new MapBackedMakeVariableSupplier(toolchainMakeVariables.buildOrThrow()),
new CcFlagsSupplier(ruleContext));
FdoContext fdoContext = common.getFdoContext();
FeatureConfiguration featureConfiguration =
CcCommon.configureFeaturesOrReportRuleError(ruleContext, ccToolchain, semantics);
PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);
semantics.validateAttributes(ruleContext);
if (ruleContext.hasErrors()) {
addEmptyRequiredProviders(targetBuilder);
return;
}
ImmutableList<TransitiveInfoCollection> deps =
ImmutableList.copyOf(ruleContext.getPrerequisites("deps"));
if (ruleContext.hasErrors()) {
addEmptyRequiredProviders(targetBuilder);
return;
}
Iterable<CcInfo> ccInfosFromDeps = AnalysisUtils.getProviders(deps, CcInfo.PROVIDER);
CcCompilationHelper compilationHelper =
new CcCompilationHelper(
ruleContext,
ruleContext,
ruleContext.getLabel(),
CppHelper.getGrepIncludes(ruleContext),
semantics,
featureConfiguration,
ccToolchain,
fdoContext,
TargetUtils.getExecutionInfo(
ruleContext.getRule(), ruleContext.isAllowTagsPropagation()),
/* shouldProcessHeaders= */ true)
.fromCommon(common, additionalCopts)
.addSources(common.getSources())
.addPrivateHeaders(common.getPrivateHeaders())
.addPublicHeaders(common.getHeaders())
.setCodeCoverageEnabled(CcCompilationHelper.isCodeCoverageEnabled(ruleContext))
.addCcCompilationContexts(
Streams.stream(ccInfosFromDeps)
.map(CcInfo::getCcCompilationContext)
.collect(ImmutableList.toImmutableList()))
.addCcCompilationContexts(
ImmutableList.of(CcCompilationHelper.getStlCcCompilationContext(ruleContext)))
.addImplementationDepsCcCompilationContexts(
CppHelper.getCompilationContextsFromDeps(
ImmutableList.copyOf(ruleContext.getPrerequisites("implementation_deps"))))
.setHeadersCheckingMode(semantics.determineHeadersCheckingMode(ruleContext));
CcLinkingHelper linkingHelper =
new CcLinkingHelper(
ruleContext,
ruleContext.getLabel(),
ruleContext,
ruleContext,
semantics,
featureConfiguration,
ccToolchain,
fdoContext,
ruleContext.getConfiguration(),
ruleContext.getFragment(CppConfiguration.class),
ruleContext.getSymbolGenerator(),
TargetUtils.getExecutionInfo(
ruleContext.getRule(), ruleContext.isAllowTagsPropagation()))
.fromCommon(ruleContext, common)
.addCcLinkingContexts(
CppHelper.getLinkingContextsFromDeps(
ImmutableList.copyOf(ruleContext.getPrerequisites("implementation_deps"))))
.setGrepIncludes(CppHelper.getGrepIncludes(ruleContext))
.setTestOrTestOnlyTarget(ruleContext.isTestOnlyTarget())
.addLinkopts(common.getLinkopts())
.emitInterfaceSharedLibraries(true)
.setAlwayslink(alwaysLink)
.setNeverLink(neverLink)
.addLinkstamps(ruleContext.getPrerequisites("linkstamp"));
Artifact soImplArtifact = null;
boolean supportsDynamicLinker = ccToolchain.supportsDynamicLinker(featureConfiguration);
// TODO(djasper): This is hacky. We should actually try to figure out whether we generate
// ccOutputs.
boolean createDynamicLibrary =
!linkStatic
&& supportsDynamicLinker
&& (appearsToHaveObjectFiles(ruleContext.attributes())
|| featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN));
if (soFilename != null) {
if (!soFilename.getPathString().endsWith(".so")) {
ruleContext.attributeError("outs", "file name must end in '.so'");
}
if (createDynamicLibrary) {
soImplArtifact = ruleContext.getBinArtifact(soFilename);
}
}
if (ruleContext.getRule().isAttrDefined("textual_hdrs", BuildType.LABEL_LIST)) {
compilationHelper.addPublicTextualHeaders(
ruleContext.getPrerequisiteArtifacts("textual_hdrs").list());
}
if (ruleContext.getRule().isAttrDefined("include_prefix", Type.STRING)
&& ruleContext.attributes().isAttributeValueExplicitlySpecified("include_prefix")) {
compilationHelper.setIncludePrefix(
ruleContext.attributes().get("include_prefix", Type.STRING));
}
if (ruleContext.getRule().isAttrDefined("strip_include_prefix", Type.STRING)
&& ruleContext.attributes().isAttributeValueExplicitlySpecified("strip_include_prefix")) {
compilationHelper.setStripIncludePrefix(
ruleContext.attributes().get("strip_include_prefix", Type.STRING));
}
if (common.getLinkopts().contains("-static")) {
ruleContext.attributeWarning("linkopts", "Using '-static' here won't work. "
+ "Did you mean to use 'linkstatic=1' instead?");
}
linkingHelper.setShouldCreateDynamicLibrary(createDynamicLibrary);
linkingHelper.setLinkerOutputArtifact(soImplArtifact);
// If the reason we're not creating a dynamic library is that the toolchain
// doesn't support it, then register an action which complains when triggered,
// which only happens when some rule explicitly depends on the dynamic library.
if (!createDynamicLibrary && !supportsDynamicLinker) {
ImmutableList.Builder<Artifact> dynamicLibraries = ImmutableList.builder();
dynamicLibraries.add(
CppHelper.getLinkedArtifact(
ruleContext,
ccToolchain,
ruleContext.getConfiguration(),
LinkTargetType.NODEPS_DYNAMIC_LIBRARY,
CppHelper.getDLLHashSuffix(ruleContext, featureConfiguration)));
if (CppHelper.useInterfaceSharedLibraries(
cppConfiguration, ccToolchain, featureConfiguration)) {
dynamicLibraries.add(
CppHelper.getLinkedArtifact(
ruleContext,
ccToolchain,
ruleContext.getConfiguration(),
LinkTargetType.INTERFACE_DYNAMIC_LIBRARY));
}
ruleContext.registerAction(
new FailAction(
ruleContext.getActionOwner(),
dynamicLibraries.build(),
"Toolchain does not support dynamic linking",
Code.DYNAMIC_LINKING_NOT_SUPPORTED));
} else if (!createDynamicLibrary
&& ruleContext.attributes().isConfigurable("srcs")) {
// If "srcs" is configurable, the .so output is always declared because the logic that
// determines implicit outs doesn't know which value of "srcs" will ultimately get chosen.
// Here, where we *do* have the correct value, it may not contain any source files to
// generate an .so with. If that's the case, register a fake generating action to prevent
// a "no generating action for this artifact" error.
ImmutableList.Builder<Artifact> dynamicLibraries = ImmutableList.builder();
dynamicLibraries.add(
CppHelper.getLinkedArtifact(
ruleContext,
ccToolchain,
ruleContext.getConfiguration(),
LinkTargetType.NODEPS_DYNAMIC_LIBRARY,
CppHelper.getDLLHashSuffix(ruleContext, featureConfiguration)));
if (CppHelper.useInterfaceSharedLibraries(
cppConfiguration, ccToolchain, featureConfiguration)) {
dynamicLibraries.add(
CppHelper.getLinkedArtifact(
ruleContext,
ccToolchain,
ruleContext.getConfiguration(),
LinkTargetType.INTERFACE_DYNAMIC_LIBRARY));
}
ruleContext.registerAction(
new FailAction(
ruleContext.getActionOwner(),
dynamicLibraries.build(),
"configurable \"srcs\" triggers an implicit .so output even though there are no"
+ " sources to compile in this configuration",
Code.SOURCE_FILES_MISSING));
}
CompilationInfo compilationInfo = compilationHelper.compile(ruleContext);
CcCompilationOutputs precompiledFilesObjects =
CcCompilationOutputs.builder()
.addObjectFiles(precompiledFiles.getObjectFiles(/* usePic= */ true))
.addPicObjectFiles(precompiledFiles.getObjectFiles(/* usePic= */ true))
.build();
CcCompilationOutputs ccCompilationOutputs =
CcCompilationOutputs.builder()
.merge(precompiledFilesObjects)
.merge(compilationInfo.getCcCompilationOutputs())
.build();
// Generate .a and .so outputs even without object files to fulfill the rule class
// contract wrt. implicit output files, if the contract says so. Behavior here differs
// between Bazel and Blaze.
CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
if (semantics.createEmptyArchive() || !ccCompilationOutputs.isEmpty()) {
if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
String dllNameSuffix = CppHelper.getDLLHashSuffix(ruleContext, featureConfiguration);
linkingHelper.setLinkedDLLNameSuffix(dllNameSuffix);
Artifact generatedDefFile = null;
Artifact defParser = common.getDefParser();
if (defParser != null) {
generatedDefFile =
CppHelper.createDefFileActions(
ruleContext,
defParser,
ccCompilationOutputs.getObjectFiles(false),
ccToolchain
.getFeatures()
.getArtifactNameForCategory(
ArtifactCategory.DYNAMIC_LIBRARY,
ruleContext.getLabel().getName() + dllNameSuffix));
targetBuilder.addOutputGroup(DEF_FILE_OUTPUT_GROUP_NAME, generatedDefFile);
}
linkingHelper.setDefFile(
CppHelper.getWindowsDefFileForLinking(
ruleContext, common.getWinDefFile(), generatedDefFile, featureConfiguration));
}
ccLinkingOutputs = linkingHelper.link(ccCompilationOutputs);
}
ImmutableSortedMap.Builder<String, NestedSet<Artifact>> outputGroups =
ImmutableSortedMap.naturalOrder();
if (!ccLinkingOutputs.isEmpty()) {
outputGroups.putAll(
addLinkerOutputArtifacts(
ruleContext,
ccToolchain,
cppConfiguration,
ruleContext.getConfiguration(),
ccCompilationOutputs,
featureConfiguration));
}
List<LibraryToLink> precompiledLibraries =
convertPrecompiledLibrariesToLibraryToLink(
ruleContext,
common,
ruleContext.getFragment(CppConfiguration.class).forcePic(),
precompiledFiles);
if (!ccCompilationOutputs.isEmpty()) {
checkIfLinkOutputsCollidingWithPrecompiledFiles(
ruleContext, ccLinkingOutputs, precompiledLibraries);
}
ImmutableList<LibraryToLink> libraryToLinks =
createLibrariesToLinkList(
ccLinkingOutputs.getLibraryToLink(),
precompiledLibraries,
ccCompilationOutputs.isEmpty());
CcLinkingContext ccLinkingContext =
linkingHelper.buildCcLinkingContextFromLibrariesToLink(
neverLink ? ImmutableList.of() : libraryToLinks,
compilationInfo.getCcCompilationContext());
CcNativeLibraryInfo ccNativeLibraryInfo =
CppHelper.collectNativeCcLibraries(ruleContext.getPrerequisites("deps"), libraryToLinks);
/*
* We always generate a static library, even if there aren't any source files.
* This keeps things simpler by avoiding special cases when making use of the library.
* For example, this is needed to ensure that building a library with "bazel build"
* will also build all of the library's "deps".
* However, we only generate a dynamic library if there are source files.
*/
// For now, we don't add the precompiled libraries to the files to build.
NestedSetBuilder<Artifact> filesBuilder = NestedSetBuilder.stableOrder();
if (!ccLinkingOutputs.isEmpty()) {
LibraryToLink artifactsToBuild = ccLinkingOutputs.getLibraryToLink();
if (artifactsToBuild.getStaticLibrary() != null) {
filesBuilder.add(artifactsToBuild.getStaticLibrary());
}
if (artifactsToBuild.getPicStaticLibrary() != null) {
filesBuilder.add(artifactsToBuild.getPicStaticLibrary());
}
if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
if (artifactsToBuild.getResolvedSymlinkDynamicLibrary() != null) {
filesBuilder.add(artifactsToBuild.getResolvedSymlinkDynamicLibrary());
} else if (artifactsToBuild.getDynamicLibrary() != null) {
filesBuilder.add(artifactsToBuild.getDynamicLibrary());
}
if (artifactsToBuild.getResolvedSymlinkInterfaceLibrary() != null) {
filesBuilder.add(artifactsToBuild.getResolvedSymlinkInterfaceLibrary());
} else if (artifactsToBuild.getInterfaceLibrary() != null) {
filesBuilder.add(artifactsToBuild.getInterfaceLibrary());
}
}
}
if (!featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
warnAboutEmptyLibraries(ruleContext, ccCompilationOutputs, linkStatic);
}
NestedSet<Artifact> filesToBuild = filesBuilder.build();
List<Artifact> instrumentedObjectFiles = new ArrayList<>();
instrumentedObjectFiles.addAll(compilationInfo.getCcCompilationOutputs().getObjectFiles(false));
instrumentedObjectFiles.addAll(compilationInfo.getCcCompilationOutputs().getObjectFiles(true));
InstrumentedFilesInfo instrumentedFilesProvider =
common.getInstrumentedFilesProvider(
instrumentedObjectFiles,
/* withBaselineCoverage= */ true,
/* virtualToOriginalHeaders= */ NestedSetBuilder.create(Order.STABLE_ORDER),
/* additionalMetadata= */ null);
CppHelper.maybeAddStaticLinkMarkerProvider(targetBuilder, ruleContext);
Runfiles.Builder builder = new Runfiles.Builder(ruleContext.getWorkspaceName());
builder.addDataDeps(ruleContext);
builder.add(ruleContext, RunfilesProvider.DEFAULT_RUNFILES);
if (addDynamicRuntimeInputArtifactsToRunfiles) {
try {
builder.addTransitiveArtifacts(
ccToolchain.getDynamicRuntimeLinkInputs(featureConfiguration));
} catch (EvalException e) {
throw ruleContext.throwWithRuleError(e);
}
}
Runfiles runfiles = builder.build();
Runfiles.Builder defaultRunfiles =
new Runfiles.Builder(ruleContext.getWorkspaceName())
.merge(runfiles)
.addArtifacts(LibraryToLink.getDynamicLibrariesForRuntime(!neverLink, libraryToLinks));
Runfiles.Builder dataRunfiles =
new Runfiles.Builder(ruleContext.getWorkspaceName())
.merge(runfiles)
.addArtifacts(
LibraryToLink.getDynamicLibrariesForRuntime(
/* linkingStatically= */ false, libraryToLinks));
Map<String, NestedSet<Artifact>> currentOutputGroups =
CcCompilationHelper.buildOutputGroupsForEmittingCompileProviders(
compilationInfo.getCcCompilationOutputs(),
compilationInfo.getCcCompilationContext(),
ruleContext.getFragment(CppConfiguration.class),
ccToolchain,
featureConfiguration,
ruleContext,
/* generateHiddenTopLevelGroup= */ true);
CcStarlarkApiProvider.maybeAdd(ruleContext, targetBuilder);
targetBuilder
.setFilesToBuild(filesToBuild)
.addNativeDeclaredProvider(
CcInfo.builder()
.setCcCompilationContext(compilationInfo.getCcCompilationContext())
.setCcLinkingContext(ccLinkingContext)
.setCcDebugInfoContext(
CppHelper.mergeCcDebugInfoContexts(
compilationInfo.getCcCompilationOutputs(), ccInfosFromDeps))
.setCcNativeLibraryInfo(ccNativeLibraryInfo)
.build())
.addOutputGroups(
CcCommon.mergeOutputGroups(
ImmutableList.of(currentOutputGroups, outputGroups.buildOrThrow())))
.addNativeDeclaredProvider(instrumentedFilesProvider)
.addProvider(RunfilesProvider.withData(defaultRunfiles.build(), dataRunfiles.build()));
}