| // 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.Preconditions; |
| import com.google.common.base.Supplier; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.events.Location; |
| import com.google.devtools.build.lib.packages.RuleErrorConsumer; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.StringSequenceBuilder; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.VariablesExtension; |
| import com.google.devtools.build.lib.syntax.EvalException; |
| import com.google.devtools.build.lib.util.FileType; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| |
| /** Enum covering all build variables we create for all various {@link CppCompileAction}. */ |
| public enum CompileBuildVariables { |
| /** Variable for the path to the source file being compiled. */ |
| SOURCE_FILE("source_file"), |
| /** |
| * Variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or |
| * --conlyopt options. |
| */ |
| USER_COMPILE_FLAGS("user_compile_flags"), |
| /** |
| * Variable for all flags coming from legacy crosstool fields, such as compiler_flag, |
| * optional_compiler_flag, cxx_flag. |
| */ |
| LEGACY_COMPILE_FLAGS("legacy_compile_flags"), |
| /** Variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */ |
| UNFILTERED_COMPILE_FLAGS("unfiltered_compile_flags"), |
| /** Variable for the path to the output file when output is an object file. */ |
| OUTPUT_OBJECT_FILE("output_object_file"), |
| /** Variable for the path to the compilation output file. */ |
| OUTPUT_FILE("output_file"), |
| /** Variable for the dependency file path */ |
| DEPENDENCY_FILE("dependency_file"), |
| /** Variable for the module file name. */ |
| MODULE_NAME("module_name"), |
| /** |
| * Variable for the collection of include paths. |
| * |
| * @see CcCompilationContext#getIncludeDirs(). |
| */ |
| INCLUDE_PATHS("include_paths"), |
| /** |
| * Variable for the collection of quote include paths. |
| * |
| * @see CcCompilationContext#getIncludeDirs(). |
| */ |
| QUOTE_INCLUDE_PATHS("quote_include_paths"), |
| /** |
| * Variable for the collection of system include paths. |
| * |
| * @see CcCompilationContext#getIncludeDirs(). |
| */ |
| SYSTEM_INCLUDE_PATHS("system_include_paths"), |
| /** Variable for the module map file name. */ |
| MODULE_MAP_FILE("module_map_file"), |
| /** Variable for the dependent module map file name. */ |
| DEPENDENT_MODULE_MAP_FILES("dependent_module_map_files"), |
| /** Variable for the collection of module files. */ |
| MODULE_FILES("module_files"), |
| /** Variable for the collection of macros defined for preprocessor. */ |
| PREPROCESSOR_DEFINES("preprocessor_defines"), |
| /** Variable for the gcov coverage file path. */ |
| GCOV_GCNO_FILE("gcov_gcno_file"), |
| /** Variable for the LTO indexing bitcode file. */ |
| LTO_INDEXING_BITCODE_FILE("lto_indexing_bitcode_file"), |
| /** Variable for the per object debug info file. */ |
| PER_OBJECT_DEBUG_INFO_FILE("per_object_debug_info_file"), |
| /** Variable present when the output is compiled as position independent. */ |
| PIC("pic"), |
| /** Variable marking that we are generating preprocessed sources (from --save_temps). */ |
| OUTPUT_PREPROCESS_FILE("output_preprocess_file"), |
| /** Variable marking that we are generating assembly source (from --save_temps). */ |
| OUTPUT_ASSEMBLY_FILE("output_assembly_file"), |
| /** Path to the fdo instrument artifact */ |
| FDO_INSTRUMENT_PATH("fdo_instrument_path"), |
| /** Path to the fdo profile artifact */ |
| FDO_PROFILE_PATH("fdo_profile_path"), |
| /** Path to the cache prefetch profile artifact */ |
| FDO_PREFETCH_HINTS_PATH("fdo_prefetch_hints_path"), |
| /** Variable for includes that compiler needs to include into sources. */ |
| INCLUDES("includes"); |
| |
| private final String variableName; |
| |
| CompileBuildVariables(String variableName) { |
| this.variableName = variableName; |
| } |
| |
| public static CcToolchainVariables setupVariablesOrReportRuleError( |
| RuleErrorConsumer ruleErrorConsumer, |
| FeatureConfiguration featureConfiguration, |
| CcToolchainProvider ccToolchainProvider, |
| String sourceFile, |
| String outputFile, |
| String gcnoFile, |
| String dwoFile, |
| String ltoIndexingFile, |
| ImmutableList<String> includes, |
| Iterable<String> userCompileFlags, |
| CppModuleMap cppModuleMap, |
| boolean usePic, |
| PathFragment fakeOutputFile, |
| String fdoStamp, |
| String dotdFileExecPath, |
| ImmutableList<VariablesExtension> variablesExtensions, |
| ImmutableMap<String, String> additionalBuildVariables, |
| Iterable<Artifact> directModuleMaps, |
| Iterable<PathFragment> includeDirs, |
| Iterable<PathFragment> quoteIncludeDirs, |
| Iterable<PathFragment> systemIncludeDirs, |
| Iterable<String> defines) { |
| try { |
| return setupVariablesOrThrowEvalException( |
| featureConfiguration, |
| ccToolchainProvider, |
| sourceFile, |
| outputFile, |
| gcnoFile, |
| dwoFile, |
| ltoIndexingFile, |
| includes, |
| userCompileFlags, |
| cppModuleMap, |
| usePic, |
| toPathString(fakeOutputFile), |
| fdoStamp, |
| dotdFileExecPath, |
| variablesExtensions, |
| additionalBuildVariables, |
| directModuleMaps, |
| getSafePathStrings(includeDirs), |
| getSafePathStrings(quoteIncludeDirs), |
| getSafePathStrings(systemIncludeDirs), |
| defines, |
| /* addLegacyCxxOptions= */ CppFileTypes.CPP_SOURCE.matches(sourceFile) |
| || CppFileTypes.CPP_HEADER.matches(sourceFile) |
| || CppFileTypes.CPP_MODULE_MAP.matches(sourceFile) |
| || CppFileTypes.CLIF_INPUT_PROTO.matches(sourceFile)); |
| } catch (EvalException e) { |
| ruleErrorConsumer.ruleError(e.getMessage()); |
| return CcToolchainVariables.EMPTY; |
| } |
| } |
| |
| public static CcToolchainVariables setupVariablesOrThrowEvalException( |
| FeatureConfiguration featureConfiguration, |
| CcToolchainProvider ccToolchainProvider, |
| String sourceFile, |
| // TODO(b/76195763): Remove once blaze with cl/189769259 is released and crosstools are |
| // updated. |
| String outputFile, |
| String gcnoFile, |
| String dwoFile, |
| String ltoIndexingFile, |
| ImmutableList<String> includes, |
| Iterable<String> userCompileFlags, |
| CppModuleMap cppModuleMap, |
| boolean usePic, |
| String fakeOutputFile, |
| String fdoStamp, |
| String dotdFileExecPath, |
| ImmutableList<VariablesExtension> variablesExtensions, |
| ImmutableMap<String, String> additionalBuildVariables, |
| Iterable<Artifact> directModuleMaps, |
| Iterable<String> includeDirs, |
| Iterable<String> quoteIncludeDirs, |
| Iterable<String> systemIncludeDirs, |
| Iterable<String> defines, |
| boolean addLegacyCxxOptions) |
| throws EvalException { |
| Preconditions.checkNotNull(directModuleMaps); |
| Preconditions.checkNotNull(includeDirs); |
| Preconditions.checkNotNull(quoteIncludeDirs); |
| Preconditions.checkNotNull(systemIncludeDirs); |
| Preconditions.checkNotNull(defines); |
| CcToolchainVariables.Builder buildVariables = |
| new CcToolchainVariables.Builder(ccToolchainProvider.getBuildVariables()); |
| |
| buildVariables.addStringSequenceVariable( |
| USER_COMPILE_FLAGS.getVariableName(), userCompileFlags); |
| |
| buildVariables.addLazyStringSequenceVariable( |
| LEGACY_COMPILE_FLAGS.getVariableName(), |
| getLegacyCompileFlagsSupplier(ccToolchainProvider, addLegacyCxxOptions)); |
| |
| if (sourceFile != null) { |
| buildVariables.addStringVariable(SOURCE_FILE.getVariableName(), sourceFile); |
| } |
| |
| if (sourceFile == null |
| || (!CppFileTypes.OBJC_SOURCE.matches(sourceFile) |
| && !CppFileTypes.OBJCPP_SOURCE.matches(sourceFile))) { |
| buildVariables.addLazyStringSequenceVariable( |
| UNFILTERED_COMPILE_FLAGS.getVariableName(), |
| getUnfilteredCompileFlagsSupplier(ccToolchainProvider)); |
| } |
| |
| String fakeOutputFileOrRealOutputFile = fakeOutputFile != null ? fakeOutputFile : outputFile; |
| |
| if (outputFile != null) { |
| // TODO(b/76195763): Remove once blaze with cl/189769259 is released and crosstools are |
| // updated. |
| if (!FileType.contains( |
| PathFragment.create(outputFile), |
| CppFileTypes.ASSEMBLER, |
| CppFileTypes.PIC_ASSEMBLER, |
| CppFileTypes.PREPROCESSED_C, |
| CppFileTypes.PREPROCESSED_CPP, |
| CppFileTypes.PIC_PREPROCESSED_C, |
| CppFileTypes.PIC_PREPROCESSED_CPP)) { |
| buildVariables.addStringVariable( |
| OUTPUT_OBJECT_FILE.getVariableName(), fakeOutputFileOrRealOutputFile); |
| } |
| |
| buildVariables.addStringVariable( |
| OUTPUT_FILE.getVariableName(), fakeOutputFileOrRealOutputFile); |
| } |
| |
| // Set dependency_file to enable <object>.d file generation. |
| if (dotdFileExecPath != null) { |
| buildVariables.addStringVariable(DEPENDENCY_FILE.getVariableName(), dotdFileExecPath); |
| } |
| |
| if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) { |
| // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis |
| // in any case, but don't crash. |
| buildVariables.addStringVariable(MODULE_NAME.getVariableName(), cppModuleMap.getName()); |
| buildVariables.addStringVariable( |
| MODULE_MAP_FILE.getVariableName(), cppModuleMap.getArtifact().getExecPathString()); |
| StringSequenceBuilder sequence = new StringSequenceBuilder(); |
| for (Artifact artifact : directModuleMaps) { |
| sequence.addValue(artifact.getExecPathString()); |
| } |
| buildVariables.addCustomBuiltVariable(DEPENDENT_MODULE_MAP_FILES.getVariableName(), sequence); |
| } |
| if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) { |
| // Module inputs will be set later when the action is executed. |
| buildVariables.addStringSequenceVariable(MODULE_FILES.getVariableName(), ImmutableSet.of()); |
| } |
| buildVariables.addStringSequenceVariable(INCLUDE_PATHS.getVariableName(), includeDirs); |
| buildVariables.addStringSequenceVariable( |
| QUOTE_INCLUDE_PATHS.getVariableName(), quoteIncludeDirs); |
| buildVariables.addStringSequenceVariable( |
| SYSTEM_INCLUDE_PATHS.getVariableName(), systemIncludeDirs); |
| |
| if (!includes.isEmpty()) { |
| buildVariables.addStringSequenceVariable(INCLUDES.getVariableName(), includes); |
| } |
| |
| Iterable<String> allDefines; |
| if (fdoStamp != null) { |
| // Stamp FDO builds with FDO subtype string |
| allDefines = |
| ImmutableList.<String>builder() |
| .addAll(defines) |
| .add(CppConfiguration.FDO_STAMP_MACRO + "=\"" + fdoStamp + "\"") |
| .build(); |
| } else { |
| allDefines = defines; |
| } |
| |
| buildVariables.addStringSequenceVariable(PREPROCESSOR_DEFINES.getVariableName(), allDefines); |
| |
| if (usePic) { |
| if (!featureConfiguration.isEnabled(CppRuleClasses.PIC) |
| && !featureConfiguration.isEnabled(CppRuleClasses.SUPPORTS_PIC)) { |
| throw new EvalException(Location.BUILTIN, CcCommon.PIC_CONFIGURATION_ERROR); |
| } |
| buildVariables.addStringVariable(PIC.getVariableName(), ""); |
| } |
| |
| if (gcnoFile != null) { |
| buildVariables.addStringVariable(GCOV_GCNO_FILE.getVariableName(), gcnoFile); |
| } |
| |
| if (dwoFile != null) { |
| buildVariables.addStringVariable(PER_OBJECT_DEBUG_INFO_FILE.getVariableName(), dwoFile); |
| } |
| |
| if (ltoIndexingFile != null) { |
| buildVariables.addStringVariable( |
| LTO_INDEXING_BITCODE_FILE.getVariableName(), ltoIndexingFile); |
| } |
| |
| buildVariables.addAllStringVariables(additionalBuildVariables); |
| for (VariablesExtension extension : variablesExtensions) { |
| extension.addVariables(buildVariables); |
| } |
| |
| return buildVariables.build(); |
| } |
| |
| /** Get the safe path strings for a list of paths to use in the build variables. */ |
| private static ImmutableList<String> getSafePathStrings(Iterable<PathFragment> paths) { |
| // Using ImmutableSet first to remove duplicates, then ImmutableList for smaller memory |
| // footprint. |
| return ImmutableSet.copyOf(paths) |
| .stream() |
| .map(PathFragment::getSafePathString) |
| .collect(ImmutableList.toImmutableList()); |
| } |
| |
| /** |
| * Supplier that computes legacy_compile_flags lazily at the execution phase. |
| * |
| * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only |
| * to arguments (to prevent accidental capture of enclosing instance which could regress memory). |
| */ |
| private static Supplier<ImmutableList<String>> getLegacyCompileFlagsSupplier( |
| CcToolchainProvider toolchain, boolean addLegacyCxxOptions) { |
| return () -> { |
| ImmutableList.Builder<String> legacyCompileFlags = ImmutableList.builder(); |
| legacyCompileFlags.addAll(toolchain.getLegacyCompileOptions()); |
| if (addLegacyCxxOptions) { |
| legacyCompileFlags.addAll(toolchain.getLegacyCxxOptions()); |
| } |
| return legacyCompileFlags.build(); |
| }; |
| } |
| |
| /** |
| * Supplier that computes unfiltered_compile_flags lazily at the execution phase. |
| * |
| * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only |
| * to arguments (to prevent accidental capture of enclosing instance which could regress memory). |
| */ |
| private static Supplier<ImmutableList<String>> getUnfilteredCompileFlagsSupplier( |
| CcToolchainProvider ccToolchain) { |
| return () -> ccToolchain.getUnfilteredCompilerOptions(); |
| } |
| |
| private static String toPathString(PathFragment a) { |
| return a == null ? null : a.getSafePathString(); |
| } |
| |
| public String getVariableName() { |
| return variableName; |
| } |
| } |