Search in sources :

Example 1 with LibraryToLink

use of com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink 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();
}
Also used : NestedSetBuilder(com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder) RuleConfiguredTargetBuilder(com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) LinkedHashMap(java.util.LinkedHashMap) ExecutionInfoProvider(com.google.devtools.build.lib.rules.test.ExecutionInfoProvider) RunfilesSupport(com.google.devtools.build.lib.analysis.RunfilesSupport) RuleContext(com.google.devtools.build.lib.analysis.RuleContext) FeatureConfiguration(com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration) Artifact(com.google.devtools.build.lib.actions.Artifact) LinkTargetType(com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType) LibraryToLink(com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink) Runfiles(com.google.devtools.build.lib.analysis.Runfiles) LinkStaticness(com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness) RuleConfiguredTargetBuilder(com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder)

Example 2 with LibraryToLink

use of com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink 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;
}
Also used : LibraryToLink(com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink) Artifact(com.google.devtools.build.lib.actions.Artifact)

Example 3 with LibraryToLink

use of com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink in project bazel by bazelbuild.

the class CppLinkActionBuilder method build.

/** Builds the Action as configured and returns it. */
public CppLinkAction build() throws InterruptedException {
    // Executable links do not have library identifiers.
    boolean hasIdentifier = (libraryIdentifier != null);
    boolean isExecutable = linkType.isExecutable();
    Preconditions.checkState(hasIdentifier != isExecutable);
    if (interfaceOutput != null && (fake || linkType != LinkTargetType.DYNAMIC_LIBRARY)) {
        throw new RuntimeException("Interface output can only be used " + "with non-fake DYNAMIC_LIBRARY targets");
    }
    final ImmutableList<Artifact> buildInfoHeaderArtifacts = !linkstamps.isEmpty() ? analysisEnvironment.getBuildInfo(ruleContext, CppBuildInfo.KEY, configuration) : ImmutableList.<Artifact>of();
    boolean needWholeArchive = wholeArchive || needWholeArchive(linkStaticness, linkType, linkopts, isNativeDeps, cppConfiguration);
    NestedSet<LibraryToLink> uniqueLibraries = libraries.build();
    final Iterable<Artifact> objectArtifacts = LinkerInputs.toLibraryArtifacts(objectFiles);
    final Iterable<LinkerInput> linkerInputs = IterablesChain.<LinkerInput>builder().add(ImmutableList.copyOf(objectFiles)).add(ImmutableIterable.from(Link.mergeInputsCmdLine(uniqueLibraries, needWholeArchive, cppConfiguration.archiveType()))).build();
    // ruleContext can only be null during testing. This is kind of ugly.
    final ImmutableSet<String> features = (ruleContext == null) ? ImmutableSet.<String>of() : ruleContext.getFeatures();
    // instantiated without a feature configuration.
    if (featureConfiguration == null) {
        if (toolchain != null) {
            featureConfiguration = CcCommon.configureFeatures(ruleContext, toolchain, CcLibraryHelper.SourceCategory.CC);
        } else {
            featureConfiguration = CcCommon.configureFeatures(ruleContext, toolchain);
        }
    }
    final LibraryToLink outputLibrary = linkType.isExecutable() ? null : LinkerInputs.newInputLibrary(output, linkType.getLinkerOutput(), libraryIdentifier, objectArtifacts, this.ltoBitcodeFiles);
    final LibraryToLink interfaceOutputLibrary = (interfaceOutput == null) ? null : LinkerInputs.newInputLibrary(interfaceOutput, ArtifactCategory.DYNAMIC_LIBRARY, libraryIdentifier, objectArtifacts, this.ltoBitcodeFiles);
    final ImmutableMap<Artifact, Artifact> linkstampMap = mapLinkstampsToOutputs(linkstamps, ruleContext, configuration, output, linkArtifactFactory);
    PathFragment ltoOutputRootPrefix = null;
    if (isLTOIndexing && allLTOArtifacts == null) {
        ltoOutputRootPrefix = FileSystemUtils.appendExtension(output.getRootRelativePath(), ".lto");
        allLTOArtifacts = createLTOArtifacts(ltoOutputRootPrefix, uniqueLibraries);
    }
    PathFragment linkerParamFileRootPath = null;
    @Nullable Artifact thinltoParamFile = null;
    if (allLTOArtifacts != null) {
        // Create artifact for the file that the LTO indexing step will emit
        // object file names into for any that were included in the link as
        // determined by the linker's symbol resolution. It will be used to
        // provide the inputs for the subsequent final native object link.
        // Note that the paths emitted into this file will have their prefixes
        // replaced with the final output directory, so they will be the paths
        // of the native object files not the input bitcode files.
        linkerParamFileRootPath = ParameterFile.derivePath(output.getRootRelativePath(), "lto-final");
        thinltoParamFile = linkArtifactFactory.create(ruleContext, configuration, linkerParamFileRootPath);
    }
    final ImmutableList<Artifact> actionOutputs;
    if (isLTOIndexing) {
        ImmutableList.Builder<Artifact> builder = ImmutableList.builder();
        for (LTOBackendArtifacts ltoA : allLTOArtifacts) {
            ltoA.addIndexingOutputs(builder);
        }
        if (thinltoParamFile != null) {
            builder.add(thinltoParamFile);
        }
        actionOutputs = builder.build();
    } else {
        actionOutputs = constructOutputs(output, linkstampMap.values(), interfaceOutputLibrary == null ? null : interfaceOutputLibrary.getArtifact(), symbolCounts);
    }
    ImmutableList<LinkerInput> runtimeLinkerInputs = ImmutableList.copyOf(LinkerInputs.simpleLinkerInputs(runtimeInputs, runtimeType));
    PathFragment paramRootPath = ParameterFile.derivePath(output.getRootRelativePath(), (isLTOIndexing) ? "lto-index" : "2");
    @Nullable final Artifact paramFile = canSplitCommandLine() ? linkArtifactFactory.create(ruleContext, configuration, paramRootPath) : null;
    // Add build variables necessary to template link args into the crosstool.
    Variables.Builder buildVariablesBuilder = new Variables.Builder();
    CppLinkVariablesExtension variablesExtension = isLTOIndexing ? new CppLinkVariablesExtension(configuration, ImmutableMap.<Artifact, Artifact>of(), needWholeArchive, linkerInputs, runtimeLinkerInputs, null, paramFile, thinltoParamFile, ltoOutputRootPrefix, null, null) : new CppLinkVariablesExtension(configuration, linkstampMap, needWholeArchive, linkerInputs, runtimeLinkerInputs, output, paramFile, thinltoParamFile, PathFragment.EMPTY_FRAGMENT, toolchain.getInterfaceSoBuilder(), interfaceOutput);
    variablesExtension.addVariables(buildVariablesBuilder);
    for (VariablesExtension extraVariablesExtension : variablesExtensions) {
        extraVariablesExtension.addVariables(buildVariablesBuilder);
    }
    Variables buildVariables = buildVariablesBuilder.build();
    Preconditions.checkArgument(linkType != LinkTargetType.INTERFACE_DYNAMIC_LIBRARY, "you can't link an interface dynamic library directly");
    if (linkType != LinkTargetType.DYNAMIC_LIBRARY) {
        Preconditions.checkArgument(interfaceOutput == null, "interface output may only be non-null for dynamic library links");
    }
    if (linkType.staticness() == Staticness.STATIC) {
        // solib dir must be null for static links
        runtimeSolibDir = null;
        Preconditions.checkArgument(linkStaticness == LinkStaticness.FULLY_STATIC, "static library link must be static");
        Preconditions.checkArgument(symbolCounts == null, "the symbol counts output must be null for static links");
        Preconditions.checkArgument(!isNativeDeps, "the native deps flag must be false for static links");
        Preconditions.checkArgument(!needWholeArchive, "the need whole archive flag must be false for static links");
    }
    LinkCommandLine.Builder linkCommandLineBuilder = new LinkCommandLine.Builder(configuration, getOwner(), ruleContext).setLinkerInputs(linkerInputs).setRuntimeInputs(runtimeLinkerInputs).setLinkTargetType(linkType).setLinkStaticness(linkStaticness).setFeatures(features).setRuntimeSolibDir(linkType.staticness() == Staticness.STATIC ? null : runtimeSolibDir).setNativeDeps(isNativeDeps).setUseTestOnlyFlags(useTestOnlyFlags).setParamFile(paramFile).setToolchain(toolchain).setFdoSupport(fdoSupport.getFdoSupport()).setBuildVariables(buildVariables).setToolPath(getToolPath()).setFeatureConfiguration(featureConfiguration);
    if (!isLTOIndexing) {
        linkCommandLineBuilder.setOutput(output).setBuildInfoHeaderArtifacts(buildInfoHeaderArtifacts).setLinkstamps(linkstampMap).setLinkopts(ImmutableList.copyOf(linkopts)).addLinkstampCompileOptions(linkstampOptions);
    } else {
        List<String> opts = new ArrayList<>(linkopts);
        opts.addAll(featureConfiguration.getCommandLine("lto-indexing", buildVariables));
        opts.addAll(cppConfiguration.getLTOIndexOptions());
        linkCommandLineBuilder.setLinkopts(ImmutableList.copyOf(opts));
    }
    LinkCommandLine linkCommandLine = linkCommandLineBuilder.build();
    // Compute the set of inputs - we only need stable order here.
    NestedSetBuilder<Artifact> dependencyInputsBuilder = NestedSetBuilder.stableOrder();
    dependencyInputsBuilder.addTransitive(crosstoolInputs);
    dependencyInputsBuilder.add(toolchain.getLinkDynamicLibraryTool());
    dependencyInputsBuilder.addTransitive(linkActionInputs.build());
    if (runtimeMiddleman != null) {
        dependencyInputsBuilder.add(runtimeMiddleman);
    }
    if (!isLTOIndexing) {
        dependencyInputsBuilder.addAll(buildInfoHeaderArtifacts);
        dependencyInputsBuilder.addAll(linkstamps);
        dependencyInputsBuilder.addTransitive(compilationInputs.build());
    }
    Iterable<Artifact> expandedInputs = LinkerInputs.toLibraryArtifacts(Link.mergeInputsDependencies(uniqueLibraries, needWholeArchive, cppConfiguration.archiveType()));
    Iterable<Artifact> expandedNonLibraryInputs = LinkerInputs.toLibraryArtifacts(objectFiles);
    if (!isLTOIndexing && allLTOArtifacts != null) {
        // We are doing LTO, and this is the real link, so substitute
        // the LTO bitcode files with the real object files they were translated into.
        Map<Artifact, Artifact> ltoMapping = new HashMap<>();
        for (LTOBackendArtifacts a : allLTOArtifacts) {
            ltoMapping.put(a.getBitcodeFile(), a.getObjectFile());
        }
        // Handle libraries.
        List<Artifact> renamedInputs = new ArrayList<>();
        for (Artifact a : expandedInputs) {
            Artifact renamed = ltoMapping.get(a);
            renamedInputs.add(renamed == null ? a : renamed);
        }
        expandedInputs = renamedInputs;
        // Handle non-libraries.
        List<Artifact> renamedNonLibraryInputs = new ArrayList<>();
        for (Artifact a : expandedNonLibraryInputs) {
            Artifact renamed = ltoMapping.get(a);
            renamedNonLibraryInputs.add(renamed == null ? a : renamed);
        }
        expandedNonLibraryInputs = renamedNonLibraryInputs;
    } else if (isLTOIndexing && allLTOArtifacts != null) {
        for (LTOBackendArtifacts a : allLTOArtifacts) {
            List<String> argv = new ArrayList<>();
            argv.addAll(cppConfiguration.getLinkOptions());
            argv.addAll(cppConfiguration.getCompilerOptions(features));
            a.setCommandLine(argv);
            a.scheduleLTOBackendAction(ruleContext, featureConfiguration, toolchain, fdoSupport, usePicForLTOBackendActions, useFissionForLTOBackendActions);
        }
    }
    // getPrimaryInput returns the first element, and that is a public interface - therefore the
    // order here is important.
    IterablesChain.Builder<Artifact> inputsBuilder = IterablesChain.<Artifact>builder().add(ImmutableList.copyOf(expandedNonLibraryInputs)).add(ImmutableList.copyOf(nonCodeInputs)).add(dependencyInputsBuilder.build()).add(ImmutableIterable.from(expandedInputs));
    if (thinltoParamFile != null && !isLTOIndexing) {
        inputsBuilder.add(ImmutableList.of(thinltoParamFile));
    }
    if (linkCommandLine.getParamFile() != null) {
        inputsBuilder.add(ImmutableList.of(linkCommandLine.getParamFile()));
        Action parameterFileWriteAction = new ParameterFileWriteAction(getOwner(), paramFile, linkCommandLine.paramCmdLine(), ParameterFile.ParameterFileType.UNQUOTED, ISO_8859_1);
        analysisEnvironment.registerAction(parameterFileWriteAction);
    }
    ImmutableMap<String, String> toolchainEnv = featureConfiguration.getEnvironmentVariables(getActionName(), buildVariables);
    // If the crosstool uses action_configs to configure cc compilation, collect execution info
    // from there, otherwise, use no execution info.
    // TODO(b/27903698): Assert that the crosstool has an action_config for this action.
    ImmutableSet.Builder<String> executionRequirements = ImmutableSet.<String>builder();
    if (featureConfiguration.actionIsConfigured(getActionName())) {
        executionRequirements.addAll(featureConfiguration.getToolForAction(getActionName()).getExecutionRequirements());
    }
    return new CppLinkAction(getOwner(), mnemonic, inputsBuilder.deduplicate().build(), actionOutputs, cppConfiguration, outputLibrary, output, interfaceOutputLibrary, fake, isLTOIndexing, allLTOArtifacts, linkCommandLine, configuration.getVariableShellEnvironment(), configuration.getLocalShellEnvironment(), toolchainEnv, executionRequirements.build());
}
Also used : Action(com.google.devtools.build.lib.actions.Action) ParameterFileWriteAction(com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction) HashMap(java.util.HashMap) ImmutableList(com.google.common.collect.ImmutableList) SequenceBuilder(com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.SequenceBuilder) Builder(com.google.common.collect.ImmutableSet.Builder) NestedSetBuilder(com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) ArrayList(java.util.ArrayList) Variables(com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables) ParameterFileWriteAction(com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction) ImmutableSet(com.google.common.collect.ImmutableSet) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) IterablesChain(com.google.devtools.build.lib.collect.IterablesChain) Artifact(com.google.devtools.build.lib.actions.Artifact) LibraryToLink(com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink) VariablesExtension(com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension) Nullable(javax.annotation.Nullable)

