Search in sources :

Example 1 with AnalysisEnvironment

use of com.google.devtools.build.lib.analysis.AnalysisEnvironment 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)

Example 2 with AnalysisEnvironment

use of com.google.devtools.build.lib.analysis.AnalysisEnvironment in project bazel by bazelbuild.

the class CppModel method createCcCompileActions.

/**
   * Constructs the C++ compiler actions. It generally creates one action for every specified source
   * file. It takes into account LIPO, fake-ness, coverage, and PIC, in addition to using the
   * settings specified on the current object. This method should only be called once.
   */
public CcCompilationOutputs createCcCompileActions() {
    CcCompilationOutputs.Builder result = new CcCompilationOutputs.Builder();
    Preconditions.checkNotNull(context);
    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
    if (shouldProvideHeaderModules()) {
        Collection<Artifact> modules = createModuleAction(result, context.getCppModuleMap());
        if (featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
            for (Artifact module : modules) {
                createModuleCodegenAction(result, module);
            }
        }
    } else if (context.getVerificationModuleMap() != null) {
        Collection<Artifact> modules = createModuleAction(result, context.getVerificationModuleMap());
        for (Artifact module : modules) {
            result.addHeaderTokenFile(module);
        }
    }
    for (CppSource source : sourceFiles) {
        Artifact sourceArtifact = source.getSource();
        Label sourceLabel = source.getLabel();
        String outputName = FileSystemUtils.removeExtension(semantics.getEffectiveSourcePath(sourceArtifact)).getPathString();
        CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact, sourceLabel);
        builder.setSemantics(semantics);
        if (!sourceArtifact.isTreeArtifact()) {
            switch(source.getType()) {
                case HEADER:
                    createHeaderAction(outputName, result, env, builder, CppFileTypes.mustProduceDotdFile(sourceArtifact));
                    break;
                case CLIF_INPUT_PROTO:
                    createClifMatchAction(outputName, result, env, builder);
                    break;
                default:
                    boolean bitcodeOutput = featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
                    createSourceAction(outputName, result, env, sourceArtifact, builder, ArtifactCategory.OBJECT_FILE, context.getCppModuleMap(), /*addObject=*/
                    true, isCodeCoverageEnabled(), /*generateDwo=*/
                    cppConfiguration.useFission() && !bitcodeOutput, CppFileTypes.mustProduceDotdFile(sourceArtifact), source.getBuildVariables());
                    break;
            }
        } else {
            switch(source.getType()) {
                case HEADER:
                    Artifact headerTokenFile = createCompileActionTemplate(env, source, builder, ImmutableList.of(ArtifactCategory.GENERATED_HEADER, ArtifactCategory.PROCESSED_HEADER));
                    result.addHeaderTokenFile(headerTokenFile);
                    break;
                case SOURCE:
                    Artifact objectFile = createCompileActionTemplate(env, source, builder, ImmutableList.of(ArtifactCategory.OBJECT_FILE));
                    result.addObjectFile(objectFile);
                    break;
                default:
                    throw new IllegalStateException("Encountered invalid source types when creating CppCompileActionTemplates");
            }
        }
    }
    compilationOutputs = result.build();
    return compilationOutputs;
}
Also used : Builder(com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs.Builder) StringSequenceBuilder(com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder) Label(com.google.devtools.build.lib.cmdline.Label) Builder(com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs.Builder) Artifact(com.google.devtools.build.lib.actions.Artifact) AnalysisEnvironment(com.google.devtools.build.lib.analysis.AnalysisEnvironment) TransitiveInfoCollection(com.google.devtools.build.lib.analysis.TransitiveInfoCollection) Collection(java.util.Collection)

Example 3 with AnalysisEnvironment

use of com.google.devtools.build.lib.analysis.AnalysisEnvironment in project bazel by bazelbuild.

the class CrosstoolCompilationSupport method registerHeaderScanningActions.

