in src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java [318:748]
public static void init(
CppSemantics semantics, RuleConfiguredTargetBuilder ruleBuilder, RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
semantics.validateDeps(ruleContext);
if (ruleContext.attributes().isAttributeValueExplicitlySpecified("dynamic_deps")) {
if (!ruleContext
.getAnalysisEnvironment()
.getStarlarkSemantics()
.getBool(BuildLanguageOptions.EXPERIMENTAL_CC_SHARED_LIBRARY)) {
ruleContext.ruleError(
"The attribute 'dynamic_deps' can only be used with the flag"
+ " --experimental_cc_shared_library.");
} else if (ruleContext.attributes().isAttributeValueExplicitlySpecified("linkshared")) {
ruleContext.ruleError(
"Do not use `linkshared` to build a shared library. Use cc_shared_library instead.");
}
}
if (ruleContext.hasErrors()) {
fillInRequiredProviders(ruleBuilder, ruleContext);
return;
}
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));
CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);
LinkTargetType linkType =
isLinkShared(ruleContext) ? LinkTargetType.DYNAMIC_LIBRARY : LinkTargetType.EXECUTABLE;
semantics.validateAttributes(ruleContext);
if (ruleContext.hasErrors()) {
fillInRequiredProviders(ruleBuilder, ruleContext);
return;
}
// if cc_binary includes "linkshared=1", then gcc will be invoked with
// linkopt "-shared", which causes the result of linking to be a shared
// library.
final Artifact binary;
// For linkshared=1 we used to force users to specify the file extension manually, as part of
// the target name.
// This is no longer necessary, the toolchain can figure out the correct file extension.
String targetName = ruleContext.getTarget().getName();
boolean hasLegacyLinkSharedName =
isLinkShared(ruleContext)
&& (CppFileTypes.SHARED_LIBRARY.matches(targetName)
|| CppFileTypes.VERSIONED_SHARED_LIBRARY.matches(targetName));
if (hasLegacyLinkSharedName) {
binary = ruleContext.getBinArtifact(PathFragment.create(targetName));
} else {
binary =
CppHelper.getLinkedArtifact(
ruleContext, ccToolchain, ruleContext.getConfiguration(), linkType);
}
LinkingMode linkingMode = getLinkStaticness(ruleContext, cppConfiguration);
ImmutableSet.Builder<String> requestedFeaturesBuilder = new ImmutableSet.Builder<>();
requestedFeaturesBuilder
.addAll(ruleContext.getFeatures())
.add(linkingMode == Link.LinkingMode.DYNAMIC ? DYNAMIC_LINKING_MODE : STATIC_LINKING_MODE);
ImmutableSet.Builder<String> disabledFeaturesBuilder = new ImmutableSet.Builder<>();
disabledFeaturesBuilder.addAll(ruleContext.getDisabledFeatures());
if (TargetUtils.isTestRule(ruleContext.getRule()) && cppConfiguration.useCcTestFeature()) {
requestedFeaturesBuilder.add(IS_CC_TEST_FEATURE_NAME);
disabledFeaturesBuilder.add(LEGACY_IS_CC_TEST_FEATURE_NAME);
}
FdoContext fdoContext = common.getFdoContext();
FeatureConfiguration featureConfiguration =
CcCommon.configureFeaturesOrReportRuleError(
ruleContext,
requestedFeaturesBuilder.build(),
/* unsupportedFeatures= */ disabledFeaturesBuilder.build(),
ccToolchain,
semantics);
ImmutableList<TransitiveInfoCollection> deps =
ImmutableList.<TransitiveInfoCollection>builder()
.addAll(ruleContext.getPrerequisites("deps"))
.add(CppHelper.mallocForTarget(ruleContext))
.build();
if (ruleContext.hasErrors()) {
fillInRequiredProviders(ruleBuilder, ruleContext);
return;
}
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= */ ImmutableList.of())
.addPrivateHeaders(common.getPrivateHeaders())
.addSources(common.getSources())
.addCcCompilationContexts(CppHelper.getCompilationContextsFromDeps(deps))
.addCcCompilationContexts(
ImmutableList.of(CcCompilationHelper.getStlCcCompilationContext(ruleContext)))
.setHeadersCheckingMode(semantics.determineHeadersCheckingMode(ruleContext))
.setCodeCoverageEnabled(CcCompilationHelper.isCodeCoverageEnabled(ruleContext));
CompilationInfo compilationInfo = compilationHelper.compile(ruleContext);
CcCompilationContext ccCompilationContext = compilationInfo.getCcCompilationContext();
CcCompilationOutputs precompiledFileObjects =
CcCompilationOutputs.builder()
.addObjectFiles(precompiledFiles.getObjectFiles(/* usePic= */ false))
.addPicObjectFiles(precompiledFiles.getObjectFiles(/* usePic= */ true))
.build();
CcCompilationOutputs ccCompilationOutputs =
CcCompilationOutputs.builder()
.merge(precompiledFileObjects)
.merge(compilationInfo.getCcCompilationOutputs())
.build();
List<Artifact> additionalLinkerInputs = common.getAdditionalLinkerInputs();
// Allows the dynamic library generated for code of test targets to be linked separately.
boolean linkCompileOutputSeparately =
ruleContext.isTestTarget()
&& linkingMode == LinkingMode.DYNAMIC
&& cppConfiguration.getDynamicModeFlag() == DynamicMode.DEFAULT
&& ruleContext.getFeatures().contains(DYNAMIC_LINK_TEST_SRCS);
// When linking the object files directly into the resulting binary, we do not need
// 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 CcCompilationHelper to
// take care of creating the library link outputs for us, so we need to set the link
// type to STATIC_LIBRARY.
//
// [*] The only library link type is STATIC_LIBRARY. EXECUTABLE specifies a normal
// cc_binary output, while DYNAMIC_LIBRARY is a cc_binary rules that produces an
// output matching a shared object, for example cc_binary(name="foo.so", ...) on linux.
CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
if (linkCompileOutputSeparately && !ccCompilationOutputs.isEmpty()) {
CcLinkingHelper linkingHelper =
new CcLinkingHelper(
ruleContext,
ruleContext.getLabel(),
ruleContext,
ruleContext,
semantics,
featureConfiguration,
ccToolchain,
fdoContext,
ruleContext.getConfiguration(),
cppConfiguration,
ruleContext.getSymbolGenerator(),
TargetUtils.getExecutionInfo(
ruleContext.getRule(), ruleContext.isAllowTagsPropagation()))
.fromCommon(ruleContext, common)
.setGrepIncludes(CppHelper.getGrepIncludes(ruleContext))
.setIsStampingEnabled(AnalysisUtils.isStampingEnabled(ruleContext))
.setTestOrTestOnlyTarget(ruleContext.isTestTarget() || ruleContext.isTestOnlyTarget())
.addCcLinkingContexts(
CppHelper.getLinkingContextsFromDeps(
ImmutableList.of(CppHelper.mallocForTarget(ruleContext))))
.emitInterfaceSharedLibraries(true)
.setAlwayslink(false);
ccLinkingOutputs = linkingHelper.link(ccCompilationOutputs);
}
boolean isStaticMode = linkingMode != LinkingMode.DYNAMIC;
CcLinkingContext depsCcLinkingContext = collectCcLinkingContext(ruleContext);
Artifact generatedDefFile = null;
Artifact winDefFile = null;
if (isLinkShared(ruleContext)) {
if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
ImmutableList.Builder<Artifact> objectFiles = ImmutableList.builder();
objectFiles.addAll(ccCompilationOutputs.getObjectFiles(false));
for (LibraryToLink library : depsCcLinkingContext.getLibraries().toList()) {
if (isStaticMode
|| (library.getDynamicLibrary() == null && library.getInterfaceLibrary() == null)) {
if (library.getPicStaticLibrary() != null) {
if (library.getPicObjectFiles() != null) {
objectFiles.addAll(library.getPicObjectFiles());
}
} else if (library.getStaticLibrary() != null) {
if (library.getObjectFiles() != null) {
objectFiles.addAll(library.getObjectFiles());
}
}
}
}
Artifact defParser = common.getDefParser();
if (defParser != null) {
generatedDefFile =
CppHelper.createDefFileActions(
ruleContext, defParser, objectFiles.build(), binary.getFilename());
}
winDefFile =
CppHelper.getWindowsDefFileForLinking(
ruleContext, common.getWinDefFile(), generatedDefFile, featureConfiguration);
}
}
boolean usePic = usePic(ruleContext, ccToolchain, cppConfiguration, featureConfiguration);
// On Windows, if GENERATE_PDB_FILE feature is enabled
// then a pdb file will be built along with the executable.
Artifact pdbFile = null;
if (featureConfiguration.isEnabled(CppRuleClasses.GENERATE_PDB_FILE)) {
pdbFile =
ruleContext.getRelatedArtifact(
binary.getOutputDirRelativePath(
ruleContext.getConfiguration().isSiblingRepositoryLayout()),
".pdb");
}
NestedSetBuilder<CcLinkingContext.LinkerInput> extraLinkTimeLibrariesNestedSet =
NestedSetBuilder.linkOrder();
NestedSetBuilder<Artifact> extraLinkTimeRuntimeLibraries = NestedSetBuilder.linkOrder();
ExtraLinkTimeLibraries extraLinkTimeLibraries =
depsCcLinkingContext.getExtraLinkTimeLibraries();
if (extraLinkTimeLibraries != null) {
ExtraLinkTimeLibrary.BuildLibraryOutput extraLinkBuildLibraryOutput =
extraLinkTimeLibraries.buildLibraries(
ruleContext, linkingMode != LinkingMode.DYNAMIC, isLinkShared(ruleContext));
extraLinkTimeLibrariesNestedSet.addTransitive(extraLinkBuildLibraryOutput.getLinkerInputs());
extraLinkTimeRuntimeLibraries.addTransitive(
extraLinkBuildLibraryOutput.getRuntimeLibraries());
}
Pair<CcLinkingOutputs, CcLauncherInfo> ccLinkingOutputsAndCcLinkingInfo =
createTransitiveLinkingActions(
ruleContext,
ruleBuilder,
ccToolchain,
featureConfiguration,
fdoContext,
common,
precompiledFiles,
ccCompilationOutputs,
additionalLinkerInputs,
ccLinkingOutputs,
ccCompilationContext,
binary,
depsCcLinkingContext,
extraLinkTimeLibrariesNestedSet.build(),
linkCompileOutputSeparately,
semantics,
linkingMode,
cppConfiguration,
linkType,
pdbFile,
winDefFile);
if (ruleContext.hasErrors()) {
fillInRequiredProviders(ruleBuilder, ruleContext);
return;
}
CcLinkingOutputs ccLinkingOutputsBinary = ccLinkingOutputsAndCcLinkingInfo.first;
CcLauncherInfo ccLauncherInfo = ccLinkingOutputsAndCcLinkingInfo.second;
LibraryToLink ccLinkingOutputsBinaryLibrary = ccLinkingOutputsBinary.getLibraryToLink();
ImmutableList.Builder<LibraryToLink> librariesBuilder = ImmutableList.builder();
if (isLinkShared(ruleContext)) {
if (ccLinkingOutputsBinaryLibrary != null) {
librariesBuilder.add(ccLinkingOutputsBinaryLibrary);
}
}
// Also add all shared libraries from srcs.
for (Artifact library : precompiledFiles.getSharedLibraries()) {
Artifact symlink = common.getDynamicLibrarySymlink(library, true);
LibraryToLink libraryToLink =
LibraryToLink.builder()
.setLibraryIdentifier(CcLinkingOutputs.libraryIdentifierOf(library))
.setDynamicLibrary(symlink)
.setResolvedSymlinkDynamicLibrary(library)
.build();
librariesBuilder.add(libraryToLink);
}
ImmutableList<LibraryToLink> libraries = librariesBuilder.build();
NestedSet<Artifact> filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, binary);
// Create the stripped binary, but don't add it to filesToBuild; it's only built when requested.
Artifact strippedFile = ruleContext.getImplicitOutputArtifact(
CppRuleClasses.CC_BINARY_STRIPPED);
CppHelper.createStripAction(
ruleContext, ccToolchain, cppConfiguration, binary, strippedFile, featureConfiguration);
NestedSet<Artifact> dwoFiles =
collectTransitiveDwoArtifacts(
ccCompilationOutputs,
CppHelper.mergeCcDebugInfoContexts(
compilationInfo.getCcCompilationOutputs(),
AnalysisUtils.getProviders(deps, CcInfo.PROVIDER)),
linkingMode,
usePic,
ccLinkingOutputsBinary.getAllLtoArtifacts());
Artifact dwpFile =
ruleContext.getImplicitOutputArtifact(CppRuleClasses.CC_BINARY_DEBUG_PACKAGE);
createDebugPackagerActions(ruleContext, ccToolchain, dwpFile, dwoFiles);
// The debug package should include the dwp file only if it was explicitly requested.
Artifact explicitDwpFile = dwpFile;
if (!ccToolchain.shouldCreatePerObjectDebugInfo(featureConfiguration, cppConfiguration)) {
explicitDwpFile = null;
} else {
// For cc_test rules, include the dwp in the runfiles if Fission is enabled and the test was
// built statically.
if (TargetUtils.isTestRule(ruleContext.getRule())
&& linkingMode != Link.LinkingMode.DYNAMIC
&& cppConfiguration.buildTestDwpIsActivated()) {
filesToBuild = NestedSetBuilder.fromNestedSet(filesToBuild).add(dwpFile).build();
}
}
// If the binary is linked dynamically and COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, collect
// all the dynamic libraries we need at runtime. Then copy these libraries next to the binary.
NestedSet<Artifact> copiedRuntimeDynamicLibraries = null;
if (featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
copiedRuntimeDynamicLibraries =
createDynamicLibrariesCopyActions(
ruleContext,
LibraryToLink.getDynamicLibrariesForRuntime(
isStaticMode, depsCcLinkingContext.getLibraries().toList()));
}
// TODO(bazel-team): Do we need to put original shared libraries (along with
// mangled symlinks) into the RunfilesSupport object? It does not seem
// logical since all symlinked libraries will be linked anyway and would
// not require manual loading but if we do, then we would need to collect
// their names and use a different constructor below.
NestedSetBuilder<Artifact> transitiveArtifacts =
NestedSetBuilder.<Artifact>stableOrder()
.addTransitive(filesToBuild)
.addTransitive(extraLinkTimeRuntimeLibraries.build());
if (featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
transitiveArtifacts.addTransitive(copiedRuntimeDynamicLibraries);
}
ImmutableList.Builder<Artifact> runtimeObjectsForCoverage =
ImmutableList.<Artifact>builder().add(binary);
RuntimeFiles runtimeFiles =
collectRunfiles(
ruleContext,
featureConfiguration,
ccToolchain,
libraries,
ccLinkingOutputs,
linkingMode,
transitiveArtifacts.build(),
linkCompileOutputSeparately);
runtimeObjectsForCoverage.addAll(runtimeFiles.runtimeObjectsForCoverage());
RunfilesSupport runfilesSupport =
RunfilesSupport.withExecutable(ruleContext, runtimeFiles.runfiles(), binary);
addTransitiveInfoProviders(
ruleContext,
ccToolchain,
cppConfiguration,
featureConfiguration,
common,
ruleBuilder,
filesToBuild,
ccCompilationOutputs,
ccCompilationContext,
libraries,
runtimeObjectsForCoverage.build());
// Support test execution on darwin.
if (ApplePlatform.isApplePlatform(ccToolchain.getTargetCpu())
&& TargetUtils.isTestRule(ruleContext.getRule())) {
ruleBuilder.addNativeDeclaredProvider(
new ExecutionInfo(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, "")));
}
// If PDB file is generated by the link action, we add it to pdb_file output group
if (pdbFile != null) {
ruleBuilder.addOutputGroup("pdb_file", pdbFile);
}
if (generatedDefFile != null) {
ruleBuilder.addOutputGroup("def_file", generatedDefFile);
}
if (!ccLinkingOutputsBinary.isEmpty()) {
LibraryToLink libraryToLink = ccLinkingOutputsBinary.getLibraryToLink();
Artifact dynamicLibraryForLinking = null;
if (libraryToLink.getInterfaceLibrary() != null) {
if (libraryToLink.getResolvedSymlinkInterfaceLibrary() != null) {
dynamicLibraryForLinking = libraryToLink.getResolvedSymlinkInterfaceLibrary();
} else {
dynamicLibraryForLinking = libraryToLink.getInterfaceLibrary();
}
} else if (libraryToLink.getDynamicLibrary() != null) {
if (libraryToLink.getResolvedSymlinkDynamicLibrary() != null) {
dynamicLibraryForLinking = libraryToLink.getResolvedSymlinkDynamicLibrary();
} else {
dynamicLibraryForLinking = libraryToLink.getDynamicLibrary();
}
}
if (dynamicLibraryForLinking != null) {
ruleBuilder.addOutputGroup("interface_library", dynamicLibraryForLinking);
}
}
if (copiedRuntimeDynamicLibraries != null) {
ruleBuilder.addOutputGroup("runtime_dynamic_libraries", copiedRuntimeDynamicLibraries);
}
CcStarlarkApiProvider.maybeAdd(ruleContext, ruleBuilder);
ruleBuilder
.addProvider(RunfilesProvider.class, RunfilesProvider.simple(runtimeFiles.runfiles()))
.addNativeDeclaredProvider(
new DebugPackageProvider(ruleContext.getLabel(), strippedFile, binary, explicitDwpFile))
.setRunfilesSupport(runfilesSupport, binary)
.addNativeDeclaredProvider(ccLauncherInfo);
}