blob: 7bb15231f8084046e3eb258926eae6d9f8cf87b2 [file] [log] [blame]
// Copyright 2017 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.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.CompilationMode;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.rules.cpp.CppActionConfigs.CppPlatform;
import com.google.devtools.build.lib.rules.cpp.Link.LinkingMode;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain.ArtifactNamePattern;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Information describing the C++ compiler derived from the CToolchain proto.
*
* <p>This wrapper class is used to re-plumb information so that it's eventually accessed through
* {@link CcToolchainProvider} instead of {@link CppConfiguration}.
*/
@AutoCodec
@Immutable
public final class CppToolchainInfo {
private final String toolchainIdentifier;
private final CcToolchainFeatures toolchainFeatures;
private final ImmutableMap<String, PathFragment> toolPaths;
private final String compiler;
private final String abiGlibcVersion;
private final String targetCpu;
private final String targetOS;
private final ImmutableList<String> rawBuiltInIncludeDirectories;
private final PathFragment defaultSysroot;
private final PathFragment runtimeSysroot;
private final String targetLibc;
private final String hostSystemName;
private final ImmutableList<String> dynamicLibraryLinkFlags;
private final ImmutableList<String> legacyLinkOptions;
private final ImmutableListMultimap<LinkingMode, String> legacyLinkOptionsFromLinkingMode;
private final ImmutableListMultimap<CompilationMode, String> legacyLinkOptionsFromCompilationMode;
private final ImmutableList<String> testOnlyLinkFlags;
private final ImmutableList<String> ldOptionsForEmbedding;
private final ImmutableList<String> objCopyOptionsForEmbedding;
private final Label ccToolchainLabel;
private final Label staticRuntimeLibsLabel;
private final Label dynamicRuntimeLibsLabel;
private final String solibDirectory;
private final String abi;
private final String targetSystemName;
private final ImmutableMap<String, String> additionalMakeVariables;
// TODO(b/65151735): Remove when cc_flags is entirely from features.
private final String legacyCcFlagsMakeVariable;
private final ImmutableList<String> crosstoolCompilerFlags;
private final ImmutableList<String> crosstoolCxxFlags;
private final ImmutableListMultimap<CompilationMode, String> cFlagsByCompilationMode;
private final ImmutableListMultimap<CompilationMode, String> cxxFlagsByCompilationMode;
private final ImmutableList<String> unfilteredCompilerFlags;
private final boolean supportsFission;
private final boolean supportsStartEndLib;
private final boolean supportsEmbeddedRuntimes;
private final boolean supportsDynamicLinker;
private final boolean supportsInterfaceSharedLibraries;
private final boolean toolchainNeedsPic;
/**
* Creates a CppToolchainInfo from CROSSTOOL info encapsulated in {@link CcToolchainConfigInfo}.
*/
public static CppToolchainInfo create(
Label toolchainLabel,
CcToolchainConfigInfo ccToolchainConfigInfo,
boolean disableLegacyCrosstoolFields,
boolean disableGenruleCcToolchainDependency)
throws EvalException {
ImmutableMap<String, PathFragment> toolPaths =
computeToolPaths(ccToolchainConfigInfo, getToolsDirectory(toolchainLabel));
PathFragment defaultSysroot =
CppConfiguration.computeDefaultSysroot(ccToolchainConfigInfo.getBuiltinSysroot());
ImmutableListMultimap.Builder<LinkingMode, String> linkOptionsFromLinkingModeBuilder =
ImmutableListMultimap.builder();
boolean haveDynamicMode = false;
if (!disableLegacyCrosstoolFields) {
// If a toolchain supports dynamic libraries at all, there must be at least one
// of the following:
// - a "DYNAMIC" section in linking_mode_flags (even if no flags are needed)
// - a non-empty list in one of the dynamicLibraryLinkerFlag fields
// If none of the above contain data, then the toolchain can't do dynamic linking.
haveDynamicMode = ccToolchainConfigInfo.hasDynamicLinkingModeFlags();
linkOptionsFromLinkingModeBuilder.putAll(
LinkingMode.DYNAMIC, ccToolchainConfigInfo.getDynamicLinkingModeFlags());
linkOptionsFromLinkingModeBuilder.putAll(
LinkingMode.LEGACY_FULLY_STATIC, ccToolchainConfigInfo.getFullyStaticLinkingModeFlags());
linkOptionsFromLinkingModeBuilder.putAll(
LinkingMode.STATIC, ccToolchainConfigInfo.getMostlyStaticLinkingModeFlags());
linkOptionsFromLinkingModeBuilder.putAll(
LinkingMode.LEGACY_MOSTLY_STATIC_LIBRARIES,
ccToolchainConfigInfo.getMostlyStaticLibrariesLinkingModeFlags());
}
ImmutableListMultimap.Builder<CompilationMode, String> cFlagsBuilder =
ImmutableListMultimap.builder();
ImmutableListMultimap.Builder<CompilationMode, String> cxxFlagsBuilder =
ImmutableListMultimap.builder();
ImmutableListMultimap.Builder<CompilationMode, String> linkOptionsFromCompilationModeBuilder =
ImmutableListMultimap.builder();
if (!disableLegacyCrosstoolFields) {
cFlagsBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.OPT),
ccToolchainConfigInfo.getOptCompilationModeCompilerFlags());
cxxFlagsBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.OPT),
ccToolchainConfigInfo.getOptCompilationModeCxxFlags());
linkOptionsFromCompilationModeBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.OPT),
ccToolchainConfigInfo.getOptCompilationModeLinkerFlags());
cFlagsBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.DBG),
ccToolchainConfigInfo.getDbgCompilationModeCompilerFlags());
cxxFlagsBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.DBG),
ccToolchainConfigInfo.getDbgCompilationModeCxxFlags());
linkOptionsFromCompilationModeBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.DBG),
ccToolchainConfigInfo.getDbgCompilationModeLinkerFlags());
cFlagsBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.FASTBUILD),
ccToolchainConfigInfo.getFastbuildCompilationModeCompilerFlags());
cxxFlagsBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.FASTBUILD),
ccToolchainConfigInfo.getFastbuildCompilationModeCxxFlags());
linkOptionsFromCompilationModeBuilder.putAll(
importCompilationMode(CrosstoolConfig.CompilationMode.FASTBUILD),
ccToolchainConfigInfo.getFastbuildCompilationModeLinkerFlags());
}
try {
return new CppToolchainInfo(
ccToolchainConfigInfo.getToolchainIdentifier(),
new CcToolchainFeatures(ccToolchainConfigInfo, getToolsDirectory(toolchainLabel)),
toolPaths,
ccToolchainConfigInfo.getCompiler(),
ccToolchainConfigInfo.getAbiLibcVersion(),
ccToolchainConfigInfo.getTargetCpu(),
ccToolchainConfigInfo.getCcTargetOs(),
ccToolchainConfigInfo.getCxxBuiltinIncludeDirectories(),
defaultSysroot,
// The runtime sysroot should really be set from --grte_top. However, currently libc has
// no way to set the sysroot. The CROSSTOOL file does set the runtime sysroot, in the
// builtin_sysroot field. This implies that you can not arbitrarily mix and match
// Crosstool and libc versions, you must always choose compatible ones.
defaultSysroot,
ccToolchainConfigInfo.getTargetLibc(),
ccToolchainConfigInfo.getHostSystemName(),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getDynamicLibraryLinkerFlags(),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getLinkerFlags(),
linkOptionsFromLinkingModeBuilder.build(),
linkOptionsFromCompilationModeBuilder.build(),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getTestOnlyLinkerFlags(),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getLdEmbedFlags(),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getObjcopyEmbedFlags(),
toolchainLabel,
disableLegacyCrosstoolFields
? null
: toolchainLabel.getRelativeWithRemapping(
!ccToolchainConfigInfo.getStaticRuntimesFilegroup().isEmpty()
? ccToolchainConfigInfo.getStaticRuntimesFilegroup()
: "static-runtime-libs-" + ccToolchainConfigInfo.getTargetCpu(),
ImmutableMap.of()),
disableLegacyCrosstoolFields
? null
: toolchainLabel.getRelativeWithRemapping(
!ccToolchainConfigInfo.getDynamicRuntimesFilegroup().isEmpty()
? ccToolchainConfigInfo.getDynamicRuntimesFilegroup()
: "dynamic-runtime-libs-" + ccToolchainConfigInfo.getTargetCpu(),
ImmutableMap.of()),
"_solib_" + ccToolchainConfigInfo.getTargetCpu(),
ccToolchainConfigInfo.getAbiVersion(),
ccToolchainConfigInfo.getTargetSystemName(),
computeAdditionalMakeVariables(
ccToolchainConfigInfo, disableGenruleCcToolchainDependency),
computeLegacyCcFlagsMakeVariable(ccToolchainConfigInfo),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getCompilerFlags(),
disableLegacyCrosstoolFields ? ImmutableList.of() : ccToolchainConfigInfo.getCxxFlags(),
cFlagsBuilder.build(),
cxxFlagsBuilder.build(),
disableLegacyCrosstoolFields
? ImmutableList.of()
: ccToolchainConfigInfo.getUnfilteredCxxFlags(),
disableLegacyCrosstoolFields ? false : ccToolchainConfigInfo.supportsFission(),
disableLegacyCrosstoolFields ? false : ccToolchainConfigInfo.supportsStartEndLib(),
disableLegacyCrosstoolFields ? false : ccToolchainConfigInfo.supportsEmbeddedRuntimes(),
disableLegacyCrosstoolFields
? false
: haveDynamicMode || !ccToolchainConfigInfo.getDynamicLibraryLinkerFlags().isEmpty(),
disableLegacyCrosstoolFields
? false
: ccToolchainConfigInfo.supportsInterfaceSharedLibraries(),
disableLegacyCrosstoolFields ? false : ccToolchainConfigInfo.needsPic());
} catch (LabelSyntaxException e) {
// All of the above label.getRelativeWithRemapping() calls are valid labels, and the
// crosstool_top was already checked earlier in the process.
throw new EvalException(Location.BUILTIN, e);
}
}
@AutoCodec.Instantiator
CppToolchainInfo(
String toolchainIdentifier,
CcToolchainFeatures toolchainFeatures,
ImmutableMap<String, PathFragment> toolPaths,
String compiler,
String abiGlibcVersion,
String targetCpu,
String targetOS,
ImmutableList<String> rawBuiltInIncludeDirectories,
PathFragment defaultSysroot,
PathFragment runtimeSysroot,
String targetLibc,
String hostSystemName,
ImmutableList<String> dynamicLibraryLinkFlags,
ImmutableList<String> legacyLinkOptions,
ImmutableListMultimap<LinkingMode, String> legacyLinkOptionsFromLinkingMode,
ImmutableListMultimap<CompilationMode, String> legacyLinkOptionsFromCompilationMode,
ImmutableList<String> testOnlyLinkFlags,
ImmutableList<String> ldOptionsForEmbedding,
ImmutableList<String> objCopyOptionsForEmbedding,
Label ccToolchainLabel,
Label staticRuntimeLibsLabel,
Label dynamicRuntimeLibsLabel,
String solibDirectory,
String abi,
String targetSystemName,
ImmutableMap<String, String> additionalMakeVariables,
String legacyCcFlagsMakeVariable,
ImmutableList<String> crosstoolCompilerFlags,
ImmutableList<String> crosstoolCxxFlags,
ImmutableListMultimap<CompilationMode, String> cFlagsByCompilationMode,
ImmutableListMultimap<CompilationMode, String> cxxFlagsByCompilationMode,
ImmutableList<String> unfilteredCompilerFlags,
boolean supportsFission,
boolean supportsStartEndLib,
boolean supportsEmbeddedRuntimes,
boolean supportsDynamicLinker,
boolean supportsInterfaceSharedLibraries,
boolean toolchainNeedsPic)
throws EvalException {
this.toolchainIdentifier = toolchainIdentifier;
// Since this field can be derived from `crosstoolInfo`, it is re-derived instead of serialized.
this.toolchainFeatures = toolchainFeatures;
this.toolPaths = toolPaths;
this.compiler = compiler;
this.abiGlibcVersion = abiGlibcVersion;
this.targetCpu = targetCpu;
this.targetOS = targetOS;
this.rawBuiltInIncludeDirectories = rawBuiltInIncludeDirectories;
this.defaultSysroot = defaultSysroot;
this.runtimeSysroot = runtimeSysroot;
this.targetLibc = targetLibc;
this.hostSystemName = hostSystemName;
this.dynamicLibraryLinkFlags = dynamicLibraryLinkFlags;
this.legacyLinkOptions = legacyLinkOptions;
this.legacyLinkOptionsFromLinkingMode = legacyLinkOptionsFromLinkingMode;
this.legacyLinkOptionsFromCompilationMode = legacyLinkOptionsFromCompilationMode;
this.testOnlyLinkFlags = testOnlyLinkFlags;
this.ldOptionsForEmbedding = ldOptionsForEmbedding;
this.objCopyOptionsForEmbedding = objCopyOptionsForEmbedding;
this.ccToolchainLabel = ccToolchainLabel;
this.staticRuntimeLibsLabel = staticRuntimeLibsLabel;
this.dynamicRuntimeLibsLabel = dynamicRuntimeLibsLabel;
this.solibDirectory = solibDirectory;
this.abi = abi;
this.targetSystemName = targetSystemName;
this.additionalMakeVariables = additionalMakeVariables;
this.legacyCcFlagsMakeVariable = legacyCcFlagsMakeVariable;
this.crosstoolCompilerFlags = crosstoolCompilerFlags;
this.crosstoolCxxFlags = crosstoolCxxFlags;
this.cFlagsByCompilationMode = cFlagsByCompilationMode;
this.cxxFlagsByCompilationMode = cxxFlagsByCompilationMode;
this.unfilteredCompilerFlags = unfilteredCompilerFlags;
this.supportsFission = supportsFission;
this.supportsStartEndLib = supportsStartEndLib;
this.supportsEmbeddedRuntimes = supportsEmbeddedRuntimes;
this.supportsDynamicLinker = supportsDynamicLinker;
this.supportsInterfaceSharedLibraries = supportsInterfaceSharedLibraries;
this.toolchainNeedsPic = toolchainNeedsPic;
}
@VisibleForTesting
static CompilationMode importCompilationMode(CrosstoolConfig.CompilationMode mode) {
return CompilationMode.valueOf(mode.name());
}
// TODO(bazel-team): Remove this once bazel supports all crosstool flags through
// feature configuration, and all crosstools have been converted.
public static CToolchain addLegacyFeatures(
CToolchain toolchain, PathFragment crosstoolTopPathFragment) {
CToolchain.Builder toolchainBuilder = CToolchain.newBuilder();
Set<ArtifactCategory> definedCategories = new HashSet<>();
for (ArtifactNamePattern pattern : toolchainBuilder.getArtifactNamePatternList()) {
try {
definedCategories.add(
ArtifactCategory.valueOf(pattern.getCategoryName().toUpperCase(Locale.ENGLISH)));
} catch (IllegalArgumentException e) {
// Invalid category name, will be detected later.
continue;
}
}
for (ArtifactCategory category : ArtifactCategory.values()) {
if (!definedCategories.contains(category) && category.getDefaultPrefix() != null
&& category.getDefaultExtension() != null) {
toolchainBuilder.addArtifactNamePattern(
ArtifactNamePattern.newBuilder()
.setCategoryName(category.toString().toLowerCase())
.setPrefix(category.getDefaultPrefix())
.setExtension(category.getDefaultExtension())
.build());
}
}
ImmutableSet<String> featureNames =
toolchain
.getFeatureList()
.stream()
.map(feature -> feature.getName())
.collect(ImmutableSet.toImmutableSet());
if (!featureNames.contains(CppRuleClasses.NO_LEGACY_FEATURES)) {
String gccToolPath = "DUMMY_GCC_TOOL";
String linkerToolPath = "DUMMY_LINKER_TOOL";
String arToolPath = "DUMMY_AR_TOOL";
String stripToolPath = "DUMMY_STRIP_TOOL";
for (ToolPath tool : toolchain.getToolPathList()) {
if (tool.getName().equals(CppConfiguration.Tool.GCC.getNamePart())) {
gccToolPath = tool.getPath();
linkerToolPath =
crosstoolTopPathFragment
.getRelative(PathFragment.create(tool.getPath()))
.getPathString();
}
if (tool.getName().equals(CppConfiguration.Tool.AR.getNamePart())) {
arToolPath = tool.getPath();
}
if (tool.getName().equals(CppConfiguration.Tool.STRIP.getNamePart())) {
stripToolPath = tool.getPath();
}
}
// TODO(b/30109612): Remove fragile legacyCompileFlags shuffle once there are no legacy
// crosstools.
// Existing projects depend on flags from legacy toolchain fields appearing first on the
// compile command line. 'legacy_compile_flags' feature contains all these flags, and so it
// needs to appear before other features from {@link CppActionConfigs}.
if (featureNames.contains(CppRuleClasses.LEGACY_COMPILE_FLAGS)) {
CToolchain.Feature legacyCompileFlags =
toolchain.getFeatureList().stream()
.filter(feature -> feature.getName().equals(CppRuleClasses.LEGACY_COMPILE_FLAGS))
.findFirst()
.get();
if (legacyCompileFlags != null) {
toolchainBuilder.addFeature(legacyCompileFlags);
}
}
if (featureNames.contains(CppRuleClasses.DEFAULT_COMPILE_FLAGS)) {
CToolchain.Feature defaultCompileFlags =
toolchain.getFeatureList().stream()
.filter(feature -> feature.getName().equals(CppRuleClasses.DEFAULT_COMPILE_FLAGS))
.findFirst()
.get();
if (defaultCompileFlags != null) {
toolchainBuilder.addFeature(defaultCompileFlags);
}
}
toolchain = removeSpecialFeatureFromToolchain(toolchain);
CppPlatform platform =
toolchain.getTargetLibc().equals(CppActionConfigs.MACOS_TARGET_LIBC)
? CppPlatform.MAC
: CppPlatform.LINUX;
toolchainBuilder.addAllActionConfig(
CppActionConfigs.getLegacyActionConfigs(
platform,
gccToolPath,
arToolPath,
stripToolPath,
toolchain.getSupportsInterfaceSharedObjects()));
toolchainBuilder.addAllFeature(
CppActionConfigs.getLegacyFeatures(
platform,
featureNames,
linkerToolPath,
toolchain.getSupportsEmbeddedRuntimes(),
toolchain.getSupportsInterfaceSharedObjects()));
}
toolchainBuilder.mergeFrom(toolchain);
if (!featureNames.contains(CppRuleClasses.NO_LEGACY_FEATURES)) {
toolchainBuilder.addAllFeature(
CppActionConfigs.getFeaturesToAppearLastInFeaturesList(featureNames));
}
return toolchainBuilder.build();
}
private static CToolchain removeSpecialFeatureFromToolchain(CToolchain toolchain) {
FieldDescriptor featuresFieldDescriptor = CToolchain.getDescriptor().findFieldByName("feature");
return toolchain
.toBuilder()
.setField(
featuresFieldDescriptor,
toolchain.getFeatureList().stream()
.filter(feature -> !feature.getName().equals(CppRuleClasses.LEGACY_COMPILE_FLAGS))
.filter(feature -> !feature.getName().equals(CppRuleClasses.DEFAULT_COMPILE_FLAGS))
.collect(ImmutableList.toImmutableList()))
.build();
}
/** @see CcToolchainProvider#getLegacyLinkOptions(). */
public ImmutableList<String> getLegacyLinkOptions() {
return legacyLinkOptions;
}
/** @see CcToolchainProvider#configureAllLegacyLinkOptions(CompilationMode, LinkingMode). */
ImmutableList<String> configureAllLegacyLinkOptions(
CompilationMode compilationMode, LinkingMode linkingMode) {
List<String> result = new ArrayList<>();
result.addAll(legacyLinkOptions);
result.addAll(legacyLinkOptionsFromCompilationMode.get(compilationMode));
result.addAll(legacyLinkOptionsFromLinkingMode.get(linkingMode));
return ImmutableList.copyOf(result);
}
/**
* Returns the toolchain identifier, which uniquely identifies the compiler version, target libc
* version, and target cpu.
*/
public String getToolchainIdentifier() {
return toolchainIdentifier;
}
/** Returns the system name which is required by the toolchain to run. */
public String getHostSystemName() {
return hostSystemName;
}
@Override
public String toString() {
return toolchainIdentifier;
}
/** Returns the compiler version string (e.g. "gcc-4.1.1"). */
public String getCompiler() {
return compiler;
}
/** Returns the libc version string (e.g. "glibc-2.2.2"). */
public String getTargetLibc() {
return targetLibc;
}
/**
* Returns the target architecture using blaze-specific constants (e.g. "piii").
*
* <p>Equivalent to {@link BuildConfiguration#getCpu()}
*/
public String getTargetCpu() {
return targetCpu;
}
/** Unused, for compatibility with things internal to Google. */
public String getTargetOS() {
return targetOS;
}
/**
* Returns the path fragment that is either absolute or relative to the execution root that can be
* used to execute the given tool.
*/
public PathFragment getToolPathFragment(CppConfiguration.Tool tool) {
return getToolPathFragment(toolPaths, tool);
}
/** Returns a label that references the current cc_toolchain target. */
public Label getCcToolchainLabel() {
return ccToolchainLabel;
}
/**
* Returns a label that references the library files needed to statically link the C++ runtime
* (i.e. libgcc.a, libgcc_eh.a, libstdc++.a) for the target architecture.
*/
public Label getStaticRuntimeLibsLabel() {
return staticRuntimeLibsLabel;
}
/**
* Returns a label that references the library files needed to dynamically link the C++ runtime
* (i.e. libgcc_s.so, libstdc++.so) for the target architecture.
*/
public Label getDynamicRuntimeLibsLabel() {
return dynamicRuntimeLibsLabel;
}
/**
* 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 configured features of the toolchain. Rules should not call this directly, but
* instead use {@code CcToolchainProvider.getFeatures}.
*/
public CcToolchainFeatures getFeatures() {
return toolchainFeatures;
}
/** Returns whether the toolchain supports the --start-lib/--end-lib options. */
public boolean supportsStartEndLib() {
return supportsStartEndLib;
}
/** Returns whether the toolchain supports dynamic linking. */
public boolean supportsDynamicLinker() {
return supportsDynamicLinker;
}
/**
* Returns whether this toolchain supports interface shared objects.
*
* <p>Should be true if this toolchain generates ELF objects.
*/
public boolean supportsInterfaceSharedLibraries() {
return supportsInterfaceSharedLibraries;
}
/**
* Returns whether the toolchain supports linking C/C++ runtime libraries supplied inside the
* toolchain distribution.
*/
public boolean supportsEmbeddedRuntimes() {
return supportsEmbeddedRuntimes;
}
/**
* Returns whether the toolchain supports "Fission" C++ builds, i.e. builds where compilation
* partitions object code and debug symbols into separate output files.
*/
public boolean supportsFission() {
return supportsFission;
}
/**
* Returns whether shared libraries must be compiled with position independent code on this
* platform.
*/
public boolean toolchainNeedsPic() {
return toolchainNeedsPic;
}
/**
* 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;
}
/**
* Returns link options for the specified flag list, combined with universal options for all
* shared libraries (regardless of link staticness).
*/
ImmutableList<String> getSharedLibraryLinkOptions(ImmutableList<String> flags) {
return ImmutableList.<String>builder().addAll(flags).addAll(dynamicLibraryLinkFlags).build();
}
/**
* Returns test-only link options such that certain test-specific features can be configured
* separately (e.g. lazy binding).
*/
public ImmutableList<String> getTestOnlyLinkOptions() {
return testOnlyLinkFlags;
}
/**
* Returns the list of options to be used with 'objcopy' when converting binary files to object
* files, or {@code null} if this operation is not supported.
*/
public ImmutableList<String> getObjCopyOptionsForEmbedding() {
return objCopyOptionsForEmbedding;
}
/**
* Returns the list of options to be used with 'ld' when converting binary files to object files,
* or {@code null} if this operation is not supported.
*/
public ImmutableList<String> getLdOptionsForEmbedding() {
return ldOptionsForEmbedding;
}
/**
* 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 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");
}
/**
* 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 the architecture component of the GNU System Name */
public String getGnuSystemArch() {
if (targetSystemName.indexOf('-') == -1) {
return targetSystemName;
}
return targetSystemName.substring(0, targetSystemName.indexOf('-'));
}
/** Returns the GNU System Name */
public String getTargetGnuSystemName() {
return targetSystemName;
}
public PathFragment getDefaultSysroot() {
return defaultSysroot;
}
/** Returns built-in include directories. */
public ImmutableList<String> getRawBuiltInIncludeDirectories() {
return rawBuiltInIncludeDirectories;
}
/** Returns compiler flags for C/C++/Asm compilation. */
public ImmutableList<String> getCompilerFlags() {
return crosstoolCompilerFlags;
}
/** Returns additional compiler flags for C++ compilation. */
public ImmutableList<String> getCxxFlags() {
return crosstoolCxxFlags;
}
/** Returns compiler flags for C compilation by compilation mode. */
public ImmutableListMultimap<CompilationMode, String> getCFlagsByCompilationMode() {
return cFlagsByCompilationMode;
}
/** Returns compiler flags for C++ compilation, by compilation mode. */
public ImmutableListMultimap<CompilationMode, String> getCxxFlagsByCompilationMode() {
return cxxFlagsByCompilationMode;
}
/** Returns unfiltered compiler options for C++ from this toolchain. */
public ImmutableList<String> getUnfilteredCompilerOptions(@Nullable PathFragment sysroot) {
if (sysroot == null) {
return unfilteredCompilerFlags;
}
return ImmutableList.<String>builder()
.add("--sysroot=" + sysroot)
.addAll(unfilteredCompilerFlags)
.build();
}
private static ImmutableMap<String, String> computeAdditionalMakeVariables(
CcToolchainConfigInfo ccToolchainConfigInfo, boolean disableGenruleCcToolchainDependency) {
Map<String, String> makeVariablesBuilder = new HashMap<>();
// The following are to be used to allow some build rules to avoid the limits on stack frame
// sizes and variable-length arrays.
// These variables are initialized here, but may be overridden by the getMakeVariables() checks.
makeVariablesBuilder.put("STACK_FRAME_UNLIMITED", "");
makeVariablesBuilder.put(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME, "");
for (Pair<String, String> variable : ccToolchainConfigInfo.getMakeVariables()) {
makeVariablesBuilder.put(variable.getFirst(), variable.getSecond());
}
if (disableGenruleCcToolchainDependency) {
makeVariablesBuilder.remove(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME);
}
return ImmutableMap.copyOf(makeVariablesBuilder);
}
// TODO(b/65151735): Remove when cc_flags is entirely from features.
private static String computeLegacyCcFlagsMakeVariable(
CcToolchainConfigInfo ccToolchainConfigInfo) {
String legacyCcFlags = "";
// Needs to ensure the last value with the name is used, to match the previous logic in
// computeAdditionalMakeVariables.
for (Pair<String, String> variable : ccToolchainConfigInfo.getMakeVariables()) {
if (variable.getFirst().equals(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME)) {
legacyCcFlags = variable.getSecond();
}
}
return legacyCcFlags;
}
private static ImmutableMap<String, PathFragment> computeToolPaths(
CcToolchainConfigInfo ccToolchainConfigInfo, PathFragment crosstoolTopPathFragment)
throws EvalException {
Map<String, PathFragment> toolPathsCollector = Maps.newHashMap();
for (Pair<String, String> tool : ccToolchainConfigInfo.getToolPaths()) {
String pathStr = tool.getSecond();
if (!PathFragment.isNormalized(pathStr)) {
throw new IllegalArgumentException("The include path '" + pathStr + "' is not normalized.");
}
PathFragment path = PathFragment.create(pathStr);
toolPathsCollector.put(tool.getFirst(), crosstoolTopPathFragment.getRelative(path));
}
if (toolPathsCollector.isEmpty()) {
// If no paths are specified, we just use the names of the tools as the path.
for (CppConfiguration.Tool tool : CppConfiguration.Tool.values()) {
toolPathsCollector.put(
tool.getNamePart(), crosstoolTopPathFragment.getRelative(tool.getNamePart()));
}
} else {
Iterable<CppConfiguration.Tool> neededTools =
Iterables.filter(
EnumSet.allOf(CppConfiguration.Tool.class),
tool -> {
if (tool == CppConfiguration.Tool.DWP) {
// When fission is unsupported, don't check for the dwp tool.
return ccToolchainConfigInfo.supportsFission();
} else if (tool == CppConfiguration.Tool.LLVM_PROFDATA) {
// TODO(tmsriram): Fix this to check if this is a llvm crosstool
// and return true. This needs changes to crosstool_config.proto.
return false;
} else if (tool == CppConfiguration.Tool.GCOVTOOL
|| tool == CppConfiguration.Tool.OBJCOPY) {
// gcov-tool and objcopy are optional, don't check whether they're present
return false;
} else {
return true;
}
});
for (CppConfiguration.Tool tool : neededTools) {
if (!toolPathsCollector.containsKey(tool.getNamePart())) {
throw new EvalException(
Location.BUILTIN, "Tool path for '" + tool.getNamePart() + "' is missing");
}
}
}
return ImmutableMap.copyOf(toolPathsCollector);
}
private static PathFragment getToolPathFragment(
ImmutableMap<String, PathFragment> toolPaths, CppConfiguration.Tool tool) {
return toolPaths.get(tool.getNamePart());
}
public PathFragment getToolsDirectory() {
return getToolsDirectory(ccToolchainLabel);
}
static PathFragment getToolsDirectory(Label ccToolchainLabel) {
return ccToolchainLabel.getPackageIdentifier().getPathUnderExecRoot();
}
}