private void registerHeaderScanningActions(Info info, ObjcProvider objcProvider, CompilationArtifacts compilationArtifacts) {
    // PIC is not used for Obj-C builds, if that changes this method will need to change
    if (!isHeaderThinningEnabled() || info.getCcCompilationOutputs().getObjectFiles(false).isEmpty()) {
        return;
    }
    ImmutableList.Builder<ObjcHeaderThinningInfo> headerThinningInfos = ImmutableList.builder();
    AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment();
    for (Artifact objectFile : info.getCcCompilationOutputs().getObjectFiles(false)) {
        ActionAnalysisMetadata generatingAction = analysisEnvironment.getLocalGeneratingAction(objectFile);
        if (generatingAction instanceof CppCompileAction) {
            CppCompileAction action = (CppCompileAction) generatingAction;
            Artifact sourceFile = action.getSourceFile();
            if (!sourceFile.isTreeArtifact() && SOURCES_FOR_HEADER_THINNING.matches(sourceFile.getFilename())) {
                headerThinningInfos.add(new ObjcHeaderThinningInfo(sourceFile, intermediateArtifacts.headersListFile(sourceFile), action.getCompilerOptions()));
            }
        }
    }
    registerHeaderScanningActions(headerThinningInfos.build(), objcProvider, compilationArtifacts);
}
Also used : AnalysisEnvironment(com.google.devtools.build.lib.analysis.AnalysisEnvironment) ImmutableList(com.google.common.collect.ImmutableList) CppCompileAction(com.google.devtools.build.lib.rules.cpp.CppCompileAction) ActionAnalysisMetadata(com.google.devtools.build.lib.actions.ActionAnalysisMetadata) Artifact(com.google.devtools.build.lib.actions.Artifact)

Example 4 with AnalysisEnvironment

use of com.google.devtools.build.lib.analysis.AnalysisEnvironment in project bazel by bazelbuild.

the class FdoSupport method configureCompilation.

/**
   * Configures a compile action builder by setting up command line options and
   * auxiliary inputs according to the FDO configuration. This method does
   * nothing If FDO is disabled.
   */
@ThreadSafe
public void configureCompilation(CppCompileActionBuilder builder, CcToolchainFeatures.Variables.Builder buildVariables, RuleContext ruleContext, PathFragment sourceName, PathFragment sourceExecPath, boolean usePic, FeatureConfiguration featureConfiguration, FdoSupportProvider fdoSupportProvider) {
    // It is a bug if this method is called with useLipo if lipo is disabled. However, it is legal
    // if is is called with !useLipo, even though lipo is enabled.
    LipoContextProvider lipoInputProvider = CppHelper.getLipoContextProvider(ruleContext);
    Preconditions.checkArgument(lipoInputProvider == null || lipoMode != LipoMode.OFF);
    // FDO is disabled -> do nothing.
    if ((fdoInstrument == null) && (fdoRoot == null)) {
        return;
    }
    if (featureConfiguration.isEnabled(CppRuleClasses.FDO_INSTRUMENT)) {
        buildVariables.addStringVariable("fdo_instrument_path", fdoInstrument.getPathString());
    }
    // Optimization phase
    if (fdoRoot != null) {
        AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
        // Declare dependency on contents of zip file.
        if (env.getSkyframeEnv().valuesMissing()) {
            return;
        }
        Iterable<Artifact> auxiliaryInputs = getAuxiliaryInputs(ruleContext, sourceName, sourceExecPath, usePic, lipoInputProvider, fdoSupportProvider);
        builder.addMandatoryInputs(auxiliaryInputs);
        if (!Iterables.isEmpty(auxiliaryInputs)) {
            if (featureConfiguration.isEnabled(CppRuleClasses.AUTOFDO)) {
                buildVariables.addStringVariable("fdo_profile_path", getAutoProfilePath(fdoProfile, fdoRootExecPath).getPathString());
            }
            if (featureConfiguration.isEnabled(CppRuleClasses.FDO_OPTIMIZE)) {
                if (fdoMode == FdoMode.LLVM_FDO) {
                    buildVariables.addStringVariable("fdo_profile_path", getLLVMProfilePath(fdoProfile, fdoRootExecPath).getPathString());
                } else {
                    buildVariables.addStringVariable("fdo_profile_path", fdoRootExecPath.getPathString());
                }
            }
        }
    }
}
Also used : AnalysisEnvironment(com.google.devtools.build.lib.analysis.AnalysisEnvironment) Artifact(com.google.devtools.build.lib.actions.Artifact) ThreadSafe(com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe)