Example 4 with LibraryToLink

use of com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink in project bazel by bazelbuild.

the class CppLinkActionBuilder method createLTOArtifacts.

private Iterable<LTOBackendArtifacts> createLTOArtifacts(PathFragment ltoOutputRootPrefix, NestedSet<LibraryToLink> uniqueLibraries) {
    Set<Artifact> compiled = new LinkedHashSet<>();
    for (LibraryToLink lib : uniqueLibraries) {
        Iterables.addAll(compiled, lib.getLTOBitcodeFiles());
    }
    // This flattens the set of object files, so for M binaries and N .o files,
    // this is O(M*N). If we had a nested set of .o files, we could have O(M + N) instead.
    Map<PathFragment, Artifact> allBitcode = new HashMap<>();
    for (LibraryToLink lib : uniqueLibraries) {
        if (!lib.containsObjectFiles()) {
            continue;
        }
        for (Artifact a : lib.getObjectFiles()) {
            if (compiled.contains(a)) {
                allBitcode.put(a.getExecPath(), a);
            }
        }
    }
    for (LinkerInput input : objectFiles) {
        if (this.ltoBitcodeFiles.contains(input.getArtifact())) {
            allBitcode.put(input.getArtifact().getExecPath(), input.getArtifact());
        }
    }
    ImmutableList.Builder<LTOBackendArtifacts> ltoOutputs = ImmutableList.builder();
    for (Artifact a : allBitcode.values()) {
        LTOBackendArtifacts ltoArtifacts = new LTOBackendArtifacts(ltoOutputRootPrefix, a, allBitcode, ruleContext, configuration, linkArtifactFactory);
        ltoOutputs.add(ltoArtifacts);
    }
    return ltoOutputs.build();
}
Also used : LinkedHashSet(java.util.LinkedHashSet) LibraryToLink(com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink) HashMap(java.util.HashMap) ImmutableList(com.google.common.collect.ImmutableList) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) Artifact(com.google.devtools.build.lib.actions.Artifact)

