linkopts = new ArrayList<>();
if (isLinkShared(context)) {
linkopts.add("-shared");
}
linkopts.addAll(common.getLinkopts());
return ImmutableList.copyOf(linkopts);
}
private static boolean linkstaticAttribute(RuleContext context) {
return context.attributes().get("linkstatic", Type.BOOLEAN);
}
/**
* Returns "true" if the {@code linkshared} attribute exists and is set.
*/
private static final boolean isLinkShared(RuleContext context) {
return context.getRule().getRuleClassObject().hasAttr("linkshared", Type.BOOLEAN)
&& context.attributes().get("linkshared", Type.BOOLEAN);
}
private static final boolean dashStaticInLinkopts(CcCommon common,
CppConfiguration cppConfiguration) {
return common.getLinkopts().contains("-static")
|| cppConfiguration.getLinkOptions().contains("-static");
}
private static final LinkStaticness getLinkStaticness(RuleContext context,
CcCommon common, CppConfiguration cppConfiguration) {
if (cppConfiguration.getDynamicMode() == DynamicMode.FULLY) {
return LinkStaticness.DYNAMIC;
} else if (dashStaticInLinkopts(common, cppConfiguration)) {
return LinkStaticness.FULLY_STATIC;
} else if (cppConfiguration.getDynamicMode() == DynamicMode.OFF
|| linkstaticAttribute(context)) {
return LinkStaticness.MOSTLY_STATIC;
} else {
return LinkStaticness.DYNAMIC;
}
}
/**
* Collects .dwo artifacts either transitively or directly, depending on the link type.
*
* For a cc_binary, we only include the .dwo files corresponding to the .o files that are
* passed into the link. For static linking, this includes all transitive dependencies. But
* for dynamic linking, dependencies are separately linked into their own shared libraries,
* so we don't need them here.
*/
private static DwoArtifactsCollector collectTransitiveDwoArtifacts(RuleContext context,
CcCommon common, CppConfiguration cppConfiguration, CcCompilationOutputs compilationOutputs) {
if (getLinkStaticness(context, common, cppConfiguration) == LinkStaticness.DYNAMIC) {
return DwoArtifactsCollector.directCollector(compilationOutputs);
} else {
return CcCommon.collectTransitiveDwoArtifacts(context, compilationOutputs);
}
}
@VisibleForTesting
public static Iterable getDwpInputs(
RuleContext context, NestedSet picDwoArtifacts, NestedSet dwoArtifacts) {
return CppHelper.usePic(context, !isLinkShared(context)) ? picDwoArtifacts : dwoArtifacts;
}
/**
* Creates the actions needed to generate this target's "debug info package"
* (i.e. its .dwp file).
*/
private static void createDebugPackagerActions(RuleContext context,
CppConfiguration cppConfiguration, Artifact dwpOutput,
DwoArtifactsCollector dwoArtifactsCollector) {
Iterable allInputs = getDwpInputs(context,
dwoArtifactsCollector.getPicDwoArtifacts(),
dwoArtifactsCollector.getDwoArtifacts());
// No inputs? Just generate a trivially empty .dwp.
//
// Note this condition automatically triggers for any build where fission is disabled.
// Because rules referencing .dwp targets may be invoked with or without fission, we need
// to support .dwp generation even when fission is disabled. Since no actual functionality
// is expected then, an empty file is appropriate.
if (Iterables.isEmpty(allInputs)) {
context.registerAction(
new FileWriteAction(context.getActionOwner(), dwpOutput, "", false));
return;
}
// Get the tool inputs necessary to run the dwp command.
NestedSet dwpTools = CppHelper.getToolchain(context).getDwp();
Preconditions.checkState(!dwpTools.isEmpty());
// We apply a hierarchical action structure to limit the maximum number of inputs to any
// single action.
//
// While the dwp tools consumes .dwo files, it can also consume intermediate .dwp files,
// allowing us to split a large input set into smaller batches of arbitrary size and order.
// Aside from the parallelism performance benefits this offers, this also reduces input
// size requirements: if a.dwo, b.dwo, c.dwo, and e.dwo are each 1 KB files, we can apply
// two intermediate actions DWP(a.dwo, b.dwo) --> i1.dwp and DWP(c.dwo, e.dwo) --> i2.dwp.
// When we then apply the final action DWP(i1.dwp, i2.dwp) --> finalOutput.dwp, the inputs
// to this action will usually total far less than 4 KB.
//
// This list tracks every action we'll need to generate the output .dwp with batching.
List packagers = new ArrayList<>();
// Step 1: generate our batches. We currently break into arbitrary batches of fixed maximum
// input counts, but we can always apply more intelligent heuristics if the need arises.
SpawnAction.Builder currentPackager = newDwpAction(cppConfiguration, dwpTools);
int inputsForCurrentPackager = 0;
for (Artifact dwoInput : allInputs) {
if (inputsForCurrentPackager == MAX_INPUTS_PER_DWP_ACTION) {
packagers.add(currentPackager);
currentPackager = newDwpAction(cppConfiguration, dwpTools);
inputsForCurrentPackager = 0;
}
currentPackager.addInputArgument(dwoInput);
inputsForCurrentPackager++;
}
packagers.add(currentPackager);
// Step 2: given the batches, create the actions.
if (packagers.size() == 1) {
// If we only have one batch, make a single "original inputs --> final output" action.
context.registerAction(Iterables.getOnlyElement(packagers)
.addArgument("-o")
.addOutputArgument(dwpOutput)
.setMnemonic("CcGenerateDwp")
.build(context));
} else {
// If we have multiple batches, make them all intermediate actions, then pipe their outputs
// into an additional action that outputs the final artifact.
//
// Note this only creates a hierarchy one level deep (i.e. we don't check if the number of
// intermediate outputs exceeds the maximum batch size). This is okay for current needs,
// which shouldn't stress those limits.
List intermediateOutputs = new ArrayList<>();
int count = 1;
for (SpawnAction.Builder packager : packagers) {
Artifact intermediateOutput =
getIntermediateDwpFile(context.getAnalysisEnvironment(), dwpOutput, count++);
context.registerAction(packager
.addArgument("-o")
.addOutputArgument(intermediateOutput)
.setMnemonic("CcGenerateIntermediateDwp")
.build(context));
intermediateOutputs.add(intermediateOutput);
}
// Now create the final action.
context.registerAction(newDwpAction(cppConfiguration, dwpTools)
.addInputArguments(intermediateOutputs)
.addArgument("-o")
.addOutputArgument(dwpOutput)
.setMnemonic("CcGenerateDwp")
.build(context));
}
}
/**
* Returns a new SpawnAction builder for generating dwp files, pre-initialized with
* standard settings.
*/
private static SpawnAction.Builder newDwpAction(CppConfiguration cppConfiguration,
NestedSet dwpTools) {
return new SpawnAction.Builder()
.addTransitiveInputs(dwpTools)
.setExecutable(cppConfiguration.getDwpExecutable())
.useParameterFile(ParameterFile.ParameterFileType.UNQUOTED);
}
/**
* Creates an intermediate dwp file keyed off the name and path of the final output.
*/
private static Artifact getIntermediateDwpFile(AnalysisEnvironment env, Artifact dwpOutput,
int orderNumber) {
PathFragment outputPath = dwpOutput.getRootRelativePath();
PathFragment intermediatePath =
FileSystemUtils.appendWithoutExtension(outputPath, "-" + orderNumber);
return env.getDerivedArtifact(
outputPath.getParentDirectory().getRelative(
INTERMEDIATE_DWP_DIR + "/" + intermediatePath.getPathString()),
dwpOutput.getRoot());
}
/**
* Collect link parameters from the transitive closure.
*/
private static CcLinkParams collectCcLinkParams(RuleContext context, CcCommon common,
boolean linkingStatically, boolean linkShared) {
CcLinkParams.Builder builder = CcLinkParams.builder(linkingStatically, linkShared);
if (isLinkShared(context)) {
// CcLinkingOutputs is empty because this target is not configured yet
builder.addCcLibrary(context, common, false, CcLinkingOutputs.EMPTY);
} else {
builder.addTransitiveTargets(
context.getPrerequisites("deps", Mode.TARGET),
CcLinkParamsProvider.TO_LINK_PARAMS, CcSpecificLinkParamsProvider.TO_LINK_PARAMS);
builder.addTransitiveTarget(CppHelper.mallocForTarget(context));
builder.addLinkOpts(getBinaryLinkopts(context, common));
}
return builder.build();
}
private static ImmutableList createBaselineCoverageArtifacts(
RuleContext context, CcCommon common, CcCompilationOutputs compilationOutputs,
boolean fake) {
if (!TargetUtils.isTestRule(context.getRule()) && !fake) {
Iterable objectFiles = compilationOutputs.getObjectFiles(
CppHelper.usePic(context, !isLinkShared(context)));
return BaselineCoverageAction.getBaselineCoverageArtifacts(context,
common.getInstrumentedFilesProvider(objectFiles).getInstrumentedFiles());
} else {
return ImmutableList.of();
}
}
}