Example 5 with AnalysisEnvironment

use of com.google.devtools.build.lib.analysis.AnalysisEnvironment in project bazel by bazelbuild.

the class CppModel method createModuleCodegenAction.

private void createModuleCodegenAction(CcCompilationOutputs.Builder result, Artifact module) {
    if (fake) {
        // If we find one, support needs to be added here.
        return;
    }
    String outputName = semantics.getEffectiveSourcePath(module).getPathString();
    // TODO(djasper): Make this less hacky after refactoring how the PIC/noPIC actions are created.
    boolean pic = module.getFilename().contains(".pic.");
    // TODO(djasper): Investigate whether we need to use a label separate from that of the module
    // map. It is used for per-file-copts.
    CppCompileActionBuilder builder = initializeCompileAction(module, Label.parseAbsoluteUnchecked(context.getCppModuleMap().getName()));
    builder.setSemantics(semantics);
    builder.setPicMode(pic);
    builder.setOutputs(ruleContext, ArtifactCategory.OBJECT_FILE, outputName, CppFileTypes.mustProduceDotdFile(module));
    PathFragment ccRelativeName = semantics.getEffectiveSourcePath(module);
    String gcnoFileName = CppHelper.getArtifactNameForCategory(ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
    // TODO(djasper): This is now duplicated. Refactor the various create..Action functions.
    Artifact gcnoFile = isCodeCoverageEnabled() && !cppConfiguration.isLipoOptimization() ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration) : null;
    boolean generateDwo = cppConfiguration.useFission();
    Artifact dwoFile = generateDwo ? getDwoFile(builder.getOutputFile()) : null;
    setupCompileBuildVariables(builder, /*usePic=*/
    pic, ccRelativeName, module.getExecPath(), gcnoFile, dwoFile, builder.getContext().getCppModuleMap(), ImmutableMap.<String, String>of());
    builder.setGcnoFile(gcnoFile);
    builder.setDwoFile(dwoFile);
    semantics.finalizeCompileActionBuilder(ruleContext, builder);
    CppCompileAction compileAction = builder.build();
    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
    env.registerAction(compileAction);
    Artifact objectFile = compileAction.getOutputFile();
    if (pic) {
        result.addPicObjectFile(objectFile);
    } else {
        result.addObjectFile(objectFile);
    }
}
Also used : AnalysisEnvironment(com.google.devtools.build.lib.analysis.AnalysisEnvironment) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) Artifact(com.google.devtools.build.lib.actions.Artifact)

Aggregations

Artifact (com.google.devtools.build.lib.actions.Artifact)7 AnalysisEnvironment (com.google.devtools.build.lib.analysis.AnalysisEnvironment)7 PathFragment (com.google.devtools.build.lib.vfs.PathFragment)3 ImmutableList (com.google.common.collect.ImmutableList)2 Label (com.google.devtools.build.lib.cmdline.Label)2 Builder (com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs.Builder)2 StringSequenceBuilder (com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder)2 ActionAnalysisMetadata (com.google.devtools.build.lib.actions.ActionAnalysisMetadata)1 Root (com.google.devtools.build.lib.actions.Root)1 TransitiveInfoCollection (com.google.devtools.build.lib.analysis.TransitiveInfoCollection)1 BuildConfiguration (com.google.devtools.build.lib.analysis.config.BuildConfiguration)1 ThreadSafe (com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe)1 CppCompileAction (com.google.devtools.build.lib.rules.cpp.CppCompileAction)1 LinkTargetType (com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType)1 LibraryToLink (com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink)1 TestParams (com.google.devtools.build.lib.rules.test.TestProvider.TestParams)1 Collection (java.util.Collection)1 TreeMap (java.util.TreeMap)1