| // Copyright 2017 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package com.google.devtools.build.lib.rules.cpp; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Preconditions; |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables; |
| import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile; |
| import com.google.devtools.build.lib.util.FileType; |
| import com.google.devtools.build.lib.util.Pair; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import javax.annotation.Nullable; |
| |
| /** The compile command line for the C++ compile action. */ |
| public final class CompileCommandLine { |
| |
| private final Artifact sourceFile; |
| private final Artifact outputFile; |
| private final Predicate<String> coptsFilter; |
| private final FeatureConfiguration featureConfiguration; |
| private final CcToolchainFeatures.Variables variables; |
| private final String actionName; |
| private final CppConfiguration cppConfiguration; |
| private final DotdFile dotdFile; |
| |
| private CompileCommandLine( |
| Artifact sourceFile, |
| Artifact outputFile, |
| Predicate<String> coptsFilter, |
| FeatureConfiguration featureConfiguration, |
| CppConfiguration cppConfiguration, |
| CcToolchainFeatures.Variables variables, |
| String actionName, |
| DotdFile dotdFile) { |
| this.sourceFile = Preconditions.checkNotNull(sourceFile); |
| this.outputFile = Preconditions.checkNotNull(outputFile); |
| this.coptsFilter = coptsFilter; |
| this.featureConfiguration = Preconditions.checkNotNull(featureConfiguration); |
| this.cppConfiguration = Preconditions.checkNotNull(cppConfiguration); |
| this.variables = variables; |
| this.actionName = actionName; |
| this.dotdFile = isGenerateDotdFile(sourceFile) ? Preconditions.checkNotNull(dotdFile) : null; |
| } |
| |
| /** Returns true if Dotd file should be generated. */ |
| private boolean isGenerateDotdFile(Artifact sourceArtifact) { |
| return CppFileTypes.headerDiscoveryRequired(sourceArtifact) |
| && !featureConfiguration.isEnabled(CppRuleClasses.PARSE_SHOWINCLUDES); |
| } |
| |
| /** Returns the environment variables that should be set for C++ compile actions. */ |
| protected Map<String, String> getEnvironment() { |
| return featureConfiguration.getEnvironmentVariables(actionName, variables); |
| } |
| |
| protected List<String> getArgv( |
| PathFragment outputFile, CcToolchainFeatures.Variables overwrittenVariables) { |
| List<String> commandLine = new ArrayList<>(); |
| |
| // first: The command name. |
| Preconditions.checkArgument( |
| featureConfiguration.actionIsConfigured(actionName), |
| String.format("Expected action_config for '%s' to be configured", actionName)); |
| commandLine.add( |
| featureConfiguration |
| .getToolForAction(actionName) |
| .getToolPath(cppConfiguration.getCrosstoolTopPathFragment()) |
| .getPathString()); |
| |
| // second: The compiler options. |
| commandLine.addAll(getCompilerOptions(overwrittenVariables)); |
| |
| if (!featureConfiguration.isEnabled(CppRuleClasses.COMPILE_ACTION_FLAGS_IN_FLAG_SET)) { |
| // third: The file to compile! |
| commandLine.add("-c"); |
| commandLine.add(sourceFile.getExecPathString()); |
| |
| // finally: The output file. (Prefixed with -o). |
| commandLine.add("-o"); |
| commandLine.add(outputFile.getPathString()); |
| } |
| |
| return commandLine; |
| } |
| |
| public List<String> getCompilerOptions( |
| @Nullable CcToolchainFeatures.Variables overwrittenVariables) { |
| List<String> options = new ArrayList<>(); |
| |
| CcToolchainFeatures.Variables updatedVariables = variables; |
| if (variables != null && overwrittenVariables != null) { |
| CcToolchainFeatures.Variables.Builder variablesBuilder = |
| new CcToolchainFeatures.Variables.Builder(variables); |
| variablesBuilder.addAllNonTransitive(overwrittenVariables); |
| updatedVariables = variablesBuilder.build(); |
| } |
| addFilteredOptions( |
| options, featureConfiguration.getPerFeatureExpansions(actionName, updatedVariables)); |
| |
| if (!featureConfiguration.isEnabled("compile_action_flags_in_flag_set")) { |
| if (FileType.contains(outputFile, CppFileTypes.ASSEMBLER, CppFileTypes.PIC_ASSEMBLER)) { |
| options.add("-S"); |
| } else if (FileType.contains( |
| outputFile, |
| CppFileTypes.PREPROCESSED_C, |
| CppFileTypes.PREPROCESSED_CPP, |
| CppFileTypes.PIC_PREPROCESSED_C, |
| CppFileTypes.PIC_PREPROCESSED_CPP)) { |
| options.add("-E"); |
| } |
| } |
| |
| return options; |
| } |
| |
| // For each option in 'in', add it to 'out' unless it is matched by the 'coptsFilter' regexp. |
| private void addFilteredOptions( |
| List<String> out, List<Pair<String, List<String>>> expandedFeatures) { |
| for (Pair<String, List<String>> pair : expandedFeatures) { |
| if (pair.getFirst().equals(CppRuleClasses.UNFILTERED_COMPILE_FLAGS_FEATURE_NAME)) { |
| out.addAll(pair.getSecond()); |
| continue; |
| } |
| |
| pair.getSecond().stream().filter(coptsFilter).forEachOrdered(out::add); |
| } |
| } |
| |
| public Artifact getSourceFile() { |
| return sourceFile; |
| } |
| |
| public DotdFile getDotdFile() { |
| return dotdFile; |
| } |
| |
| public Variables getVariables() { |
| return variables; |
| } |
| |
| /** |
| * Returns all user provided copts flags. |
| * |
| * TODO(b/64108724): Get rid of this method when we don't need to parse copts to collect include |
| * directories anymore (meaning there is a way of specifying include directories using an |
| * explicit attribute, not using platform-dependent garbage bag that copts is). |
| */ |
| public ImmutableList<String> getCopts() { |
| if (variables.isAvailable(CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME)) { |
| return Variables.toStringList(variables, CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME); |
| } else { |
| return ImmutableList.of(); |
| } |
| } |
| |
| public static Builder builder( |
| Artifact sourceFile, |
| Artifact outputFile, |
| Predicate<String> coptsFilter, |
| String actionName, |
| CppConfiguration cppConfiguration, |
| DotdFile dotdFile) { |
| return new Builder( |
| sourceFile, outputFile, coptsFilter, actionName, cppConfiguration, dotdFile); |
| } |
| |
| /** A builder for a {@link CompileCommandLine}. */ |
| public static final class Builder { |
| private final Artifact sourceFile; |
| private final Artifact outputFile; |
| private Predicate<String> coptsFilter; |
| private FeatureConfiguration featureConfiguration; |
| private CcToolchainFeatures.Variables variables = Variables.EMPTY; |
| private final String actionName; |
| private final CppConfiguration cppConfiguration; |
| @Nullable private final DotdFile dotdFile; |
| |
| public CompileCommandLine build() { |
| return new CompileCommandLine( |
| Preconditions.checkNotNull(sourceFile), |
| Preconditions.checkNotNull(outputFile), |
| Preconditions.checkNotNull(coptsFilter), |
| Preconditions.checkNotNull(featureConfiguration), |
| Preconditions.checkNotNull(cppConfiguration), |
| Preconditions.checkNotNull(variables), |
| Preconditions.checkNotNull(actionName), |
| dotdFile); |
| } |
| |
| private Builder( |
| Artifact sourceFile, |
| Artifact outputFile, |
| Predicate<String> coptsFilter, |
| String actionName, |
| CppConfiguration cppConfiguration, |
| DotdFile dotdFile) { |
| this.sourceFile = sourceFile; |
| this.outputFile = outputFile; |
| this.coptsFilter = coptsFilter; |
| this.actionName = actionName; |
| this.cppConfiguration = cppConfiguration; |
| this.dotdFile = dotdFile; |
| } |
| |
| /** Sets the feature configuration for this compile action. */ |
| public Builder setFeatureConfiguration(FeatureConfiguration featureConfiguration) { |
| this.featureConfiguration = featureConfiguration; |
| return this; |
| } |
| |
| public Builder setVariables(Variables variables) { |
| this.variables = variables; |
| return this; |
| } |
| |
| @VisibleForTesting |
| Builder setCoptsFilter(Predicate<String> filter) { |
| this.coptsFilter = Preconditions.checkNotNull(filter); |
| return this; |
| } |
| } |
| } |