cc_library
rules.
*/
public abstract class CcLibrary implements RuleConfiguredTargetFactory {
private final CppSemantics semantics;
protected CcLibrary(CppSemantics semantics) {
this.semantics = semantics;
}
// These file extensions don't generate object files.
private static final FileTypeSet NO_OBJECT_GENERATING_FILETYPES = FileTypeSet.of(
CppFileTypes.CPP_HEADER, CppFileTypes.ARCHIVE, CppFileTypes.PIC_ARCHIVE,
CppFileTypes.ALWAYS_LINK_LIBRARY, CppFileTypes.ALWAYS_LINK_PIC_LIBRARY,
CppFileTypes.SHARED_LIBRARY, CppFileTypes.VERSIONED_SHARED_LIBRARY);
private static Runfiles collectRunfiles(RuleContext context,
CcLinkingOutputs ccLinkingOutputs,
CcToolchainProvider ccToolchain,
boolean neverLink, boolean addDynamicRuntimeInputArtifactsToRunfiles,
boolean linkingStatically) {
Runfiles.Builder builder = new Runfiles.Builder(
context.getWorkspaceName(), context.getConfiguration().legacyExternalRunfiles());
// neverlink= true creates a library that will never be linked into any binary that depends on
// it, but instead be loaded as an extension. So we need the dynamic library for this in the
// runfiles.
builder.addArtifacts(ccLinkingOutputs.getLibrariesForRunfiles(linkingStatically && !neverLink));
builder.add(context, CppRunfilesProvider.runfilesFunction(linkingStatically));
builder.addDataDeps(context);
if (addDynamicRuntimeInputArtifactsToRunfiles) {
builder.addTransitiveArtifacts(ccToolchain.getDynamicRuntimeLinkInputs());
}
return builder.build();
}
@Override
public ConfiguredTarget create(RuleContext context)
throws RuleErrorException, InterruptedException {
RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(context);
LinkTargetType linkType = getStaticLinkType(context);
boolean linkStatic = context.attributes().get("linkstatic", Type.BOOLEAN);
init(semantics, context, builder, linkType,
/*neverLink =*/ false,
linkStatic,
/*collectLinkstamp =*/ true,
/*addDynamicRuntimeInputArtifactsToRunfiles =*/ false);
return builder.build();
}
public static void init(
CppSemantics semantics,
RuleContext ruleContext,
RuleConfiguredTargetBuilder targetBuilder,
LinkTargetType linkType,
boolean neverLink,
boolean linkStatic,
boolean collectLinkstamp,
boolean addDynamicRuntimeInputArtifactsToRunfiles)
throws RuleErrorException, InterruptedException {
final CcCommon common = new CcCommon(ruleContext);
CcToolchainProvider ccToolchain = common.getToolchain();
FdoSupportProvider fdoSupport = common.getFdoSupport();
FeatureConfiguration featureConfiguration =
CcCommon.configureFeatures(ruleContext, ccToolchain);
PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);
semantics.validateAttributes(ruleContext);
if (ruleContext.hasErrors()) {
return;
}
CcLibraryHelper helper =
new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport)
.fromCommon(common)
.addLinkopts(common.getLinkopts())
.addSources(common.getSources())
.addPublicHeaders(common.getHeaders())
.enableCcNativeLibrariesProvider()
.enableCompileProviders()
.enableInterfaceSharedObjects()
// 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.
.setGenerateLinkActionsIfEmpty(
ruleContext.getRule().getImplicitOutputsFunction() != ImplicitOutputsFunction.NONE)
.setLinkType(linkType)
.setNeverLink(neverLink)
.addPrecompiledFiles(precompiledFiles);
if (collectLinkstamp) {
helper.addLinkstamps(ruleContext.getPrerequisites("linkstamp", Mode.TARGET));
}
Artifact soImplArtifact = null;
boolean supportsDynamicLinker =
ruleContext.getFragment(CppConfiguration.class).supportsDynamicLinker();
// 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 (ruleContext.getRule().isAttrDefined("outs", Type.STRING_LIST)) {
ListIn some cases, this may return "true" even though the rule actually has no object files.
* For example, it will return true for a rule such as
* cc_library(name = 'foo', srcs = [':bar'])
because we can't tell what ':bar' is;
* it might be a genrule that generates a source file, or it might be a genrule that generates a
* header file. Likewise,
* cc_library(name = 'foo', srcs = select({':a': ['foo.cc'], ':b': []}))
returns
* "true" even though the sources *may* be empty. This reflects the fact that there's no way
* to tell which value "srcs" will take without knowing the rule's configuration.
*
*
In other cases, this may return "false" even though the rule actually does have object
* files. For example, it will return false for a rule such as
* cc_library(name = 'foo', srcs = ['bar.h'])
but as in the other example above,
* we can't tell whether 'bar.h' is a file name or a rule name, and 'bar.h' could in fact be the
* name of a genrule that generates a source file.
*/
public static boolean appearsToHaveObjectFiles(AttributeMap rule) {
if ((rule instanceof RawAttributeMapper) && rule.isConfigurable("srcs")) {
// Since this method gets called by loading phase logic (e.g. the cc_library implicit outputs
// function), the attribute mapper may not be able to resolve configurable attributes. When
// that's the case, there's no way to know which value a configurable "srcs" will take, so
// we conservatively assume object files are possible.
return true;
}
List