blob: b332a30615320a50a854d1ebff1db0595bb4ce52 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.rules.cpp;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.LicensesProvider;
import com.google.devtools.build.lib.analysis.PackageSpecificationProvider;
import com.google.devtools.build.lib.analysis.RuleErrorConsumer;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.Depset;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.cpp.CcToolchain.AdditionalBuildVariablesComputer;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcToolchainProviderApi;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Location;
import com.google.devtools.build.lib.syntax.Starlark;
import com.google.devtools.build.lib.vfs.PathFragment;
import javax.annotation.Nullable;
/** Information about a C++ compiler used by the <code>cc_*</code> rules. */
@Immutable
@AutoCodec
public final class CcToolchainProvider extends ToolchainInfo
implements CcToolchainProviderApi<FeatureConfigurationForStarlark>, HasCcToolchainLabel {
/** An empty toolchain to be returned in the error case (instead of null). */
public static final CcToolchainProvider EMPTY_TOOLCHAIN_IS_ERROR =
new CcToolchainProvider(
/* values= */ ImmutableMap.of(),
/* cppConfiguration= */ null,
/* toolchainFeatures= */ null,
/* crosstoolTopPathFragment= */ null,
/* allFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* allFilesMiddleman= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* compilerFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* compilerFilesWithoutIncludes= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* stripFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* objcopyFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* asFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* arFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* linkerFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* interfaceSoBuilder= */ null,
/* dwpFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* coverageFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* libcLink= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* targetLibcLink= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* staticRuntimeLinkInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* staticRuntimeLinkMiddleman= */ null,
/* dynamicRuntimeLinkInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/* dynamicRuntimeLinkMiddleman= */ null,
/* dynamicRuntimeSolibDir= */ PathFragment.EMPTY_FRAGMENT,
CcCompilationContext.EMPTY,
/* supportsParamFiles= */ false,
/* supportsHeaderParsing= */ false,
(buildOptions) -> CcToolchainVariables.EMPTY,
CcToolchainVariables.EMPTY,
/* builtinIncludeFiles= */ ImmutableList.of(),
/* targetBuiltinIncludeFiles= */ ImmutableList.of(),
/* linkDynamicLibraryTool= */ null,
/* builtInIncludeDirectories= */ ImmutableList.of(),
/* sysroot= */ null,
/* targetSysroot= */ null,
/* fdoContext= */ null,
/* isToolConfiguration= */ false,
/* licensesProvider= */ null,
/* toolPaths= */ ImmutableMap.of(),
/* toolchainIdentifier= */ "",
/* compiler= */ "",
/* abiGlibcVersion= */ "",
/* targetCpu= */ "",
/* targetOS= */ "",
/* defaultSysroot= */ PathFragment.EMPTY_FRAGMENT,
/* runtimeSysroot= */ PathFragment.EMPTY_FRAGMENT,
/* targetLibc= */ "",
/* hostSystemName= */ "",
/* ccToolchainLabel= */ null,
/* solibDirectory= */ "",
/* abi= */ "",
/* targetSystemName= */ "",
/* additionalMakeVariables= */ ImmutableMap.of(),
/* legacyCcFlagsMakeVariable= */ "",
/* allowlistForLayeringCheck= */ null,
/* allowListForLooseHeaderCheck= */ null);
@Nullable private final CppConfiguration cppConfiguration;
private final PathFragment crosstoolTopPathFragment;
private final NestedSet<Artifact> allFiles;
private final NestedSet<Artifact> allFilesMiddleman;
private final NestedSet<Artifact> compilerFiles;
private final NestedSet<Artifact> compilerFilesWithoutIncludes;
private final NestedSet<Artifact> stripFiles;
private final NestedSet<Artifact> objcopyFiles;
private final NestedSet<Artifact> asFiles;
private final NestedSet<Artifact> arFiles;
private final NestedSet<Artifact> linkerFiles;
private final Artifact interfaceSoBuilder;
private final NestedSet<Artifact> dwpFiles;
private final NestedSet<Artifact> coverageFiles;
private final NestedSet<Artifact> libcLink;
private final NestedSet<Artifact> targetLibcLink;
@Nullable private final NestedSet<Artifact> staticRuntimeLinkInputs;
@Nullable private final Artifact staticRuntimeLinkMiddleman;
@Nullable private final NestedSet<Artifact> dynamicRuntimeLinkInputs;
@Nullable private final Artifact dynamicRuntimeLinkMiddleman;
private final PathFragment dynamicRuntimeSolibDir;
private final CcInfo ccInfo;
private final boolean supportsParamFiles;
private final boolean supportsHeaderParsing;
private final AdditionalBuildVariablesComputer additionalBuildVariablesComputer;
private final CcToolchainVariables buildVariables;
private final ImmutableList<Artifact> builtinIncludeFiles;
private final ImmutableList<Artifact> targetBuiltinIncludeFiles;
@Nullable private final Artifact linkDynamicLibraryTool;
private final ImmutableList<PathFragment> builtInIncludeDirectories;
@Nullable private final PathFragment sysroot;
private final PathFragment targetSysroot;
private final boolean isToolConfiguration;
private final ImmutableMap<String, PathFragment> toolPaths;
private final CcToolchainFeatures toolchainFeatures;
private final String toolchainIdentifier;
private final String compiler;
private final String targetCpu;
private final String targetOS;
private final PathFragment defaultSysroot;
private final PathFragment runtimeSysroot;
private final String abiGlibcVersion;
private final String abi;
private final String targetLibc;
private final String hostSystemName;
private final String targetSystemName;
private final Label ccToolchainLabel;
private final String solibDirectory;
private final ImmutableMap<String, String> additionalMakeVariables;
// TODO(b/65151735): Remove when cc_flags is entirely from features.
private final String legacyCcFlagsMakeVariable;
/**
* WARNING: We don't like {@link FdoContext}. Its {@link FdoContext#fdoProfilePath} is pure path
* and that is horrible as it breaks many Bazel assumptions! Don't do bad stuff with it, don't
* take inspiration from it.
*/
private final FdoContext fdoContext;
private final LicensesProvider licensesProvider;
private final PackageSpecificationProvider allowlistForLayeringCheck;
private final PackageSpecificationProvider allowListForLooseHeaderCheck;
public CcToolchainProvider(
ImmutableMap<String, Object> values,
@Nullable CppConfiguration cppConfiguration,
CcToolchainFeatures toolchainFeatures,
PathFragment crosstoolTopPathFragment,
NestedSet<Artifact> allFiles,
NestedSet<Artifact> allFilesMiddleman,
NestedSet<Artifact> compilerFiles,
NestedSet<Artifact> compilerFilesWithoutIncludes,
NestedSet<Artifact> stripFiles,
NestedSet<Artifact> objcopyFiles,
NestedSet<Artifact> asFiles,
NestedSet<Artifact> arFiles,
NestedSet<Artifact> linkerFiles,
Artifact interfaceSoBuilder,
NestedSet<Artifact> dwpFiles,
NestedSet<Artifact> coverageFiles,
NestedSet<Artifact> libcLink,
NestedSet<Artifact> targetLibcLink,
NestedSet<Artifact> staticRuntimeLinkInputs,
@Nullable Artifact staticRuntimeLinkMiddleman,
NestedSet<Artifact> dynamicRuntimeLinkInputs,
@Nullable Artifact dynamicRuntimeLinkMiddleman,
PathFragment dynamicRuntimeSolibDir,
CcCompilationContext ccCompilationContext,
boolean supportsParamFiles,
boolean supportsHeaderParsing,
AdditionalBuildVariablesComputer additionalBuildVariablesComputer,
CcToolchainVariables buildVariables,
ImmutableList<Artifact> builtinIncludeFiles,
ImmutableList<Artifact> targetBuiltinIncludeFiles,
Artifact linkDynamicLibraryTool,
ImmutableList<PathFragment> builtInIncludeDirectories,
@Nullable PathFragment sysroot,
@Nullable PathFragment targetSysroot,
FdoContext fdoContext,
boolean isToolConfiguration,
LicensesProvider licensesProvider,
ImmutableMap<String, PathFragment> toolPaths,
String toolchainIdentifier,
String compiler,
String abiGlibcVersion,
String targetCpu,
String targetOS,
PathFragment defaultSysroot,
PathFragment runtimeSysroot,
String targetLibc,
String hostSystemName,
Label ccToolchainLabel,
String solibDirectory,
String abi,
String targetSystemName,
ImmutableMap<String, String> additionalMakeVariables,
String legacyCcFlagsMakeVariable,
PackageSpecificationProvider allowlistForLayeringCheck,
PackageSpecificationProvider allowListForLooseHeaderCheck) {
super(values, Location.BUILTIN);
this.cppConfiguration = cppConfiguration;
this.crosstoolTopPathFragment = crosstoolTopPathFragment;
this.allFiles = Preconditions.checkNotNull(allFiles);
this.allFilesMiddleman = Preconditions.checkNotNull(allFilesMiddleman);
this.compilerFiles = Preconditions.checkNotNull(compilerFiles);
this.compilerFilesWithoutIncludes = Preconditions.checkNotNull(compilerFilesWithoutIncludes);
this.stripFiles = Preconditions.checkNotNull(stripFiles);
this.objcopyFiles = Preconditions.checkNotNull(objcopyFiles);
this.asFiles = Preconditions.checkNotNull(asFiles);
this.arFiles = Preconditions.checkNotNull(arFiles);
this.linkerFiles = Preconditions.checkNotNull(linkerFiles);
this.interfaceSoBuilder = interfaceSoBuilder;
this.dwpFiles = Preconditions.checkNotNull(dwpFiles);
this.coverageFiles = Preconditions.checkNotNull(coverageFiles);
this.libcLink = Preconditions.checkNotNull(libcLink);
this.targetLibcLink = Preconditions.checkNotNull(targetLibcLink);
this.staticRuntimeLinkInputs = staticRuntimeLinkInputs;
this.staticRuntimeLinkMiddleman = staticRuntimeLinkMiddleman;
this.dynamicRuntimeLinkInputs = dynamicRuntimeLinkInputs;
this.dynamicRuntimeLinkMiddleman = dynamicRuntimeLinkMiddleman;
this.dynamicRuntimeSolibDir = Preconditions.checkNotNull(dynamicRuntimeSolibDir);
this.ccInfo =
CcInfo.builder()
.setCcCompilationContext(Preconditions.checkNotNull(ccCompilationContext))
.build();
this.supportsParamFiles = supportsParamFiles;
this.supportsHeaderParsing = supportsHeaderParsing;
this.additionalBuildVariablesComputer = additionalBuildVariablesComputer;
this.buildVariables = buildVariables;
this.builtinIncludeFiles = builtinIncludeFiles;
this.targetBuiltinIncludeFiles = targetBuiltinIncludeFiles;
this.linkDynamicLibraryTool = linkDynamicLibraryTool;
this.builtInIncludeDirectories = builtInIncludeDirectories;
this.sysroot = sysroot;
this.targetSysroot = targetSysroot;
this.defaultSysroot = defaultSysroot;
this.runtimeSysroot = runtimeSysroot;
this.fdoContext = fdoContext == null ? FdoContext.getDisabledContext() : fdoContext;
this.isToolConfiguration = isToolConfiguration;
this.licensesProvider = licensesProvider;
this.toolPaths = toolPaths;
this.toolchainFeatures = toolchainFeatures;
this.toolchainIdentifier = toolchainIdentifier;
this.compiler = compiler;
this.abiGlibcVersion = abiGlibcVersion;
this.targetCpu = targetCpu;
this.targetOS = targetOS;
this.targetLibc = targetLibc;
this.hostSystemName = hostSystemName;
this.ccToolchainLabel = ccToolchainLabel;
this.solibDirectory = solibDirectory;
this.abi = abi;
this.targetSystemName = targetSystemName;
this.additionalMakeVariables = additionalMakeVariables;
this.legacyCcFlagsMakeVariable = legacyCcFlagsMakeVariable;
this.allowlistForLayeringCheck = allowlistForLayeringCheck;
this.allowListForLooseHeaderCheck = allowListForLooseHeaderCheck;
}
/**
* See {@link #usePicForDynamicLibraries(FeatureConfigurationForStarlark)}. This method is there
* only to serve Starlark callers.
*/
@Override
public boolean usePicForDynamicLibrariesFromStarlark(
FeatureConfigurationForStarlark featureConfiguration) {
return usePicForDynamicLibraries(
featureConfiguration
.getCppConfigurationFromFeatureConfigurationCreatedForStarlark_andIKnowWhatImDoing(),
featureConfiguration.getFeatureConfiguration());
}
/**
* 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(CppRuleClasses.SUPPORTS_PIC);
}
/**
* 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(CppRuleClasses.PER_OBJECT_DEBUG_INFO);
}
/** Whether the toolchains supports header parsing. */
public boolean supportsHeaderParsing() {
return supportsHeaderParsing;
}
/**
* 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(CppRuleClasses.PARSE_HEADERS);
}
@Override
public void addGlobalMakeVariables(ImmutableMap.Builder<String, String> globalMakeEnvBuilder) {
ImmutableMap.Builder<String, String> result = ImmutableMap.builder();
// hardcoded CC->gcc setting for unit tests
result.put("CC", getToolPathStringOrNull(Tool.GCC));
// Make variables provided by crosstool/gcc compiler suite.
result.put("AR", getToolPathStringOrNull(Tool.AR));
result.put("NM", getToolPathStringOrNull(Tool.NM));
result.put("LD", getToolPathStringOrNull(Tool.LD));
String objcopyTool = getToolPathStringOrNull(Tool.OBJCOPY);
if (objcopyTool != null) {
// objcopy is optional in Crosstool
result.put("OBJCOPY", objcopyTool);
}
result.put("STRIP", getToolPathStringOrNull(Tool.STRIP));
String gcovtool = getToolPathStringOrNull(Tool.GCOVTOOL);
if (gcovtool != null) {
// gcov-tool is optional in Crosstool
result.put("GCOVTOOL", gcovtool);
}
if (getTargetLibc().startsWith("glibc-")) {
result.put("GLIBC_VERSION", getTargetLibc().substring("glibc-".length()));
} else {
result.put("GLIBC_VERSION", getTargetLibc());
}
result.put("C_COMPILER", getCompiler());
// Deprecated variables
// TODO(bazel-team): delete all of these.
result.put("CROSSTOOLTOP", crosstoolTopPathFragment.getPathString());
// TODO(kmensah): Remove when Starlark dependencies can be updated to rely on
// CcToolchainProvider.
result.putAll(getAdditionalMakeVariables());
result.put("ABI_GLIBC_VERSION", getAbiGlibcVersion());
result.put("ABI", getAbi());
globalMakeEnvBuilder.putAll(result.build());
}
/**
* Returns the path fragment that is either absolute or relative to the execution root that can be
* used to execute the given tool.
*
* @throws RuleErrorException when the tool is not specified by the toolchain.
*/
public PathFragment getToolPathFragment(
CppConfiguration.Tool tool, RuleErrorConsumer ruleErrorConsumer) throws RuleErrorException {
PathFragment toolPathFragment = getToolPathFragmentOrNull(tool);
if (toolPathFragment == null) {
throw ruleErrorConsumer.throwWithRuleError(
String.format(
"cc_toolchain '%s' with identifier '%s' doesn't define a tool path for '%s'",
getCcToolchainLabel(), getToolchainIdentifier(), tool.getNamePart()));
}
return toolPathFragment;
}
/**
* Returns the path fragment that is either absolute or relative to the execution root that can be
* used to execute the given tool.
*/
@Nullable
public String getToolPathStringOrNull(Tool tool) {
PathFragment toolPathFragment = getToolPathFragmentOrNull(tool);
return toolPathFragment == null ? null : toolPathFragment.getPathString();
}
/**
* Returns the path fragment that is either absolute or relative to the execution root that can be
* used to execute the given tool.
*/
@Nullable
public PathFragment getToolPathFragmentOrNull(CppConfiguration.Tool tool) {
return CcToolchainProviderHelper.getToolPathFragment(toolPaths, tool);
}
@Override
public ImmutableList<String> getBuiltInIncludeDirectoriesAsStrings() {
return builtInIncludeDirectories
.stream()
.map(PathFragment::getSafePathString)
.collect(ImmutableList.toImmutableList());
}
@Override
public Depset getAllFilesForStarlark() {
return Depset.of(Artifact.TYPE, getAllFiles());
}
@Override
public Depset getStaticRuntimeLibForStarlark(
FeatureConfigurationForStarlark featureConfigurationForStarlark) throws EvalException {
return Depset.of(
Artifact.TYPE,
getStaticRuntimeLinkInputs(featureConfigurationForStarlark.getFeatureConfiguration()));
}
@Override
public Depset getDynamicRuntimeLibForStarlark(
FeatureConfigurationForStarlark featureConfigurationForStarlark) throws EvalException {
return Depset.of(
Artifact.TYPE,
getDynamicRuntimeLinkInputs(featureConfigurationForStarlark.getFeatureConfiguration()));
}
public ImmutableList<PathFragment> getBuiltInIncludeDirectories() {
return builtInIncludeDirectories;
}
/** Returns the identifier of the toolchain as specified in the {@code CToolchain} proto. */
public String getToolchainIdentifier() {
return toolchainIdentifier;
}
/** Returns all the files in Crosstool. Is not a middleman. */
public NestedSet<Artifact> getAllFiles() {
return allFiles;
}
/** Returns a middleman for all the files in Crosstool. */
public NestedSet<Artifact> getAllFilesMiddleman() {
return allFilesMiddleman;
}
/** Returns the files necessary for compilation. */
public NestedSet<Artifact> getCompilerFiles() {
return compilerFiles;
}
/**
* Returns the files necessary for compilation excluding headers, assuming that included files
* will be discovered by input discovery. If the toolchain does not provide this fileset, falls
* back to {@link #getCompilerFiles()}.
*/
public NestedSet<Artifact> getCompilerFilesWithoutIncludes() {
if (compilerFilesWithoutIncludes.isEmpty()) {
return getCompilerFiles();
}
return compilerFilesWithoutIncludes;
}
/** Returns the files necessary for a 'strip' invocation. */
public NestedSet<Artifact> getStripFiles() {
return stripFiles;
}
/** Returns the files necessary for an 'objcopy' invocation. */
public NestedSet<Artifact> getObjcopyFiles() {
return objcopyFiles;
}
/**
* Returns the files necessary for an 'as' invocation. May be empty if the CROSSTOOL file does not
* define as_files.
*/
public NestedSet<Artifact> getAsFiles() {
return asFiles;
}
/**
* Returns the files necessary for an 'ar' invocation. May be empty if the CROSSTOOL file does not
* define ar_files.
*/
public NestedSet<Artifact> getArFiles() {
return arFiles;
}
/** Returns the files necessary for linking, including the files needed for libc. */
public NestedSet<Artifact> getLinkerFiles() {
return linkerFiles;
}
public NestedSet<Artifact> getDwpFiles() {
return dwpFiles;
}
/** Returns the files necessary for capturing code coverage. */
public NestedSet<Artifact> getCoverageFiles() {
return coverageFiles;
}
public NestedSet<Artifact> getLibcLink(CppConfiguration cppConfiguration) {
if (cppConfiguration.equals(getCppConfigurationEvenThoughItCanBeDifferentThanWhatTargetHas())) {
return libcLink;
} else {
return targetLibcLink;
}
}
/**
* Returns true if the featureConfiguration includes statically linking the cpp runtimes.
*
* @param featureConfiguration the relevant FeatureConfiguration.
*/
public boolean shouldStaticallyLinkCppRuntimes(FeatureConfiguration featureConfiguration) {
return featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES);
}
/** Returns the static runtime libraries. */
public NestedSet<Artifact> getStaticRuntimeLinkInputs(FeatureConfiguration featureConfiguration)
throws EvalException {
if (shouldStaticallyLinkCppRuntimes(featureConfiguration)) {
if (staticRuntimeLinkInputs == null) {
throw Starlark.errorf(
"Toolchain supports embedded runtimes, but didn't provide static_runtime_lib"
+ " attribute.");
}
return staticRuntimeLinkInputs;
} else {
return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
}
}
/** 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;
}
}
/** Returns the dynamic runtime libraries. */
public NestedSet<Artifact> getDynamicRuntimeLinkInputs(FeatureConfiguration featureConfiguration)
throws EvalException {
if (shouldStaticallyLinkCppRuntimes(featureConfiguration)) {
if (dynamicRuntimeLinkInputs == null) {
throw new EvalException(
"Toolchain supports embedded runtimes, but didn't provide dynamic_runtime_lib"
+ " attribute.");
}
return dynamicRuntimeLinkInputs;
} else {
return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
}
}
/** 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;
}
}
/**
* Returns the name of the directory where the solib symlinks for the dynamic runtime libraries
* live. The directory itself will be under the root of the host configuration in the 'bin'
* directory.
*/
public PathFragment getDynamicRuntimeSolibDir() {
return dynamicRuntimeSolibDir;
}
/** Returns the {@code CcCompilationContext} for the toolchain. */
public CcCompilationContext getCcCompilationContext() {
return ccInfo.getCcCompilationContext();
}
/** Returns the {@code CcInfo} for the toolchain. */
public CcInfo getCcInfo() {
return ccInfo;
}
/**
* Whether the toolchains supports parameter files.
*/
public boolean supportsParamFiles() {
return supportsParamFiles;
}
/**
* Returns the configured features of the toolchain.
*/
@Nullable
public CcToolchainFeatures getFeatures() {
return toolchainFeatures;
}
@Override
public Label getCcToolchainLabel() {
return ccToolchainLabel;
}
/**
* Returns the run time sysroot, which is where the dynamic linker and system libraries are found
* at runtime. This is usually an absolute path. If the toolchain compiler does not support
* sysroots, then this method returns <code>null</code>.
*/
public PathFragment getRuntimeSysroot() {
return runtimeSysroot;
}
/**
* Return the name of the directory (relative to the bin directory) that holds mangled links to
* shared libraries. This name is always set to the '{@code _solib_<cpu_archictecture_name>}.
*/
public String getSolibDirectory() {
return solibDirectory;
}
/** Returns whether the toolchain supports dynamic linking. */
public boolean supportsDynamicLinker(FeatureConfiguration featureConfiguration) {
return featureConfiguration.isEnabled(CppRuleClasses.SUPPORTS_DYNAMIC_LINKER);
}
public boolean doNotSplitLinkingCmdline() {
return getFeatures()
.getActivatableNames()
.contains(CppRuleClasses.DO_NOT_SPLIT_LINKING_CMDLINE);
}
/** Returns whether the toolchain supports the --start-lib/--end-lib options. */
public boolean supportsStartEndLib(FeatureConfiguration featureConfiguration) {
return featureConfiguration.isEnabled(CppRuleClasses.SUPPORTS_START_END_LIB);
}
/** Returns whether this toolchain supports interface shared libraries. */
public boolean supportsInterfaceSharedLibraries(FeatureConfiguration featureConfiguration) {
return featureConfiguration.isEnabled(CppRuleClasses.SUPPORTS_INTERFACE_SHARED_LIBRARIES);
}
/**
* Return CppConfiguration instance that was used to configure CcToolchain.
*
* <p>If C++ rules use platforms/toolchains without
* https://github.com/bazelbuild/proposals/blob/master/designs/2019-02-12-toolchain-transitions.md
* implemented, CcToolchain is analyzed in the host configuration. This configuration is not what
* should be used by rules using the toolchain. This method should only be used to access stuff
* from CppConfiguration that is identical between host and target (e.g. incompatible flag
* values). Don't use it if you don't know what you're doing.
*
* <p>Once toolchain transitions are implemented, we can safely use the CppConfiguration from the
* toolchain in rules.
*/
CppConfiguration getCppConfigurationEvenThoughItCanBeDifferentThanWhatTargetHas() {
return cppConfiguration;
}
/** Return context-sensitive fdo instrumentation path. */
public String getCSFdoInstrument() {
return cppConfiguration.getCSFdoInstrument();
}
/** Returns build variables to be templated into the crosstool. */
public CcToolchainVariables getBuildVariables(
BuildOptions buildOptions, CppConfiguration cppConfiguration) {
if (cppConfiguration.enableCcToolchainResolution()) {
// With platforms, cc toolchain is analyzed in the host configuration, so we cannot reuse
// build variables instance.
return CcToolchainProviderHelper.getBuildVariables(
buildOptions,
cppConfiguration,
getSysrootPathFragment(cppConfiguration),
additionalBuildVariablesComputer);
}
return buildVariables;
}
/**
* Return the set of include files that may be included even if they are not mentioned in the
* source file or any of the headers included by it.
*
* @param cppConfiguration
*/
public ImmutableList<Artifact> getBuiltinIncludeFiles(CppConfiguration cppConfiguration) {
if (cppConfiguration.equals(getCppConfigurationEvenThoughItCanBeDifferentThanWhatTargetHas())) {
return builtinIncludeFiles;
} else {
return targetBuiltinIncludeFiles;
}
}
/**
* Returns the tool which should be used for linking dynamic libraries, or in case it's not
* specified by the crosstool this will be @tools_repository/tools/cpp:link_dynamic_library
*/
public Artifact getLinkDynamicLibraryTool() {
return linkDynamicLibraryTool;
}
/**
* Returns the tool that builds interface libraries from dynamic libraries.
*/
public Artifact getInterfaceSoBuilder() {
return interfaceSoBuilder;
}
@Override
@Nullable
public String getSysroot() {
return sysroot != null ? sysroot.getPathString() : null;
}
public PathFragment getSysrootPathFragment(CppConfiguration cppConfiguration) {
if (cppConfiguration.equals(getCppConfigurationEvenThoughItCanBeDifferentThanWhatTargetHas())) {
return sysroot;
} else {
return targetSysroot;
}
}
/**
* Returns the abi we're using, which is a gcc version. E.g.: "gcc-3.4". Note that in practice we
* might be using gcc-3.4 as ABI even when compiling with gcc-4.1.0, because ABIs are backwards
* compatible.
*/
// TODO(bazel-team): The javadoc should clarify how this is used in Blaze.
public String getAbi() {
return abi;
}
/**
* Returns the glibc version used by the abi we're using. This is a glibc version number (e.g.,
* "2.2.2"). Note that in practice we might be using glibc 2.2.2 as ABI even when compiling with
* gcc-4.2.2, gcc-4.3.1, or gcc-4.4.0 (which use glibc 2.3.6), because ABIs are backwards
* compatible.
*/
// TODO(bazel-team): The javadoc should clarify how this is used in Blaze.
public String getAbiGlibcVersion() {
return abiGlibcVersion;
}
/** Returns the compiler version string (e.g. "gcc-4.1.1"). */
@Override
public String getCompiler() {
return compiler;
}
/** Returns the libc version string (e.g. "glibc-2.2.2"). */
@Override
public String getTargetLibc() {
return targetLibc;
}
/** Returns the target architecture using blaze-specific constants (e.g. "piii"). */
@Override
public String getTargetCpu() {
return targetCpu;
}
/**
* Returns a map of additional make variables for use by {@link BuildConfiguration}. These are to
* used to allow some build rules to avoid the limits on stack frame sizes and variable-length
* arrays.
*
* <p>The returned map must contain an entry for {@code STACK_FRAME_UNLIMITED}, though the entry
* may be an empty string.
*/
public ImmutableMap<String, String> getAdditionalMakeVariables() {
return additionalMakeVariables;
}
/**
* Returns the legacy value of the CC_FLAGS Make variable.
*
* @deprecated Use the CC_FLAGS from feature configuration instead.
*/
// TODO(b/65151735): Remove when cc_flags is entirely from features.
@Deprecated
public String getLegacyCcFlagsMakeVariable() {
return legacyCcFlagsMakeVariable;
}
public FdoContext getFdoContext() {
return fdoContext;
}
/**
* Unused, for compatibility with things internal to Google.
*
* <p>Deprecated: Use platforms.
*/
@Deprecated
public String getTargetOS() {
return targetOS;
}
/** Returns the system name which is required by the toolchain to run. */
public String getHostSystemName() {
return hostSystemName;
}
/** Returns the GNU System Name */
@Override
public String getTargetGnuSystemName() {
return targetSystemName;
}
/** Returns the architecture component of the GNU System Name */
public String getGnuSystemArch() {
if (targetSystemName.indexOf('-') == -1) {
return targetSystemName;
}
return targetSystemName.substring(0, targetSystemName.indexOf('-'));
}
public final boolean isLLVMCompiler() {
// TODO(tmsriram): Checking for "llvm" does not handle all the cases. This
// is temporary until the crosstool configuration is modified to add fields that
// indicate which flavor of fdo is being used.
return toolchainIdentifier.contains("llvm");
}
// Not all of CcToolchainProvider is exposed to Starlark, which makes implementing deep equality
// impossible: if Java-only parts are considered, the behavior is surprising in Starlark, if they
// are not, the behavior is surprising in Java. Thus, object identity it is.
@Override
public boolean equals(Object other) {
return other == this;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
public boolean isToolConfiguration() {
return isToolConfiguration;
}
public LicensesProvider getLicensesProvider() {
return licensesProvider;
}
public PathFragment getDefaultSysroot() {
return defaultSysroot;
}
public boolean requireCtxInConfigureFeatures() {
return getCppConfigurationEvenThoughItCanBeDifferentThanWhatTargetHas()
.requireCtxInConfigureFeatures();
}
@VisibleForTesting
NestedSet<Artifact> getStaticRuntimeLibForTesting() {
return staticRuntimeLinkInputs;
}
@VisibleForTesting
NestedSet<Artifact> getDynamicRuntimeLibForTesting() {
return dynamicRuntimeLinkInputs;
}
public PackageSpecificationProvider getAllowlistForLayeringCheck() {
return allowlistForLayeringCheck;
}
public PackageSpecificationProvider getAllowlistForLooseHeaderCheck() {
return allowListForLooseHeaderCheck;
}
}