Example 5 with LibraryToLink

use of com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink in project bazel by bazelbuild.

the class CppModel method createCcLinkActions.

/**
   * Constructs the C++ linker actions. It generally generates two actions, one for a static library
   * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
   * it additionally creates a third action to generate a PIC static library.
   *
   * <p>For dynamic libraries, this method can additionally create an interface shared library that
   * can be used for linking, but doesn't contain any executable code. This increases the number of
   * cache hits for link actions. Call {@link #setAllowInterfaceSharedObjects(boolean)} to enable
   * this behavior.
   *
   * @throws RuleErrorException
   */
public CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs, Iterable<Artifact> nonCodeLinkerInputs) throws RuleErrorException, InterruptedException {
    // For now only handle static links. Note that the dynamic library link below ignores linkType.
    // TODO(bazel-team): Either support non-static links or move this check to setLinkType().
    Preconditions.checkState(linkType.staticness() == Staticness.STATIC, "can only handle static links");
    CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder();
    if (cppConfiguration.isLipoContextCollector()) {
        // because it needs some data that's not available at this point.
        return result.build();
    }
    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
    boolean usePicForBinaries = CppHelper.usePic(ruleContext, true);
    boolean usePicForSharedLibs = CppHelper.usePic(ruleContext, false);
    // Create static library (.a). The linkType only reflects whether the library is alwayslink or
    // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases
    // for (usePicForSharedLibs usePicForBinaries):
    //
    // (1) (false false) -> no pic code
    // (2) (true false)  -> shared libraries as pic, but not binaries
    // (3) (true true)   -> both shared libraries and binaries as pic
    //
    // In case (3), we always need PIC, so only create one static library containing the PIC object
    // files. The name therefore does not match the content.
    //
    // Presumably, it is done this way because the .a file is an implicit output of every cc_library
    // rule, so we can't use ".pic.a" that in the always-PIC case.
    // If the crosstool is configured to select an output artifact, we use that selection.
    // Otherwise, we use linux defaults.
    Artifact linkedArtifact = getLinkedArtifact(linkType);
    PathFragment labelName = new PathFragment(ruleContext.getLabel().getName());
    String libraryIdentifier = ruleContext.getPackageDirectory().getRelative(labelName.replaceName("lib" + labelName.getBaseName())).getPathString();
    CppLinkAction maybePicAction = newLinkActionBuilder(linkedArtifact).addObjectFiles(ccOutputs.getObjectFiles(usePicForBinaries)).addNonCodeInputs(nonCodeLinkerInputs).addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles()).setLinkType(linkType).setLinkStaticness(LinkStaticness.FULLY_STATIC).addActionInputs(linkActionInputs).setLibraryIdentifier(libraryIdentifier).addVariablesExtensions(variablesExtensions).setFeatureConfiguration(featureConfiguration).build();
    env.registerAction(maybePicAction);
    if (linkType != LinkTargetType.EXECUTABLE) {
        result.addStaticLibrary(maybePicAction.getOutputLibrary());
    }
    // one contains the PIC code, so the names match the content.
    if (!usePicForBinaries && usePicForSharedLibs) {
        LinkTargetType picLinkType = (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY) ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY : LinkTargetType.PIC_STATIC_LIBRARY;
        // If the crosstool is configured to select an output artifact, we use that selection.
        // Otherwise, we use linux defaults.
        Artifact picArtifact = getLinkedArtifact(picLinkType);
        CppLinkAction picAction = newLinkActionBuilder(picArtifact).addObjectFiles(ccOutputs.getObjectFiles(true)).addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles()).setLinkType(picLinkType).setLinkStaticness(LinkStaticness.FULLY_STATIC).addActionInputs(linkActionInputs).setLibraryIdentifier(libraryIdentifier).addVariablesExtensions(variablesExtensions).setFeatureConfiguration(featureConfiguration).build();
        env.registerAction(picAction);
        if (linkType != LinkTargetType.EXECUTABLE) {
            result.addPicStaticLibrary(picAction.getOutputLibrary());
        }
    }
    if (!createDynamicLibrary) {
        return result.build();
    }
    // Create dynamic library.
    Artifact soImpl;
    String mainLibraryIdentifier;
    if (soImplArtifact == null) {
        // If the crosstool is configured to select an output artifact, we use that selection.
        // Otherwise, we use linux defaults.
        soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
        mainLibraryIdentifier = libraryIdentifier;
    } else {
        // This branch is only used for vestigial Google-internal rules where the name of the output
        // file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
        // we just hardcode some reasonable logic to compute the library identifier and hope that this
        // will eventually go away.
        soImpl = soImplArtifact;
        mainLibraryIdentifier = FileSystemUtils.removeExtension(soImpl.getRootRelativePath().getPathString());
    }
    List<String> sonameLinkopts = ImmutableList.of();
    Artifact soInterface = null;
    if (cppConfiguration.useInterfaceSharedObjects() && allowInterfaceSharedObjects) {
        soInterface = CppHelper.getLinuxLinkedArtifact(ruleContext, configuration, LinkTargetType.INTERFACE_DYNAMIC_LIBRARY, linkedArtifactNameSuffix);
        sonameLinkopts = ImmutableList.of("-Wl,-soname=" + SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), false));
    }
    // Should we also link in any libraries that this library depends on?
    // That is required on some systems...
    CppLinkActionBuilder linkActionBuilder = newLinkActionBuilder(soImpl).setInterfaceOutput(soInterface).addObjectFiles(ccOutputs.getObjectFiles(usePicForSharedLibs)).addNonCodeInputs(ccOutputs.getHeaderTokenFiles()).addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles()).setLinkType(LinkTargetType.DYNAMIC_LIBRARY).setLinkStaticness(LinkStaticness.DYNAMIC).addActionInputs(linkActionInputs).setLibraryIdentifier(mainLibraryIdentifier).addLinkopts(linkopts).addLinkopts(sonameLinkopts).setRuntimeInputs(ArtifactCategory.DYNAMIC_LIBRARY, ccToolchain.getDynamicRuntimeLinkMiddleman(), ccToolchain.getDynamicRuntimeLinkInputs()).setFeatureConfiguration(featureConfiguration).addVariablesExtensions(variablesExtensions);
    if (!ccOutputs.getLtoBitcodeFiles().isEmpty() && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
        linkActionBuilder.setLTOIndexing(true);
        linkActionBuilder.setUsePicForLTOBackendActions(usePicForSharedLibs);
        // If support is ever added for generating a dwp file for shared
        // library targets (e.g. when linkstatic=0), then this should change
        // to generate dwo files when cppConfiguration.useFission(),
        // and the dwp generating action for the shared library should
        // include all of the resulting dwo files.
        linkActionBuilder.setUseFissionForLTOBackendActions(false);
        CppLinkAction indexAction = linkActionBuilder.build();
        env.registerAction(indexAction);
        linkActionBuilder.setLTOIndexing(false);
    }
    CppLinkAction action = linkActionBuilder.build();
    env.registerAction(action);
    if (linkType == LinkTargetType.EXECUTABLE) {
        return result.build();
    }
    LibraryToLink dynamicLibrary = action.getOutputLibrary();
    LibraryToLink interfaceLibrary = action.getInterfaceOutputLibrary();
    if (interfaceLibrary == null) {
        interfaceLibrary = dynamicLibrary;
    }
    // mangled name only.
    if (neverLink) {
        result.addDynamicLibrary(interfaceLibrary);
        result.addExecutionDynamicLibrary(dynamicLibrary);
    } else {
        Artifact libraryLink = SolibSymlinkAction.getDynamicLibrarySymlink(ruleContext, interfaceLibrary.getArtifact(), false, false, ruleContext.getConfiguration());
        result.addDynamicLibrary(LinkerInputs.solibLibraryToLink(libraryLink, interfaceLibrary.getArtifact(), libraryIdentifier));
        Artifact implLibraryLink = SolibSymlinkAction.getDynamicLibrarySymlink(ruleContext, dynamicLibrary.getArtifact(), false, false, ruleContext.getConfiguration());
        result.addExecutionDynamicLibrary(LinkerInputs.solibLibraryToLink(implLibraryLink, dynamicLibrary.getArtifact(), libraryIdentifier));
    }
    return result.build();
}
Also used : Builder(com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs.Builder) StringSequenceBuilder(com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) Artifact(com.google.devtools.build.lib.actions.Artifact) LinkTargetType(com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType) LibraryToLink(com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink) AnalysisEnvironment(com.google.devtools.build.lib.analysis.AnalysisEnvironment)

Aggregations

LibraryToLink (com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink)14 Artifact (com.google.devtools.build.lib.actions.Artifact)12 PathFragment (com.google.devtools.build.lib.vfs.PathFragment)6 NestedSetBuilder (com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder)4 FeatureConfiguration (com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration)4 ArrayList (java.util.ArrayList)4 Runfiles (com.google.devtools.build.lib.analysis.Runfiles)3 ImmutableList (com.google.common.collect.ImmutableList)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 NestedSet (com.google.devtools.build.lib.collect.nestedset.NestedSet)2 LinkTargetType (com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 LinkedHashSet (java.util.LinkedHashSet)2 Test (org.junit.Test)2 Function (com.google.common.base.Function)1 Builder (com.google.common.collect.ImmutableSet.Builder)1 ImmutableSetMultimap (com.google.common.collect.ImmutableSetMultimap)1 Action (com.google.devtools.build.lib.actions.Action)1 FailAction (com.google.devtools.build.lib.actions.FailAction)1