com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration - java examples

Here are the examples of the java api com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

56 Examples 7

19 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns true if interface shared objects should be used in the build implied by the given
 * cppConfiguration and toolchain.
 */
public static boolean useInterfaceSharedLibraries(CppConfiguration cppConfiguration, CcToolchainProvider toolchain, FeatureConfiguration featureConfiguration) {
    return toolchain.supportsInterfaceSharedLibraries(featureConfiguration) && cppConfiguration.getUseInterfaceSharedLibraries();
}

19 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns the FDO build subtype.
 */
public static String getFdoBuildStamp(CppConfiguration cppConfiguration, FdoContext fdoContext, FeatureConfiguration featureConfiguration) {
    FdoContext.BranchFdoProfile branchFdoProfile = fdoContext.getBranchFdoProfile();
    if (branchFdoProfile != null) {
        if (branchFdoProfile.isAutoFdo()) {
            return featureConfiguration.isEnabled(CppRuleClreplacedes.AUTOFDO) ? "AFDO" : null;
        }
        if (branchFdoProfile.isAutoXBinaryFdo()) {
            return featureConfiguration.isEnabled(CppRuleClreplacedes.XBINARYFDO) ? "XFDO" : null;
        }
    }
    if (cppConfiguration.isCSFdo()) {
        return "CSFDO";
    }
    if (cppConfiguration.isFdo()) {
        return "FDO";
    }
    return null;
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns true if the featureConfiguration includes statically linking the cpp runtimes.
 *
 * @param featureConfiguration the relevant FeatureConfiguration.
 */
public boolean shouldStaticallyLinkCppRuntimes(FeatureConfiguration featureConfiguration) {
    return featureConfiguration.isEnabled(CppRuleClreplacedes.STATIC_LINK_CPP_RUNTIMES);
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns true if headers should be parsed in this build.
 *
 * <p>This means headers in 'srcs' and 'hdrs' will be "compiled" using {@link CppCompileAction}).
 * It will run compiler's parser to ensure the header is self-contained. This is required for
 * layering_check to work.
 */
public boolean shouldProcessHeaders(FeatureConfiguration featureConfiguration, CppConfiguration cppConfiguration) {
    // If parse_headers_verifies_modules is switched on, we verify that headers are
    // self-contained by building the module instead.
    return !cppConfiguration.getParseHeadersVerifiesModules() && featureConfiguration.isEnabled(CppRuleClreplacedes.PARSE_HEADERS);
}

19 View Complete Implementation : CcToolchainTest.java
Copyright Apache License 2.0
Author : bazelbuild
private boolean usePicForBinariesWithConfiguration(String... configuration) throws Exception {
    useConfiguration(configuration);
    ConfiguredTarget target = getConfiguredTarget("//a:b");
    CcToolchainProvider toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER);
    CppConfiguration cppConfiguration = getRuleContext(target).getFragment(CppConfiguration.clreplaced);
    FeatureConfiguration featureConfiguration = CcCommon.configureFeaturesOrThrowEvalException(/* requestedFeatures= */
    ImmutableSet.of(), /* unsupportedFeatures= */
    ImmutableSet.of(), toolchainProvider, cppConfiguration);
    return CppHelper.usePicForBinaries(toolchainProvider, cppConfiguration, featureConfiguration);
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns true if PER_OBJECT_DEBUG_INFO are specified and supported by the CROSSTOOL for the
 * build implied by the given configuration, toolchain and feature configuration.
 */
public boolean shouldCreatePerObjectDebugInfo(FeatureConfiguration featureConfiguration, CppConfiguration cppConfiguration) {
    return cppConfiguration.fissionIsActiveForCurrentCompilationMode() && featureConfiguration.isEnabled(CppRuleClreplacedes.PER_OBJECT_DEBUG_INFO);
}

19 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns the type of archives being used by the build implied by the given config and toolchain.
 */
public static Link.ArchiveType getArchiveType(CppConfiguration config, CcToolchainProvider toolchain, FeatureConfiguration featureConfiguration) {
    return useStartEndLib(config, toolchain, featureConfiguration) ? Link.ArchiveType.START_END_LIB : Link.ArchiveType.REGULAR;
}

19 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
// TODO(bazel-team): figure out a way to merge these 2 methods. See the Todo in
// CcCommonConfiguredTarget.noCoptsMatches().
/**
 * Returns whether binaries must be compiled with position independent code.
 */
public static boolean usePicForBinaries(CcToolchainProvider toolchain, CppConfiguration cppConfiguration, FeatureConfiguration featureConfiguration) {
    return cppConfiguration.forcePic() || (toolchain.usePicForDynamicLibraries(cppConfiguration, featureConfiguration) && cppConfiguration.getCompilationMode() != CompilationMode.OPT);
}

19 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns true if the build implied by the given config and toolchain uses --start-lib/--end-lib
 * ld options.
 */
public static boolean useStartEndLib(CppConfiguration config, CcToolchainProvider toolchain, FeatureConfiguration featureConfiguration) {
    return config.startEndLibIsRequested() && toolchain.supportsStartEndLib(featureConfiguration);
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns the static runtime libraries.
 */
public NestedSet<Artifact> getStaticRuntimeLinkInputs(FeatureConfiguration featureConfiguration) throws EvalException {
    if (shouldStaticallyLinkCppRuntimes(featureConfiguration)) {
        if (staticRuntimeLinkInputs == null) {
            throw new EvalException(Location.BUILTIN, "Toolchain supports embedded runtimes, but didn't " + "provide static_runtime_lib attribute.");
        }
        return staticRuntimeLinkInputs;
    } else {
        return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
    }
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns the dynamic runtime libraries.
 */
public NestedSet<Artifact> getDynamicRuntimeLinkInputs(FeatureConfiguration featureConfiguration) throws EvalException {
    if (shouldStaticallyLinkCppRuntimes(featureConfiguration)) {
        if (dynamicRuntimeLinkInputs == null) {
            throw new EvalException(Location.BUILTIN, "Toolchain supports embedded runtimes, but didn't " + "provide dynamic_runtime_lib attribute.");
        }
        return dynamicRuntimeLinkInputs;
    } else {
        return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
    }
}

19 View Complete Implementation : CppLinkActionTest.java
Copyright Apache License 2.0
Author : bazelbuild
@Test
public void testToolchainFeatureFlags() throws Exception {
    RuleContext ruleContext = createDummyRuleContext();
    FeatureConfiguration featureConfiguration = CcToolchainFeaturesTest.buildFeatures(MockCcSupport.EMPTY_EXECUTABLE_ACTION_CONFIG, "feature {", "   name: 'a'", "   flag_set {", "      action: '" + Link.LinkTargetType.EXECUTABLE.getActionName() + "'", "      flag_group { flag: 'some_flag' }", "   }", "}").getFeatureConfiguration(ImmutableSet.of("a", Link.LinkTargetType.EXECUTABLE.getActionName()));
    CppLinkAction linkAction = createLinkBuilder(ruleContext, Link.LinkTargetType.EXECUTABLE, "dummyRuleContext/out", ImmutableList.<Artifact>of(), ImmutableList.<LibraryToLink>of(), featureConfiguration).build();
    replacedertThat(linkAction.getArguments()).contains("some_flag");
}

19 View Complete Implementation : LinkBuildVariablesTestCase.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns the value of a given sequence variable in context of the given Variables instance.
 */
protected static List<String> getSequenceVariableValue(RuleContext ruleContext, CcToolchainVariables variables, String variable) throws Exception {
    FeatureConfiguration mockFeatureConfiguration = buildFeatures(ruleContext, "feature {", "  name: 'a'", "  flag_set {", "  action: 'foo'", "    flag_group {", "      iterate_over: '" + variable + "'", "      flag: '%{" + variable + "}'", "    }", "  }", "}").getFeatureConfiguration(ImmutableSet.of("a"));
    return mockFeatureConfiguration.getCommandLine("foo", variables);
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Determines if we should apply -fPIC for this rule's C++ compilations. This determination is
 * generally made by the global C++ configuration settings "needsPic" and "usePicForBinaries".
 * However, an individual rule may override these settings by applying -fPIC" to its "nocopts"
 * attribute. This allows incompatible rules to "opt out" of global PIC settings (see bug:
 * "Provide a way to turn off -fPIC for targets that can't be built that way").
 *
 * @return true if this rule's compilations should apply -fPIC, false otherwise
 */
public boolean usePicForDynamicLibraries(CppConfiguration cppConfiguration, FeatureConfiguration featureConfiguration) {
    return cppConfiguration.forcePic() || featureConfiguration.isEnabled(CppRuleClreplacedes.SUPPORTS_PIC);
}

19 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns whether the toolchain supports dynamic linking.
 */
public boolean supportsDynamicLinker(FeatureConfiguration featureConfiguration) {
    return featureConfiguration.isEnabled(CppRuleClreplacedes.SUPPORTS_DYNAMIC_LINKER);
}

19 View Complete Implementation : CppLinkActionTest.java
Copyright Apache License 2.0
Author : bazelbuild
@Test
public void testToolchainFeatureEnv() throws Exception {
    RuleContext ruleContext = createDummyRuleContext();
    FeatureConfiguration featureConfiguration = CcToolchainFeaturesTest.buildFeatures(MockCcSupport.EMPTY_EXECUTABLE_ACTION_CONFIG, "feature {", "   name: 'a'", "   env_set {", "      action: '" + Link.LinkTargetType.EXECUTABLE.getActionName() + "'", "      env_entry { key: 'foo', value: 'bar' }", "   }", "}").getFeatureConfiguration(ImmutableSet.of(Link.LinkTargetType.EXECUTABLE.getActionName(), "a"));
    CppLinkAction linkAction = createLinkBuilder(ruleContext, Link.LinkTargetType.EXECUTABLE, "dummyRuleContext/out", ImmutableList.<Artifact>of(), ImmutableList.<LibraryToLink>of(), featureConfiguration).build();
    replacedertThat(linkAction.getIncompleteEnvironmentForTesting()).containsEntry("foo", "bar");
}

18 View Complete Implementation : MockCppSemantics.java
Copyright Apache License 2.0
Author : bazelbuild
@Override
public void finalizeCompileActionBuilder(BuildConfiguration configuration, FeatureConfiguration featureConfiguration, CppCompileActionBuilder actionBuilder) {
}

18 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns whether the toolchain supports the --start-lib/--end-lib options.
 */
public boolean supportsStartEndLib(FeatureConfiguration featureConfiguration) {
    return featureConfiguration.isEnabled(CppRuleClreplacedes.SUPPORTS_START_END_LIB);
}

18 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns an aggregating middleman that represents the static runtime libraries.
 */
@Nullable
public Artifact getStaticRuntimeLinkMiddleman(RuleErrorConsumer ruleErrorConsumer, FeatureConfiguration featureConfiguration) throws RuleErrorException {
    if (shouldStaticallyLinkCppRuntimes(featureConfiguration)) {
        if (staticRuntimeLinkInputs == null) {
            throw ruleErrorConsumer.throwWithRuleError("Toolchain supports embedded runtimes, but didn't " + "provide static_runtime_lib attribute.");
        }
        return staticRuntimeLinkMiddleman;
    } else {
        return null;
    }
}

18 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns an aggregating middleman that represents the dynamic runtime libraries.
 */
@Nullable
public Artifact getDynamicRuntimeLinkMiddleman(RuleErrorConsumer ruleContext, FeatureConfiguration featureConfiguration) throws RuleErrorException {
    if (shouldStaticallyLinkCppRuntimes(featureConfiguration)) {
        if (dynamicRuntimeLinkInputs == null) {
            throw ruleContext.throwWithRuleError("Toolchain supports embedded runtimes, but didn't " + "provide dynamic_runtime_lib attribute.");
        }
        return dynamicRuntimeLinkMiddleman;
    } else {
        return null;
    }
}

18 View Complete Implementation : CcToolchainProvider.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns whether this toolchain supports interface shared libraries.
 */
public boolean supportsInterfaceSharedLibraries(FeatureConfiguration featureConfiguration) {
    return featureConfiguration.isEnabled(CppRuleClreplacedes.SUPPORTS_INTERFACE_SHARED_LIBRARIES);
}

18 View Complete Implementation : CppCompileActionBuilder.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Sets the feature configuration to be used for the action.
 */
public CppCompileActionBuilder setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
    Preconditions.checkNotNull(featureConfiguration);
    this.featureConfiguration = featureConfiguration;
    return this;
}

18 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
public static ImmutableMap<String, String> getEnvironmentVariables(RuleErrorConsumer ruleErrorConsumer, FeatureConfiguration featureConfiguration, CcToolchainVariables variables, String actionName) throws RuleErrorException {
    try {
        return featureConfiguration.getEnvironmentVariables(actionName, variables);
    } catch (ExpansionException e) {
        throw ruleErrorConsumer.throwWithRuleError(e.getMessage());
    }
}

18 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns true when {@link CppRuleClreplacedes#WINDOWS_EXPORT_ALL_SYMBOLS} feature is enabled and
 * {@link CppRuleClreplacedes#NO_WINDOWS_EXPORT_ALL_SYMBOLS} feature is not enabled and no custom DEF
 * file is specified in win_def_file attribute.
 */
public static boolean shouldUseGeneratedDefFile(RuleContext ruleContext, FeatureConfiguration featureConfiguration) {
    return featureConfiguration.isEnabled(CppRuleClreplacedes.WINDOWS_EXPORT_ALL_SYMBOLS) && !featureConfiguration.isEnabled(CppRuleClreplacedes.NO_WINDOWS_EXPORT_ALL_SYMBOLS) && ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET) == null;
}

18 View Complete Implementation : FeatureConfigurationForStarlark.java
Copyright Apache License 2.0
Author : bazelbuild
public static FeatureConfigurationForStarlark from(FeatureConfiguration featureConfiguration, CppConfiguration cppConfiguration, BuildOptions buildOptions) {
    return new FeatureConfigurationForStarlark(featureConfiguration, cppConfiguration, buildOptions);
}

18 View Complete Implementation : FeatureConfigurationForStarlark.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Wrapper for {@link FeatureConfiguration}, {@link CppConfiguration}, and {@link BuildOptions}.
 *
 * <p>Instances are created in Starlark by cc_common.configure_features(ctx, cc_toolchain), and
 * preplaceded around pretending to be {@link FeatureConfiguration}. Then when the need arises, we get
 * the {@link CppConfiguration} and {@link BuildOptions} from it and use it in times when
 * configuration of cc_toolchain is different than configuration of the rule depending on it.
 */
// TODO(b/129045294): Remove once cc_toolchain has target configuration.
public clreplaced FeatureConfigurationForStarlark implements FeatureConfigurationApi {

    private final FeatureConfiguration featureConfiguration;

    private final CppConfiguration cppConfiguration;

    private final BuildOptions buildOptions;

    public static FeatureConfigurationForStarlark from(FeatureConfiguration featureConfiguration, CppConfiguration cppConfiguration, BuildOptions buildOptions) {
        return new FeatureConfigurationForStarlark(featureConfiguration, cppConfiguration, buildOptions);
    }

    private FeatureConfigurationForStarlark(FeatureConfiguration featureConfiguration, CppConfiguration cppConfiguration, BuildOptions buildOptions) {
        this.featureConfiguration = Preconditions.checkNotNull(featureConfiguration);
        this.cppConfiguration = Preconditions.checkNotNull(cppConfiguration);
        this.buildOptions = buildOptions;
    }

    public FeatureConfiguration getFeatureConfiguration() {
        return featureConfiguration;
    }

    @Override
    public void debugPrint(Printer printer) {
        printer.append("<FeatureConfiguration(");
        printer.append(Joiner.on(", ").join(featureConfiguration.getEnabledFeatureNames()));
        printer.append(")>");
    }

    /**
     * Get {@link CppConfiguration} that is threaded along with {@link FeatureConfiguration}. Do this
     * only when you're completely aware of why this method was added and hlopko@ allowed you to.
     *
     * @deprecated will be removed soon by b/129045294.
     */
    @Deprecated
    CppConfiguration getCppConfigurationFromFeatureConfigurationCreatedForStarlark_andIKnowWhatImDoing() {
        return cppConfiguration;
    }

    /**
     * Get {@link BuildOptions} that is threaded along with {@link FeatureConfiguration}. Do this only
     * when you're completely aware of why this method was added and hlopko@ allowed you to.
     *
     * @deprecated will be removed soon by b/129045294.
     */
    @Deprecated
    BuildOptions getBuildOptionsFromFeatureConfigurationCreatedForStarlark_andIKnowWhatImDoing() {
        return buildOptions;
    }
}

18 View Complete Implementation : LibrariesToLinkCollector.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Clreplaced that goes over linker inputs and produces {@link LibraryToLinkValue}s
 */
public clreplaced LibrariesToLinkCollector {

    private final boolean isNativeDeps;

    private final PathFragment toolchainLibrariesSolibDir;

    private final CppConfiguration cppConfiguration;

    private final CcToolchainProvider ccToolchainProvider;

    private final Artifact outputArtifact;

    private final boolean isLtoIndexing;

    private final PathFragment solibDir;

    private final Iterable<? extends LinkerInput> linkerInputs;

    private final Iterable<LtoBackendArtifacts> allLtoArtifacts;

    private final boolean allowLtoIndexing;

    private final Artifact thinltoParamFile;

    private final FeatureConfiguration featureConfiguration;

    private final boolean needWholeArchive;

    private final String rpathRoot;

    private final boolean needToolchainLibrariesRpath;

    private final Map<Artifact, Artifact> ltoMap;

    public LibrariesToLinkCollector(boolean isNativeDeps, CppConfiguration cppConfiguration, CcToolchainProvider toolchain, PathFragment toolchainLibrariesSolibDir, LinkTargetType linkType, Link.LinkingMode linkingMode, Artifact output, PathFragment solibDir, boolean isLtoIndexing, Iterable<LtoBackendArtifacts> allLtoArtifacts, FeatureConfiguration featureConfiguration, Artifact thinltoParamFile, boolean allowLtoIndexing, Iterable<LinkerInput> linkerInputs, boolean needWholeArchive) {
        this.isNativeDeps = isNativeDeps;
        this.cppConfiguration = cppConfiguration;
        this.ccToolchainProvider = toolchain;
        this.toolchainLibrariesSolibDir = toolchainLibrariesSolibDir;
        this.outputArtifact = output;
        this.solibDir = solibDir;
        this.isLtoIndexing = isLtoIndexing;
        this.allLtoArtifacts = allLtoArtifacts;
        this.featureConfiguration = featureConfiguration;
        this.thinltoParamFile = thinltoParamFile;
        this.allowLtoIndexing = allowLtoIndexing;
        this.linkerInputs = linkerInputs;
        this.needWholeArchive = needWholeArchive;
        needToolchainLibrariesRpath = toolchainLibrariesSolibDir != null && (linkType.isDynamicLibrary() || (linkType == LinkTargetType.EXECUTABLE && linkingMode == LinkingMode.DYNAMIC));
        // Calculate the correct relative value for the "-rpath" link option (which sets
        // the search path for finding shared libraries).
        if (isNativeDeps && cppConfiguration.shareNativeDeps()) {
            // For shared native libraries, special symlinking is applied to ensure C++
            // toolchain libraries are available under $ORIGIN/_solib_[arch]. So we set the RPATH to find
            // them.
            // 
            // Note that we have to do this because $ORIGIN points to different paths for
            // different targets. In other words, blaze-bin/d1/d2/d3/a_shareddeps.so and
            // blaze-bin/d4/b_shareddeps.so have different path depths. The first could
            // reference a standard blaze-bin/_solib_[arch] via $ORIGIN/../../../_solib[arch],
            // and the second could use $ORIGIN/../_solib_[arch]. But since this is a shared
            // artifact, both are symlinks to the same place, so
            // there's no *one* RPATH setting that fits all targets involved in the sharing.
            rpathRoot = ccToolchainProvider.getSolibDirectory() + "/";
        } else {
            rpathRoot = Strings.repeat("../", outputArtifact.getRootRelativePath().segmentCount() - 1) + ccToolchainProvider.getSolibDirectory() + "/";
        }
        ltoMap = generateLtoMap();
    }

    /**
     * Result of {@link LibrariesToLinkCollector#collectLibrariesToLink()}. Provides access to
     * computed sequence of {@link LibraryToLinkValue}s and accompanying library search directories.
     */
    public static clreplaced CollectedLibrariesToLink {

        private final SequenceBuilder librariesToLink;

        private final NestedSet<LinkerInput> expandedLinkerInputs;

        private final NestedSet<String> librarySearchDirectories;

        private final NestedSet<String> runtimeLibrarySearchDirectories;

        private CollectedLibrariesToLink(SequenceBuilder librariesToLink, NestedSet<LinkerInput> expandedLinkerInputs, NestedSet<String> librarySearchDirectories, NestedSet<String> runtimeLibrarySearchDirectories) {
            this.librariesToLink = librariesToLink;
            this.expandedLinkerInputs = expandedLinkerInputs;
            this.librarySearchDirectories = librarySearchDirectories;
            this.runtimeLibrarySearchDirectories = runtimeLibrarySearchDirectories;
        }

        public SequenceBuilder getLibrariesToLink() {
            return librariesToLink;
        }

        // TODO(b/78347840): Figure out how to make these Artifacts.
        public NestedSet<LinkerInput> getExpandedLinkerInputs() {
            return expandedLinkerInputs;
        }

        public NestedSet<String> getLibrarySearchDirectories() {
            return librarySearchDirectories;
        }

        public NestedSet<String> getRuntimeLibrarySearchDirectories() {
            return runtimeLibrarySearchDirectories;
        }
    }

    /**
     * When linking a shared library fully or mostly static then we need to link in *all* dependent
     * files, not just what the shared library needs for its own code. This is done by wrapping all
     * objects/libraries with -Wl,-whole-archive and -Wl,-no-whole-archive. For this case the
     * globalNeedWholeArchive parameter must be set to true. Otherwise only library objects (.lo) need
     * to be wrapped with -Wl,-whole-archive and -Wl,-no-whole-archive.
     *
     * <p>TODO: Factor out of the bazel binary into build variables for crosstool action_configs.
     */
    public CollectedLibrariesToLink collectLibrariesToLink() {
        NestedSetBuilder<String> librarySearchDirectories = NestedSetBuilder.linkOrder();
        NestedSetBuilder<String> runtimeLibrarySearchDirectories = NestedSetBuilder.linkOrder();
        ImmutableSet.Builder<String> rpathRootsForExplicitSoDeps = ImmutableSet.builder();
        NestedSetBuilder<LinkerInput> expandedLinkerInputsBuilder = NestedSetBuilder.linkOrder();
        // List of command line parameters that need to be placed *outside* of
        // --whole-archive ... --no-whole-archive.
        SequenceBuilder librariesToLink = new SequenceBuilder();
        String toolchainLibrariesSolibName = toolchainLibrariesSolibDir != null ? toolchainLibrariesSolibDir.getBaseName() : null;
        if (isNativeDeps && cppConfiguration.shareNativeDeps()) {
            if (needToolchainLibrariesRpath) {
                runtimeLibrarySearchDirectories.add("../" + toolchainLibrariesSolibName + "/");
            }
        } else {
            // For all other links, calculate the relative path from the output file to _solib_[arch]
            // (the directory where all shared libraries are stored, which resides under the blaze-bin
            // directory. In other words, given blaze-bin/my/package/binary, rpathRoot would be
            // "../../_solib_[arch]".
            if (needToolchainLibrariesRpath) {
                runtimeLibrarySearchDirectories.add(Strings.repeat("../", outputArtifact.getRootRelativePath().segmentCount() - 1) + toolchainLibrariesSolibName + "/");
            }
            if (isNativeDeps) {
                // We also retain the $ORIGIN/ path to solibs that are in _solib_<arch>, as opposed to
                // the package directory)
                if (needToolchainLibrariesRpath) {
                    runtimeLibrarySearchDirectories.add("../" + toolchainLibrariesSolibName + "/");
                }
            }
        }
        if (needToolchainLibrariesRpath) {
            if (isNativeDeps) {
                runtimeLibrarySearchDirectories.add(".");
            }
            runtimeLibrarySearchDirectories.add(toolchainLibrariesSolibName + "/");
        }
        Pair<Boolean, Boolean> includeSolibsPair = addLinkerInputs(librarySearchDirectories, rpathRootsForExplicitSoDeps, librariesToLink, expandedLinkerInputsBuilder);
        boolean includeSolibDir = includeSolibsPair.first;
        boolean includeToolchainLibrariesSolibDir = includeSolibsPair.second;
        Preconditions.checkState(ltoMap == null || ltoMap.isEmpty(), "Still have LTO objects left: %s", ltoMap);
        NestedSetBuilder<String> allRuntimeLibrarySearchDirectories = NestedSetBuilder.linkOrder();
        // rpath ordering matters for performance; first add the one where most libraries are found.
        if (includeSolibDir) {
            allRuntimeLibrarySearchDirectories.add(rpathRoot);
        }
        allRuntimeLibrarySearchDirectories.addAll(rpathRootsForExplicitSoDeps.build());
        if (includeToolchainLibrariesSolibDir) {
            allRuntimeLibrarySearchDirectories.addTransitive(runtimeLibrarySearchDirectories.build());
        }
        return new CollectedLibrariesToLink(librariesToLink, expandedLinkerInputsBuilder.build(), librarySearchDirectories.build(), allRuntimeLibrarySearchDirectories.build());
    }

    private Pair<Boolean, Boolean> addLinkerInputs(NestedSetBuilder<String> librarySearchDirectories, ImmutableSet.Builder<String> rpathEntries, SequenceBuilder librariesToLink, NestedSetBuilder<LinkerInput> expandedLinkerInputsBuilder) {
        boolean includeSolibDir = false;
        boolean includeToolchainLibrariesSolibDir = false;
        for (LinkerInput input : linkerInputs) {
            if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY || input.getArtifactCategory() == ArtifactCategory.INTERFACE_LIBRARY) {
                PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
                // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, dynamic libraries are not symlinked
                // under solibDir, so don't check it and don't include solibDir.
                if (!featureConfiguration.isEnabled(CppRuleClreplacedes.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
                    Preconditions.checkState(libDir.startsWith(solibDir) || libDir.startsWith(toolchainLibrariesSolibDir), "Artifact '%s' is not under directory expected '%s'," + " neither it is in directory for toolchain libraries '%'.", input.getArtifact(), solibDir, toolchainLibrariesSolibDir);
                    if (libDir.equals(solibDir)) {
                        includeSolibDir = true;
                    }
                    if (libDir.equals(toolchainLibrariesSolibDir)) {
                        includeToolchainLibrariesSolibDir = true;
                    }
                }
                addDynamicInputLinkOptions(input, librariesToLink, expandedLinkerInputsBuilder, librarySearchDirectories, rpathEntries);
            } else {
                addStaticInputLinkOptions(input, librariesToLink, expandedLinkerInputsBuilder);
            }
        }
        return Pair.of(includeSolibDir, includeToolchainLibrariesSolibDir);
    }

    /**
     * Adds command-line options for a dynamic library input file into options and libOpts.
     *
     * @param librariesToLink - a collection that will be exposed as a build variable.
     */
    private void addDynamicInputLinkOptions(LinkerInput input, SequenceBuilder librariesToLink, NestedSetBuilder<LinkerInput> expandedLinkerInputsBuilder, NestedSetBuilder<String> librarySearchDirectories, ImmutableSet.Builder<String> rpathRootsForExplicitSoDeps) {
        Preconditions.checkState(input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY || input.getArtifactCategory() == ArtifactCategory.INTERFACE_LIBRARY);
        Preconditions.checkState(!Link.useStartEndLib(input, CppHelper.getArchiveType(cppConfiguration, ccToolchainProvider, featureConfiguration)));
        expandedLinkerInputsBuilder.add(input);
        if (featureConfiguration.isEnabled(CppRuleClreplacedes.TARGETS_WINDOWS) && ccToolchainProvider.supportsInterfaceSharedLibraries(featureConfiguration)) {
            // On Windows, dynamic library (dll) cannot be linked directly when using toolchains that
            // support interface library (eg. MSVC). If the user is doing so, it is only to be referenced
            // in other places (such as copy_dynamic_libraries_to_binary); skip adding it.
            if (CppFileTypes.SHARED_LIBRARY.matches(input.getArtifact().getFilename())) {
                return;
            }
        }
        Artifact inputArtifact = input.getArtifact();
        PathFragment libDir = inputArtifact.getExecPath().getParentDirectory();
        if (!libDir.equals(solibDir) && (toolchainLibrariesSolibDir == null || !toolchainLibrariesSolibDir.equals(libDir))) {
            String dotdots = "";
            PathFragment commonParent = solibDir;
            while (!libDir.startsWith(commonParent)) {
                dotdots += "../";
                commonParent = commonParent.getParentDirectory();
            }
            rpathRootsForExplicitSoDeps.add(rpathRoot + dotdots + libDir.relativeTo(commonParent).getPathString());
        }
        librarySearchDirectories.add(inputArtifact.getExecPath().getParentDirectory().getPathString());
        String name = inputArtifact.getFilename();
        if (CppFileTypes.SHARED_LIBRARY.matches(name)) {
            // Use normal shared library resolution rules for shared libraries.
            String libName = name.replaceAll("(^lib|\\.(so|dylib)$)", "");
            librariesToLink.addValue(LibraryToLinkValue.forDynamicLibrary(libName));
        } else if (CppFileTypes.VERSIONED_SHARED_LIBRARY.matches(name)) {
            // Versioned shared libraries require the exact library filename, e.g.:
            // -lfoo -> libfoo.so
            // -l:libfoo.so.1 -> libfoo.so.1
            librariesToLink.addValue(LibraryToLinkValue.forVersionedDynamicLibrary(name));
        } else {
            // Interface shared objects have a non-standard extension
            // that the linker won't be able to find.  So use the
            // filename directly rather than a -l option.  Since the
            // library has an SONAME attribute, this will work fine.
            librariesToLink.addValue(LibraryToLinkValue.forInterfaceLibrary(inputArtifact.getExecPathString()));
        }
    }

    /**
     * Get the effective path for the object artifact, being careful not to create new strings if
     * possible.
     *
     * @param: objectFile - Artifact representing an object file.
     * @param -inputIsFake - Is this object being used for a cc_fake_binary.
     */
    private static String effectiveObjectFilePath(Artifact objectFile, boolean inputIsFake) {
        // Avoid making new strings as much as possible! This called for every object file used in the
        // build.
        if (inputIsFake) {
            return Link.FAKE_OBJECT_PREFIX + objectFile.getExecPathString();
        }
        return objectFile.getExecPathString();
    }

    /**
     * Adds command-line options for a static library or non-library input into options.
     *
     * @param librariesToLink - a collection that will be exposed as a build variable.
     */
    private void addStaticInputLinkOptions(LinkerInput input, SequenceBuilder librariesToLink, NestedSetBuilder<LinkerInput> expandedLinkerInputsBuilder) {
        ArtifactCategory artifactCategory = input.getArtifactCategory();
        Preconditions.checkArgument(artifactCategory.equals(ArtifactCategory.OBJECT_FILE) || artifactCategory.equals(ArtifactCategory.STATIC_LIBRARY) || artifactCategory.equals(ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY));
        boolean isAlwaysLinkStaticLibrary = artifactCategory == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY;
        // input.disableWholeArchive() should only be true for libstdc++/libc++ etc.
        boolean inputIsWholeArchive = !input.disableWholeArchive() && (isAlwaysLinkStaticLibrary || needWholeArchive);
        // If we had any LTO artifacts, ltoMap whould be non-null. In that case,
        // we should have created a thinltoParamFile which the LTO indexing
        // step will populate with the exec paths that correspond to the LTO
        // artifacts that the linker decided to include based on symbol resolution.
        // Those files will be included directly in the link (and not wrapped
        // in --start-lib/--end-lib) to ensure consistency between the two link
        // steps.
        Preconditions.checkState(ltoMap == null || thinltoParamFile != null || !allowLtoIndexing);
        // start-lib/end-lib library: adds its input object files.
        if (Link.useStartEndLib(input, CppHelper.getArchiveType(cppConfiguration, ccToolchainProvider, featureConfiguration))) {
            Iterable<Artifact> archiveMembers = input.getObjectFiles();
            if (!Iterables.isEmpty(archiveMembers)) {
                ImmutableList.Builder<Artifact> nonLtoArchiveMembersBuilder = ImmutableList.builder();
                for (Artifact member : archiveMembers) {
                    Artifact a;
                    if (ltoMap != null && (a = ltoMap.remove(member)) != null) {
                        // When ltoMap is non-null the backend artifact may be missing due to libraries that
                        // list .o files explicitly, or generate .o files from replacedembler.
                        if (handledByLtoIndexing(a, allowLtoIndexing)) {
                            // The LTO artifacts that should be included in the final link
                            // are listed in the thinltoParamFile, generated by the LTO indexing.
                            // Even if this object file is being skipped for exposure as a Build variable, it's
                            // still an input to this action.
                            expandedLinkerInputsBuilder.add(LinkerInputs.simpleLinkerInput(a, ArtifactCategory.OBJECT_FILE, /* disableWholeArchive= */
                            false));
                            continue;
                        }
                        // No LTO indexing step, so use the LTO backend's generated artifact directly
                        // instead of the bitcode object.
                        member = a;
                    }
                    nonLtoArchiveMembersBuilder.add(member);
                    expandedLinkerInputsBuilder.add(LinkerInputs.simpleLinkerInput(member, ArtifactCategory.OBJECT_FILE, /* disableWholeArchive  = */
                    false));
                }
                ImmutableList<Artifact> nonLtoArchiveMembers = nonLtoArchiveMembersBuilder.build();
                if (!nonLtoArchiveMembers.isEmpty()) {
                    if (inputIsWholeArchive) {
                        for (Artifact member : nonLtoArchiveMembers) {
                            if (member.isTreeArtifact()) {
                                // TODO(b/78189629): This object filegroup is expanded at action time but wrapped
                                // with --start/--end-lib. There's currently no way to force these objects to be
                                // linked in.
                                librariesToLink.addValue(LibraryToLinkValue.forObjectFileGroup(ImmutableList.<Artifact>of(member), /* isWholeArchive= */
                                true));
                            } else {
                                // TODO(b/78189629): These each need to be their own LibraryToLinkValue so they're
                                // not wrapped in --start/--end-lib (which lets the linker leave out objects with
                                // unreferenced code).
                                librariesToLink.addValue(LibraryToLinkValue.forObjectFile(effectiveObjectFilePath(member, input.isFake()), /* isWholeArchive= */
                                true));
                            }
                        }
                    } else {
                        librariesToLink.addValue(LibraryToLinkValue.forObjectFileGroup(nonLtoArchiveMembers, /* isWholeArchive= */
                        false));
                    }
                }
            }
        } else {
            Artifact inputArtifact = input.getArtifact();
            Artifact a;
            if (ltoMap != null && (a = ltoMap.remove(inputArtifact)) != null) {
                if (handledByLtoIndexing(a, allowLtoIndexing)) {
                    // The LTO artifacts that should be included in the final link
                    // are listed in the thinltoParamFile, generated by the LTO indexing.
                    // Even if this object file is being skipped for exposure as a build variable, it's
                    // still an input to this action.
                    expandedLinkerInputsBuilder.add(LinkerInputs.simpleLinkerInput(a, ArtifactCategory.OBJECT_FILE, /* disableWholeArchive= */
                    false));
                    return;
                }
                // No LTO indexing step, so use the LTO backend's generated artifact directly
                // instead of the bitcode object.
                inputArtifact = a;
            }
            if (artifactCategory.equals(ArtifactCategory.OBJECT_FILE)) {
                if (inputArtifact.isTreeArtifact()) {
                    librariesToLink.addValue(LibraryToLinkValue.forObjectFileGroup(ImmutableList.<Artifact>of(inputArtifact), inputIsWholeArchive));
                } else {
                    librariesToLink.addValue(LibraryToLinkValue.forObjectFile(effectiveObjectFilePath(inputArtifact, input.isFake()), inputIsWholeArchive));
                }
                if (!input.isLinkstamp()) {
                    expandedLinkerInputsBuilder.add(input);
                }
            } else {
                librariesToLink.addValue(LibraryToLinkValue.forStaticLibrary(effectiveObjectFilePath(inputArtifact, input.isFake()), inputIsWholeArchive));
                expandedLinkerInputsBuilder.add(input);
            }
        }
    }

    /**
     * Returns true if this artifact is produced from a bitcode file that will be input to the LTO
     * indexing step, in which case that step will add it to the generated thinltoParamFile for
     * inclusion in the final link step if the linker decides to include it.
     *
     * @param a is an artifact produced by an LTO backend.
     * @param allowLtoIndexing
     */
    private static boolean handledByLtoIndexing(Artifact a, boolean allowLtoIndexing) {
        // If no LTO indexing is allowed for this link, then none are handled by LTO indexing.
        // Otherwise, this may be from a linkstatic library that we decided not to include in
        // LTO indexing because we are linking a test, to improve scalability when linking many tests.
        return allowLtoIndexing && !a.getRootRelativePath().startsWith(PathFragment.create(CppLinkActionBuilder.SHARED_NONLTO_BACKEND_ROOT_PREFIX));
    }

    private Map<Artifact, Artifact> generateLtoMap() {
        if (isLtoIndexing || allLtoArtifacts == null) {
            return null;
        }
        // TODO(bazel-team): The LTO final link can only work if there are individual .o files on
        // the command line. Rather than crashing, this should issue a nice error. We will get
        // this by
        // 1) moving supports_start_end_lib to a toolchain feature
        // 2) having thin_lto require start_end_lib
        // As a bonus, we can rephrase --nostart_end_lib as --features=-start_end_lib and get rid
        // of a command line option.
        Preconditions.checkState(CppHelper.useStartEndLib(cppConfiguration, ccToolchainProvider, featureConfiguration));
        Map<Artifact, Artifact> ltoMap = new HashMap<>();
        for (LtoBackendArtifacts l : allLtoArtifacts) {
            ltoMap.put(l.getBitcodeFile(), l.getObjectFile());
        }
        return ltoMap;
    }
}

18 View Complete Implementation : ObjcCppSemantics.java
Copyright Apache License 2.0
Author : bazelbuild
@Override
public void finalizeCompileActionBuilder(BuildConfiguration configuration, FeatureConfiguration featureConfiguration, CppCompileActionBuilder actionBuilder) {
    actionBuilder.addTransitiveMandatoryInputs(actionBuilder.getToolchain().getAllFilesMiddleman()).setShouldScanIncludes(includeProcessingType == INCLUDE_SCANNING);
    if (includeProcessingType == NO_PROCESSING) {
        // TODO(b/62060839): Identify the mechanism used to add generated headers in c++, and recycle
        // it here.
        actionBuilder.addTransitiveMandatoryInputs(objcProvider.getGeneratedHeaders());
    }
}

18 View Complete Implementation : CppLinkActionTest.java
Copyright Apache License 2.0
Author : bazelbuild
@Test
public void testSplitExecutableLinkCommandDynamicWithNoSplitting() throws Exception {
    getreplacedysisMock().ccSupport().setupCcToolchainConfig(mockToolsConfig, CcToolchainConfig.builder().withFeatures(CppRuleClreplacedes.DO_NOT_SPLIT_LINKING_CMDLINE));
    RuleContext ruleContext = createDummyRuleContext();
    FeatureConfiguration featureConfiguration = getMockFeatureConfiguration(/* envVars= */
    ImmutableMap.of());
    CppLinkAction linkAction = createLinkBuilder(ruleContext, LinkTargetType.DYNAMIC_LIBRARY, "dummyRuleContext/out.so", ImmutableList.of(), ImmutableList.of(), featureConfiguration).setLibraryIdentifier("library").build();
    Pair<List<String>, List<String>> result = linkAction.getLinkCommandLine().splitCommandline();
    replacedertThat(result.first.stream().map(x -> removeOutDirectory(x)).collect(ImmutableList.toImmutableList())).containsExactly("crosstool/gcc_tool", "@/k8-fastbuild/bin/dummyRuleContext/out.so-2.params").inOrder();
    replacedertThat(result.second.stream().map(x -> removeOutDirectory(x)).collect(ImmutableList.toImmutableList())).containsExactly("-shared", "-o", "/k8-fastbuild/bin/dummyRuleContext/out.so", "-Wl,-S", "--sysroot=/usr/grte/v1").inOrder();
}

18 View Complete Implementation : CppLinkActionTest.java
Copyright Apache License 2.0
Author : bazelbuild
private CppLinkActionBuilder createLinkBuilder(RuleContext ruleContext, Link.LinkTargetType type, String outputPath, Iterable<Artifact> nonLibraryInputs, ImmutableList<LibraryToLink> libraryInputs, FeatureConfiguration featureConfiguration) {
    CcToolchainProvider toolchain = CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
    CppLinkActionBuilder builder = new CppLinkActionBuilder(ruleContext, ruleContext, ruleContext.getLabel(), ActionsTestUtil.createArtifact(getTargetConfiguration().getBinDirectory(ruleContext.getRule().getRepository()), outputPath), ruleContext.getConfiguration(), toolchain, toolchain.getFdoContext(), featureConfiguration, MockCppSemantics.INSTANCE).addObjectFiles(nonLibraryInputs).addLibraries(libraryInputs).setLinkType(type).setLinkerFiles(NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER)).setLinkingMode(LinkingMode.STATIC);
    return builder;
}

18 View Complete Implementation : CppLinkActionTest.java
Copyright Apache License 2.0
Author : bazelbuild
@Test
public void testExecutionRequirementsFromCrosstool() throws Exception {
    RuleContext ruleContext = createDummyRuleContext();
    FeatureConfiguration featureConfiguration = CcToolchainFeaturesTest.buildFeatures("action_config {", "   config_name: '" + LinkTargetType.EXECUTABLE.getActionName() + "'", "   action_name: '" + LinkTargetType.EXECUTABLE.getActionName() + "'", "   tool {", "      tool_path: 'DUMMY_TOOL'", "      execution_requirement: 'dummy-exec-requirement'", "   }", "}").getFeatureConfiguration(ImmutableSet.of(LinkTargetType.EXECUTABLE.getActionName()));
    CppLinkAction linkAction = createLinkBuilder(ruleContext, LinkTargetType.EXECUTABLE, "dummyRuleContext/out", ImmutableList.of(), ImmutableList.of(), featureConfiguration).build();
    replacedertThat(linkAction.getExecutionInfo()).containsEntry("dummy-exec-requirement", "");
}

18 View Complete Implementation : LinkBuildVariablesTestCase.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns the value of a given string variable in context of the given Variables instance.
 */
protected static String getVariableValue(RuleContext ruleContext, CcToolchainVariables variables, String variable) throws Exception {
    FeatureConfiguration mockFeatureConfiguration = buildFeatures(ruleContext, "feature {", "  name: 'a'", "  flag_set {", "  action: 'foo'", "    flag_group {", "      flag: '%{" + variable + "}'", "    }", "  }", "}").getFeatureConfiguration(ImmutableSet.of("a"));
    return Iterables.getOnlyElement(mockFeatureConfiguration.getCommandLine("foo", variables));
}

17 View Complete Implementation : BazelJavaSemantics.java
Copyright Apache License 2.0
Author : bazelbuild
@Override
public Pair<Artifact, Artifact> getLauncher(RuleContext ruleContext, JavaCommon common, DeployArchiveBuilder deployArchiveBuilder, DeployArchiveBuilder unstrippedDeployArchiveBuilder, Builder runfilesBuilder, List<String> jvmFlags, JavaTargetAttributes.Builder attributesBuilder, boolean shouldStrip, CcToolchainProvider ccToolchain, FeatureConfiguration featureConfiguration) {
    Artifact launcher = JavaHelper.launcherArtifactForTarget(this, ruleContext);
    return new Pair<>(launcher, launcher);
}

17 View Complete Implementation : CompileCommandLine.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * The compile command line for the C++ compile action.
 */
@AutoCodec
public final clreplaced CompileCommandLine {

    private final Artifact sourceFile;

    private final CoptsFilter coptsFilter;

    private final FeatureConfiguration featureConfiguration;

    private final CcToolchainVariables variables;

    private final String actionName;

    private final Artifact dotdFile;

    @AutoCodec.Instantiator
    @VisibleForSerialization
    CompileCommandLine(Artifact sourceFile, CoptsFilter coptsFilter, FeatureConfiguration featureConfiguration, CcToolchainVariables variables, String actionName, Artifact dotdFile) {
        this.sourceFile = Preconditions.checkNotNull(sourceFile);
        this.coptsFilter = coptsFilter;
        this.featureConfiguration = Preconditions.checkNotNull(featureConfiguration);
        this.variables = variables;
        this.actionName = actionName;
        this.dotdFile = isGenerateDotdFile(sourceFile) ? dotdFile : null;
    }

    /**
     * Returns true if Dotd file should be generated.
     */
    private boolean isGenerateDotdFile(Artifact sourceArtifact) {
        return CppFileTypes.headerDiscoveryRequired(sourceArtifact) && !featureConfiguration.isEnabled(CppRuleClreplacedes.PARSE_SHOWINCLUDES);
    }

    /**
     * Returns the environment variables that should be set for C++ compile actions.
     */
    protected Map<String, String> getEnvironment() throws CommandLineExpansionException {
        try {
            return featureConfiguration.getEnvironmentVariables(actionName, variables);
        } catch (ExpansionException e) {
            throw new CommandLineExpansionException(e.getMessage());
        }
    }

    /**
     * Returns the tool path for the compilation based on the current feature configuration.
     */
    @VisibleForTesting
    public String getToolPath() {
        Preconditions.checkArgument(featureConfiguration.actionIsConfigured(actionName), "Expected action_config for '%s' to be configured", actionName);
        return featureConfiguration.getToolPathForAction(actionName);
    }

    /**
     * @param overwrittenVariables: Variables that will overwrite original build variables. When null,
     *     unmodified original variables are used.
     */
    protected List<String> getArguments(@Nullable PathFragment parameterFilePath, @Nullable CcToolchainVariables overwrittenVariables) throws CommandLineExpansionException {
        List<String> commandLine = new ArrayList<>();
        // first: The command name.
        commandLine.add(getToolPath());
        // second: The compiler options.
        if (parameterFilePath != null) {
            commandLine.add("@" + parameterFilePath.getSafePathString());
        } else {
            commandLine.addAll(getCompilerOptions(overwrittenVariables));
        }
        return commandLine;
    }

    /**
     * Returns {@link CommandLine} instance that contains the exactly same command line as the {@link
     * CppCompileAction}.
     *
     * @param cppCompileAction - {@link CppCompileAction} owning this {@link CompileCommandLine}.
     */
    public CommandLine getFilteredFeatureConfigurationCommandLine(CppCompileAction cppCompileAction) {
        return new CommandLine() {

            @Override
            public Iterable<String> arguments() throws CommandLineExpansionException {
                CcToolchainVariables overwrittenVariables = cppCompileAction.getOverwrittenVariables();
                List<String> compilerOptions = getCompilerOptions(overwrittenVariables);
                return ImmutableList.<String>builder().add(getToolPath()).addAll(compilerOptions).build();
            }
        };
    }

    public List<String> getCompilerOptions(@Nullable CcToolchainVariables overwrittenVariables) throws CommandLineExpansionException {
        try {
            List<String> options = new ArrayList<>();
            CcToolchainVariables updatedVariables = variables;
            if (variables != null && overwrittenVariables != null) {
                CcToolchainVariables.Builder variablesBuilder = CcToolchainVariables.builder(variables);
                variablesBuilder.addAllNonTransitive(overwrittenVariables);
                updatedVariables = variablesBuilder.build();
            }
            addFilteredOptions(options, featureConfiguration.getPerFeatureExpansions(actionName, updatedVariables));
            return options;
        } catch (ExpansionException e) {
            throw new CommandLineExpansionException(e.getMessage());
        }
    }

    // For each option in 'in', add it to 'out' unless it is matched by the 'coptsFilter' regexp.
    private void addFilteredOptions(List<String> out, List<Pair<String, List<String>>> expandedFeatures) {
        for (Pair<String, List<String>> pair : expandedFeatures) {
            if (pair.getFirst().equals(CppRuleClreplacedes.UNFILTERED_COMPILE_FLAGS_FEATURE_NAME)) {
                out.addAll(pair.getSecond());
                continue;
            }
            // We do not uses Java's stream API here as it causes a substantial overhead compared to the
            // very little work that this is actually doing.
            for (String flag : pair.getSecond()) {
                if (coptsFilter.preplacedesFilter(flag)) {
                    out.add(flag);
                }
            }
        }
    }

    public Artifact getSourceFile() {
        return sourceFile;
    }

    public Artifact getDotdFile() {
        return dotdFile;
    }

    public CcToolchainVariables getVariables() {
        return variables;
    }

    /**
     * Returns all user provided copts flags.
     *
     * TODO(b/64108724): Get rid of this method when we don't need to parse copts to collect include
     * directories anymore (meaning there is a way of specifying include directories using an
     * explicit attribute, not using platform-dependent garbage bag that copts is).
     */
    public ImmutableList<String> getCopts() {
        if (variables.isAvailable(CompileBuildVariables.USER_COMPILE_FLAGS.getVariableName())) {
            try {
                return CcToolchainVariables.toStringList(variables, CompileBuildVariables.USER_COMPILE_FLAGS.getVariableName());
            } catch (ExpansionException e) {
                throw new IllegalStateException("Should not happen - 'user_compile_flags' should be a string list, but wasn't.");
            }
        } else {
            return ImmutableList.of();
        }
    }

    public static Builder builder(Artifact sourceFile, CoptsFilter coptsFilter, String actionName, Artifact dotdFile) {
        return new Builder(sourceFile, coptsFilter, actionName, dotdFile);
    }

    /**
     * A builder for a {@link CompileCommandLine}.
     */
    public static final clreplaced Builder {

        private final Artifact sourceFile;

        private CoptsFilter coptsFilter;

        private FeatureConfiguration featureConfiguration;

        private CcToolchainVariables variables = CcToolchainVariables.EMPTY;

        private final String actionName;

        @Nullable
        private final Artifact dotdFile;

        public CompileCommandLine build() {
            return new CompileCommandLine(Preconditions.checkNotNull(sourceFile), Preconditions.checkNotNull(coptsFilter), Preconditions.checkNotNull(featureConfiguration), Preconditions.checkNotNull(variables), Preconditions.checkNotNull(actionName), dotdFile);
        }

        private Builder(Artifact sourceFile, CoptsFilter coptsFilter, String actionName, Artifact dotdFile) {
            this.sourceFile = sourceFile;
            this.coptsFilter = coptsFilter;
            this.actionName = actionName;
            this.dotdFile = dotdFile;
        }

        /**
         * Sets the feature configuration for this compile action.
         */
        public Builder setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
            this.featureConfiguration = featureConfiguration;
            return this;
        }

        public Builder setVariables(CcToolchainVariables variables) {
            this.variables = variables;
            return this;
        }

        @VisibleForTesting
        Builder setCoptsFilter(CoptsFilter filter) {
            this.coptsFilter = Preconditions.checkNotNull(filter);
            return this;
        }
    }
}

17 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Convenience function for finding the static runtime inputs for the current toolchain. Useful
 * for non C++ rules that link against the C++ runtime.
 */
public static NestedSet<Artifact> getDefaultCcToolchainStaticRuntimeInputs(RuleContext ruleContext) throws RuleErrorException {
    CcToolchainProvider defaultToolchain = getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
    if (defaultToolchain == null) {
        return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
    }
    FeatureConfiguration featureConfiguration = CcCommon.configureFeaturesOrReportRuleError(ruleContext, defaultToolchain);
    try {
        return defaultToolchain.getStaticRuntimeLinkInputs(featureConfiguration);
    } catch (EvalException e) {
        throw ruleContext.throwWithRuleError(e.getMessage());
    }
}

17 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Decide which DEF file should be used for the linking action.
 *
 * @return The artifact of the DEF file that should be used for the linking action.
 */
public static Artifact getWindowsDefFileForLinking(RuleContext ruleContext, Artifact customDefFile, Artifact generatedDefFile, FeatureConfiguration featureConfiguration) {
    // 1. If a custom DEF file is specified in win_def_file attribute, use it.
    // 2. If a generated DEF file is available and should be used, use it.
    // 3. Otherwise, we use an empty DEF file to ensure the import library will be generated.
    if (customDefFile != null) {
        return customDefFile;
    } else if (generatedDefFile != null && CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) {
        return generatedDefFile;
    } else {
        return createEmptyDefFileAction(ruleContext);
    }
}

17 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Convenience function for finding the dynamic runtime inputs for the current toolchain. Useful
 * for Starlark-defined rules that link against the C++ runtime.
 *
 * <p>This uses the default feature configuration. Do *not* use this method in rules that use a
 * non-default feature configuration, or risk a mismatch.
 */
public static NestedSet<Artifact> getDefaultCcToolchainDynamicRuntimeInputsFromStarlark(RuleContext ruleContext) throws EvalException {
    CcToolchainProvider defaultToolchain = getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
    if (defaultToolchain == null) {
        return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
    }
    FeatureConfiguration featureConfiguration = CcCommon.configureFeaturesOrReportRuleError(ruleContext, defaultToolchain);
    return defaultToolchain.getDynamicRuntimeLinkInputs(featureConfiguration);
}

17 View Complete Implementation : CppLinkActionTest.java
Copyright Apache License 2.0
Author : bazelbuild
@Test
public void testInterfaceOutputForDynamicLibraryLegacy() throws Exception {
    RuleContext ruleContext = createDummyRuleContext();
    FeatureConfiguration featureConfiguration = CcToolchainFeaturesTest.buildFeatures(MockCcSupport.SUPPORTS_INTERFACE_SHARED_LIBRARIES_FEATURE, "feature {", "   name: 'build_interface_libraries'", "   flag_set {", "       action: '" + LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName() + "',", "       flag_group {", "           flag: '%{generate_interface_library}'", "           flag: '%{interface_library_builder_path}'", "           flag: '%{interface_library_input_path}'", "           flag: '%{interface_library_output_path}'", "       }", "   }", "}", "feature {", "   name: 'dynamic_library_linker_tool'", "   flag_set {", "       action: 'c++-link-nodeps-dynamic-library'", "       flag_group {", "           flag: 'dynamic_library_linker_tool'", "       }", "   }", "}", "feature {", "    name: 'has_configured_linker_path'", "}", "action_config {", "   config_name: '" + LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName() + "'", "   action_name: '" + LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName() + "'", "   tool {", "       tool_path: 'custom/crosstool/scripts/link_dynamic_library.sh'", "   }", "   implies: 'has_configured_linker_path'", "   implies: 'build_interface_libraries'", "   implies: 'dynamic_library_linker_tool'", "}").getFeatureConfiguration(ImmutableSet.of("build_interface_libraries", "dynamic_library_linker_tool", LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName()));
    CppLinkActionBuilder builder = createLinkBuilder(ruleContext, LinkTargetType.NODEPS_DYNAMIC_LIBRARY, "foo.so", ImmutableList.<Artifact>of(), ImmutableList.<LibraryToLink>of(), featureConfiguration).setLibraryIdentifier("foo").setInterfaceOutput(scratchArtifact("FakeInterfaceOutput.ifso"));
    List<String> commandLine = builder.build().getCommandLine(null);
    replacedertThat(commandLine).hreplacedize(6);
    replacedertThat(commandLine.get(0)).endsWith("custom/crosstool/scripts/link_dynamic_library.sh");
    replacedertThat(commandLine.get(1)).isEqualTo("yes");
    replacedertThat(commandLine.get(2)).endsWith("tools/cpp/build_interface_so");
    replacedertThat(commandLine.get(3)).endsWith("foo.so");
    replacedertThat(commandLine.get(4)).isEqualTo("out/FakeInterfaceOutput.ifso");
    replacedertThat(commandLine.get(5)).isEqualTo("dynamic_library_linker_tool");
}

16 View Complete Implementation : CcLibrary.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Adds linker output artifacts to the given map, to be registered on the configured target as
 * output groups.
 */
private static Map<String, NestedSet<Artifact>> addLinkerOutputArtifacts(RuleContext ruleContext, CcToolchainProvider ccToolchain, CppConfiguration cppConfiguration, BuildConfiguration configuration, CcCompilationOutputs ccCompilationOutputs, FeatureConfiguration featureConfiguration) throws RuleErrorException {
    NestedSetBuilder<Artifact> archiveFile = new NestedSetBuilder<>(Order.STABLE_ORDER);
    NestedSetBuilder<Artifact> dynamicLibrary = new NestedSetBuilder<>(Order.STABLE_ORDER);
    ImmutableSortedMap.Builder<String, NestedSet<Artifact>> outputGroups = ImmutableSortedMap.naturalOrder();
    if (!ruleContext.attributes().has("alwayslink", Type.BOOLEAN) || !ruleContext.attributes().has("linkstatic", Type.BOOLEAN)) {
        return outputGroups.build();
    }
    if (ruleContext.attributes().get("alwayslink", Type.BOOLEAN)) {
        archiveFile.add(CppHelper.getLinkedArtifact(ruleContext, ccToolchain, configuration, Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY, /* linkedArtifactNameSuffix= */
        ""));
    } else {
        archiveFile.add(CppHelper.getLinkedArtifact(ruleContext, ccToolchain, configuration, Link.LinkTargetType.STATIC_LIBRARY, /* linkedArtifactNameSuffix= */
        ""));
    }
    if (!ruleContext.attributes().get("linkstatic", Type.BOOLEAN) && !ccCompilationOutputs.isEmpty()) {
        dynamicLibrary.add(CppHelper.getLinkedArtifact(ruleContext, ccToolchain, configuration, Link.LinkTargetType.NODEPS_DYNAMIC_LIBRARY, /* linkedArtifactNameSuffix= */
        ""));
        if (CppHelper.useInterfaceSharedLibraries(cppConfiguration, ccToolchain, featureConfiguration)) {
            dynamicLibrary.add(CppHelper.getLinkedArtifact(ruleContext, ccToolchain, configuration, LinkTargetType.INTERFACE_DYNAMIC_LIBRARY, /* linkedArtifactNameSuffix= */
            ""));
        }
    }
    outputGroups.put(ARCHIVE_LIBRARY_OUTPUT_GROUP_NAME, archiveFile.build());
    outputGroups.put(DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME, dynamicLibrary.build());
    return outputGroups.build();
}

16 View Complete Implementation : CcLibrary.java
Copyright Apache License 2.0
Author : bazelbuild
private static NestedSet<Artifact> collectHiddenTopLevelArtifacts(RuleContext ruleContext, CcToolchainProvider toolchain, CcCompilationOutputs ccCompilationOutputs, FeatureConfiguration featureConfiguration) {
    // Ensure that we build all the dependencies, otherwise users may get confused.
    NestedSetBuilder<Artifact> artifactsToForceBuilder = NestedSetBuilder.stableOrder();
    CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.clreplaced);
    boolean processHeadersInDependencies = cppConfiguration.processHeadersInDependencies();
    boolean usePic = toolchain.usePicForDynamicLibraries(cppConfiguration, featureConfiguration);
    artifactsToForceBuilder.addTransitive(ccCompilationOutputs.getFilesToCompile(processHeadersInDependencies, usePic));
    for (OutputGroupInfo dep : ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) {
        artifactsToForceBuilder.addTransitive(dep.getOutputGroup(OutputGroupInfo.HIDDEN_TOP_LEVEL));
    }
    return artifactsToForceBuilder.build();
}

16 View Complete Implementation : CppHelper.java
Copyright Apache License 2.0
Author : bazelbuild
public static ImmutableList<String> getCommandLine(RuleErrorConsumer ruleErrorConsumer, FeatureConfiguration featureConfiguration, CcToolchainVariables variables, String actionName) throws RuleErrorException {
    try {
        return ImmutableList.copyOf(featureConfiguration.getCommandLine(actionName, variables));
    } catch (ExpansionException e) {
        throw ruleErrorConsumer.throwWithRuleError(e.getMessage());
    }
}

16 View Complete Implementation : LtoBackendArtifacts.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Adds the AFDO profile path to the variable builder and the profile tothe inputs of the action.
 */
@ThreadSafe
private static void addProfileForLtoBackend(LtoBackendAction.Builder builder, FdoContext fdoContext, FeatureConfiguration featureConfiguration, CcToolchainVariables.Builder buildVariables) {
    Artifact prefetch = fdoContext.getPrefetchHintsArtifact();
    if (prefetch != null) {
        buildVariables.addStringVariable("fdo_prefetch_hints_path", prefetch.getExecPathString());
        builder.addInput(fdoContext.getPrefetchHintsArtifact());
    }
    if (!featureConfiguration.isEnabled(CppRuleClreplacedes.AUTOFDO) && !featureConfiguration.isEnabled(CppRuleClreplacedes.CS_FDO_OPTIMIZE) && !featureConfiguration.isEnabled(CppRuleClreplacedes.XBINARYFDO)) {
        return;
    }
    FdoContext.BranchFdoProfile branchFdoProfile = Preconditions.checkNotNull(fdoContext.getBranchFdoProfile());
    Artifact profile = branchFdoProfile.getProfileArtifact();
    buildVariables.addStringVariable("fdo_profile_path", profile.getExecPathString());
    builder.addInput(branchFdoProfile.getProfileArtifact());
}

15 View Complete Implementation : BazelCppSemantics.java
Copyright Apache License 2.0
Author : bazelbuild
@Override
public void finalizeCompileActionBuilder(BuildConfiguration configuration, FeatureConfiguration featureConfiguration, CppCompileActionBuilder actionBuilder) {
    CcToolchainProvider toolchain = actionBuilder.getToolchain();
    actionBuilder.addTransitiveMandatoryInputs(configuration.getFragment(CppConfiguration.clreplaced).useSpecificToolFiles() ? (actionBuilder.getActionName().equals(CppActionNames.replacedEMBLE) ? toolchain.getAsFiles() : toolchain.getCompilerFiles()) : toolchain.getAllFiles()).setShouldScanIncludes(false);
}

15 View Complete Implementation : CcCommon.java
Copyright Apache License 2.0
Author : bazelbuild
private static List<String> computeCcFlagsFromFeatureConfig(RuleContext ruleContext, CcToolchainProvider toolchainProvider) throws RuleErrorException {
    FeatureConfiguration featureConfiguration = null;
    CppConfiguration cppConfiguration;
    if (toolchainProvider.requireCtxInConfigureFeatures()) {
        // When --incompatible_require_ctx_in_configure_features is flipped, this whole method will go
        // away. But I'm keeping it there so we can experiment with flags before they are flipped.
        cppConfiguration = ruleContext.getFragment(CppConfiguration.clreplaced);
    } else {
        cppConfiguration = toolchainProvider.getCppConfigurationEvenThoughItCanBeDifferentThanWhatTargetHas();
    }
    try {
        featureConfiguration = configureFeaturesOrThrowEvalException(ruleContext.getFeatures(), ruleContext.getDisabledFeatures(), toolchainProvider, cppConfiguration);
    } catch (EvalException e) {
        ruleContext.ruleError(e.getMessage());
    }
    if (featureConfiguration.actionIsConfigured(CppActionNames.CC_FLAGS_MAKE_VARIABLE)) {
        CcToolchainVariables buildVariables = toolchainProvider.getBuildVariables(ruleContext.getConfiguration().getOptions(), cppConfiguration);
        return CppHelper.getCommandLine(ruleContext, featureConfiguration, buildVariables, CppActionNames.CC_FLAGS_MAKE_VARIABLE);
    }
    return ImmutableList.of();
}

14 View Complete Implementation : CppLinkstampCompileHelper.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Creates {@link CppCompileAction} to compile linkstamp source
 *
 * @param inputsForInvalidation: see {@link CppCompileAction#inputsForInvalidation}
 */
public static CppCompileAction createLinkstampCompileAction(RuleErrorConsumer ruleErrorConsumer, ActionConstructionContext actionConstructionContext, @Nullable Artifact grepIncludes, BuildConfiguration configuration, Artifact sourceFile, Artifact outputFile, NestedSet<Artifact> compilationInputs, NestedSet<Artifact> nonCodeInputs, NestedSet<Artifact> inputsForInvalidation, ImmutableList<Artifact> buildInfoHeaderArtifacts, Iterable<String> additionalLinkstampDefines, CcToolchainProvider ccToolchainProvider, boolean codeCoverageEnabled, CppConfiguration cppConfiguration, String fdoBuildStamp, FeatureConfiguration featureConfiguration, boolean needsPic, String labelReplacement, String outputReplacement, CppSemantics semantics) {
    CppCompileActionBuilder builder = new CppCompileActionBuilder(actionConstructionContext, grepIncludes, ccToolchainProvider, configuration).addMandatoryInputs(compilationInputs).setVariables(getVariables(ruleErrorConsumer, sourceFile, outputFile, labelReplacement, outputReplacement, additionalLinkstampDefines, buildInfoHeaderArtifacts, featureConfiguration, configuration.getOptions(), cppConfiguration, ccToolchainProvider, needsPic, fdoBuildStamp, codeCoverageEnabled)).setFeatureConfiguration(featureConfiguration).setSourceFile(sourceFile).setSemantics(semantics).setOutputs(outputFile, null).setInputsForInvalidation(inputsForInvalidation).setBuiltinIncludeFiles(buildInfoHeaderArtifacts).addMandatoryInputs(nonCodeInputs).setShareable(true).setShouldScanIncludes(false).setActionName(CppActionNames.LINKSTAMP_COMPILE);
    semantics.finalizeCompileActionBuilder(configuration, featureConfiguration, builder);
    return builder.buildOrThrowIllegalStateException();
}

14 View Complete Implementation : LinkCommandLine.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Represents the command line of a linker invocation. It supports executables and dynamic libraries
 * as well as static libraries.
 */
@AutoCodec
@Immutable
public final clreplaced LinkCommandLine extends CommandLine {

    private final String actionName;

    private final String forcedToolPath;

    private final CcToolchainVariables variables;

    // The feature config can be null for tests.
    @Nullable
    private final FeatureConfiguration featureConfiguration;

    private final ImmutableList<Artifact> buildInfoHeaderArtifacts;

    private final NestedSet<Artifact> linkerInputArtifacts;

    private final LinkTargetType linkTargetType;

    private final Link.LinkingMode linkingMode;

    @Nullable
    private final PathFragment toolchainLibrariesSolibDir;

    private final boolean nativeDeps;

    private final boolean useTestOnlyFlags;

    private final boolean doNotSplitLinkingCmdLine;

    @Nullable
    private final Artifact paramFile;

    @VisibleForSerialization
    LinkCommandLine(String actionName, String forcedToolPath, ImmutableList<Artifact> buildInfoHeaderArtifacts, NestedSet<Artifact> linkerInputArtifacts, LinkTargetType linkTargetType, Link.LinkingMode linkingMode, @Nullable PathFragment toolchainLibrariesSolibDir, boolean nativeDeps, boolean useTestOnlyFlags, @Nullable Artifact paramFile, CcToolchainVariables variables, @Nullable FeatureConfiguration featureConfiguration, boolean doNotSplitLinkingCmdLine) {
        this.actionName = actionName;
        this.forcedToolPath = forcedToolPath;
        this.variables = variables;
        this.featureConfiguration = featureConfiguration;
        this.buildInfoHeaderArtifacts = Preconditions.checkNotNull(buildInfoHeaderArtifacts);
        this.linkerInputArtifacts = Preconditions.checkNotNull(linkerInputArtifacts);
        this.linkTargetType = Preconditions.checkNotNull(linkTargetType);
        this.linkingMode = Preconditions.checkNotNull(linkingMode);
        this.toolchainLibrariesSolibDir = toolchainLibrariesSolibDir;
        this.nativeDeps = nativeDeps;
        this.useTestOnlyFlags = useTestOnlyFlags;
        this.paramFile = paramFile;
        this.doNotSplitLinkingCmdLine = doNotSplitLinkingCmdLine;
    }

    @Nullable
    public Artifact getParamFile() {
        return paramFile;
    }

    /**
     * See {@link CppLinkAction#getBuildInfoHeaderArtifacts()}
     */
    public ImmutableList<Artifact> getBuildInfoHeaderArtifacts() {
        return buildInfoHeaderArtifacts;
    }

    /**
     * Returns the (ordered, immutable) list of paths to the linker's input files.
     */
    public NestedSet<Artifact> getLinkerInputArtifacts() {
        return linkerInputArtifacts;
    }

    @Nullable
    @VisibleForTesting
    public FeatureConfiguration getFeatureConfiguration() {
        return featureConfiguration;
    }

    public String getActionName() {
        return actionName;
    }

    /**
     * Returns the current type of link target set.
     */
    public LinkTargetType getLinkTargetType() {
        return linkTargetType;
    }

    /**
     * Returns the "staticness" of the link.
     */
    public Link.LinkingMode getLinkingMode() {
        return linkingMode;
    }

    /**
     * Returns the path to the linker.
     */
    public String getLinkerPathString() {
        return featureConfiguration.getToolPathForAction(linkTargetType.getActionName());
    }

    /**
     * Returns the location of the C++ runtime solib symlinks. If null, the C++ dynamic runtime
     * libraries either do not exist (because they do not come from the depot) or they are in the
     * regular solib directory.
     */
    @Nullable
    public PathFragment getToolchainLibrariesSolibDir() {
        return toolchainLibrariesSolibDir;
    }

    /**
     * Returns true for libraries linked as native dependencies for other languages.
     */
    public boolean isNativeDeps() {
        return nativeDeps;
    }

    /**
     * Returns true if this link should use test-specific flags (e.g. $EXEC_ORIGIN as the root for
     * finding shared libraries or lazy binding); false by default. See bug "Please use $EXEC_ORIGIN
     * instead of $ORIGIN when linking cc_tests" for further context.
     */
    public boolean useTestOnlyFlags() {
        return useTestOnlyFlags;
    }

    /**
     * Returns the build variables used to template the crosstool for this linker invocation.
     */
    @VisibleForTesting
    public CcToolchainVariables getBuildVariables() {
        return this.variables;
    }

    /**
     * Splits the link command-line into a part to be written to a parameter file, and the remaining
     * actual command line to be executed (which references the parameter file). Should only be used
     * if getParamFile() is not null.
     */
    @VisibleForTesting
    final Pair<List<String>, List<String>> splitCommandline() throws CommandLineExpansionException {
        return splitCommandline(paramFile, getRawLinkArgv(null), linkTargetType, doNotSplitLinkingCmdLine);
    }

    @VisibleForTesting
    final Pair<List<String>, List<String>> splitCommandline(@Nullable ArtifactExpander expander) throws CommandLineExpansionException {
        return splitCommandline(paramFile, getRawLinkArgv(expander), linkTargetType, doNotSplitLinkingCmdLine);
    }

    private static Pair<List<String>, List<String>> splitCommandline(Artifact paramFile, List<String> args, LinkTargetType linkTargetType, boolean doNotSplitLinkingCmdline) {
        Preconditions.checkNotNull(paramFile);
        if (linkTargetType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER) {
            // Ar link commands can also generate huge command lines.
            List<String> paramFileArgs = new ArrayList<>();
            List<String> commandlineArgs = new ArrayList<>();
            extractArgumentsForStaticLinkParamFile(args, commandlineArgs, paramFileArgs);
            return Pair.of(commandlineArgs, paramFileArgs);
        } else {
            // Gcc link commands tend to generate humongous commandlines for some targets, which may
            // not fit on some remote execution machines. To work around this we will employ the help of
            // a parameter file and preplaced any linker options through it.
            List<String> paramFileArgs = new ArrayList<>();
            List<String> commandlineArgs = new ArrayList<>();
            extractArgumentsForDynamicLinkParamFile(args, commandlineArgs, paramFileArgs, doNotSplitLinkingCmdline);
            return Pair.of(commandlineArgs, paramFileArgs);
        }
    }

    public CommandLine getCommandLineForStarlark() {
        return new CommandLine() {

            @Override
            public Iterable<String> arguments() throws CommandLineExpansionException {
                return arguments(/* artifactExpander= */
                null);
            }

            @Override
            public Iterable<String> arguments(ArtifactExpander artifactExpander) throws CommandLineExpansionException {
                if (paramFile == null) {
                    return ImmutableList.copyOf(getRawLinkArgv(artifactExpander));
                } else {
                    return ImmutableList.<String>builder().add(getLinkerPathString()).addAll(splitCommandline(artifactExpander).getSecond()).build();
                }
            }
        };
    }

    /**
     * A {@link CommandLine} implementation that returns the command line args pertaining to the
     * .params file.
     */
    @AutoCodec
    @VisibleForSerialization
    static clreplaced ParamFileCommandLine extends CommandLine {

        private final Artifact paramsFile;

        private final LinkTargetType linkTargetType;

        private final String forcedToolPath;

        private final FeatureConfiguration featureConfiguration;

        private final String actionName;

        private final CcToolchainVariables variables;

        private final boolean doNotSplitLinkingCmdLine;

        public ParamFileCommandLine(Artifact paramsFile, LinkTargetType linkTargetType, String forcedToolPath, FeatureConfiguration featureConfiguration, String actionName, CcToolchainVariables variables, boolean doNotSplitLinkingCmdLine) {
            this.paramsFile = paramsFile;
            this.linkTargetType = linkTargetType;
            this.forcedToolPath = forcedToolPath;
            this.featureConfiguration = featureConfiguration;
            this.actionName = actionName;
            this.variables = variables;
            this.doNotSplitLinkingCmdLine = doNotSplitLinkingCmdLine;
        }

        @Override
        public Iterable<String> arguments() throws CommandLineExpansionException {
            List<String> argv = getRawLinkArgv(null, forcedToolPath, featureConfiguration, actionName, linkTargetType, variables);
            return splitCommandline(paramsFile, argv, linkTargetType, doNotSplitLinkingCmdLine).getSecond();
        }

        @Override
        public Iterable<String> arguments(ArtifactExpander expander) throws CommandLineExpansionException {
            List<String> argv = getRawLinkArgv(expander, forcedToolPath, featureConfiguration, actionName, linkTargetType, variables);
            return splitCommandline(paramsFile, argv, linkTargetType, doNotSplitLinkingCmdLine).getSecond();
        }
    }

    /**
     * Returns just the .params file portion of the command-line as a {@link CommandLine}.
     */
    CommandLine paramCmdLine() {
        Preconditions.checkNotNull(paramFile);
        return new ParamFileCommandLine(paramFile, linkTargetType, forcedToolPath, featureConfiguration, actionName, variables, doNotSplitLinkingCmdLine);
    }

    public static void extractArgumentsForStaticLinkParamFile(List<String> args, List<String> commandlineArgs, List<String> paramFileArgs) {
        // ar command, must not be moved!
        commandlineArgs.add(args.get(0));
        int argsSize = args.size();
        for (int i = 1; i < argsSize; i++) {
            String arg = args.get(i);
            if (arg.startsWith("@")) {
                // params file, keep it in the command line
                commandlineArgs.add(arg);
            } else {
                // the rest goes to the params file
                paramFileArgs.add(arg);
            }
        }
    }

    public static void extractArgumentsForDynamicLinkParamFile(List<String> args, List<String> commandlineArgs, List<String> paramFileArgs, boolean doNotSplitLinkingCmdline) {
        // Note, that it is not important that all linker arguments are extracted so that
        // they can be moved into a parameter file, but the vast majority should.
        // gcc command, must not be moved!
        commandlineArgs.add(args.get(0));
        int argsSize = args.size();
        if (doNotSplitLinkingCmdline) {
            for (int i = 1; i < argsSize; i++) {
                String arg = args.get(i);
                if (arg.startsWith("@")) {
                    // params file, keep it in the command line
                    commandlineArgs.add(arg);
                } else {
                    // the rest goes to the params file
                    paramFileArgs.add(arg);
                }
            }
        } else {
            for (int i = 1; i < argsSize; i++) {
                String arg = args.get(i);
                if (arg.isEmpty()) {
                    continue;
                }
                if (arg.equals("-Wl,-no-whole-archive")) {
                    paramFileArgs.add("-no-whole-archive");
                } else if (arg.equals("-Wl,-whole-archive")) {
                    paramFileArgs.add("-whole-archive");
                } else if (arg.equals("-Wl,--start-group")) {
                    paramFileArgs.add("--start-group");
                } else if (arg.equals("-Wl,--end-group")) {
                    paramFileArgs.add("--end-group");
                } else if (arg.equals("-Wl,--start-lib")) {
                    paramFileArgs.add("--start-lib");
                } else if (arg.equals("-Wl,--end-lib")) {
                    paramFileArgs.add("--end-lib");
                } else if (arg.charAt(0) == '-') {
                    if (arg.startsWith("-l")) {
                        paramFileArgs.add(arg);
                    } else {
                        // Anything else starting with a '-' can stay on the commandline.
                        commandlineArgs.add(arg);
                        if (arg.equals("-o")) {
                            // Special case for '-o': add the following argument as well - it is the output file!
                            commandlineArgs.add(args.get(++i));
                        }
                    }
                } else if (CppFileTypes.OBJECT_FILE.apply(arg) || CppFileTypes.PIC_OBJECT_FILE.apply(arg) || CppFileTypes.ARCHIVE.apply(arg) || CppFileTypes.PIC_ARCHIVE.apply(arg) || CppFileTypes.ALWAYS_LINK_LIBRARY.apply(arg) || CppFileTypes.ALWAYS_LINK_PIC_LIBRARY.apply(arg) || CppFileTypes.SHARED_LIBRARY.apply(arg) || CppFileTypes.INTERFACE_SHARED_LIBRARY.apply(arg) || CppFileTypes.VERSIONED_SHARED_LIBRARY.apply(arg)) {
                    // All objects of any kind go into the linker parameters.
                    paramFileArgs.add(arg);
                } else {
                    // Everything that's left stays conservatively on the commandline.
                    commandlineArgs.add(arg);
                }
            }
        }
    }

    /**
     * Returns a raw link command for the given link invocation, including both command and arguments
     * (argv). The version that uses the expander is preferred, but that one can't be used during
     * replacedysis.
     *
     * @return raw link command line.
     */
    public List<String> getRawLinkArgv() throws CommandLineExpansionException {
        return getRawLinkArgv(null);
    }

    /**
     * Returns a raw link command for the given link invocation, including both command and arguments
     * (argv).
     *
     * @param expander ArtifactExpander for expanding TreeArtifacts.
     * @return raw link command line.
     */
    public List<String> getRawLinkArgv(@Nullable ArtifactExpander expander) throws CommandLineExpansionException {
        return getRawLinkArgv(expander, forcedToolPath, featureConfiguration, actionName, linkTargetType, variables);
    }

    private static List<String> getRawLinkArgv(@Nullable ArtifactExpander expander, String forcedToolPath, FeatureConfiguration featureConfiguration, String actionName, LinkTargetType linkTargetType, CcToolchainVariables variables) throws CommandLineExpansionException {
        List<String> argv = new ArrayList<>();
        if (forcedToolPath != null) {
            argv.add(forcedToolPath);
        } else {
            Preconditions.checkArgument(featureConfiguration.actionIsConfigured(actionName), String.format("Expected action_config for '%s' to be configured", actionName));
            argv.add(featureConfiguration.getToolPathForAction(linkTargetType.getActionName()));
        }
        try {
            argv.addAll(featureConfiguration.getCommandLine(actionName, variables, expander));
        } catch (ExpansionException e) {
            throw new CommandLineExpansionException(e.getMessage());
        }
        return argv;
    }

    List<String> getCommandLine(@Nullable ArtifactExpander expander) throws CommandLineExpansionException {
        // Try to shorten the command line by use of a parameter file.
        // This makes the output with --subcommands (et al) more readable.
        if (paramFile != null) {
            Pair<List<String>, List<String>> split = splitCommandline(expander);
            return split.first;
        } else {
            return getRawLinkArgv(expander);
        }
    }

    @Override
    public List<String> arguments() throws CommandLineExpansionException {
        return getRawLinkArgv(null);
    }

    @Override
    public Iterable<String> arguments(ArtifactExpander artifactExpander) throws CommandLineExpansionException {
        return getRawLinkArgv(artifactExpander);
    }

    /**
     * A builder for a {@link LinkCommandLine}.
     */
    public static final clreplaced Builder {

        private String forcedToolPath;

        private ImmutableList<Artifact> buildInfoHeaderArtifacts = ImmutableList.of();

        private NestedSet<Artifact> linkerInputArtifacts = NestedSetBuilder.emptySet(Order.STABLE_ORDER);

        @Nullable
        private LinkTargetType linkTargetType;

        private Link.LinkingMode linkingMode = Link.LinkingMode.STATIC;

        @Nullable
        private PathFragment toolchainLibrariesSolibDir;

        private boolean nativeDeps;

        private boolean useTestOnlyFlags;

        @Nullable
        private Artifact paramFile;

        private CcToolchainVariables variables;

        private FeatureConfiguration featureConfiguration;

        private boolean doNotSplitLinkingCmdLine;

        private String actionName;

        public LinkCommandLine build() {
            if (linkTargetType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER) {
                Preconditions.checkArgument(buildInfoHeaderArtifacts.isEmpty(), "build info headers may only be present on dynamic library or executable links");
            }
            if (variables == null) {
                variables = CcToolchainVariables.EMPTY;
            }
            return new LinkCommandLine(actionName, forcedToolPath, buildInfoHeaderArtifacts, linkerInputArtifacts, linkTargetType, linkingMode, toolchainLibrariesSolibDir, nativeDeps, useTestOnlyFlags, paramFile, variables, featureConfiguration, doNotSplitLinkingCmdLine);
        }

        /**
         * Use given tool path instead of the one from feature configuration
         */
        public Builder forceToolPath(String forcedToolPath) {
            this.forcedToolPath = forcedToolPath;
            return this;
        }

        /**
         * Sets the feature configuration for this link action.
         */
        public Builder setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
            this.featureConfiguration = featureConfiguration;
            return this;
        }

        /**
         * Sets the type of the link. It is an error to try to set this to {@link
         * LinkTargetType#INTERFACE_DYNAMIC_LIBRARY}. Note that all the static target types (see {@link
         * LinkTargetType#linkerOrArchiver}) are equivalent, and there is no check that the output
         * artifact matches the target type extension.
         */
        public Builder setLinkTargetType(LinkTargetType linkTargetType) {
            Preconditions.checkArgument(linkTargetType != LinkTargetType.INTERFACE_DYNAMIC_LIBRARY);
            this.linkTargetType = linkTargetType;
            return this;
        }

        /**
         * Sets a list of linker input artifacts. These get turned into linker options depending on the
         * staticness and the target type. This call makes an immutable copy of the inputs, if the
         * provided Iterable isn't already immutable (see {@link CollectionUtils#makeImmutable}).
         */
        public Builder setLinkerInputArtifacts(NestedSet<Artifact> linkerInputArtifacts) {
            this.linkerInputArtifacts = linkerInputArtifacts;
            return this;
        }

        /**
         * Sets how static the link is supposed to be. For static target types (see {@link
         * LinkTargetType#linkerOrArchiver()}}), the {@link #build} method throws an exception if this
         * is not {@link LinkingMode#STATIC}. The default setting is {@link LinkingMode#STATIC}.
         */
        public Builder setLinkingMode(Link.LinkingMode linkingMode) {
            this.linkingMode = linkingMode;
            return this;
        }

        /**
         * The build info header artifacts are generated header files that are used for link stamping.
         * The {@link #build} method throws an exception if the build info header artifacts are
         * non-empty for a static link (see {@link LinkTargetType#linkerOrArchiver()}}).
         */
        public Builder setBuildInfoHeaderArtifacts(ImmutableList<Artifact> buildInfoHeaderArtifacts) {
            this.buildInfoHeaderArtifacts = buildInfoHeaderArtifacts;
            return this;
        }

        /**
         * Whether the resulting library is intended to be used as a native library from another
         * programming language. This influences the rpath. The {@link #build} method throws an
         * exception if this is true for a static link (see {@link LinkTargetType#linkerOrArchiver()}}).
         */
        public Builder setNativeDeps(boolean nativeDeps) {
            this.nativeDeps = nativeDeps;
            return this;
        }

        /**
         * Sets whether to use test-specific linker flags, e.g. {@code $EXEC_ORIGIN} instead of {@code
         * $ORIGIN} in the rpath or lazy binding.
         */
        public Builder setUseTestOnlyFlags(boolean useTestOnlyFlags) {
            this.useTestOnlyFlags = useTestOnlyFlags;
            return this;
        }

        public Builder setParamFile(Artifact paramFile) {
            this.paramFile = paramFile;
            return this;
        }

        public Builder setBuildVariables(CcToolchainVariables variables) {
            this.variables = variables;
            return this;
        }

        public Builder setToolchainLibrariesSolibDir(PathFragment toolchainLibrariesSolibDir) {
            this.toolchainLibrariesSolibDir = toolchainLibrariesSolibDir;
            return this;
        }

        public Builder doNotSplitLinkingCmdLine() {
            this.doNotSplitLinkingCmdLine = true;
            return this;
        }

        public Builder setActionName(String actionName) {
            this.actionName = actionName;
            return this;
        }
    }
}

13 View Complete Implementation : CcCommon.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Returns artifacts that help debug the state of C++ features for the given ruleContext.
 */
public static Map<String, NestedSet<Artifact>> createSaveFeatureStateArtifacts(CppConfiguration cppConfiguration, FeatureConfiguration featureConfiguration, RuleContext ruleContext) {
    ImmutableMap.Builder<String, NestedSet<Artifact>> outputGroupsBuilder = ImmutableMap.builder();
    if (cppConfiguration.saveFeatureState()) {
        Artifact enabledFeaturesFile = ruleContext.getUniqueDirectoryArtifact("feature_debug", "enabled_features.txt");
        ruleContext.registerAction(FileWriteAction.create(ruleContext, enabledFeaturesFile, featureConfiguration.getEnabledFeatureNames().toString(), /* makeExecutable= */
        false));
        Artifact requestedFeaturesFile = ruleContext.getUniqueDirectoryArtifact("feature_debug", "requested_features.txt");
        ruleContext.registerAction(FileWriteAction.create(ruleContext, requestedFeaturesFile, featureConfiguration.getRequestedFeatures().toString(), /* makeExecutable= */
        false));
        outputGroupsBuilder.put(OutputGroupInfo.DEFAULT, NestedSetBuilder.<Artifact>stableOrder().add(enabledFeaturesFile).add(requestedFeaturesFile).build());
    }
    return outputGroupsBuilder.build();
}

13 View Complete Implementation : LinkCommandLine.java
Copyright Apache License 2.0
Author : bazelbuild
private static List<String> getRawLinkArgv(@Nullable ArtifactExpander expander, String forcedToolPath, FeatureConfiguration featureConfiguration, String actionName, LinkTargetType linkTargetType, CcToolchainVariables variables) throws CommandLineExpansionException {
    List<String> argv = new ArrayList<>();
    if (forcedToolPath != null) {
        argv.add(forcedToolPath);
    } else {
        Preconditions.checkArgument(featureConfiguration.actionIsConfigured(actionName), String.format("Expected action_config for '%s' to be configured", actionName));
        argv.add(featureConfiguration.getToolPathForAction(linkTargetType.getActionName()));
    }
    try {
        argv.addAll(featureConfiguration.getCommandLine(actionName, variables, expander));
    } catch (ExpansionException e) {
        throw new CommandLineExpansionException(e.getMessage());
    }
    return argv;
}

13 View Complete Implementation : CppLinkstampCompileHelperTest.java
Copyright Apache License 2.0
Author : bazelbuild
/**
 * Regression test for b/73447914: Linkstamps were not re-built when only volatile data changed,
 * i.e. when we modified cc_binary source, linkstamp was not recompiled so we got old timestamps.
 * The proper behavior is to recompile linkstamp whenever any input to cc_binary action changes.
 * And the current implementation solves this by adding all linking inputs as
 * inputsForInvalidation to linkstamp compile action.
 */
@Test
public void testLinkstampCompileDependsOnAllCcBinaryLinkingInputs() throws Exception {
    scratch.file("x/BUILD", "cc_binary(", "  name = 'foo',", "  deps = ['bar'],", "  srcs = [ 'main.cc' ],", ")", "cc_library(", "  name = 'bar',", "  srcs = [ 'bar.cc' ],", "  linkstamp = 'ls.cc',", ")");
    useConfiguration();
    ConfiguredTarget target = getConfiguredTarget("//x:foo");
    Artifact executable = getExecutable(target);
    CcToolchainProvider toolchain = CppHelper.getToolchainUsingDefaultCcToolchainAttribute(getRuleContext(target));
    CppConfiguration cppConfiguration = getRuleContext(target).getFragment(CppConfiguration.clreplaced);
    FeatureConfiguration featureConfiguration = CcCommon.configureFeaturesOrThrowEvalException(/* requestedFeatures= */
    ImmutableSet.of(), /* unsupportedFeatures= */
    ImmutableSet.of(), toolchain, cppConfiguration);
    boolean usePic = CppHelper.usePicForBinaries(toolchain, cppConfiguration, featureConfiguration);
    CppLinkAction generatingAction = (CppLinkAction) getGeneratingAction(executable);
    Artifact compiledLinkstamp = ActionsTestUtil.getFirstArtifactEndingWith(generatingAction.getInputs(), "ls.o");
    CppCompileAction linkstampCompileAction = (CppCompileAction) getGeneratingAction(compiledLinkstamp);
    Artifact mainObject = ActionsTestUtil.getFirstArtifactEndingWith(generatingAction.getInputs(), usePic ? "main.pic.o" : "main.o");
    Artifact bar = generatingAction.getInputs().toList().stream().filter(a -> a.getExecPath().getBaseName().contains("bar")).findFirst().get();
    ImmutableList<Artifact> linkstampInputs = linkstampCompileAction.getInputs().toList();
    replacedertThat(linkstampInputs).containsAtLeast(mainObject, bar);
}

11 View Complete Implementation : LtoBackendArtifacts.java
Copyright Apache License 2.0
Author : bazelbuild
private void scheduleLtoBackendAction(RuleErrorConsumer ruleErrorConsumer, BuildOptions buildOptions, CppConfiguration cppConfiguration, ActionConstructionContext actionConstructionContext, RepositoryName repositoryName, FeatureConfiguration featureConfiguration, CcToolchainProvider ccToolchain, FdoContext fdoContext, boolean usePic, boolean generateDwo, BuildConfiguration configuration, LinkArtifactFactory linkArtifactFactory, List<String> userCompileFlags, @Nullable BitcodeFiles bitcodeFiles) throws RuleErrorException {
    LtoBackendAction.Builder builder = new LtoBackendAction.Builder();
    builder.addInput(bitcodeFile);
    Preconditions.checkState((index == null) == (imports == null), "Either both or neither index and imports files should be null");
    if (imports != null) {
        builder.addImportsInfo(bitcodeFiles, imports);
        // Although the imports file is not used by the LTOBackendAction while the action is
        // executing, it is needed during the input discovery phase, and we must list it as an input
        // to the action in order for it to be preserved under --discard_orphaned_artifacts.
        builder.addInput(imports);
    }
    if (index != null) {
        builder.addInput(index);
    }
    builder.addTransitiveInputs(ccToolchain.getCompilerFiles());
    builder.addOutput(objectFile);
    builder.setProgressMessage("LTO Backend Compile %s", objectFile.getExecPath());
    builder.setMnemonic("CcLtoBackendCompile");
    CcToolchainVariables.Builder buildVariablesBuilder = CcToolchainVariables.builder(ccToolchain.getBuildVariables(buildOptions, cppConfiguration));
    if (index != null) {
        buildVariablesBuilder.addStringVariable("thinlto_index", index.getExecPath().toString());
    } else {
        // An empty input indicates not to perform cross-module optimization.
        buildVariablesBuilder.addStringVariable("thinlto_index", "/dev/null");
    }
    // The output from the LTO backend step is a native object file.
    buildVariablesBuilder.addStringVariable("thinlto_output_object_file", objectFile.getExecPath().toString());
    // The input to the LTO backend step is the bitcode file.
    buildVariablesBuilder.addStringVariable("thinlto_input_bitcode_file", bitcodeFile.getExecPath().toString());
    addProfileForLtoBackend(builder, fdoContext, featureConfiguration, buildVariablesBuilder);
    // Add the context sensitive instrument path to the backend.
    if (featureConfiguration.isEnabled(CppRuleClreplacedes.CS_FDO_INSTRUMENT)) {
        buildVariablesBuilder.addStringVariable(CompileBuildVariables.CS_FDO_INSTRUMENT_PATH.getVariableName(), ccToolchain.getCSFdoInstrument());
    }
    if (generateDwo) {
        dwoFile = linkArtifactFactory.create(actionConstructionContext, repositoryName, configuration, FileSystemUtils.replaceExtension(objectFile.getRootRelativePath(), ".dwo"));
        builder.addOutput(dwoFile);
        buildVariablesBuilder.addStringVariable(CompileBuildVariables.PER_OBJECT_DEBUG_INFO_FILE.getVariableName(), dwoFile.getExecPathString());
        buildVariablesBuilder.addStringVariable(CompileBuildVariables.IS_USING_FISSION.getVariableName(), "");
    }
    buildVariablesBuilder.addStringSequenceVariable(CompileBuildVariables.USER_COMPILE_FLAGS.getVariableName(), userCompileFlags);
    CcToolchainVariables buildVariables = buildVariablesBuilder.build();
    if (cppConfiguration.useStandaloneLtoIndexingCommandLines()) {
        if (!featureConfiguration.actionIsConfigured(CppActionNames.LTO_BACKEND)) {
            throw ruleErrorConsumer.throwWithRuleError("Thinlto build is requested, but the C++ toolchain doesn't define an action_config for" + " 'lto-backend' action.");
        }
        PathFragment compiler = PathFragment.create(featureConfiguration.getToolPathForAction(CppActionNames.LTO_BACKEND));
        builder.setExecutable(compiler);
    } else {
        PathFragment compiler = ccToolchain.getToolPathFragment(Tool.GCC, ruleErrorConsumer);
        builder.setExecutable(compiler);
    }
    CommandLine ltoCommandLine = new CommandLine() {

        @Override
        public Iterable<String> arguments() throws CommandLineExpansionException {
            return arguments(/* artifactExpander= */
            null);
        }

        @Override
        public Iterable<String> arguments(ArtifactExpander artifactExpander) throws CommandLineExpansionException {
            ImmutableList.Builder<String> args = ImmutableList.builder();
            try {
                args.addAll(featureConfiguration.getCommandLine(CppActionNames.LTO_BACKEND, buildVariables, artifactExpander));
            } catch (ExpansionException e) {
                throw new CommandLineExpansionException(e.getMessage());
            }
            // If this is a PIC compile (set based on the CppConfiguration), the PIC
            // option should be added after the rest of the command line so that it
            // cannot be overridden. This is consistent with the ordering in the
            // CppCompileAction's compiler options.
            if (usePic) {
                args.add("-fPIC");
            }
            return args.build();
        }
    };
    builder.addCommandLine(ltoCommandLine);
    actionConstructionContext.registerAction(builder.build(actionConstructionContext));
}