diff options
Diffstat (limited to 'src')
16 files changed, 644 insertions, 330 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index 749f747f8c..507fc0b0fc 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -16,7 +16,6 @@ package com.google.devtools.build.lib.bazel.rules; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Functions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; @@ -109,6 +108,7 @@ import com.google.devtools.build.lib.rules.cpp.CppBuildInfo; import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader; import com.google.devtools.build.lib.rules.cpp.CppOptions; import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; +import com.google.devtools.build.lib.rules.cpp.CpuTransformer; import com.google.devtools.build.lib.rules.cpp.proto.CcProtoAspect; import com.google.devtools.build.lib.rules.cpp.proto.CcProtoLibraryRule; import com.google.devtools.build.lib.rules.extra.ActionListenerRule; @@ -342,8 +342,7 @@ public class BazelRuleClassProvider { public void init(Builder builder) { builder.addSkylarkAccessibleTopLevels("cc_common", CcModule.INSTANCE); - builder.addConfig( - CppOptions.class, new CppConfigurationLoader(Functions.<String>identity())); + builder.addConfig(CppOptions.class, new CppConfigurationLoader(CpuTransformer.IDENTITY)); builder.addBuildInfoFactory(new CppBuildInfo()); builder.addDynamicTransitionMaps(CppRuleClasses.DYNAMIC_TRANSITIONS_MAP); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java index 880495b011..bc9dbef87e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java @@ -322,7 +322,7 @@ public class CcToolchain implements RuleConfiguredTargetFactory { if (toolchain != null) { try { toolchainInfo = - new CppToolchainInfo( + CppToolchainInfo.create( toolchain, cppConfiguration.getCrosstoolTopPathFragment(), cppConfiguration.getCcToolchainRuleLabel()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java index bf53bd53c4..667f37804b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java @@ -43,9 +43,12 @@ import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader.CppConfigu import com.google.devtools.build.lib.rules.cpp.CrosstoolConfigurationLoader.CrosstoolFile; import com.google.devtools.build.lib.rules.cpp.transitions.ContextCollectorOwnerTransition; import com.google.devtools.build.lib.rules.cpp.transitions.DisableLipoTransition; +import com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; 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.vfs.FileSystemProvider; 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; @@ -59,13 +62,16 @@ import javax.annotation.Nullable; * architecture, target architecture, compiler version, and a standard library version. It has * information about the tools locations and the flags required for compiling. */ +@AutoCodec(dependency = FileSystemProvider.class) @SkylarkModule( name = "cpp", doc = "A configuration fragment for C++.", category = SkylarkModuleCategory.CONFIGURATION_FRAGMENT ) @Immutable -public class CppConfiguration extends BuildConfiguration.Fragment { +public final class CppConfiguration extends BuildConfiguration.Fragment { + public static final InjectingObjectCodec<CppConfiguration, FileSystemProvider> CODEC = + new CppConfiguration_AutoCodec(); /** * String indicating a Mac system, for example when used in a crosstool configuration's host or @@ -159,7 +165,6 @@ public class CppConfiguration extends BuildConfiguration.Fragment { // it here so that the output directory doesn't depend on the CToolchain. When we will eventually // verify that the two are the same, we can remove one of desiredCpu and targetCpu. private final String desiredCpu; - private final LipoMode lipoMode; private final boolean convertLipoToThinLto; private final PathFragment crosstoolTopPathFragment; @@ -190,7 +195,7 @@ public class CppConfiguration extends BuildConfiguration.Fragment { private final ImmutableList<String> ltoindexOptions; private final CppOptions cppOptions; - private final Function<String, String> cpuTransformer; + private final CpuTransformer cpuTransformerEnum; // The dynamic mode for linking. private final boolean stripBinaries; @@ -207,34 +212,14 @@ public class CppConfiguration extends BuildConfiguration.Fragment { private final CppToolchainInfo cppToolchainInfo; - protected CppConfiguration(CppConfigurationParameters params) + static CppConfiguration create(CppConfigurationParameters params) throws InvalidConfigurationException { CrosstoolConfig.CToolchain toolchain = params.toolchain; - cppOptions = params.cppOptions; - this.desiredCpu = Preconditions.checkNotNull(params.commonOptions.cpu); - this.lipoMode = cppOptions.getLipoMode(); - this.convertLipoToThinLto = cppOptions.convertLipoToThinLto; - this.crosstoolTop = params.crosstoolTop; - this.crosstoolFile = params.crosstoolFile; - this.ccToolchainLabel = params.ccToolchainLabel; - this.stlLabel = params.stlLabel; - this.compilationMode = params.commonOptions.compilationMode; - this.useLLVMCoverageMap = params.commonOptions.useLLVMCoverageMapFormat; - this.lipoContextCollector = cppOptions.isLipoContextCollector(); - this.crosstoolTopPathFragment = crosstoolTop.getPackageIdentifier().getPathUnderExecRoot(); - this.cpuTransformer = params.cpuTransformer; - this.cppToolchainInfo = new CppToolchainInfo(toolchain, crosstoolTopPathFragment, crosstoolTop); - this.shouldProvideMakeVariables = - params.commonOptions.makeVariableSource == MakeVariableSource.CONFIGURATION; - - this.fdoZip = params.fdoZip; - this.stripBinaries = - (cppOptions.stripBinaries == StripMode.ALWAYS - || (cppOptions.stripBinaries == StripMode.SOMETIMES - && compilationMode == CompilationMode.FASTBUILD)); - - this.copts = ImmutableList.copyOf(cppOptions.coptList); - this.cxxopts = ImmutableList.copyOf(cppOptions.cxxoptList); + CppOptions cppOptions = params.cppOptions; + PathFragment crosstoolTopPathFragment = + params.crosstoolTop.getPackageIdentifier().getPathUnderExecRoot(); + CppToolchainInfo cppToolchainInfo = + CppToolchainInfo.create(toolchain, crosstoolTopPathFragment, params.crosstoolTop); ListMultimap<CompilationMode, String> cFlags = ArrayListMultimap.create(); ListMultimap<CompilationMode, String> cxxFlags = ArrayListMultimap.create(); @@ -248,6 +233,8 @@ public class CppConfiguration extends BuildConfiguration.Fragment { cxxFlags.putAll(realmode, flags.getCxxFlagList()); } + CompilationMode compilationMode = params.commonOptions.compilationMode; + ListMultimap<LipoMode, String> lipoCFlags = ArrayListMultimap.create(); ListMultimap<LipoMode, String> lipoCxxFlags = ArrayListMultimap.create(); for (CrosstoolConfig.LipoModeFlags flags : toolchain.getLipoModeFlagsList()) { @@ -256,93 +243,165 @@ public class CppConfiguration extends BuildConfiguration.Fragment { lipoCxxFlags.putAll(realmode, flags.getCxxFlagList()); } - this.sysrootLabel = params.sysrootLabel; - this.nonConfiguredSysroot = - params.sysrootLabel == null - ? cppToolchainInfo.getDefaultSysroot() - : params.sysrootLabel.getPackageFragment(); - - ImmutableList.Builder<String> unfilteredCoptsBuilder = ImmutableList.builder(); + 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"); + } - unfilteredCoptsBuilder.addAll(toolchain.getUnfilteredCxxFlagList()); - unfilteredCompilerFlags = - new FlagList( - unfilteredCoptsBuilder.build(), - FlagList.convertOptionalOptions(toolchain.getOptionalUnfilteredCxxFlagList()), - ImmutableList.<String>of()); + ImmutableList.Builder<String> cxxOptsBuilder = + ImmutableList.<String>builder() + .addAll(toolchain.getCxxFlagList()) + .addAll(cxxFlags.get(compilationMode)) + .addAll(lipoCxxFlags.get(cppOptions.getLipoMode())); ImmutableList.Builder<String> linkoptsBuilder = ImmutableList.builder(); linkoptsBuilder.addAll(cppOptions.linkoptList); if (cppOptions.experimentalOmitfp) { linkoptsBuilder.add("-Wl,--eh-frame-hdr"); } - 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 = + return new CppConfiguration( + params.crosstoolTop, + params.crosstoolFile, + Preconditions.checkNotNull(params.commonOptions.cpu), + cppOptions.convertLipoToThinLto, + crosstoolTopPathFragment, + params.fdoZip, + params.ccToolchainLabel, + params.stlLabel, + params.sysrootLabel == null + ? cppToolchainInfo.getDefaultSysroot() + : params.sysrootLabel.getPackageFragment(), + params.sysrootLabel, new FlagList( coptsBuilder.build(), FlagList.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 = + ImmutableList.copyOf(cppOptions.coptList)), new FlagList( cxxOptsBuilder.build(), FlagList.convertOptionalOptions(toolchain.getOptionalCxxFlagList()), - ImmutableList.copyOf(cppOptions.cxxoptList)); - - fullyStaticLinkFlags = + ImmutableList.copyOf(cppOptions.cxxoptList)), + new FlagList( + ImmutableList.copyOf(toolchain.getUnfilteredCxxFlagList()), + FlagList.convertOptionalOptions(toolchain.getOptionalUnfilteredCxxFlagList()), + ImmutableList.<String>of()), + ImmutableList.copyOf(cppOptions.conlyoptList), new FlagList( - configureLinkerOptions( + cppToolchainInfo.configureLinkerOptions( compilationMode, - lipoMode, + cppOptions.getLipoMode(), LinkingMode.FULLY_STATIC, cppToolchainInfo.getLdExecutable()), FlagList.convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), - ImmutableList.<String>of()); - mostlyStaticLinkFlags = + ImmutableList.<String>of()), new FlagList( - configureLinkerOptions( + cppToolchainInfo.configureLinkerOptions( compilationMode, - lipoMode, + cppOptions.getLipoMode(), LinkingMode.MOSTLY_STATIC, cppToolchainInfo.getLdExecutable()), FlagList.convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), - ImmutableList.<String>of()); - mostlyStaticSharedLinkFlags = + ImmutableList.<String>of()), new FlagList( - configureLinkerOptions( + cppToolchainInfo.configureLinkerOptions( compilationMode, - lipoMode, + cppOptions.getLipoMode(), LinkingMode.MOSTLY_STATIC_LIBRARIES, cppToolchainInfo.getLdExecutable()), FlagList.convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), - ImmutableList.<String>of()); - dynamicLinkFlags = + ImmutableList.<String>of()), new FlagList( - configureLinkerOptions( - compilationMode, lipoMode, LinkingMode.DYNAMIC, cppToolchainInfo.getLdExecutable()), + cppToolchainInfo.configureLinkerOptions( + compilationMode, + cppOptions.getLipoMode(), + LinkingMode.DYNAMIC, + cppToolchainInfo.getLdExecutable()), FlagList.convertOptionalOptions(toolchain.getOptionalLinkerFlagList()), - ImmutableList.<String>of()); + ImmutableList.<String>of()), + ImmutableList.copyOf(cppOptions.coptList), + ImmutableList.copyOf(cppOptions.cxxoptList), + linkoptsBuilder.build(), + ImmutableList.copyOf(cppOptions.ltoindexoptList), + cppOptions, + params.cpuTransformer, + (cppOptions.stripBinaries == StripMode.ALWAYS + || (cppOptions.stripBinaries == StripMode.SOMETIMES + && compilationMode == CompilationMode.FASTBUILD)), + compilationMode, + params.commonOptions.useLLVMCoverageMapFormat, + params.commonOptions.makeVariableSource == MakeVariableSource.CONFIGURATION, + cppOptions.isLipoContextCollector(), + cppToolchainInfo); + } + + @AutoCodec.Constructor + CppConfiguration( + Label crosstoolTop, + CrosstoolFile crosstoolFile, + String desiredCpu, + boolean convertLipoToThinLto, + PathFragment crosstoolTopPathFragment, + Path fdoZip, + Label ccToolchainLabel, + Label stlLabel, + PathFragment nonConfiguredSysroot, + Label sysrootLabel, + FlagList compilerFlags, + FlagList cxxFlags, + FlagList unfilteredCompilerFlags, + ImmutableList<String> cOptions, + FlagList fullyStaticLinkFlags, + FlagList mostlyStaticLinkFlags, + FlagList mostlyStaticSharedLinkFlags, + FlagList dynamicLinkFlags, + ImmutableList<String> copts, + ImmutableList<String> cxxopts, + ImmutableList<String> linkOptions, + ImmutableList<String> ltoindexOptions, + CppOptions cppOptions, + CpuTransformer cpuTransformerEnum, + boolean stripBinaries, + CompilationMode compilationMode, + boolean useLLVMCoverageMap, + boolean shouldProvideMakeVariables, + boolean lipoContextCollector, + CppToolchainInfo cppToolchainInfo) { + this.crosstoolTop = crosstoolTop; + this.crosstoolFile = crosstoolFile; + this.desiredCpu = desiredCpu; + this.convertLipoToThinLto = convertLipoToThinLto; + this.crosstoolTopPathFragment = crosstoolTopPathFragment; + this.fdoZip = fdoZip; + this.ccToolchainLabel = ccToolchainLabel; + this.stlLabel = stlLabel; + this.nonConfiguredSysroot = nonConfiguredSysroot; + this.sysrootLabel = sysrootLabel; + this.compilerFlags = compilerFlags; + this.cxxFlags = cxxFlags; + this.unfilteredCompilerFlags = unfilteredCompilerFlags; + this.cOptions = cOptions; + this.fullyStaticLinkFlags = fullyStaticLinkFlags; + this.mostlyStaticLinkFlags = mostlyStaticLinkFlags; + this.mostlyStaticSharedLinkFlags = mostlyStaticSharedLinkFlags; + this.dynamicLinkFlags = dynamicLinkFlags; + this.copts = copts; + this.cxxopts = cxxopts; + this.linkOptions = linkOptions; + this.ltoindexOptions = ltoindexOptions; + this.cppOptions = cppOptions; + this.cpuTransformerEnum = cpuTransformerEnum; + this.stripBinaries = stripBinaries; + this.compilationMode = compilationMode; + this.useLLVMCoverageMap = useLLVMCoverageMap; + this.shouldProvideMakeVariables = shouldProvideMakeVariables; + this.lipoContextCollector = lipoContextCollector; + this.cppToolchainInfo = cppToolchainInfo; } @VisibleForTesting @@ -350,22 +409,6 @@ public class CppConfiguration extends BuildConfiguration.Fragment { return LinkingMode.valueOf(mode.name()); } - /** - * Deprecated: Use {@link CcToolchainProvider#configureLinkerOptions(CompilationMode, LipoMode, - * LinkingMode, PathFragment)} - */ - @VisibleForTesting - @Deprecated - // TODO(b/64384912): Remove skylark dependants and delete. - private ImmutableList<String> configureLinkerOptions( - CompilationMode compilationMode, - LipoMode lipoMode, - LinkingMode linkingMode, - PathFragment ldExecutable) { - return cppToolchainInfo.configureLinkerOptions( - compilationMode, lipoMode, linkingMode, ldExecutable); - } - /** Returns the {@link CppToolchainInfo} used by this configuration. */ public CppToolchainInfo getCppToolchainInfo() { return cppToolchainInfo; @@ -391,7 +434,7 @@ public class CppConfiguration extends BuildConfiguration.Fragment { /** Returns the transformer that should be applied to cpu names in toolchain selection. */ public Function<String, String> getCpuTransformer() { - return cpuTransformer; + return cpuTransformerEnum.getTransformer(); } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java index 7ede7d4fdc..57a5a0487f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.rules.cpp; -import com.google.common.base.Function; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.RedirectChaser; @@ -57,14 +56,13 @@ public class CppConfigurationLoader implements ConfigurationFragmentFactory { return ImmutableSet.<Class<? extends FragmentOptions>>of(CppOptions.class); } - private final Function<String, String> cpuTransformer; + private final CpuTransformer cpuTransformer; /** - * Creates a new CrosstoolConfigurationLoader instance with the given - * configuration provider. The configuration provider is used to perform - * caller-specific configuration file lookup. + * Creates a new CrosstoolConfigurationLoader instance with the given configuration provider. The + * configuration provider is used to perform caller-specific configuration file lookup. */ - public CppConfigurationLoader(Function<String, String> cpuTransformer) { + public CppConfigurationLoader(CpuTransformer cpuTransformer) { this.cpuTransformer = cpuTransformer; } @@ -75,7 +73,7 @@ public class CppConfigurationLoader implements ConfigurationFragmentFactory { if (params == null) { return null; } - return new CppConfiguration(params); + return CppConfiguration.create(params); } /** @@ -92,7 +90,7 @@ public class CppConfigurationLoader implements ConfigurationFragmentFactory { protected final Label stlLabel; protected final Path fdoZip; protected final Label sysrootLabel; - protected final Function<String, String> cpuTransformer; + protected final CpuTransformer cpuTransformer; CppConfigurationParameters( CrosstoolConfig.CToolchain toolchain, @@ -104,7 +102,7 @@ public class CppConfigurationLoader implements ConfigurationFragmentFactory { Label ccToolchainLabel, Label stlLabel, Label sysrootLabel, - Function<String, String> cpuTransformer) { + CpuTransformer cpuTransformer) { this.toolchain = toolchain; this.crosstoolFile = crosstoolFile; this.cacheKeySuffix = cacheKeySuffix; @@ -148,7 +146,8 @@ public class CppConfigurationLoader implements ConfigurationFragmentFactory { return null; } CrosstoolConfig.CToolchain toolchain = - CrosstoolConfigurationLoader.selectToolchain(file.getProto(), options, cpuTransformer); + CrosstoolConfigurationLoader.selectToolchain( + file.getProto(), options, cpuTransformer.getTransformer()); // FDO // TODO(bazel-team): move this to CppConfiguration.prepareHook diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java index be90290faf..5b87c548e1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java @@ -15,7 +15,6 @@ package com.google.devtools.build.lib.rules.cpp; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; @@ -30,6 +29,8 @@ import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.rules.cpp.CppActionConfigs.CppPlatform; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool; +import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; 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; @@ -55,8 +56,10 @@ import java.util.Set; * <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 { + public static final ObjectCodec<CppToolchainInfo> CODEC = new CppToolchainInfo_AutoCodec(); private CToolchain toolchain; private final PathFragment crosstoolTopPathFragment; @@ -83,8 +86,8 @@ public final class CppToolchainInfo { private final ImmutableListMultimap<LipoMode, String> linkOptionsFromLipoMode; private final ImmutableListMultimap<CompilationMode, String> linkOptionsFromCompilationMode; private final ImmutableList<String> testOnlyLinkFlags; - private final ImmutableList<String> ldOptions; - private final ImmutableList<String> objcopyOptions; + private final ImmutableList<String> ldOptionsForEmbedding; + private final ImmutableList<String> objCopyOptionsForEmbedding; private final Label staticRuntimeLibsLabel; private final Label dynamicRuntimeLibsLabel; @@ -99,8 +102,8 @@ public final class CppToolchainInfo { private final ImmutableList<OptionalFlag> crosstoolOptionalCompilerFlags; private final ImmutableList<OptionalFlag> crosstoolOptionalCxxFlags; - private final ImmutableListMultimap<CompilationMode, String> cFlags; - private final ImmutableListMultimap<CompilationMode, String> cxxFlags; + private final ImmutableListMultimap<CompilationMode, String> cFlagsByCompilationMode; + private final ImmutableListMultimap<CompilationMode, String> cxxFlagsByCompilationMode; private final ImmutableListMultimap<LipoMode, String> lipoCFlags; private final ImmutableListMultimap<LipoMode, String> lipoCxxFlags; @@ -113,103 +116,31 @@ public final class CppToolchainInfo { private final boolean toolchainNeedsPic; /** Creates a CppToolchainInfo from a toolchain. */ - public CppToolchainInfo( - CToolchain cToolchain, PathFragment crosstoolTopPathFragment, Label toolchainLabel) + public static CppToolchainInfo create( + CToolchain inputToolchain, PathFragment crosstoolTopPathFragment, Label toolchainLabel) throws InvalidConfigurationException { - this.toolchain = cToolchain; - this.crosstoolTopPathFragment = crosstoolTopPathFragment; - this.hostSystemName = toolchain.getHostSystemName(); - this.compiler = toolchain.getCompiler(); - this.targetCpu = toolchain.getTargetCpu(); - this.targetSystemName = toolchain.getTargetSystemName(); - this.targetLibc = toolchain.getTargetLibc(); - this.targetOS = toolchain.getCcTargetOs(); - - try { - this.staticRuntimeLibsLabel = - toolchainLabel.getRelative( - toolchain.hasStaticRuntimesFilegroup() - ? toolchain.getStaticRuntimesFilegroup() - : "static-runtime-libs-" + targetCpu); - this.dynamicRuntimeLibsLabel = - toolchainLabel.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); - } + CToolchain toolchain = addLegacyFeatures(inputToolchain, crosstoolTopPathFragment); + ImmutableMap<String, PathFragment> toolPaths = + computeToolPaths(toolchain, crosstoolTopPathFragment); + PathFragment defaultSysroot = CppConfiguration.computeDefaultSysroot(toolchain); - // Needs to be set before the first call to isLLVMCompiler(). - this.toolchainIdentifier = toolchain.getToolchainIdentifier(); - - 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.supportsEmbeddedRuntimes = toolchain.getSupportsEmbeddedRuntimes(); - this.toolchain = addLegacyFeatures(toolchain); - this.toolchainFeatures = new CcToolchainFeatures(toolchain); - this.supportsGoldLinker = toolchain.getSupportsGoldLinker(); - this.supportsStartEndLib = toolchain.getSupportsStartEndLib(); - this.supportsInterfaceSharedObjects = toolchain.getSupportsInterfaceSharedObjects(); - this.supportsFission = toolchain.getSupportsFission(); + ImmutableListMultimap.Builder<LinkingMode, String> linkOptionsFromLinkingModeBuilder = + ImmutableListMultimap.builder(); - Map<String, PathFragment> toolPathsCollector = Maps.newHashMap(); - for (CrosstoolConfig.ToolPath tool : toolchain.getToolPathList()) { - PathFragment path = PathFragment.create(tool.getPath()); - if (!path.isNormalized()) { - throw new IllegalArgumentException( - "The include path '" + tool.getPath() + "' is not normalized."); - } - toolPathsCollector.put(tool.getName(), crosstoolTopPathFragment.getRelative(path)); - } + // 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; - if (toolPathsCollector.isEmpty()) { - // If no paths are specified, we just use the names of the tools as the path. - for (Tool tool : Tool.values()) { - toolPathsCollector.put( - tool.getNamePart(), crosstoolTopPathFragment.getRelative(tool.getNamePart())); - } - } else { - Iterable<Tool> neededTools = - Iterables.filter( - EnumSet.allOf(Tool.class), - tool -> { - if (tool == Tool.DWP) { - // When fission is unsupported, don't check for the dwp tool. - return supportsFission(); - } else if (tool == 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 == 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 (!toolPathsCollector.containsKey(tool.getNamePart())) { - throw new IllegalArgumentException( - "Tool path for '" + tool.getNamePart() + "' is missing"); - } + for (LinkingModeFlags flags : toolchain.getLinkingModeFlagsList()) { + LinkingMode realmode = CppConfiguration.importLinkingMode(flags.getMode()); + if (realmode == LinkingMode.DYNAMIC) { + haveDynamicMode = true; } + linkOptionsFromLinkingModeBuilder.putAll(realmode, flags.getLinkerFlagList()); } - this.toolPaths = ImmutableMap.copyOf(toolPathsCollector); - - this.crosstoolCompilerFlags = ImmutableList.copyOf(toolchain.getCompilerFlagList()); - this.crosstoolCxxFlags = ImmutableList.copyOf(toolchain.getCxxFlagList()); - this.crosstoolOptionalCompilerFlags = - ImmutableList.copyOf(toolchain.getOptionalCompilerFlagList()); - this.crosstoolOptionalCxxFlags = ImmutableList.copyOf(toolchain.getOptionalCxxFlagList()); ImmutableListMultimap.Builder<CompilationMode, String> cFlagsBuilder = ImmutableListMultimap.builder(); @@ -224,8 +155,6 @@ public final class CppToolchainInfo { cFlagsBuilder.putAll(realmode, flags.getCompilerFlagList()); cxxFlagsBuilder.putAll(realmode, flags.getCxxFlagList()); } - cFlags = cFlagsBuilder.build(); - cxxFlags = cxxFlagsBuilder.build(); ImmutableListMultimap.Builder<LipoMode, String> lipoCFlagsBuilder = ImmutableListMultimap.builder(); @@ -236,99 +165,164 @@ public final class CppToolchainInfo { lipoCFlagsBuilder.putAll(realmode, flags.getCompilerFlagList()); lipoCxxFlagsBuilder.putAll(realmode, flags.getCxxFlagList()); } - lipoCFlags = lipoCFlagsBuilder.build(); - lipoCxxFlags = lipoCxxFlagsBuilder.build(); - - ImmutableList.Builder<String> unfilteredCoptsBuilder = ImmutableList.builder(); - - unfilteredCoptsBuilder.addAll(toolchain.getUnfilteredCxxFlagList()); - - ImmutableListMultimap.Builder<CompilationMode, String> linkOptionsFromCompilationModeBuilder = - ImmutableListMultimap.builder(); - 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()); - linkOptionsFromCompilationModeBuilder.putAll(realmode, flags.getLinkerFlagList()); - } - linkOptionsFromCompilationMode = linkOptionsFromCompilationModeBuilder.build(); - - ImmutableListMultimap.Builder<LipoMode, String> linkOptionsFromLipoModeBuilder = - ImmutableListMultimap.builder(); - for (CrosstoolConfig.LipoModeFlags flags : toolchain.getLipoModeFlagsList()) { - LipoMode realmode = flags.getMode(); - linkOptionsFromLipoModeBuilder.putAll(realmode, flags.getLinkerFlagList()); - } - linkOptionsFromLipoMode = linkOptionsFromLipoModeBuilder.build(); - - ImmutableListMultimap.Builder<LinkingMode, String> linkOptionsFromLinkingModeBuilder = - ImmutableListMultimap.builder(); - - // 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 = CppConfiguration.importLinkingMode(flags.getMode()); - if (realmode == LinkingMode.DYNAMIC) { - haveDynamicMode = true; - } - linkOptionsFromLinkingModeBuilder.putAll(realmode, flags.getLinkerFlagList()); - } - linkOptionsFromLinkingMode = linkOptionsFromLinkingModeBuilder.build(); - - 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), - FlagList.convertOptionalOptions(optionalLinkerFlagList), - ImmutableList.<String>of()); - - this.objcopyOptions = ImmutableList.copyOf(toolchain.getObjcopyEmbedFlagList()); - this.ldOptions = ImmutableList.copyOf(toolchain.getLdEmbedFlagList()); - - this.abi = toolchain.getAbiVersion(); - this.abiGlibcVersion = toolchain.getAbiLibcVersion(); - - this.defaultSysroot = CppConfiguration.computeDefaultSysroot(toolchain); - - this.rawBuiltInIncludeDirectories = - ImmutableList.copyOf(toolchain.getCxxBuiltinIncludeDirectoryList()); - - // The default value for optional string attributes is the empty string. - - // 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; - - this.testOnlyLinkFlags = ImmutableList.copyOf(toolchain.getTestOnlyLinkerFlagList()); - this.toolchainNeedsPic = toolchain.getNeedsPic(); - - 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(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME, ""); - for (CrosstoolConfig.MakeVariable variable : toolchain.getMakeVariableList()) { - makeVariablesBuilder.put(variable.getName(), variable.getValue()); + try { + return new CppToolchainInfo( + toolchain, + crosstoolTopPathFragment, + toolchain.getToolchainIdentifier(), + toolPaths, + toolchain.getCompiler(), + getToolPathFragment(toolPaths, CppConfiguration.Tool.LD), + toolchain.getAbiLibcVersion(), + toolchain.getTargetCpu(), + toolchain.getCcTargetOs(), + ImmutableList.copyOf(toolchain.getCxxBuiltinIncludeDirectoryList()), + 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, + toolchain.getTargetLibc(), + toolchain.getHostSystemName(), + new FlagList( + ImmutableList.copyOf(toolchain.getDynamicLibraryLinkerFlagList()), + FlagList.convertOptionalOptions(toolchain.getOptionalDynamicLibraryLinkerFlagList()), + ImmutableList.<String>of()), + ImmutableList.copyOf(toolchain.getLinkerFlagList()), + linkOptionsFromLinkingModeBuilder.build(), + computeLinkOptionsFromLipoMode(toolchain), + computeLinkOptionsFromCompilationMode(toolchain), + ImmutableList.copyOf(toolchain.getTestOnlyLinkerFlagList()), + ImmutableList.copyOf(toolchain.getLdEmbedFlagList()), + ImmutableList.copyOf(toolchain.getObjcopyEmbedFlagList()), + toolchainLabel.getRelative( + toolchain.hasStaticRuntimesFilegroup() + ? toolchain.getStaticRuntimesFilegroup() + : "static-runtime-libs-" + toolchain.getTargetCpu()), + toolchainLabel.getRelative( + toolchain.hasDynamicRuntimesFilegroup() + ? toolchain.getDynamicRuntimesFilegroup() + : "dynamic-runtime-libs-" + toolchain.getTargetCpu()), + "_solib_" + toolchain.getTargetCpu(), + toolchain.getAbiVersion(), + toolchain.getTargetSystemName(), + computeAdditionalMakeVariables(toolchain), + ImmutableList.copyOf(toolchain.getCompilerFlagList()), + ImmutableList.copyOf(toolchain.getCxxFlagList()), + ImmutableList.copyOf(toolchain.getOptionalCompilerFlagList()), + ImmutableList.copyOf(toolchain.getOptionalCxxFlagList()), + cFlagsBuilder.build(), + cxxFlagsBuilder.build(), + lipoCFlagsBuilder.build(), + lipoCxxFlagsBuilder.build(), + toolchain.getSupportsFission(), + toolchain.getSupportsStartEndLib(), + toolchain.getSupportsEmbeddedRuntimes(), + haveDynamicMode + || !toolchain.getDynamicLibraryLinkerFlagList().isEmpty() + || !toolchain.getOptionalDynamicLibraryLinkerFlagList().isEmpty(), + toolchain.getSupportsInterfaceSharedObjects(), + toolchain.getSupportsGoldLinker(), + toolchain.getNeedsPic()); + } 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); } - this.additionalMakeVariables = ImmutableMap.copyOf(makeVariablesBuilder); + } - this.ldExecutable = getToolPathFragment(CppConfiguration.Tool.LD); + @AutoCodec.Constructor + CppToolchainInfo( + CToolchain toolchain, + PathFragment crosstoolTopPathFragment, + String toolchainIdentifier, + ImmutableMap<String, PathFragment> toolPaths, + String compiler, + PathFragment ldExecutable, + String abiGlibcVersion, + String targetCpu, + String targetOS, + ImmutableList<String> rawBuiltInIncludeDirectories, + PathFragment defaultSysroot, + PathFragment runtimeSysroot, + String targetLibc, + String hostSystemName, + FlagList dynamicLibraryLinkFlags, + ImmutableList<String> commonLinkOptions, + ImmutableListMultimap<LinkingMode, String> linkOptionsFromLinkingMode, + ImmutableListMultimap<LipoMode, String> linkOptionsFromLipoMode, + ImmutableListMultimap<CompilationMode, String> linkOptionsFromCompilationMode, + ImmutableList<String> testOnlyLinkFlags, + ImmutableList<String> ldOptionsForEmbedding, + ImmutableList<String> objCopyOptionsForEmbedding, + Label staticRuntimeLibsLabel, + Label dynamicRuntimeLibsLabel, + String solibDirectory, + String abi, + String targetSystemName, + ImmutableMap<String, String> additionalMakeVariables, + ImmutableList<String> crosstoolCompilerFlags, + ImmutableList<String> crosstoolCxxFlags, + ImmutableList<OptionalFlag> crosstoolOptionalCompilerFlags, + ImmutableList<OptionalFlag> crosstoolOptionalCxxFlags, + ImmutableListMultimap<CompilationMode, String> cFlagsByCompilationMode, + ImmutableListMultimap<CompilationMode, String> cxxFlagsByCompilationMode, + ImmutableListMultimap<LipoMode, String> lipoCFlags, + ImmutableListMultimap<LipoMode, String> lipoCxxFlags, + boolean supportsFission, + boolean supportsStartEndLib, + boolean supportsEmbeddedRuntimes, + boolean supportsDynamicLinker, + boolean supportsInterfaceSharedObjects, + boolean supportsGoldLinker, + boolean toolchainNeedsPic) + throws InvalidConfigurationException { + this.toolchain = toolchain; + this.crosstoolTopPathFragment = crosstoolTopPathFragment; + this.toolchainIdentifier = toolchainIdentifier; + // Since this field can be derived from `toolchain`, it is re-derived instead of serialized. + this.toolchainFeatures = new CcToolchainFeatures(toolchain); + this.toolPaths = toolPaths; + this.compiler = compiler; + this.ldExecutable = ldExecutable; + 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.commonLinkOptions = commonLinkOptions; + this.linkOptionsFromLinkingMode = linkOptionsFromLinkingMode; + this.linkOptionsFromLipoMode = linkOptionsFromLipoMode; + this.linkOptionsFromCompilationMode = linkOptionsFromCompilationMode; + this.testOnlyLinkFlags = testOnlyLinkFlags; + this.ldOptionsForEmbedding = ldOptionsForEmbedding; + this.objCopyOptionsForEmbedding = objCopyOptionsForEmbedding; + this.staticRuntimeLibsLabel = staticRuntimeLibsLabel; + this.dynamicRuntimeLibsLabel = dynamicRuntimeLibsLabel; + this.solibDirectory = solibDirectory; + this.abi = abi; + this.targetSystemName = targetSystemName; + this.additionalMakeVariables = additionalMakeVariables; + this.crosstoolCompilerFlags = crosstoolCompilerFlags; + this.crosstoolCxxFlags = crosstoolCxxFlags; + this.crosstoolOptionalCompilerFlags = crosstoolOptionalCompilerFlags; + this.crosstoolOptionalCxxFlags = crosstoolOptionalCxxFlags; + this.cFlagsByCompilationMode = cFlagsByCompilationMode; + this.cxxFlagsByCompilationMode = cxxFlagsByCompilationMode; + this.lipoCFlags = lipoCFlags; + this.lipoCxxFlags = lipoCxxFlags; + this.supportsFission = supportsFission; + this.supportsStartEndLib = supportsStartEndLib; + this.supportsEmbeddedRuntimes = supportsEmbeddedRuntimes; + this.supportsDynamicLinker = supportsDynamicLinker; + this.supportsInterfaceSharedObjects = supportsInterfaceSharedObjects; + this.supportsGoldLinker = supportsGoldLinker; + this.toolchainNeedsPic = toolchainNeedsPic; } @VisibleForTesting @@ -338,7 +332,8 @@ public final class CppToolchainInfo { // 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) { + private static CToolchain addLegacyFeatures( + CToolchain toolchain, PathFragment crosstoolTopPathFragment) { CToolchain.Builder toolchainBuilder = CToolchain.newBuilder(); Set<ArtifactCategory> definedCategories = new HashSet<>(); @@ -408,13 +403,13 @@ public final class CppToolchainInfo { TextFormat.merge( CppActionConfigs.getCppActionConfigs( - getTargetLibc().equals("macosx") ? CppPlatform.MAC : CppPlatform.LINUX, + toolchain.getTargetLibc().equals("macosx") ? CppPlatform.MAC : CppPlatform.LINUX, featureNames, gccToolPath, linkerToolPath, arToolPath, stripToolPath, - supportsEmbeddedRuntimes, + toolchain.getSupportsEmbeddedRuntimes(), toolchain.getSupportsInterfaceSharedObjects()), toolchainBuilder); } catch (ParseException e) { @@ -439,7 +434,7 @@ public final class CppToolchainInfo { return toolchainBuilder.build(); } - private CToolchain removeLegacyCompileFlagsFeatureFromToolchain(CToolchain toolchain) { + private static CToolchain removeLegacyCompileFlagsFeatureFromToolchain(CToolchain toolchain) { FieldDescriptor featuresFieldDescriptor = CToolchain.getDescriptor().findFieldByName("feature"); return toolchain .toBuilder() @@ -529,7 +524,7 @@ public final class CppToolchainInfo { * #getLdExecutable} instead! */ public PathFragment getToolPathFragment(CppConfiguration.Tool tool) { - return toolPaths.get(tool.getNamePart()); + return getToolPathFragment(toolPaths, tool); } /** @@ -665,7 +660,7 @@ public final class CppToolchainInfo { * files, or {@code null} if this operation is not supported. */ public ImmutableList<String> getObjCopyOptionsForEmbedding() { - return objcopyOptions; + return objCopyOptionsForEmbedding; } /** @@ -673,7 +668,7 @@ public final class CppToolchainInfo { * or {@code null} if this operation is not supported. */ public ImmutableList<String> getLdOptionsForEmbedding() { - return ldOptions; + return ldOptionsForEmbedding; } /** @@ -741,12 +736,12 @@ public final class CppToolchainInfo { /** Returns compiler flags for C compilation by compilation mode. */ public ImmutableListMultimap<CompilationMode, String> getCFlagsByCompilationMode() { - return cFlags; + return cFlagsByCompilationMode; } /** Returns compiler flags for C++ compilation, by compilation mode. */ public ImmutableListMultimap<CompilationMode, String> getCxxFlagsByCompilationMode() { - return cxxFlags; + return cxxFlagsByCompilationMode; } /** Returns compiler flags for C compilation by lipo mode. */ @@ -768,4 +763,94 @@ public final class CppToolchainInfo { public ImmutableList<OptionalFlag> getOptionalCxxFlags() { return crosstoolOptionalCxxFlags; } + + private static ImmutableMap<String, String> computeAdditionalMakeVariables(CToolchain toolchain) { + 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(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME, ""); + for (CrosstoolConfig.MakeVariable variable : toolchain.getMakeVariableList()) { + makeVariablesBuilder.put(variable.getName(), variable.getValue()); + } + return ImmutableMap.copyOf(makeVariablesBuilder); + } + + private static ImmutableListMultimap<CompilationMode, String> + computeLinkOptionsFromCompilationMode(CToolchain toolchain) { + ImmutableListMultimap.Builder<CompilationMode, String> linkOptionsFromCompilationModeBuilder = + ImmutableListMultimap.builder(); + 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()); + linkOptionsFromCompilationModeBuilder.putAll(realmode, flags.getLinkerFlagList()); + } + return linkOptionsFromCompilationModeBuilder.build(); + } + + private static ImmutableListMultimap<LipoMode, String> computeLinkOptionsFromLipoMode( + CToolchain toolchain) { + ImmutableListMultimap.Builder<LipoMode, String> linkOptionsFromLipoModeBuilder = + ImmutableListMultimap.builder(); + for (CrosstoolConfig.LipoModeFlags flags : toolchain.getLipoModeFlagsList()) { + LipoMode realmode = flags.getMode(); + linkOptionsFromLipoModeBuilder.putAll(realmode, flags.getLinkerFlagList()); + } + return linkOptionsFromLipoModeBuilder.build(); + } + + private static ImmutableMap<String, PathFragment> computeToolPaths( + CToolchain toolchain, PathFragment crosstoolTopPathFragment) { + Map<String, PathFragment> toolPathsCollector = Maps.newHashMap(); + for (CrosstoolConfig.ToolPath tool : toolchain.getToolPathList()) { + PathFragment path = PathFragment.create(tool.getPath()); + if (!path.isNormalized()) { + throw new IllegalArgumentException( + "The include path '" + tool.getPath() + "' is not normalized."); + } + toolPathsCollector.put(tool.getName(), crosstoolTopPathFragment.getRelative(path)); + } + + if (toolPathsCollector.isEmpty()) { + // If no paths are specified, we just use the names of the tools as the path. + for (Tool tool : Tool.values()) { + toolPathsCollector.put( + tool.getNamePart(), crosstoolTopPathFragment.getRelative(tool.getNamePart())); + } + } else { + Iterable<Tool> neededTools = + Iterables.filter( + EnumSet.allOf(Tool.class), + tool -> { + if (tool == Tool.DWP) { + // When fission is unsupported, don't check for the dwp tool. + return toolchain.getSupportsFission(); + } else if (tool == 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 == 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 (!toolPathsCollector.containsKey(tool.getNamePart())) { + throw new IllegalArgumentException( + "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()); + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CpuTransformer.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CpuTransformer.java new file mode 100644 index 0000000000..220e8e4fd7 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CpuTransformer.java @@ -0,0 +1,41 @@ +// 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.base.Function; +import com.google.common.base.Functions; + +/** Catalog of possible cpu transformers. */ +public enum CpuTransformer { + IDENTITY { + @Override + public Function<String, String> getTransformer() { + return Functions.identity(); + } + }, + /** + * NOT TO BE USED in Bazel. + * + * <p>Google-internal workaround. + */ + FAKE { + @Override + public Function<String, String> getTransformer() { + return FakeCPU::getRealCPU; + } + }; + + public abstract Function<String, String> getTransformer(); +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java index aa12a860c3..0753fbfba5 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java @@ -32,6 +32,8 @@ import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.vfs.FileSystemUtils; @@ -66,17 +68,20 @@ public class CrosstoolConfigurationLoader { */ private static final Cache<String, CrosstoolRelease> crosstoolReleaseCache = CacheBuilder.newBuilder().concurrencyLevel(4).maximumSize(100).build(); - /** - * A class that holds the results of reading a CROSSTOOL file. - */ + /** A class that holds the results of reading a CROSSTOOL file. */ + @AutoCodec public static class CrosstoolFile { + public static final ObjectCodec<CrosstoolFile> CODEC = + new CrosstoolConfigurationLoader_CrosstoolFile_AutoCodec(); + private final String location; - private final CrosstoolConfig.CrosstoolRelease crosstool; + private final CrosstoolConfig.CrosstoolRelease proto; private final String md5; - CrosstoolFile(String location, CrosstoolConfig.CrosstoolRelease crosstool, String md5) { + @AutoCodec.Constructor + CrosstoolFile(String location, CrosstoolConfig.CrosstoolRelease proto, String md5) { this.location = location; - this.crosstool = crosstool; + this.proto = proto; this.md5 = md5; } @@ -91,7 +96,7 @@ public class CrosstoolConfigurationLoader { * Returns the parsed contents of the CROSSTOOL file. */ public CrosstoolConfig.CrosstoolRelease getProto() { - return crosstool; + return proto; } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCPU.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCPU.java new file mode 100644 index 0000000000..edfa7a460f --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCPU.java @@ -0,0 +1,67 @@ +// Copyright 2018 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; + +/** + * DO NOT USE in Bazel. + * + * <p>A temporary, and very regrettable Google-only hack that allows us to support targeting other + * platforms in certain cases. + */ +public class FakeCPU { + + private FakeCPU() { + // Private constructor to prohibit creating objects. + } + + /** + * These are fake CPU values used to indicate that amd64 OSX / Windows should be + * the targeted architecture and platform. This is a hack to support compiling + * Go targeting OSX and Windows, until we have proper support for this kind of thing. + * It is largely unsupported. + */ + public static final String DARWIN_FAKE_CPU = "x86_64-darwin"; + public static final String WINDOWS_FAKE_CPU_64 = "x86_64-windows"; + public static final String WINDOWS_FAKE_CPU_32 = "x86_32-windows"; + + public static boolean isFakeCPU(String cpu) { + return DARWIN_FAKE_CPU.equals(cpu) || WINDOWS_FAKE_CPU_32.equals(cpu) + || WINDOWS_FAKE_CPU_64.equals(cpu); + } + + /** + * Returns the real CPU for a (possible) fake CPU. If isFakeCPU(fakeCPU) + * returns true, + * this method will return the actual target CPU that should be used. + * Otherwise, it + * will simply return fakeCPU. + */ + public static String getRealCPU(String fakeCPU) { + if (isFakeCPU(fakeCPU)) { + // We have a special fake CPU for 32 bit Windows binaries. + if (WINDOWS_FAKE_CPU_32.equals(fakeCPU)) { + return "piii"; + } + // If targeting darwin or windows 64, pretend to be k8 so that we don't need to + // mess with crosstool configurations. A big fat warning was printed by the + // ConfigurationFactory warning people that they shouldn't expect anything + // other than go_{binary,library} to work, so the spurious + // k8 results we will return for other languages are fine. + return "k8"; + } else { + return fakeCPU; + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FlagList.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FlagList.java index 33185298c6..258cf630ce 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FlagList.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FlagList.java @@ -18,21 +18,28 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain; import java.io.Serializable; import java.util.List; /** Represents a list of c++ tool flags. */ +@AutoCodec @Immutable public class FlagList implements Serializable { + public static final ObjectCodec<FlagList> CODEC = new FlagList_AutoCodec(); + /** Represents an optional flag that can be toggled using the package features mechanism. */ + @AutoCodec @Immutable - @VisibleForTesting static class OptionalFlag implements Serializable { + public static final ObjectCodec<OptionalFlag> CODEC = new FlagList_OptionalFlag_AutoCodec(); + private final String name; private final ImmutableList<String> flags; - @VisibleForTesting + @AutoCodec.Constructor OptionalFlag(String name, ImmutableList<String> flags) { this.name = name; this.flags = flags; @@ -51,7 +58,7 @@ public class FlagList implements Serializable { private final ImmutableList<OptionalFlag> optionalFlags; private final ImmutableList<String> suffixFlags; - @VisibleForTesting + @AutoCodec.Constructor FlagList( ImmutableList<String> prefixFlags, ImmutableList<OptionalFlag> optionalFlags, diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java index d2585278ea..c58f1a96cc 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java @@ -27,7 +27,7 @@ import com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.Marshaller.Context; import com.google.devtools.build.lib.skyframe.serialization.strings.StringCodecs; -import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.AbstractMessage; import com.google.protobuf.ProtocolMessageEnum; import java.util.Collection; import java.util.Comparator; @@ -446,7 +446,7 @@ class Marshallers { new Marshaller() { @Override public boolean matches(DeclaredType type) { - return isSubtype(type, GeneratedMessage.class); + return isSubtype(type, AbstractMessage.class); } @Override diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/FsUtils.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/FsUtils.java index ee019b8c49..4a8858c194 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/FsUtils.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/FsUtils.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.skyframe.serialization.testutils; import com.google.devtools.build.lib.vfs.FileSystem; +import com.google.devtools.build.lib.vfs.FileSystemProvider; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; @@ -24,6 +25,8 @@ public class FsUtils { public static final FileSystem TEST_FILESYSTEM = new InMemoryFileSystem(); + public static final FileSystemProvider TEST_FILESYSTEM_PROVIDER = () -> TEST_FILESYSTEM; + public static final RootedPath TEST_ROOT = RootedPath.toRootedPath( TEST_FILESYSTEM.getPath(PathFragment.create("/anywhere/at/all")), diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystemProvider.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystemProvider.java new file mode 100644 index 0000000000..160bb2ecf9 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystemProvider.java @@ -0,0 +1,21 @@ +// Copyright 2018 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.vfs; + +/** Abstraction for injecting FileSystem dependencies. */ +public interface FileSystemProvider { + + FileSystem getFileSystem(); +} diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Path.java b/src/main/java/com/google/devtools/build/lib/vfs/Path.java index e66fc079ea..fa6b6b4f78 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/Path.java +++ b/src/main/java/com/google/devtools/build/lib/vfs/Path.java @@ -16,11 +16,15 @@ package com.google.devtools.build.lib.vfs; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; +import com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec; +import com.google.devtools.build.lib.skyframe.serialization.SerializationException; import com.google.devtools.build.lib.skylarkinterface.SkylarkPrintable; import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter; import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.util.StringCanonicalizer; import com.google.devtools.build.lib.vfs.FileSystem.HashFunction; +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.CodedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -55,6 +59,8 @@ import java.util.Objects; @ThreadSafe public class Path implements Comparable<Path>, Serializable, SkylarkPrintable, FileType.HasFileType { + public static final InjectingObjectCodec<Path, FileSystemProvider> CODEC = + new PathCodecWithInjectedFileSystem(); /** Filesystem-specific factory for {@link Path} objects. */ public static interface PathFactory { @@ -1237,4 +1243,27 @@ public class Path } while (!a.equals(b)); // This has to happen eventually. return previousa.name.compareTo(previousb.name); } + + private static class PathCodecWithInjectedFileSystem + implements InjectingObjectCodec<Path, FileSystemProvider> { + + @Override + public Class<Path> getEncodedClass() { + return Path.class; + } + + @Override + public void serialize( + FileSystemProvider unusedDependency, Path path, CodedOutputStream codedOut) + throws IOException, SerializationException { + PathFragment.CODEC.serialize(path.asFragment(), codedOut); + } + + @Override + public Path deserialize(FileSystemProvider fsProvider, CodedInputStream codedIn) + throws IOException, SerializationException { + PathFragment pathFragment = PathFragment.CODEC.deserialize(codedIn); + return fsProvider.getFileSystem().getPath(pathFragment); + } + } } diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java index aca42726d5..3fd15f8a28 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java @@ -13,7 +13,6 @@ // limitations under the License. package com.google.devtools.build.lib.analysis.mock; -import com.google.common.base.Functions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; @@ -30,6 +29,7 @@ import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.swift.SwiftConfiguration; import com.google.devtools.build.lib.rules.config.ConfigFeatureFlagConfiguration; import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader; +import com.google.devtools.build.lib.rules.cpp.CpuTransformer; import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader; import com.google.devtools.build.lib.rules.java.JvmConfigurationLoader; import com.google.devtools.build.lib.rules.objc.J2ObjcConfiguration; @@ -275,7 +275,7 @@ public final class BazelAnalysisMock extends AnalysisMock { public List<ConfigurationFragmentFactory> getDefaultConfigurationFragmentFactories() { return ImmutableList.<ConfigurationFragmentFactory>of( new BazelConfiguration.Loader(), - new CppConfigurationLoader(Functions.<String>identity()), + new CppConfigurationLoader(CpuTransformer.IDENTITY), new PythonConfigurationLoader(), new BazelPythonConfiguration.Loader(), new JvmConfigurationLoader(), diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java index 1cc7282f44..cfd41e7dc6 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java @@ -17,7 +17,6 @@ package com.google.devtools.build.lib.rules.cpp; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import com.google.common.base.Functions; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -62,7 +61,7 @@ public class CrosstoolConfigurationLoaderTest extends AnalysisTestCase { private CppConfigurationLoader loader(String crosstoolFileContents) throws IOException { getAnalysisMock().ccSupport().setupCrosstoolWithRelease(mockToolsConfig, crosstoolFileContents); - return new CppConfigurationLoader(Functions.<String>identity()); + return new CppConfigurationLoader(CpuTransformer.IDENTITY); } @Before diff --git a/src/test/java/com/google/devtools/build/lib/vfs/PathTest.java b/src/test/java/com/google/devtools/build/lib/vfs/PathTest.java index 8a1e14fbcf..eaad458438 100644 --- a/src/test/java/com/google/devtools/build/lib/vfs/PathTest.java +++ b/src/test/java/com/google/devtools/build/lib/vfs/PathTest.java @@ -16,10 +16,14 @@ package com.google.devtools.build.lib.vfs; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.testing.EqualsTester; import com.google.common.testing.GcFinalization; import com.google.devtools.build.lib.clock.BlazeClock; +import com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodecAdapter; +import com.google.devtools.build.lib.skyframe.serialization.testutils.FsUtils; +import com.google.devtools.build.lib.skyframe.serialization.testutils.ObjectCodecTester; import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -309,6 +313,18 @@ public class PathTest { assertThat(uri.toString()).isEqualTo("file:///tmp/foo%20bar.txt"); } + @Test + public void testCodec() throws Exception { + ObjectCodecTester.newBuilder( + new InjectingObjectCodecAdapter<>(Path.CODEC, FsUtils.TEST_FILESYSTEM_PROVIDER)) + .addSubjects( + ImmutableList.of( + FsUtils.TEST_FILESYSTEM.getPath("/"), + FsUtils.TEST_FILESYSTEM.getPath("/some/path"), + FsUtils.TEST_FILESYSTEM.getPath("/some/other/path/with/empty/last/fragment/"))) + .buildAndRunTests(); + } + private void assertAsFragmentWorks(String expected) { assertThat(filesystem.getPath(expected).asFragment()).isEqualTo(PathFragment.create(expected)); } |