| // 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.Predicate; |
| import com.google.common.collect.ArrayListMultimap; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableMap.Builder; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.ListMultimap; |
| import com.google.common.collect.Maps; |
| import com.google.devtools.build.lib.analysis.RuleContext; |
| 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.config.CompilationMode; |
| import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; |
| import com.google.devtools.build.lib.analysis.config.PerLabelOptions; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; |
| import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; |
| import com.google.devtools.build.lib.events.Event; |
| import com.google.devtools.build.lib.events.EventHandler; |
| import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader.CppConfigurationParameters; |
| import com.google.devtools.build.lib.rules.cpp.CppLinkActionConfigs.CppLinkPlatform; |
| import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; |
| import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; |
| import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; |
| import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; |
| import com.google.devtools.build.lib.util.Preconditions; |
| import com.google.devtools.build.lib.vfs.Path; |
| 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.ActionConfig; |
| import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain.ArtifactNamePattern; |
| import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LinkingModeFlags; |
| import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LipoMode; |
| import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath; |
| import com.google.devtools.common.options.OptionsParsingException; |
| import com.google.protobuf.TextFormat; |
| import com.google.protobuf.TextFormat.ParseException; |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * This class represents the C/C++ parts of the {@link BuildConfiguration}, including the host |
| * architecture, target architecture, compiler version, and a standard library version. It has |
| * information about the tools locations and the flags required for compiling. |
| */ |
| @SkylarkModule( |
| name = "cpp", |
| doc = "A configuration fragment for C++", |
| category = SkylarkModuleCategory.CONFIGURATION_FRAGMENT |
| ) |
| @Immutable |
| public class CppConfiguration extends BuildConfiguration.Fragment { |
| |
| /** |
| * String indicating a Mac system, for example when used in a crosstool configuration's host or |
| * target system name. |
| */ |
| public static final String MAC_SYSTEM_NAME = "x86_64-apple-macosx"; |
| |
| /** |
| * An enumeration of all the tools that comprise a toolchain. |
| */ |
| public enum Tool { |
| AR("ar"), |
| CPP("cpp"), |
| GCC("gcc"), |
| GCOV("gcov"), |
| GCOVTOOL("gcov-tool"), |
| LD("ld"), |
| NM("nm"), |
| OBJCOPY("objcopy"), |
| OBJDUMP("objdump"), |
| STRIP("strip"), |
| DWP("dwp"); |
| |
| private final String namePart; |
| |
| private Tool(String namePart) { |
| this.namePart = namePart; |
| } |
| |
| public String getNamePart() { |
| return namePart; |
| } |
| } |
| |
| /** |
| * Values for the --hdrs_check option. Note that Bazel only supports and will default to "strict". |
| */ |
| public static enum HeadersCheckingMode { |
| /** |
| * Legacy behavior: Silently allow any source header file in any of the directories of the |
| * containing package to be included by sources in this rule and dependent rules. |
| */ |
| LOOSE, |
| /** Warn about undeclared headers. */ |
| WARN, |
| /** Disallow undeclared headers. */ |
| STRICT |
| } |
| |
| /** |
| * --dynamic_mode parses to DynamicModeFlag, but AUTO will be translated based on platform, |
| * resulting in a DynamicMode value. |
| */ |
| public enum DynamicMode { OFF, DEFAULT, FULLY } |
| |
| /** |
| * This enumeration is used for the --strip option. |
| */ |
| public enum StripMode { |
| |
| ALWAYS("always"), // Always strip. |
| SOMETIMES("sometimes"), // Strip iff compilationMode == FASTBUILD. |
| NEVER("never"); // Never strip. |
| |
| private final String mode; |
| |
| private StripMode(String mode) { |
| this.mode = mode; |
| } |
| |
| @Override |
| public String toString() { |
| return mode; |
| } |
| } |
| |
| /** Storage for the libc label, if given. */ |
| public static class LibcTop implements Serializable { |
| private final Label label; |
| |
| LibcTop(Label label) { |
| Preconditions.checkArgument(label != null); |
| this.label = label; |
| } |
| |
| public Label getLabel() { |
| return label; |
| } |
| |
| public PathFragment getSysroot() { |
| return label.getPackageFragment(); |
| } |
| |
| @Override |
| public String toString() { |
| return label.toString(); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (this == other) { |
| return true; |
| } else if (other instanceof LibcTop) { |
| return label.equals(((LibcTop) other).label); |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| return label.hashCode(); |
| } |
| } |
| |
| /** |
| * This macro will be passed as a command-line parameter (eg. -DBUILD_FDO_TYPE="LIPO"). |
| * For possible values see {@code CppModel.getFdoBuildStamp()}. |
| */ |
| public static final String FDO_STAMP_MACRO = "BUILD_FDO_TYPE"; |
| |
| /** |
| * Represents an optional flag that can be toggled using the package features mechanism. |
| */ |
| @Immutable |
| @VisibleForTesting |
| static class OptionalFlag implements Serializable { |
| private final String name; |
| private final ImmutableList<String> flags; |
| |
| @VisibleForTesting |
| OptionalFlag(String name, ImmutableList<String> flags) { |
| this.name = name; |
| this.flags = flags; |
| } |
| |
| private ImmutableList<String> getFlags() { |
| return flags; |
| } |
| |
| private String getName() { |
| return name; |
| } |
| } |
| |
| @Immutable |
| @VisibleForTesting |
| static class FlagList implements Serializable { |
| private final ImmutableList<String> prefixFlags; |
| private final ImmutableList<OptionalFlag> optionalFlags; |
| private final ImmutableList<String> suffixFlags; |
| |
| @VisibleForTesting |
| FlagList(ImmutableList<String> prefixFlags, |
| ImmutableList<OptionalFlag> optionalFlags, |
| ImmutableList<String> suffixFlags) { |
| this.prefixFlags = prefixFlags; |
| this.optionalFlags = optionalFlags; |
| this.suffixFlags = suffixFlags; |
| } |
| |
| @VisibleForTesting |
| ImmutableList<String> evaluate(Iterable<String> features) { |
| ImmutableSet<String> featureSet = ImmutableSet.copyOf(features); |
| ImmutableList.Builder<String> result = ImmutableList.builder(); |
| result.addAll(prefixFlags); |
| for (OptionalFlag optionalFlag : optionalFlags) { |
| // The flag is added if the default is true and the flag is not specified, |
| // or if the default is false and the flag is specified. |
| if (featureSet.contains(optionalFlag.getName())) { |
| result.addAll(optionalFlag.getFlags()); |
| } |
| } |
| |
| result.addAll(suffixFlags); |
| return result.build(); |
| } |
| } |
| |
| private final Label crosstoolTop; |
| private final String hostSystemName; |
| private final String compiler; |
| private final String targetCpu; |
| private final String targetSystemName; |
| private final String targetLibc; |
| private final LipoMode lipoMode; |
| private final PathFragment crosstoolTopPathFragment; |
| |
| private final String abi; |
| private final String abiGlibcVersion; |
| |
| private final String toolchainIdentifier; |
| |
| private final CcToolchainFeatures toolchainFeatures; |
| private final boolean supportsGoldLinker; |
| private final boolean supportsStartEndLib; |
| private final boolean supportsDynamicLinker; |
| private final boolean supportsInterfaceSharedObjects; |
| private final boolean supportsEmbeddedRuntimes; |
| private final boolean supportsFission; |
| |
| // We encode three states with two booleans: |
| // (1) (false false) -> no pic code |
| // (2) (true false) -> shared libraries as pic, but not binaries |
| // (3) (true true) -> both shared libraries and binaries as pic |
| private final boolean toolchainNeedsPic; |
| private final boolean usePicForBinaries; |
| |
| private final Path fdoZip; |
| |
| // TODO(bazel-team): All these labels (except for ccCompilerRuleLabel) can be removed once the |
| // transition to the cc_compiler rule is complete. |
| private final Label libcLabel; |
| private final Label staticRuntimeLibsLabel; |
| private final Label dynamicRuntimeLibsLabel; |
| private final Label ccToolchainLabel; |
| |
| private final PathFragment sysroot; |
| private final PathFragment runtimeSysroot; |
| private final List<PathFragment> builtInIncludeDirectories; |
| |
| private final Map<String, PathFragment> toolPaths; |
| private final PathFragment ldExecutable; |
| |
| // Only used during construction. |
| private final ImmutableList<String> commonLinkOptions; |
| private final ListMultimap<CompilationMode, String> linkOptionsFromCompilationMode; |
| private final ListMultimap<LipoMode, String> linkOptionsFromLipoMode; |
| private final ListMultimap<LinkingMode, String> linkOptionsFromLinkingMode; |
| |
| private final FlagList compilerFlags; |
| private final FlagList cxxFlags; |
| private final FlagList unfilteredCompilerFlags; |
| private final ImmutableList<String> cOptions; |
| |
| private final FlagList fullyStaticLinkFlags; |
| private final FlagList mostlyStaticLinkFlags; |
| private final FlagList mostlyStaticSharedLinkFlags; |
| private final FlagList dynamicLinkFlags; |
| private final FlagList dynamicLibraryLinkFlags; |
| private final ImmutableList<String> testOnlyLinkFlags; |
| |
| private final ImmutableList<String> linkOptions; |
| private final ImmutableList<String> ltoindexOptions; |
| |
| private final ImmutableList<String> objcopyOptions; |
| private final ImmutableList<String> ldOptions; |
| private final ImmutableList<String> arOptions; |
| |
| private final ImmutableMap<String, String> additionalMakeVariables; |
| |
| private final CppOptions cppOptions; |
| |
| // The dynamic mode for linking. |
| private final DynamicMode dynamicMode; |
| private final boolean stripBinaries; |
| private final String solibDirectory; |
| private final CompilationMode compilationMode; |
| private final boolean useLLVMCoverageMap; |
| |
| /** |
| * If true, the ConfiguredTarget is only used to get the necessary cross-referenced |
| * CppCompilationContexts, but registering build actions is disabled. |
| */ |
| private final boolean lipoContextCollector; |
| |
| protected CppConfiguration(CppConfigurationParameters params) |
| throws InvalidConfigurationException { |
| CrosstoolConfig.CToolchain toolchain = params.toolchain; |
| cppOptions = params.cppOptions; |
| this.hostSystemName = toolchain.getHostSystemName(); |
| this.compiler = toolchain.getCompiler(); |
| this.targetCpu = toolchain.getTargetCpu(); |
| this.lipoMode = cppOptions.getLipoMode(); |
| this.targetSystemName = toolchain.getTargetSystemName(); |
| this.targetLibc = toolchain.getTargetLibc(); |
| this.crosstoolTop = params.crosstoolTop; |
| this.ccToolchainLabel = params.ccToolchainLabel; |
| this.compilationMode = params.commonOptions.compilationMode; |
| this.useLLVMCoverageMap = params.commonOptions.useLLVMCoverageMapFormat; |
| this.lipoContextCollector = cppOptions.lipoCollector; |
| |
| |
| this.crosstoolTopPathFragment = crosstoolTop.getPackageIdentifier().getPathUnderExecRoot(); |
| |
| try { |
| this.staticRuntimeLibsLabel = |
| crosstoolTop.getRelative( |
| toolchain.hasStaticRuntimesFilegroup() |
| ? toolchain.getStaticRuntimesFilegroup() |
| : "static-runtime-libs-" + targetCpu); |
| this.dynamicRuntimeLibsLabel = |
| crosstoolTop.getRelative( |
| toolchain.hasDynamicRuntimesFilegroup() |
| ? toolchain.getDynamicRuntimesFilegroup() |
| : "dynamic-runtime-libs-" + targetCpu); |
| } catch (LabelSyntaxException e) { |
| // All of the above label.getRelative() calls are valid labels, and the crosstool_top |
| // was already checked earlier in the process. |
| throw new AssertionError(e); |
| } |
| |
| if (cppOptions.lipoMode == LipoMode.BINARY) { |
| // TODO(bazel-team): implement dynamic linking with LIPO |
| this.dynamicMode = DynamicMode.OFF; |
| } else { |
| switch (cppOptions.dynamicMode) { |
| case DEFAULT: |
| this.dynamicMode = DynamicMode.DEFAULT; break; |
| case OFF: this.dynamicMode = DynamicMode.OFF; break; |
| case FULLY: this.dynamicMode = DynamicMode.FULLY; break; |
| default: throw new IllegalStateException("Invalid dynamicMode."); |
| } |
| } |
| |
| this.fdoZip = params.fdoZip; |
| this.stripBinaries = |
| (cppOptions.stripBinaries == StripMode.ALWAYS |
| || (cppOptions.stripBinaries == StripMode.SOMETIMES |
| && compilationMode == CompilationMode.FASTBUILD)); |
| |
| CrosstoolConfigurationIdentifier crosstoolConfig = |
| CrosstoolConfigurationIdentifier.fromToolchain(toolchain); |
| Preconditions.checkState(crosstoolConfig.getCpu().equals(targetCpu)); |
| Preconditions.checkState(crosstoolConfig.getCompiler().equals(compiler)); |
| Preconditions.checkState(crosstoolConfig.getLibc().equals(targetLibc)); |
| |
| this.solibDirectory = "_solib_" + targetCpu; |
| |
| this.toolchainIdentifier = toolchain.getToolchainIdentifier(); |
| |
| toolchain = addLegacyFeatures(toolchain); |
| this.toolchainFeatures = new CcToolchainFeatures(toolchain); |
| this.supportsGoldLinker = toolchain.getSupportsGoldLinker(); |
| this.supportsStartEndLib = toolchain.getSupportsStartEndLib(); |
| this.supportsInterfaceSharedObjects = toolchain.getSupportsInterfaceSharedObjects(); |
| this.supportsEmbeddedRuntimes = toolchain.getSupportsEmbeddedRuntimes(); |
| this.supportsFission = toolchain.getSupportsFission(); |
| this.toolchainNeedsPic = toolchain.getNeedsPic(); |
| this.usePicForBinaries = |
| toolchain.getNeedsPic() && compilationMode != CompilationMode.OPT; |
| |
| this.toolPaths = Maps.newHashMap(); |
| for (CrosstoolConfig.ToolPath tool : toolchain.getToolPathList()) { |
| PathFragment path = new PathFragment(tool.getPath()); |
| if (!path.isNormalized()) { |
| throw new IllegalArgumentException("The include path '" + tool.getPath() |
| + "' is not normalized."); |
| } |
| toolPaths.put(tool.getName(), crosstoolTopPathFragment.getRelative(path)); |
| } |
| |
| if (toolPaths.isEmpty()) { |
| // If no paths are specified, we just use the names of the tools as the path. |
| for (Tool tool : Tool.values()) { |
| toolPaths.put(tool.getNamePart(), |
| crosstoolTopPathFragment.getRelative(tool.getNamePart())); |
| } |
| } else { |
| Iterable<Tool> neededTools = Iterables.filter(EnumSet.allOf(Tool.class), |
| new Predicate<Tool>() { |
| @Override |
| public boolean apply(Tool tool) { |
| if (tool == Tool.DWP) { |
| // When fission is unsupported, don't check for the dwp tool. |
| return supportsFission(); |
| } else if (tool == Tool.GCOVTOOL || tool == Tool.OBJCOPY) { |
| // gcov-tool and objcopy are optional, don't check whether they're present |
| return false; |
| } else { |
| return true; |
| } |
| } |
| }); |
| for (Tool tool : neededTools) { |
| if (!toolPaths.containsKey(tool.getNamePart())) { |
| throw new IllegalArgumentException("Tool path for '" + tool.getNamePart() |
| + "' is missing"); |
| } |
| } |
| } |
| |
| ListMultimap<CompilationMode, String> cFlags = ArrayListMultimap.create(); |
| ListMultimap<CompilationMode, String> cxxFlags = ArrayListMultimap.create(); |
| linkOptionsFromCompilationMode = ArrayListMultimap.create(); |
| for (CrosstoolConfig.CompilationModeFlags flags : toolchain.getCompilationModeFlagsList()) { |
| // Remove this when CROSSTOOL files no longer contain 'coverage'. |
| if (flags.getMode() == CrosstoolConfig.CompilationMode.COVERAGE) { |
| continue; |
| } |
| CompilationMode realmode = importCompilationMode(flags.getMode()); |
| cFlags.putAll(realmode, flags.getCompilerFlagList()); |
| cxxFlags.putAll(realmode, flags.getCxxFlagList()); |
| linkOptionsFromCompilationMode.putAll(realmode, flags.getLinkerFlagList()); |
| } |
| |
| ListMultimap<LipoMode, String> lipoCFlags = ArrayListMultimap.create(); |
| ListMultimap<LipoMode, String> lipoCxxFlags = ArrayListMultimap.create(); |
| linkOptionsFromLipoMode = ArrayListMultimap.create(); |
| for (CrosstoolConfig.LipoModeFlags flags : toolchain.getLipoModeFlagsList()) { |
| LipoMode realmode = flags.getMode(); |
| lipoCFlags.putAll(realmode, flags.getCompilerFlagList()); |
| lipoCxxFlags.putAll(realmode, flags.getCxxFlagList()); |
| linkOptionsFromLipoMode.putAll(realmode, flags.getLinkerFlagList()); |
| } |
| |
| linkOptionsFromLinkingMode = ArrayListMultimap.create(); |
| |
| // 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. |
| boolean haveDynamicMode = false; |
| |
| for (LinkingModeFlags flags : toolchain.getLinkingModeFlagsList()) { |
| LinkingMode realmode = importLinkingMode(flags.getMode()); |
| if (realmode == LinkingMode.DYNAMIC) { |
| haveDynamicMode = true; |
| } |
| linkOptionsFromLinkingMode.putAll(realmode, flags.getLinkerFlagList()); |
| } |
| |
| this.commonLinkOptions = ImmutableList.copyOf(toolchain.getLinkerFlagList()); |
| List<String> linkerFlagList = toolchain.getDynamicLibraryLinkerFlagList(); |
| List<CToolchain.OptionalFlag> optionalLinkerFlagList = |
| toolchain.getOptionalDynamicLibraryLinkerFlagList(); |
| if (!linkerFlagList.isEmpty() || !optionalLinkerFlagList.isEmpty()) { |
| haveDynamicMode = true; |
| } |
| this.supportsDynamicLinker = haveDynamicMode; |
| dynamicLibraryLinkFlags = new FlagList( |
| ImmutableList.copyOf(linkerFlagList), |
| convertOptionalOptions(optionalLinkerFlagList), |
| ImmutableList.<String>of()); |
| |
| this.objcopyOptions = ImmutableList.copyOf(toolchain.getObjcopyEmbedFlagList()); |
| this.ldOptions = ImmutableList.copyOf(toolchain.getLdEmbedFlagList()); |
| this.arOptions = copyOrDefaultIfEmpty(toolchain.getArFlagList(), "rcsD"); |
| |
| this.abi = toolchain.getAbiVersion(); |
| this.abiGlibcVersion = toolchain.getAbiLibcVersion(); |
| |
| // The default value for optional string attributes is the empty string. |
| PathFragment defaultSysroot = toolchain.getBuiltinSysroot().length() == 0 |
| ? null |
| : new PathFragment(toolchain.getBuiltinSysroot()); |
| if ((defaultSysroot != null) && !defaultSysroot.isNormalized()) { |
| throw new IllegalArgumentException("The built-in sysroot '" + defaultSysroot |
| + "' is not normalized."); |
| } |
| |
| if ((cppOptions.libcTop != null) && (defaultSysroot == null)) { |
| throw new InvalidConfigurationException("The selected toolchain " + toolchainIdentifier |
| + " does not support setting --grte_top."); |
| } |
| LibcTop libcTop = cppOptions.libcTop; |
| if ((libcTop == null) && !toolchain.getDefaultGrteTop().isEmpty()) { |
| try { |
| libcTop = new CppOptions.LibcTopConverter().convert(toolchain.getDefaultGrteTop()); |
| } catch (OptionsParsingException e) { |
| throw new InvalidConfigurationException(e.getMessage(), e); |
| } |
| } |
| if ((libcTop != null) && (libcTop.getLabel() != null)) { |
| libcLabel = libcTop.getLabel(); |
| } else { |
| libcLabel = null; |
| } |
| |
| ImmutableList.Builder<PathFragment> builtInIncludeDirectoriesBuilder |
| = ImmutableList.builder(); |
| sysroot = libcTop == null ? defaultSysroot : libcTop.getSysroot(); |
| for (String s : toolchain.getCxxBuiltinIncludeDirectoryList()) { |
| builtInIncludeDirectoriesBuilder.add( |
| resolveIncludeDir(s, sysroot, crosstoolTopPathFragment)); |
| } |
| builtInIncludeDirectories = builtInIncludeDirectoriesBuilder.build(); |
| |
| // 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. |
| runtimeSysroot = defaultSysroot; |
| |
| String sysrootFlag; |
| if (sysroot != null) { |
| sysrootFlag = "--sysroot=" + sysroot; |
| } else { |
| sysrootFlag = null; |
| } |
| |
| ImmutableList.Builder<String> unfilteredCoptsBuilder = ImmutableList.builder(); |
| if (sysrootFlag != null) { |
| unfilteredCoptsBuilder.add(sysrootFlag); |
| } |
| unfilteredCoptsBuilder.addAll(toolchain.getUnfilteredCxxFlagList()); |
| unfilteredCompilerFlags = new FlagList( |
| unfilteredCoptsBuilder.build(), |
| convertOptionalOptions(toolchain.getOptionalUnfilteredCxxFlagList()), |
| ImmutableList.<String>of()); |
| |
| ImmutableList.Builder<String> linkoptsBuilder = ImmutableList.builder(); |
| linkoptsBuilder.addAll(cppOptions.linkoptList); |
| if (cppOptions.experimentalOmitfp) { |
| linkoptsBuilder.add("-Wl,--eh-frame-hdr"); |
| } |
| if (sysrootFlag != null) { |
| linkoptsBuilder.add(sysrootFlag); |
| } |
| this.linkOptions = linkoptsBuilder.build(); |
| |
| ImmutableList.Builder<String> ltoindexoptsBuilder = ImmutableList.builder(); |
| ltoindexoptsBuilder.addAll(cppOptions.ltoindexoptList); |
| this.ltoindexOptions = ltoindexoptsBuilder.build(); |
| |
| ImmutableList.Builder<String> coptsBuilder = ImmutableList.<String>builder() |
| .addAll(toolchain.getCompilerFlagList()) |
| .addAll(cFlags.get(compilationMode)) |
| .addAll(lipoCFlags.get(cppOptions.getLipoMode())); |
| if (cppOptions.experimentalOmitfp) { |
| coptsBuilder.add("-fomit-frame-pointer"); |
| coptsBuilder.add("-fasynchronous-unwind-tables"); |
| coptsBuilder.add("-DNO_FRAME_POINTER"); |
| } |
| this.compilerFlags = new FlagList( |
| coptsBuilder.build(), |
| convertOptionalOptions(toolchain.getOptionalCompilerFlagList()), |
| ImmutableList.copyOf(cppOptions.coptList)); |
| |
| this.cOptions = ImmutableList.copyOf(cppOptions.conlyoptList); |
| |
| ImmutableList.Builder<String> cxxOptsBuilder = ImmutableList.<String>builder() |
| .addAll(toolchain.getCxxFlagList()) |
| .addAll(cxxFlags.get(compilationMode)) |
| .addAll(lipoCxxFlags.get(cppOptions.getLipoMode())); |
| |
| this.cxxFlags = new FlagList( |
| cxxOptsBuilder.build(), |
| convertOptionalOptions(toolchain.getOptionalCxxFlagList()), |
| ImmutableList.copyOf(cppOptions.cxxoptList)); |
| |
| this.ldExecutable = getToolPathFragment(CppConfiguration.Tool.LD); |
| |
| boolean stripBinaries = |
| (cppOptions.stripBinaries == StripMode.ALWAYS) |
| || ((cppOptions.stripBinaries == StripMode.SOMETIMES) |
| && (compilationMode == CompilationMode.FASTBUILD)); |
| |
| fullyStaticLinkFlags = new FlagList( |
| configureLinkerOptions(compilationMode, lipoMode, LinkingMode.FULLY_STATIC, |
| ldExecutable, stripBinaries), |
| convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), |
| ImmutableList.<String>of()); |
| mostlyStaticLinkFlags = new FlagList( |
| configureLinkerOptions(compilationMode, lipoMode, LinkingMode.MOSTLY_STATIC, |
| ldExecutable, stripBinaries), |
| convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), |
| ImmutableList.<String>of()); |
| mostlyStaticSharedLinkFlags = new FlagList( |
| configureLinkerOptions(compilationMode, lipoMode, |
| LinkingMode.MOSTLY_STATIC_LIBRARIES, ldExecutable, stripBinaries), |
| convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), |
| ImmutableList.<String>of()); |
| dynamicLinkFlags = new FlagList( |
| configureLinkerOptions(compilationMode, lipoMode, LinkingMode.DYNAMIC, |
| ldExecutable, stripBinaries), |
| convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), |
| ImmutableList.<String>of()); |
| testOnlyLinkFlags = ImmutableList.copyOf(toolchain.getTestOnlyLinkerFlagList()); |
| |
| 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. Ensure that these are always set. |
| makeVariablesBuilder.put("STACK_FRAME_UNLIMITED", ""); |
| makeVariablesBuilder.put("CC_FLAGS", ""); |
| for (CrosstoolConfig.MakeVariable variable : toolchain.getMakeVariableList()) { |
| makeVariablesBuilder.put(variable.getName(), variable.getValue()); |
| } |
| if (sysrootFlag != null) { |
| String ccFlags = makeVariablesBuilder.get("CC_FLAGS"); |
| ccFlags = ccFlags.isEmpty() ? sysrootFlag : ccFlags + " " + sysrootFlag; |
| makeVariablesBuilder.put("CC_FLAGS", ccFlags); |
| } |
| this.additionalMakeVariables = ImmutableMap.copyOf(makeVariablesBuilder); |
| } |
| |
| private ImmutableList<OptionalFlag> convertOptionalOptions( |
| List<CrosstoolConfig.CToolchain.OptionalFlag> optionalFlagList) |
| throws IllegalArgumentException { |
| ImmutableList.Builder<OptionalFlag> result = ImmutableList.builder(); |
| |
| for (CrosstoolConfig.CToolchain.OptionalFlag crosstoolOptionalFlag : optionalFlagList) { |
| String name = crosstoolOptionalFlag.getDefaultSettingName(); |
| result.add(new OptionalFlag( |
| name, |
| ImmutableList.copyOf(crosstoolOptionalFlag.getFlagList()))); |
| } |
| |
| return result.build(); |
| } |
| |
| private boolean linkActionsAreConfigured(CToolchain toolchain) { |
| |
| for (LinkTargetType type : Link.MANDATORY_LINK_TARGET_TYPES) { |
| boolean typeIsConfigured = false; |
| for (ActionConfig actionConfig : toolchain.getActionConfigList()) { |
| if (actionConfig.getActionName().equals(type.getActionName())) { |
| typeIsConfigured = true; |
| break; |
| } |
| } |
| if (!typeIsConfigured) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // TODO(bazel-team): Remove this once bazel supports all crosstool flags through |
| // feature configuration, and all crosstools have been converted. |
| private CToolchain addLegacyFeatures(CToolchain toolchain) { |
| CToolchain.Builder toolchainBuilder = CToolchain.newBuilder(); |
| |
| Set<ArtifactCategory> definedCategories = new HashSet<>(); |
| for (ArtifactNamePattern pattern : toolchainBuilder.getArtifactNamePatternList()) { |
| try { |
| definedCategories.add(ArtifactCategory.valueOf(pattern.getCategoryName().toUpperCase())); |
| } catch (IllegalArgumentException e) { |
| // Invalid category name, will be detected later. |
| continue; |
| } |
| } |
| |
| for (ArtifactCategory category : ArtifactCategory.values()) { |
| if (!definedCategories.contains(category) && category.getDefaultPattern() != null) { |
| toolchainBuilder.addArtifactNamePattern(ArtifactNamePattern.newBuilder() |
| .setCategoryName(category.toString().toLowerCase()) |
| .setPattern(category.getDefaultPattern()) |
| .build()); |
| } |
| } |
| |
| ImmutableSet.Builder<String> featuresBuilder = ImmutableSet.builder(); |
| for (CToolchain.Feature feature : toolchain.getFeatureList()) { |
| featuresBuilder.add(feature.getName()); |
| } |
| Set<String> features = featuresBuilder.build(); |
| if (!features.contains(CppRuleClasses.NO_LEGACY_FEATURES)) { |
| try { |
| if (!linkActionsAreConfigured(toolchain)) { |
| String linkerToolPath = "DUMMY_LINKER_TOOL"; |
| for (ToolPath tool : toolchain.getToolPathList()) { |
| if (tool.getName().equals(Tool.GCC.getNamePart())) { |
| linkerToolPath = |
| crosstoolTopPathFragment |
| .getRelative(new PathFragment(tool.getPath())) |
| .getPathString(); |
| } |
| } |
| if (getTargetLibc().equals("macosx")) { |
| TextFormat.merge( |
| CppLinkActionConfigs.getCppLinkActionConfigs( |
| CppLinkPlatform.MAC, features, linkerToolPath), |
| toolchainBuilder); |
| } else { |
| TextFormat.merge( |
| CppLinkActionConfigs.getCppLinkActionConfigs( |
| CppLinkPlatform.LINUX, features, linkerToolPath), |
| toolchainBuilder); |
| } |
| } |
| |
| if (!features.contains("dependency_file")) { |
| // Gcc options: |
| // -MD turns on .d file output as a side-effect (doesn't imply -E) |
| // -MM[D] enables user includes only, not system includes |
| // -MF <name> specifies the dotd file name |
| // Issues: |
| // -M[M] alone subverts actual .o output (implies -E) |
| // -M[M]D alone breaks some of the .d naming assumptions |
| // This combination gets user and system includes with specified name: |
| // -MD -MF <name> |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'dependency_file'" |
| + " flag_set {" |
| + " action: 'assemble'" |
| + " action: 'preprocess-assemble'" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'c++-module-compile'" |
| + " action: 'objc-compile'" |
| + " action: 'objc++-compile'" |
| + " action: 'c++-header-preprocessing'" |
| + " action: 'c++-header-parsing'" |
| + " expand_if_all_available: 'dependency_file'" |
| + " flag_group {" |
| + " flag: '-MD'" |
| + " flag: '-MF'" |
| + " flag: '%{dependency_file}'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| |
| if (!features.contains("random_seed")) { |
| // GCC and Clang give randomized names to symbols which are defined in |
| // an anonymous namespace but have external linkage. To make |
| // computation of these deterministic, we want to override the |
| // default seed for the random number generator. It's safe to use |
| // any value which differs for all translation units; we use the |
| // path to the object file. |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'random_seed'" |
| + " flag_set {" |
| + " action: 'c++-compile'" |
| + " action: 'c++-module-compile'" |
| + " flag_group {" |
| + " flag: '-frandom-seed=%{output_file}'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| |
| if (!features.contains("pic")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'pic'" |
| + " flag_set {" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'c++-module-compile'" |
| + " action: 'preprocess-assemble'" |
| + " expand_if_all_available: 'pic'" |
| + " flag_group {" |
| + " flag: '-fPIC'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| |
| if (!features.contains("per_object_debug_info")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'per_object_debug_info'" |
| + " flag_set {" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'assemble'" |
| + " action: 'preprocess-assemble'" |
| + " expand_if_all_available: 'per_object_debug_info_file'" |
| + " flag_group {" |
| + " flag: '-gsplit-dwarf'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| |
| if (!features.contains("preprocessor_defines")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'preprocessor_defines'" |
| + " flag_set {" |
| + " action: 'preprocess-assemble'" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'c++-header-parsing'" |
| + " action: 'c++-header-preprocessing'" |
| + " action: 'c++-module-compile'" |
| + " action: 'clif-match'" |
| + " flag_group {" |
| + " flag: '-D%{preprocessor_defines}'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| if (!features.contains("include_paths")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'include_paths'" |
| + " flag_set {" |
| + " action: 'preprocess-assemble'" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'c++-header-parsing'" |
| + " action: 'c++-header-preprocessing'" |
| + " action: 'c++-module-compile'" |
| + " action: 'clif-match'" |
| + " action: 'objc-compile'" |
| + " action: 'objc++-compile'" |
| + " flag_group {" |
| + " flag: '-iquote'" |
| + " flag: '%{quote_include_paths}'" |
| + " }" |
| + " flag_group {" |
| + " flag: '-I%{include_paths}'" |
| + " }" |
| + " flag_group {" |
| + " flag: '-isystem'" |
| + " flag: '%{system_include_paths}'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| if (!features.contains("fdo_instrument")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'fdo_instrument'" |
| + " provides: 'profile'" |
| + " flag_set {" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'c++-link-interface-dynamic-library'" |
| + " action: 'c++-link-dynamic-library'" |
| + " action: 'c++-link-executable'" |
| + " flag_group {" |
| + " flag: '-fprofile-generate=%{fdo_instrument_path}'" |
| + " flag: '-fno-data-sections'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| if (!features.contains("fdo_optimize")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'fdo_optimize'" |
| + " provides: 'profile'" |
| + " flag_set {" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " expand_if_all_available: 'fdo_profile_path'" |
| + " flag_group {" |
| + " flag: '-fprofile-use=%{fdo_profile_path}'" |
| + " flag: '-Xclang-only=-Wno-profile-instr-unprofiled'" |
| + " flag: '-Xclang-only=-Wno-profile-instr-out-of-date'" |
| + " flag: '-fprofile-correction'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| if (!features.contains("autofdo")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'autofdo'" |
| + " provides: 'profile'" |
| + " flag_set {" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " expand_if_all_available: 'fdo_profile_path'" |
| + " flag_group {" |
| + " flag: '-fauto-profile=%{fdo_profile_path}'" |
| + " flag: '-fprofile-correction'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| if (!features.contains("lipo")) { |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'lipo'" |
| + " requires { feature: 'autofdo' }" |
| + " requires { feature: 'fdo_optimize' }" |
| + " requires { feature: 'fdo_instrument' }" |
| + " flag_set {" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " flag_group {" |
| + " flag: '-fripa'" |
| + " }" |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| if (!features.contains("coverage")) { |
| String compileFlags; |
| String linkerFlags; |
| if (useLLVMCoverageMap) { |
| compileFlags = |
| "flag_group {" |
| + " flag: '-fprofile-instr-generate'" |
| + " flag: '-fcoverage-mapping'" |
| + "}"; |
| linkerFlags = " flag_group {" + " flag: '-fprofile-instr-generate'" + "}"; |
| } else { |
| compileFlags = |
| " expand_if_all_available: 'gcov_gcno_file'" |
| + "flag_group {" |
| + " flag: '-fprofile-arcs'" |
| + " flag: '-ftest-coverage'" |
| + "}"; |
| linkerFlags = " flag_group {" + " flag: '-lgcov'" + "}"; |
| } |
| TextFormat.merge( |
| "" |
| + "feature {" |
| + " name: 'coverage'" |
| + " provides: 'profile'" |
| + " flag_set {" |
| + " action: 'preprocess-assemble'" |
| + " action: 'c-compile'" |
| + " action: 'c++-compile'" |
| + " action: 'c++-header-parsing'" |
| + " action: 'c++-header-preprocessing'" |
| + " action: 'c++-module-compile'" |
| + compileFlags |
| + " }" |
| + " flag_set {" |
| + " action: 'c++-link-interface-dynamic-library'" |
| + " action: 'c++-link-dynamic-library'" |
| + " action: 'c++-link-executable'" |
| + linkerFlags |
| + " }" |
| + "}", |
| toolchainBuilder); |
| } |
| } catch (ParseException e) { |
| // Can only happen if we change the proto definition without changing our |
| // configuration above. |
| throw new RuntimeException(e); |
| } |
| } |
| |
| toolchainBuilder.mergeFrom(toolchain); |
| return toolchainBuilder.build(); |
| } |
| |
| private static ImmutableList<String> copyOrDefaultIfEmpty(List<String> list, |
| String defaultValue) { |
| return list.isEmpty() ? ImmutableList.of(defaultValue) : ImmutableList.copyOf(list); |
| } |
| |
| @VisibleForTesting |
| static CompilationMode importCompilationMode(CrosstoolConfig.CompilationMode mode) { |
| return CompilationMode.valueOf(mode.name()); |
| } |
| |
| @VisibleForTesting |
| static LinkingMode importLinkingMode(CrosstoolConfig.LinkingMode mode) { |
| return LinkingMode.valueOf(mode.name()); |
| } |
| |
| private static final String SYSROOT_START = "%sysroot%/"; |
| private static final String WORKSPACE_START = "%workspace%/"; |
| private static final String CROSSTOOL_START = "%crosstool_top%/"; |
| private static final String PACKAGE_START = "%package("; |
| private static final String PACKAGE_END = ")%"; |
| |
| /** |
| * Resolve the given include directory. |
| * |
| * <p>If it starts with %sysroot%/, that part is replaced with the actual sysroot. |
| * |
| * <p>If it starts with %workspace%/, that part is replaced with the empty string |
| * (essentially making it relative to the build directory). |
| * |
| * <p>If it starts with %crosstool_top%/ or is any relative path, it is |
| * interpreted relative to the crosstool top. The use of assumed-crosstool-relative |
| * specifications is considered deprecated, and all such uses should eventually |
| * be replaced by "%crosstool_top%/". |
| * |
| * <p>If it is of the form %package(@repository//my/package)%/folder, then it is |
| * interpreted as the named folder in the appropriate package. All of the normal |
| * package syntax is supported. The /folder part is optional. |
| * |
| * <p>It is illegal if it starts with a % and does not match any of the above |
| * forms to avoid accidentally silently ignoring misspelled prefixes. |
| * |
| * <p>If it is absolute, it remains unchanged. |
| */ |
| static PathFragment resolveIncludeDir(String s, PathFragment sysroot, |
| PathFragment crosstoolTopPathFragment) throws InvalidConfigurationException { |
| PathFragment pathPrefix; |
| String pathString; |
| int packageEndIndex = s.indexOf(PACKAGE_END); |
| if (packageEndIndex != -1 && s.startsWith(PACKAGE_START)) { |
| String packageString = s.substring(PACKAGE_START.length(), packageEndIndex); |
| try { |
| pathPrefix = PackageIdentifier.parse(packageString).getSourceRoot(); |
| } catch (LabelSyntaxException e) { |
| throw new InvalidConfigurationException("The package '" + packageString + "' is not valid"); |
| } |
| int pathStartIndex = packageEndIndex + PACKAGE_END.length(); |
| if (pathStartIndex + 1 < s.length()) { |
| if (s.charAt(pathStartIndex) != '/') { |
| throw new InvalidConfigurationException( |
| "The path in the package for '" + s + "' is not valid"); |
| } |
| pathString = s.substring(pathStartIndex + 1, s.length()); |
| } else { |
| pathString = ""; |
| } |
| } else if (s.startsWith(SYSROOT_START)) { |
| if (sysroot == null) { |
| throw new InvalidConfigurationException("A %sysroot% prefix is only allowed if the " |
| + "default_sysroot option is set"); |
| } |
| pathPrefix = sysroot; |
| pathString = s.substring(SYSROOT_START.length(), s.length()); |
| } else if (s.startsWith(WORKSPACE_START)) { |
| pathPrefix = PathFragment.EMPTY_FRAGMENT; |
| pathString = s.substring(WORKSPACE_START.length(), s.length()); |
| } else { |
| pathPrefix = crosstoolTopPathFragment; |
| if (s.startsWith(CROSSTOOL_START)) { |
| pathString = s.substring(CROSSTOOL_START.length(), s.length()); |
| } else if (s.startsWith("%")) { |
| throw new InvalidConfigurationException( |
| "The include path '" + s + "' has an " + "unrecognized %prefix%"); |
| } else { |
| pathString = s; |
| } |
| } |
| |
| PathFragment path = new PathFragment(pathString); |
| if (!path.isNormalized()) { |
| throw new InvalidConfigurationException("The include path '" + s + "' is not normalized."); |
| } |
| return pathPrefix.getRelative(path); |
| } |
| |
| @VisibleForTesting |
| ImmutableList<String> configureLinkerOptions( |
| CompilationMode compilationMode, LipoMode lipoMode, LinkingMode linkingMode, |
| PathFragment ldExecutable, boolean stripBinaries) { |
| List<String> result = new ArrayList<>(); |
| result.addAll(commonLinkOptions); |
| |
| if (stripBinaries) { |
| result.add("-Wl,-S"); |
| } |
| |
| result.addAll(linkOptionsFromCompilationMode.get(compilationMode)); |
| result.addAll(linkOptionsFromLipoMode.get(lipoMode)); |
| result.addAll(linkOptionsFromLinkingMode.get(linkingMode)); |
| return ImmutableList.copyOf(result); |
| } |
| |
| /** |
| * Returns the toolchain identifier, which uniquely identifies the compiler |
| * version, target libc version, target cpu, and LIPO linkage. |
| */ |
| public String getToolchainIdentifier() { |
| return toolchainIdentifier; |
| } |
| |
| /** |
| * Returns the path of the crosstool. |
| */ |
| public PathFragment getCrosstoolTopPathFragment() { |
| return crosstoolTopPathFragment; |
| } |
| |
| /** |
| * 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"). |
| */ |
| @SkylarkCallable(name = "compiler", structField = true, doc = "C++ compiler.") |
| public String getCompiler() { |
| return compiler; |
| } |
| |
| /** |
| * Returns the libc version string (e.g. "glibc-2.2.2"). |
| */ |
| @SkylarkCallable(name = "libc", structField = true, doc = "libc version string.") |
| public String getTargetLibc() { |
| return targetLibc; |
| } |
| |
| /** |
| * Returns the target architecture using blaze-specific constants (e.g. "piii"). |
| */ |
| @SkylarkCallable(name = "cpu", structField = true, doc = "Target CPU of the C++ toolchain.") |
| public String getTargetCpu() { |
| return targetCpu; |
| } |
| |
| /** |
| * Returns the path fragment that is either absolute or relative to the |
| * execution root that can be used to execute the given tool. |
| * |
| * <p>Note that you must not use this method to get the linker location, but |
| * use {@link #getLdExecutable} instead! |
| */ |
| public PathFragment getToolPathFragment(CppConfiguration.Tool tool) { |
| return toolPaths.get(tool.getNamePart()); |
| } |
| |
| /** |
| * Returns a label that forms a dependency to the files required for the |
| * sysroot that is used. |
| */ |
| public Label getLibcLabel() { |
| return libcLabel; |
| } |
| |
| /** |
| * 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 supportsEmbeddedRuntimes() ? staticRuntimeLibsLabel : null; |
| } |
| |
| /** |
| * 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 supportsEmbeddedRuntimes() ? dynamicRuntimeLibsLabel : null; |
| } |
| |
| /** |
| * Returns the label of the <code>cc_compiler</code> rule for the C++ configuration. |
| */ |
| public Label getCcToolchainRuleLabel() { |
| return ccToolchainLabel; |
| } |
| |
| /** |
| * 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 the configured current compilation mode. Rules should not call this directly, but |
| * instead use {@code CcToolchainProvider.getCompilationMode}. |
| */ |
| public CompilationMode getCompilationMode() { |
| return compilationMode; |
| } |
| |
| /** |
| * Returns whether the toolchain supports the gold linker. |
| */ |
| public boolean supportsGoldLinker() { |
| return supportsGoldLinker; |
| } |
| |
| /** |
| * 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 build_interface_so can build interface shared objects for this toolchain. |
| * Should be true if this toolchain generates ELF objects. |
| */ |
| public boolean supportsInterfaceSharedObjects() { |
| return supportsInterfaceSharedObjects; |
| } |
| |
| /** |
| * 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 EXEC_ORIGIN libraries resolution. |
| */ |
| public boolean supportsExecOrigin() { |
| // We're rolling out support for this in the same release that also supports embedded runtimes. |
| 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 whether binaries must be compiled with position independent code. |
| */ |
| public boolean usePicForBinaries() { |
| return usePicForBinaries; |
| } |
| |
| /** |
| * Returns the type of archives being used. |
| */ |
| public Link.ArchiveType archiveType() { |
| return useStartEndLib() ? Link.ArchiveType.START_END_LIB : Link.ArchiveType.REGULAR; |
| } |
| |
| /** |
| * Returns the ar flags to be used. |
| */ |
| public ImmutableList<String> getArFlags() { |
| return arOptions; |
| } |
| |
| /** |
| * Returns the built-in list of system include paths for the toolchain |
| * compiler. All paths in this list should be relative to the exec directory. |
| * They may be absolute if they are also installed on the remote build nodes or |
| * for local compilation. |
| */ |
| @SkylarkCallable(name = "built_in_include_directories", structField = true, |
| doc = "Built-in system include paths for the toolchain compiler. All paths in this list" |
| + " should be relative to the exec directory. They may be absolute if they are also installed" |
| + " on the remote build nodes or for local compilation.") |
| public List<PathFragment> getBuiltInIncludeDirectories() { |
| return builtInIncludeDirectories; |
| } |
| |
| /** |
| * Returns the sysroot to be used. If the toolchain compiler does not support |
| * different sysroots, or the sysroot is the same as the default sysroot, then |
| * this method returns <code>null</code>. |
| */ |
| @SkylarkCallable(name = "sysroot", structField = true, |
| doc = "Returns the sysroot to be used. If the toolchain compiler does not support " |
| + "different sysroots, or the sysroot is the same as the default sysroot, then " |
| + "this method returns <code>None</code>.") |
| public PathFragment getSysroot() { |
| return sysroot; |
| } |
| |
| /** |
| * 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 the default options to use for compiling C, C++, and assembler. |
| * This is just the options that should be used for all three languages. |
| * There may be additional C-specific or C++-specific options that should be used, |
| * in addition to the ones returned by this method. |
| */ |
| @SkylarkCallable( |
| name = "compiler_options", |
| doc = |
| "Returns the default options to use for compiling C, C++, and assembler. " |
| + "This is just the options that should be used for all three languages. " |
| + "There may be additional C-specific or C++-specific options that should be used, " |
| + "in addition to the ones returned by this method" |
| ) |
| public ImmutableList<String> getCompilerOptions(Iterable<String> features) { |
| return compilerFlags.evaluate(features); |
| } |
| |
| /** |
| * Returns the list of additional C-specific options to use for compiling |
| * C. These should be go on the command line after the common options |
| * returned by {@link #getCompilerOptions}. |
| */ |
| @SkylarkCallable(name = "c_options", structField = true, |
| doc = "Returns the list of additional C-specific options to use for compiling C. " |
| + "These should be go on the command line after the common options returned by " |
| + "<code>compiler_options</code>") |
| public ImmutableList<String> getCOptions() { |
| return cOptions; |
| } |
| |
| /** |
| * Returns the list of additional C++-specific options to use for compiling |
| * C++. These should be go on the command line after the common options |
| * returned by {@link #getCompilerOptions}. |
| */ |
| @SkylarkCallable( |
| name = "cxx_options", |
| doc = |
| "Returns the list of additional C++-specific options to use for compiling C++. " |
| + "These should be go on the command line after the common options returned by " |
| + "<code>compiler_options</code>" |
| ) |
| public ImmutableList<String> getCxxOptions(Iterable<String> features) { |
| return cxxFlags.evaluate(features); |
| } |
| |
| /** |
| * Returns the default list of options which cannot be filtered by BUILD |
| * rules. These should be appended to the command line after filtering. |
| */ |
| @SkylarkCallable( |
| name = "unfiltered_compiler_options", |
| doc = |
| "Returns the default list of options which cannot be filtered by BUILD " |
| + "rules. These should be appended to the command line after filtering." |
| ) |
| public ImmutableList<String> getUnfilteredCompilerOptions(Iterable<String> features) { |
| return unfilteredCompilerFlags.evaluate(features); |
| } |
| |
| /** |
| * Returns the set of command-line linker options, including any flags |
| * inferred from the command-line options. |
| * |
| * @see Link |
| */ |
| // TODO(bazel-team): Clean up the linker options computation! |
| @SkylarkCallable(name = "link_options", structField = true, |
| doc = "Returns the set of command-line linker options, including any flags " |
| + "inferred from the command-line options.") |
| public ImmutableList<String> getLinkOptions() { |
| return linkOptions; |
| } |
| |
| /** Returns the set of command-line LTO indexing options. */ |
| public ImmutableList<String> getLTOIndexOptions() { |
| return ltoindexOptions; |
| } |
| |
| /** |
| * Returns the immutable list of linker options for fully statically linked |
| * outputs. Does not include command-line options passed via --linkopt or |
| * --linkopts. |
| * |
| * @param features default settings affecting this link |
| * @param sharedLib true if the output is a shared lib, false if it's an executable |
| */ |
| @SkylarkCallable( |
| name = "fully_static_link_options", |
| doc = |
| "Returns the immutable list of linker options for fully statically linked " |
| + "outputs. Does not include command-line options passed via --linkopt or " |
| + "--linkopts." |
| ) |
| public ImmutableList<String> getFullyStaticLinkOptions(Iterable<String> features, |
| Boolean sharedLib) { |
| if (sharedLib) { |
| return getSharedLibraryLinkOptions(mostlyStaticLinkFlags, features); |
| } else { |
| return fullyStaticLinkFlags.evaluate(features); |
| } |
| } |
| |
| /** |
| * Returns the immutable list of linker options for mostly statically linked |
| * outputs. Does not include command-line options passed via --linkopt or |
| * --linkopts. |
| * |
| * @param features default settings affecting this link |
| * @param sharedLib true if the output is a shared lib, false if it's an executable |
| */ |
| @SkylarkCallable( |
| name = "mostly_static_link_options", |
| doc = |
| "Returns the immutable list of linker options for mostly statically linked " |
| + "outputs. Does not include command-line options passed via --linkopt or " |
| + "--linkopts." |
| ) |
| public ImmutableList<String> getMostlyStaticLinkOptions(Iterable<String> features, |
| Boolean sharedLib) { |
| if (sharedLib) { |
| return getSharedLibraryLinkOptions( |
| supportsEmbeddedRuntimes ? mostlyStaticSharedLinkFlags : dynamicLinkFlags, |
| features); |
| } else { |
| return mostlyStaticLinkFlags.evaluate(features); |
| } |
| } |
| |
| /** |
| * Returns the immutable list of linker options for artifacts that are not |
| * fully or mostly statically linked. Does not include command-line options |
| * passed via --linkopt or --linkopts. |
| * |
| * @param features default settings affecting this link |
| * @param sharedLib true if the output is a shared lib, false if it's an executable |
| */ |
| @SkylarkCallable( |
| name = "dynamic_link_options", |
| doc = |
| "Returns the immutable list of linker options for artifacts that are not " |
| + "fully or mostly statically linked. Does not include command-line options " |
| + "passed via --linkopt or --linkopts." |
| ) |
| public ImmutableList<String> getDynamicLinkOptions(Iterable<String> features, Boolean sharedLib) { |
| if (sharedLib) { |
| return getSharedLibraryLinkOptions(dynamicLinkFlags, features); |
| } else { |
| return dynamicLinkFlags.evaluate(features); |
| } |
| } |
| |
| /** |
| * Returns link options for the specified flag list, combined with universal options |
| * for all shared libraries (regardless of link staticness). |
| */ |
| private ImmutableList<String> getSharedLibraryLinkOptions(FlagList flags, |
| Iterable<String> features) { |
| return ImmutableList.<String>builder() |
| .addAll(flags.evaluate(features)) |
| .addAll(dynamicLibraryLinkFlags.evaluate(features)) |
| .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 objcopyOptions; |
| } |
| |
| /** |
| * 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 ldOptions; |
| } |
| |
| /** |
| * 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. |
| */ |
| @VisibleForTesting |
| public ImmutableMap<String, String> getAdditionalMakeVariables() { |
| return additionalMakeVariables; |
| } |
| |
| /** |
| * Returns the execution path to the linker binary to use for this build. |
| * Relative paths are relative to the execution root. |
| */ |
| public PathFragment getLdExecutable() { |
| return ldExecutable; |
| } |
| |
| /** |
| * Returns the dynamic linking mode (full, off, or default). |
| */ |
| public DynamicMode getDynamicMode() { |
| return dynamicMode; |
| } |
| |
| /* |
| * If true then the directory name for non-LIPO targets will have a '-lipodata' suffix in |
| * AutoFDO mode. |
| */ |
| public boolean getAutoFdoLipoData() { |
| return cppOptions.autoFdoLipoData; |
| } |
| |
| /** |
| * Returns the STL label if given on the command line. {@code null} |
| * otherwise. |
| */ |
| public Label getStl() { |
| return cppOptions.stl; |
| } |
| |
| /** |
| * Returns the currently active LIPO compilation mode. |
| */ |
| public LipoMode getLipoMode() { |
| return cppOptions.lipoMode; |
| } |
| |
| public boolean isFdo() { |
| return cppOptions.isFdo(); |
| } |
| |
| public boolean isLipoOptimization() { |
| // The LIPO optimization bits are set in the LIPO context collector configuration, too. |
| return cppOptions.isLipoOptimization() && !isLipoContextCollector(); |
| } |
| |
| public boolean isLipoOptimizationOrInstrumentation() { |
| return cppOptions.isLipoOptimizationOrInstrumentation() && !isLipoContextCollector(); |
| } |
| |
| /** |
| * Returns true if it is AutoFDO LIPO build. |
| */ |
| public boolean isAutoFdoLipo() { |
| return cppOptions.fdoOptimize != null |
| && CppFileTypes.GCC_AUTO_PROFILE.matches(cppOptions.fdoOptimize) |
| && getLipoMode() != LipoMode.OFF; |
| } |
| |
| /** |
| * Returns whether or not to strip the binaries. |
| */ |
| public boolean shouldStripBinaries() { |
| return stripBinaries; |
| } |
| |
| /** |
| * Returns the additional options to pass to strip when generating a |
| * {@code <name>.stripped} binary by this build. |
| */ |
| public ImmutableList<String> getStripOpts() { |
| return ImmutableList.copyOf(cppOptions.stripoptList); |
| } |
| |
| /** |
| * Returns whether temporary outputs from gcc will be saved. |
| */ |
| public boolean getSaveTemps() { |
| return cppOptions.saveTemps; |
| } |
| |
| /** |
| * Returns the {@link PerLabelOptions} to apply to the gcc command line, if |
| * the label of the compiled file matches the regular expression. |
| */ |
| public ImmutableList<PerLabelOptions> getPerFileCopts() { |
| return ImmutableList.copyOf(cppOptions.perFileCopts); |
| } |
| |
| public Label getLipoContextLabel() { |
| return cppOptions.getLipoContextLabel(); |
| } |
| |
| /** |
| * Returns the custom malloc library label. |
| */ |
| public Label customMalloc() { |
| return cppOptions.customMalloc; |
| } |
| |
| /** |
| * Returns true if mostly-static C++ binaries should be skipped. |
| */ |
| public boolean skipStaticOutputs() { |
| return cppOptions.skipStaticOutputs; |
| } |
| |
| /** |
| * Returns whether we are processing headers in dependencies of built C++ targets. |
| */ |
| public boolean processHeadersInDependencies() { |
| return cppOptions.processHeadersInDependencies; |
| } |
| |
| /** |
| * Returns true if Fission is specified for this build and supported by the crosstool. |
| */ |
| public boolean useFission() { |
| return cppOptions.fissionModes.contains(compilationMode) && supportsFission(); |
| } |
| |
| /** |
| * Returns true if Fission is enabled for this build and the user requested automatic building |
| * of .dwp files for C++ test targets. |
| */ |
| public boolean shouldBuildTestDwp() { |
| return useFission() && cppOptions.buildTestDwp; |
| } |
| |
| /** |
| * Returns true if all C++ compilations should produce position-independent code, links should |
| * produce position-independent executables, and dependencies with equivalent pre-built pic and |
| * nopic versions should apply the pic versions. Returns false if default settings should be |
| * applied (i.e. make no special provisions for pic code). |
| */ |
| public boolean forcePic() { |
| return cppOptions.forcePic; |
| } |
| |
| public boolean useStartEndLib() { |
| return cppOptions.useStartEndLib && supportsStartEndLib(); |
| } |
| |
| /** |
| * Returns true if interface shared objects should be used. |
| */ |
| public boolean useInterfaceSharedObjects() { |
| return supportsInterfaceSharedObjects() && cppOptions.useInterfaceSharedObjects; |
| } |
| |
| public boolean forceIgnoreDashStatic() { |
| return cppOptions.forceIgnoreDashStatic; |
| } |
| |
| /** |
| * Returns true if shared libraries must be compiled with position independent code |
| * on this platform or in this configuration. |
| */ |
| public boolean needsPic() { |
| return forcePic() || toolchainNeedsPic(); |
| } |
| |
| /** |
| * Returns true iff we should use ".pic.o" files when linking executables. |
| */ |
| public boolean usePicObjectsForBinaries() { |
| return forcePic() || usePicForBinaries(); |
| } |
| |
| public boolean legacyWholeArchive() { |
| return cppOptions.legacyWholeArchive; |
| } |
| |
| public boolean getSymbolCounts() { |
| return cppOptions.symbolCounts; |
| } |
| |
| public boolean getInmemoryDotdFiles() { |
| return cppOptions.inmemoryDotdFiles; |
| } |
| |
| public boolean getSkipUnusedModules() { |
| return cppOptions.skipUnusedModules; |
| } |
| |
| public boolean getPruneMoreModules() { |
| return cppOptions.pruneMoreModules; |
| } |
| |
| public LibcTop getLibcTop() { |
| return cppOptions.libcTop; |
| } |
| |
| public boolean getUseInterfaceSharedObjects() { |
| return cppOptions.useInterfaceSharedObjects; |
| } |
| |
| /** |
| * 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 path to the GNU binutils 'objcopy' binary to use for this |
| * build. (Corresponds to $(OBJCOPY) in make-dbg.) Relative paths are |
| * relative to the execution root. |
| */ |
| @SkylarkCallable(name = "objcopy_executable", structField = true, |
| doc = "Path to GNU binutils 'objcopy' binary") |
| public PathFragment getObjCopyExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.OBJCOPY); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'gcc' binary that should be used |
| * by this build. This binary should support compilation of both C (*.c) |
| * and C++ (*.cc) files. Relative paths are relative to the execution root. |
| */ |
| @SkylarkCallable(name = "compiler_executable", structField = true, |
| doc = "Path to C/C++ compiler binary") |
| public PathFragment getCppExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.GCC); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'g++' binary that should be used |
| * by this build. This binary should support linking of both C (*.c) |
| * and C++ (*.cc) files. Relative paths are relative to the execution root. |
| */ |
| public PathFragment getCppLinkExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.GCC); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'cpp' binary that should be used |
| * by this build. Relative paths are relative to the execution root. |
| */ |
| @SkylarkCallable(name = "preprocessor_executable", structField = true, |
| doc = "Path to C/C++ preprocessor binary") |
| public PathFragment getCpreprocessorExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.CPP); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'gcov' binary that should be used |
| * by this build to analyze C++ coverage data. Relative paths are relative to |
| * the execution root. |
| */ |
| public PathFragment getGcovExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.GCOV); |
| } |
| |
| /** |
| * Returns the path to the 'gcov-tool' executable that should be used |
| * by this build. Relative paths are relative to the execution root. |
| */ |
| public PathFragment getGcovToolExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.GCOVTOOL); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'nm' executable that should be used |
| * by this build. Used only for testing. Relative paths are relative to the |
| * execution root. |
| */ |
| @SkylarkCallable(name = "nm_executable", structField = true, |
| doc = "Path to GNU binutils 'nm' binary") |
| public PathFragment getNmExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.NM); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'objdump' executable that should be |
| * used by this build. Used only for testing. Relative paths are relative to |
| * the execution root. |
| */ |
| @SkylarkCallable(name = "objdump_executable", structField = true, |
| doc = "Path to GNU binutils 'objdump' binary") |
| public PathFragment getObjdumpExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.OBJDUMP); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'ar' binary to use for this build. |
| * Relative paths are relative to the execution root. |
| */ |
| @SkylarkCallable(name = "ar_executable", structField = true, |
| doc = "Path to GNU binutils 'ar' binary") |
| public PathFragment getArExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.AR); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'strip' executable that should be used |
| * by this build. Relative paths are relative to the execution root. |
| */ |
| @SkylarkCallable(name = "strip_executable", structField = true, |
| doc = "Path to GNU binutils 'strip' binary") |
| public PathFragment getStripExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.STRIP); |
| } |
| |
| /** |
| * Returns the path to the GNU binutils 'dwp' binary that should be used by this |
| * build to combine debug info output from individual C++ compilations (i.e. .dwo |
| * files) into aggregate target-level debug packages. Relative paths are relative to the |
| * execution root. See https://gcc.gnu.org/wiki/DebugFission . |
| */ |
| public PathFragment getDwpExecutable() { |
| return getToolPathFragment(CppConfiguration.Tool.DWP); |
| } |
| |
| /** |
| * Returns the GNU System Name |
| */ |
| @SkylarkCallable(name = "target_gnu_system_name", structField = true, |
| doc = "The GNU System Name.") |
| 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('-')); |
| } |
| |
| /** |
| * Returns whether the configuration's purpose is only to collect LIPO-related data. |
| */ |
| public boolean isLipoContextCollector() { |
| return lipoContextCollector; |
| } |
| |
| @Override |
| public void reportInvalidOptions(EventHandler reporter, BuildOptions buildOptions) { |
| CppOptions cppOptions = buildOptions.get(CppOptions.class); |
| if (stripBinaries) { |
| boolean warn = cppOptions.coptList.contains("-g"); |
| for (PerLabelOptions opt : cppOptions.perFileCopts) { |
| warn |= opt.getOptions().contains("-g"); |
| } |
| if (warn) { |
| reporter.handle(Event.warn("Stripping enabled, but '--copt=-g' (or --per_file_copt=...@-g) " |
| + "specified. Debug information will be generated and then stripped away. This is " |
| + "probably not what you want! Use '-c dbg' for debug mode, or use '--strip=never' " |
| + "to disable stripping")); |
| } |
| } |
| |
| if (cppOptions.fdoInstrument != null && cppOptions.fdoOptimize != null) { |
| reporter.handle(Event.error("Cannot instrument and optimize for FDO at the same time. " |
| + "Remove one of the '--fdo_instrument' and '--fdo_optimize' options")); |
| } |
| |
| if (cppOptions.lipoContext != null) { |
| if (cppOptions.lipoMode != LipoMode.BINARY || cppOptions.fdoOptimize == null) { |
| reporter.handle(Event.warn("The --lipo_context option can only be used together with " |
| + "--fdo_optimize=<profile zip> and --lipo=binary. LIPO context will be ignored.")); |
| } |
| } else { |
| if (cppOptions.lipoMode == LipoMode.BINARY && cppOptions.fdoOptimize != null) { |
| reporter.handle(Event.error("The --lipo_context option must be specified when using " |
| + "--fdo_optimize=<profile zip> and --lipo=binary")); |
| } |
| } |
| if (cppOptions.lipoMode == LipoMode.BINARY && compilationMode != CompilationMode.OPT) { |
| reporter.handle(Event.error( |
| "'--lipo=binary' can only be used with '--compilation_mode=opt' (or '-c opt')")); |
| } |
| |
| if (cppOptions.fissionModes.contains(compilationMode) && !supportsFission()) { |
| reporter.handle( |
| Event.warn( |
| "Fission is not supported by this crosstool. Please use a supporting " |
| + "crosstool to enable fission")); |
| } |
| if (cppOptions.buildTestDwp && !useFission()) { |
| reporter.handle(Event.warn("Test dwp file requested, but Fission is not enabled. To " |
| + "generate a dwp for the test executable, use '--fission=yes' with a toolchain " |
| + "that supports Fission and build statically.")); |
| } |
| } |
| |
| @Override |
| public void addGlobalMakeVariables(Builder<String, String> globalMakeEnvBuilder) { |
| // hardcoded CC->gcc setting for unit tests |
| globalMakeEnvBuilder.put("CC", getCppExecutable().getPathString()); |
| |
| // Make variables provided by crosstool/gcc compiler suite. |
| globalMakeEnvBuilder.put("AR", getArExecutable().getPathString()); |
| globalMakeEnvBuilder.put("NM", getNmExecutable().getPathString()); |
| PathFragment objcopyTool = getObjCopyExecutable(); |
| if (objcopyTool != null) { |
| // objcopy is optional in Crosstool |
| globalMakeEnvBuilder.put("OBJCOPY", objcopyTool.getPathString()); |
| } |
| globalMakeEnvBuilder.put("STRIP", getStripExecutable().getPathString()); |
| |
| PathFragment gcovtool = getGcovToolExecutable(); |
| if (gcovtool != null) { |
| // gcov-tool is optional in Crosstool |
| globalMakeEnvBuilder.put("GCOVTOOL", gcovtool.getPathString()); |
| } |
| |
| if (getTargetLibc().startsWith("glibc-")) { |
| globalMakeEnvBuilder.put("GLIBC_VERSION", |
| getTargetLibc().substring("glibc-".length())); |
| } else { |
| globalMakeEnvBuilder.put("GLIBC_VERSION", getTargetLibc()); |
| } |
| |
| globalMakeEnvBuilder.put("C_COMPILER", getCompiler()); |
| globalMakeEnvBuilder.put("TARGET_CPU", getTargetCpu()); |
| |
| // Deprecated variables |
| |
| // TODO(bazel-team): delete all of these. |
| globalMakeEnvBuilder.put("CROSSTOOLTOP", crosstoolTopPathFragment.getPathString()); |
| |
| globalMakeEnvBuilder.putAll(getAdditionalMakeVariables()); |
| |
| globalMakeEnvBuilder.put("ABI_GLIBC_VERSION", getAbiGlibcVersion()); |
| globalMakeEnvBuilder.put("ABI", abi); |
| } |
| |
| @Override |
| public String getOutputDirectoryName() { |
| String lipoSuffix; |
| if (getLipoMode() != LipoMode.OFF && !isAutoFdoLipo()) { |
| lipoSuffix = "-lipo"; |
| } else if (getAutoFdoLipoData()) { |
| lipoSuffix = "-lipodata"; |
| } else { |
| lipoSuffix = ""; |
| } |
| return toolchainIdentifier + lipoSuffix; |
| } |
| |
| @Override |
| public String getPlatformName() { |
| return getToolchainIdentifier(); |
| } |
| |
| public boolean alwaysAttachExtraActions() { |
| return true; |
| } |
| |
| /** |
| * Returns true if we should share identical native libraries between different targets. |
| */ |
| public boolean shareNativeDeps() { |
| return cppOptions.shareNativeDeps; |
| } |
| |
| public boolean isStrictSystemIncludes() { |
| return cppOptions.strictSystemIncludes; |
| } |
| |
| @Override |
| public Map<String, Object> lateBoundOptionDefaults() { |
| // --cpu and --compiler initially default to null because their *actual* defaults aren't known |
| // until they're read from the CROSSTOOL. Feed the CROSSTOOL defaults in here. |
| return ImmutableMap.<String, Object>of( |
| "cpu", getTargetCpu(), |
| "compiler", getCompiler()); |
| } |
| |
| public PathFragment getFdoInstrument() { |
| return cppOptions.fdoInstrument; |
| } |
| |
| public Path getFdoZip() { |
| return fdoZip; |
| } |
| |
| /** |
| * Return set of features enabled by the CppConfiguration, specifically |
| * the FDO and LIPO related features enabled by options. |
| */ |
| @Override |
| public ImmutableSet<String> configurationEnabledFeatures(RuleContext ruleContext) { |
| ImmutableSet.Builder<String> requestedFeatures = ImmutableSet.builder(); |
| if (cppOptions.fdoInstrument != null) { |
| requestedFeatures.add(CppRuleClasses.FDO_INSTRUMENT); |
| } |
| |
| boolean isFdo = fdoZip != null && compilationMode == CompilationMode.OPT; |
| if (isFdo && !CppFileTypes.GCC_AUTO_PROFILE.matches(fdoZip)) { |
| requestedFeatures.add(CppRuleClasses.FDO_OPTIMIZE); |
| } |
| if (isFdo && CppFileTypes.GCC_AUTO_PROFILE.matches(fdoZip)) { |
| requestedFeatures.add(CppRuleClasses.AUTOFDO); |
| } |
| if (isLipoOptimizationOrInstrumentation()) { |
| requestedFeatures.add(CppRuleClasses.LIPO); |
| } |
| if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { |
| requestedFeatures.add(CppRuleClasses.COVERAGE); |
| } |
| return requestedFeatures.build(); |
| } |
| } |