use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class CcBinary method init.
public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleContext, boolean fake) throws InterruptedException, RuleErrorException {
ruleContext.checkSrcsSamePackage(true);
CcCommon common = new CcCommon(ruleContext);
CcToolchainProvider ccToolchain = common.getToolchain();
FdoSupportProvider fdoSupport = common.getFdoSupport();
FeatureConfiguration featureConfiguration = CcCommon.configureFeatures(ruleContext, ccToolchain);
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()) {
return null;
}
List<String> linkopts = common.getLinkopts();
LinkStaticness linkStaticness = getLinkStaticness(ruleContext, linkopts, cppConfiguration);
// We currently only want link the dynamic library generated for test code separately.
boolean linkCompileOutputSeparately = ruleContext.isTestTarget() && cppConfiguration.getLinkCompileOutputSeparately() && linkStaticness == LinkStaticness.DYNAMIC;
CcLibraryHelper helper = new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport).fromCommon(common).addSources(common.getSources()).addDeps(ImmutableList.of(CppHelper.mallocForTarget(ruleContext))).setFake(fake).addPrecompiledFiles(precompiledFiles).enableInterfaceSharedObjects();
// 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
// (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
// 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.
helper.setLinkType(linkCompileOutputSeparately ? LinkTargetType.STATIC_LIBRARY : linkType);
CcLibraryHelper.Info info = helper.build();
CppCompilationContext cppCompilationContext = info.getCppCompilationContext();
CcCompilationOutputs ccCompilationOutputs = info.getCcCompilationOutputs();
// 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. In this case, the name of the executable target should end
// in ".so" or "dylib" or ".dll".
PathFragment binaryPath = new PathFragment(ruleContext.getTarget().getName());
if (!isLinkShared(ruleContext)) {
binaryPath = new PathFragment(binaryPath.getPathString() + OsUtils.executableExtension());
}
Artifact binary = ruleContext.getBinArtifact(binaryPath);
if (isLinkShared(ruleContext) && !CppFileTypes.SHARED_LIBRARY.matches(binary.getFilename()) && !CppFileTypes.VERSIONED_SHARED_LIBRARY.matches(binary.getFilename())) {
ruleContext.attributeError("linkshared", "'linkshared' used in non-shared library");
return null;
}
CppLinkActionBuilder linkActionBuilder = determineLinkerArguments(ruleContext, ccToolchain, fdoSupport, common, precompiledFiles, info, cppCompilationContext.getTransitiveCompilationPrerequisites(), fake, binary, linkStaticness, linkopts, linkCompileOutputSeparately);
linkActionBuilder.setUseTestOnlyFlags(ruleContext.isTestTarget());
if (linkStaticness == LinkStaticness.DYNAMIC) {
linkActionBuilder.setRuntimeInputs(ArtifactCategory.DYNAMIC_LIBRARY, ccToolchain.getDynamicRuntimeLinkMiddleman(), ccToolchain.getDynamicRuntimeLinkInputs());
} else {
linkActionBuilder.setRuntimeInputs(ArtifactCategory.STATIC_LIBRARY, ccToolchain.getStaticRuntimeLinkMiddleman(), ccToolchain.getStaticRuntimeLinkInputs());
// TODO(bazel-team): Move this to CcToolchain.
if (!ccToolchain.getStaticRuntimeLinkInputs().isEmpty()) {
linkActionBuilder.addLinkopt("-static-libgcc");
}
}
linkActionBuilder.setLinkType(linkType);
linkActionBuilder.setLinkStaticness(linkStaticness);
linkActionBuilder.setFake(fake);
linkActionBuilder.setFeatureConfiguration(featureConfiguration);
if (CppLinkAction.enableSymbolsCounts(cppConfiguration, fake, linkType)) {
linkActionBuilder.setSymbolCountsOutput(ruleContext.getBinArtifact(CppLinkAction.symbolCountsFileName(binaryPath)));
}
if (isLinkShared(ruleContext)) {
linkActionBuilder.setLibraryIdentifier(CcLinkingOutputs.libraryIdentifierOf(binary));
}
// Store immutable context for use in other *_binary rules that are implemented by
// linking the interpreter (Java, Python, etc.) together with native deps.
CppLinkAction.Context linkContext = new CppLinkAction.Context(linkActionBuilder);
Iterable<LTOBackendArtifacts> ltoBackendArtifacts = ImmutableList.of();
boolean usePic = CppHelper.usePic(ruleContext, !isLinkShared(ruleContext));
if (featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
linkActionBuilder.setLTOIndexing(true);
linkActionBuilder.setUsePicForLTOBackendActions(usePic);
linkActionBuilder.setUseFissionForLTOBackendActions(cppConfiguration.useFission());
CppLinkAction indexAction = linkActionBuilder.build();
ruleContext.registerAction(indexAction);
ltoBackendArtifacts = indexAction.getAllLTOBackendArtifacts();
linkActionBuilder.setLTOIndexing(false);
}
CppLinkAction linkAction = linkActionBuilder.build();
ruleContext.registerAction(linkAction);
LibraryToLink outputLibrary = linkAction.getOutputLibrary();
Iterable<Artifact> fakeLinkerInputs = fake ? linkAction.getInputs() : ImmutableList.<Artifact>of();
Artifact executable = linkAction.getLinkOutput();
CcLinkingOutputs.Builder linkingOutputsBuilder = new CcLinkingOutputs.Builder();
if (isLinkShared(ruleContext)) {
linkingOutputsBuilder.addDynamicLibrary(outputLibrary);
linkingOutputsBuilder.addExecutionDynamicLibrary(outputLibrary);
}
// Also add all shared libraries from srcs.
for (Artifact library : precompiledFiles.getSharedLibraries()) {
Artifact symlink = common.getDynamicLibrarySymlink(library, true);
LibraryToLink symlinkLibrary = LinkerInputs.solibLibraryToLink(symlink, library, CcLinkingOutputs.libraryIdentifierOf(library));
linkingOutputsBuilder.addDynamicLibrary(symlinkLibrary);
linkingOutputsBuilder.addExecutionDynamicLibrary(symlinkLibrary);
}
CcLinkingOutputs linkingOutputs = linkingOutputsBuilder.build();
NestedSet<Artifact> filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, executable);
// 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, executable, strippedFile);
DwoArtifactsCollector dwoArtifacts = collectTransitiveDwoArtifacts(ruleContext, ccCompilationOutputs, linkStaticness, cppConfiguration.useFission(), usePic, ltoBackendArtifacts);
Artifact dwpFile = ruleContext.getImplicitOutputArtifact(CppRuleClasses.CC_BINARY_DEBUG_PACKAGE);
createDebugPackagerActions(ruleContext, ccToolchain, cppConfiguration, dwpFile, dwoArtifacts);
// The debug package should include the dwp file only if it was explicitly requested.
Artifact explicitDwpFile = dwpFile;
if (!cppConfiguration.useFission()) {
explicitDwpFile = null;
} else {
// built statically.
if (TargetUtils.isTestRule(ruleContext.getRule()) && linkStaticness != LinkStaticness.DYNAMIC && cppConfiguration.shouldBuildTestDwp()) {
filesToBuild = NestedSetBuilder.fromNestedSet(filesToBuild).add(dwpFile).build();
}
}
// 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.
Runfiles runfiles = collectRunfiles(ruleContext, ccToolchain, linkingOutputs, info, linkStaticness, filesToBuild, fakeLinkerInputs, fake, helper.getCompilationUnitSources(), linkCompileOutputSeparately);
RunfilesSupport runfilesSupport = RunfilesSupport.withExecutable(ruleContext, runfiles, executable, ruleContext.getConfiguration().buildRunfiles());
TransitiveLipoInfoProvider transitiveLipoInfo;
if (cppConfiguration.isLipoContextCollector()) {
transitiveLipoInfo = common.collectTransitiveLipoLabels(ccCompilationOutputs);
} else {
transitiveLipoInfo = TransitiveLipoInfoProvider.EMPTY;
}
RuleConfiguredTargetBuilder ruleBuilder = new RuleConfiguredTargetBuilder(ruleContext);
addTransitiveInfoProviders(ruleContext, cppConfiguration, common, ruleBuilder, filesToBuild, ccCompilationOutputs, cppCompilationContext, linkingOutputs, dwoArtifacts, transitiveLipoInfo, fake);
Map<Artifact, IncludeScannable> scannableMap = new LinkedHashMap<>();
Map<PathFragment, Artifact> sourceFileMap = new LinkedHashMap<>();
if (cppConfiguration.isLipoContextCollector()) {
for (IncludeScannable scannable : transitiveLipoInfo.getTransitiveIncludeScannables()) {
// These should all be CppCompileActions, which should have only one source file.
// This is also checked when they are put into the nested set.
Artifact source = Iterables.getOnlyElement(scannable.getIncludeScannerSources());
scannableMap.put(source, scannable);
sourceFileMap.put(source.getExecPath(), source);
}
}
// Support test execution on darwin.
if (Platform.isApplePlatform(cppConfiguration.getTargetCpu()) && TargetUtils.isTestRule(ruleContext.getRule())) {
ruleBuilder.addNativeDeclaredProvider(new ExecutionInfoProvider(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, "")));
}
return ruleBuilder.addProvider(RunfilesProvider.class, RunfilesProvider.simple(runfiles)).addProvider(CppDebugPackageProvider.class, new CppDebugPackageProvider(ruleContext.getLabel(), strippedFile, executable, explicitDwpFile)).setRunfilesSupport(runfilesSupport, executable).addProvider(LipoContextProvider.class, new LipoContextProvider(cppCompilationContext, ImmutableMap.copyOf(scannableMap), ImmutableMap.copyOf(sourceFileMap))).addProvider(CppLinkAction.Context.class, linkContext).addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider()).build();
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class CcBinary method determineLinkerArguments.
/**
* Given 'temps', traverse this target and its dependencies and collect up all the object files,
* libraries, linker options, linkstamps attributes and linker scripts.
*/
private static CppLinkActionBuilder determineLinkerArguments(RuleContext context, CcToolchainProvider toolchain, FdoSupportProvider fdoSupport, CcCommon common, PrecompiledFiles precompiledFiles, CcLibraryHelper.Info info, ImmutableSet<Artifact> compilationPrerequisites, boolean fake, Artifact binary, LinkStaticness linkStaticness, List<String> linkopts, boolean linkCompileOutputSeparately) throws InterruptedException {
CppLinkActionBuilder builder = new CppLinkActionBuilder(context, binary, toolchain, fdoSupport).setCrosstoolInputs(toolchain.getLink()).addNonCodeInputs(compilationPrerequisites);
// generated dynamic library they are compiled into.
if (linkCompileOutputSeparately) {
for (LibraryToLink library : info.getCcLinkingOutputs().getDynamicLibraries()) {
builder.addLibrary(library);
}
} else {
boolean usePic = CppHelper.usePic(context, !isLinkShared(context));
Iterable<Artifact> objectFiles = info.getCcCompilationOutputs().getObjectFiles(usePic);
if (fake) {
builder.addFakeObjectFiles(objectFiles);
} else {
builder.addObjectFiles(objectFiles);
}
}
builder.addLTOBitcodeFiles(info.getCcCompilationOutputs().getLtoBitcodeFiles());
builder.addNonCodeInputs(common.getLinkerScripts());
// entries during linking process.
for (Artifact library : precompiledFiles.getLibraries()) {
if (Link.SHARED_LIBRARY_FILETYPES.matches(library.getFilename())) {
builder.addLibrary(LinkerInputs.solibLibraryToLink(common.getDynamicLibrarySymlink(library, true), library, CcLinkingOutputs.libraryIdentifierOf(library)));
} else if (Link.LINK_LIBRARY_FILETYPES.matches(library.getFilename())) {
builder.addLibrary(LinkerInputs.precompiledLibraryToLink(library, ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY));
} else if (Link.ARCHIVE_FILETYPES.matches(library.getFilename())) {
builder.addLibrary(LinkerInputs.precompiledLibraryToLink(library, ArtifactCategory.STATIC_LIBRARY));
} else {
throw new IllegalStateException();
}
}
// Then the link params from the closure of deps.
CcLinkParams linkParams = collectCcLinkParams(context, linkStaticness != LinkStaticness.DYNAMIC, isLinkShared(context), linkopts);
builder.addLinkParams(linkParams, context);
return builder;
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class CcCommon method getLooseIncludeDirs.
/**
* Determines a list of loose include directories that are only allowed to be referenced when
* headers checking is {@link HeadersCheckingMode#LOOSE} or {@link HeadersCheckingMode#WARN}.
*/
List<PathFragment> getLooseIncludeDirs() {
List<PathFragment> result = new ArrayList<>();
// The package directory of the rule contributes includes. Note that this also covers all
// non-subpackage sub-directories.
PathFragment rulePackage = ruleContext.getLabel().getPackageIdentifier().getPathUnderExecRoot();
result.add(rulePackage);
// Gather up all the dirs from the rule's srcs as well as any of the srcs outputs.
if (hasAttribute("srcs", BuildType.LABEL_LIST)) {
for (TransitiveInfoCollection src : ruleContext.getPrerequisitesIf("srcs", Mode.TARGET, FileProvider.class)) {
PathFragment packageDir = src.getLabel().getPackageIdentifier().getPathUnderExecRoot();
for (Artifact a : src.getProvider(FileProvider.class).getFilesToBuild()) {
result.add(packageDir);
// Attempt to gather subdirectories that might contain include files.
result.add(a.getRootRelativePath().getParentDirectory());
}
}
}
// Add in any 'includes' attribute values as relative path fragments
if (ruleContext.getRule().isAttributeValueExplicitlySpecified("includes")) {
PathFragment packageFragment = ruleContext.getLabel().getPackageIdentifier().getPathUnderExecRoot();
// For now, anything with an 'includes' needs a blanket declaration
result.add(packageFragment.getRelative("**"));
}
return result;
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class CcCommon method getSources.
/**
* Returns a list of ({@link Artifact}, {@link Label}) pairs. Each pair represents an input
* source file and the label of the rule that generates it (or the label of the source file
* itself if it is an input file).
*/
List<Pair<Artifact, Label>> getSources() {
Map<Artifact, Label> map = Maps.newLinkedHashMap();
Iterable<? extends TransitiveInfoCollection> providers = ruleContext.getPrerequisitesIf("srcs", Mode.TARGET, FileProvider.class);
for (TransitiveInfoCollection provider : providers) {
for (Artifact artifact : provider.getProvider(FileProvider.class).getFilesToBuild()) {
// TODO(bazel-team): We currently do not produce an error for duplicate headers and other
// non-source artifacts with different labels, as that would require cleaning up the code
// base without significant benefit; we should eventually make this consistent one way or
// the other.
Label oldLabel = map.put(artifact, provider.getLabel());
boolean isHeader = CppFileTypes.CPP_HEADER.matches(artifact.getExecPath());
if (!isHeader && SourceCategory.CC_AND_OBJC.getSourceTypes().matches(artifact.getExecPathString()) && oldLabel != null && !oldLabel.equals(provider.getLabel())) {
ruleContext.attributeError("srcs", String.format("Artifact '%s' is duplicated (through '%s' and '%s')", artifact.getExecPathString(), oldLabel, provider.getLabel()));
}
}
}
ImmutableList.Builder<Pair<Artifact, Label>> result = ImmutableList.builder();
for (Map.Entry<Artifact, Label> entry : map.entrySet()) {
result.add(Pair.of(entry.getKey(), entry.getValue()));
}
return result.build();
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class CcCommon method collectCompilationPrerequisites.
/**
* Collects compilation prerequisite artifacts.
*/
static NestedSet<Artifact> collectCompilationPrerequisites(RuleContext ruleContext, CppCompilationContext context) {
// TODO(bazel-team): Use context.getCompilationPrerequisites() instead; note that this will
// need cleaning up the prerequisites, as the compilation context currently collects them
// transitively (to get transitive headers), but source files are not transitive compilation
// prerequisites.
NestedSetBuilder<Artifact> prerequisites = NestedSetBuilder.stableOrder();
if (ruleContext.attributes().has("srcs", BuildType.LABEL_LIST)) {
for (FileProvider provider : ruleContext.getPrerequisites("srcs", Mode.TARGET, FileProvider.class)) {
prerequisites.addAll(FileType.filter(provider.getFilesToBuild(), SourceCategory.CC_AND_OBJC.getSourceTypes()));
}
}
prerequisites.addTransitive(context.getDeclaredIncludeSrcs());
prerequisites.addTransitive(context.getAdditionalInputs());
prerequisites.addTransitive(context.getTransitiveModules(true));
prerequisites.addTransitive(context.getTransitiveModules(false));
return prerequisites.build();
}
Aggregations