diff options
16 files changed, 447 insertions, 117 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationMakeVariableContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationMakeVariableContext.java index dc830e89fe..2a17ddf838 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationMakeVariableContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationMakeVariableContext.java @@ -17,23 +17,23 @@ package com.google.devtools.build.lib.analysis; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.MakeVariableExpander.ExpansionException; +import com.google.devtools.build.lib.analysis.MakeVariableSupplier.MapBackedMakeVariableSupplier; +import com.google.devtools.build.lib.analysis.MakeVariableSupplier.PackageBackedMakeVariableSupplier; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.syntax.SkylarkDict; +import com.google.devtools.build.lib.util.Preconditions; import java.util.LinkedHashMap; import java.util.Map; /** - * Implements make variable expansion for make variables that depend on the - * configuration and the target (not on behavior of the - * {@link ConfiguredTarget} implementation) + * Implements make variable expansion for make variables that depend on the configuration and the + * target (not on behavior of the {@link ConfiguredTarget} implementation). Retrieved Make variable + * value can be modified using {@link MakeVariableSupplier} */ public class ConfigurationMakeVariableContext implements MakeVariableExpander.Context { - private final Package pkg; - private final ImmutableMap<String, String> ruleEnv; - private final ImmutableMap<String, String> commandLineEnv; - private final ImmutableMap<String, String> globalEnv; - private final String platform; + + private final ImmutableList<? extends MakeVariableSupplier> allMakeVariableSuppliers; // TODO(b/37567440): Remove when Skylark callers can be updated to get this from // CcToolchainProvider. We should use CcCommon.CC_TOOLCHAIN_ATTRIBUTE_NAME, but we didn't want to @@ -43,47 +43,65 @@ public class ConfigurationMakeVariableContext implements MakeVariableExpander.Co public ConfigurationMakeVariableContext( RuleContext ruleContext, Package pkg, BuildConfiguration configuration) { - this(ruleContext.getMakeVariables(defaultMakeVariableAttributes), pkg, configuration); + this( + ruleContext.getMakeVariables(defaultMakeVariableAttributes), + pkg, + configuration, + ImmutableList.<MakeVariableSupplier>of()); } public ConfigurationMakeVariableContext( ImmutableMap<String, String> ruleMakeVariables, Package pkg, BuildConfiguration configuration) { - this.pkg = pkg; - this.ruleEnv = ruleMakeVariables; - this.commandLineEnv = ImmutableMap.copyOf(configuration.getCommandLineBuildVariables()); - this.globalEnv = ImmutableMap.copyOf(configuration.getGlobalMakeEnvironment()); - this.platform = configuration.getPlatformName(); + this(ruleMakeVariables, pkg, configuration, ImmutableList.<MakeVariableSupplier>of()); + } + + public ConfigurationMakeVariableContext( + RuleContext ruleContext, + Package pkg, + BuildConfiguration configuration, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { + this( + ruleContext.getMakeVariables(defaultMakeVariableAttributes), + pkg, + configuration, + makeVariableSuppliers); + } + + public ConfigurationMakeVariableContext( + ImmutableMap<String, String> ruleMakeVariables, + Package pkg, + BuildConfiguration configuration, + Iterable<? extends MakeVariableSupplier> extraMakeVariableSuppliers) { + this.allMakeVariableSuppliers = + ImmutableList.<MakeVariableSupplier>builder() + .addAll(Preconditions.checkNotNull(extraMakeVariableSuppliers)) + .add(new MapBackedMakeVariableSupplier(ruleMakeVariables)) + .add(new MapBackedMakeVariableSupplier(configuration.getCommandLineBuildVariables())) + .add(new PackageBackedMakeVariableSupplier(pkg, configuration.getPlatformName())) + .add(new MapBackedMakeVariableSupplier(configuration.getGlobalMakeEnvironment())) + .build(); } @Override - public String lookupMakeVariable(String var) throws ExpansionException { - String value = ruleEnv.get(var); - if (value == null) { - value = commandLineEnv.get(var); - } - if (value == null) { - value = pkg.lookupMakeVariable(var, platform); - } - if (value == null) { - value = globalEnv.get(var); + public String lookupMakeVariable(String variableName) throws ExpansionException { + for (MakeVariableSupplier supplier : allMakeVariableSuppliers) { + String variableValue = supplier.getMakeVariable(variableName); + if (variableValue != null) { + return variableValue; + } } - if (value == null) { - throw new MakeVariableExpander.ExpansionException("$(" + var + ") not defined"); - } - - return value; + throw new MakeVariableExpander.ExpansionException("$(" + variableName + ") not defined"); } public SkylarkDict<String, String> collectMakeVariables() { Map<String, String> map = new LinkedHashMap<>(); // Collect variables in the reverse order as in lookupMakeVariable // because each update is overwriting. - map.putAll(pkg.getAllMakeVariables(platform)); - map.putAll(globalEnv); - map.putAll(commandLineEnv); - map.putAll(ruleEnv); + for (MakeVariableSupplier supplier : allMakeVariableSuppliers.reverse()) { + map.putAll(supplier.getAllMakeVariables()); + } return SkylarkDict.<String, String>copyOf(null, map); } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableSupplier.java b/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableSupplier.java new file mode 100644 index 0000000000..911456965b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableSupplier.java @@ -0,0 +1,78 @@ +// 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.analysis; + +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.packages.Package; +import com.google.devtools.build.lib.util.Preconditions; +import javax.annotation.Nullable; + +/** + * Instances of {@link MakeVariableSupplier} passed to {@link ConfigurationMakeVariableContext} will + * be called before getting value from {@link ConfigurationMakeVariableContext} itself. + */ +public interface MakeVariableSupplier { + + /** Returns Make variable value or null if value is not supplied. */ + @Nullable + String getMakeVariable(String variableName); + + /** Returns all Make variables that it supplies */ + ImmutableMap<String, String> getAllMakeVariables(); + + /** {@link MakeVariableSupplier} that reads variables it supplies from a map. */ + class MapBackedMakeVariableSupplier implements MakeVariableSupplier { + + private final ImmutableMap<String, String> makeVariables; + + public MapBackedMakeVariableSupplier(ImmutableMap<String, String> makeVariables) { + this.makeVariables = Preconditions.checkNotNull(makeVariables); + } + + @Nullable + @Override + public String getMakeVariable(String variableName) { + return makeVariables.get(variableName); + } + + @Override + public ImmutableMap<String, String> getAllMakeVariables() { + return makeVariables; + } + } + + /** {@link MakeVariableSupplier} that reads variables it supplies from a {@link Package} */ + class PackageBackedMakeVariableSupplier implements MakeVariableSupplier { + + private final String platform; + private final Package pkg; + + public PackageBackedMakeVariableSupplier(Package pkg, String platform) { + this.pkg = pkg; + this.platform = platform; + } + + @Nullable + @Override + public String getMakeVariable(String variableName) { + return pkg.lookupMakeVariable(variableName, platform); + } + + @Override + public ImmutableMap<String, String> getAllMakeVariables() { + return pkg.getAllMakeVariables(platform); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java index 170d323631..2077a88733 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java @@ -92,6 +92,7 @@ import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; @@ -942,17 +943,46 @@ public final class RuleContext extends TargetContext * @return a list of strings containing the expanded and tokenized values for the attribute */ public ImmutableList<String> getTokenizedStringListAttr(String attributeName) { - return getExpandedStringListAttr(attributeName, Tokenize.YES); + return getExpandedStringListAttr(attributeName, Tokenize.YES, Collections.EMPTY_LIST); } /** - * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags, - * and optionally tokenizes the result. + * Gets an attribute of type STRING_LIST expanding Make variables, $(location) tags into the + * dependency location (see {@link LocationExpander} for details) and tokenizes the result. + * + * @param attributeName the name of the attribute to process + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} + * @return a list of strings containing the expanded and tokenized values for the attribute + */ + public ImmutableList<String> getTokenizedStringListAttr( + String attributeName, Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { + return getExpandedStringListAttr(attributeName, Tokenize.YES, makeVariableSuppliers); + } + + /** + * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags, and + * optionally tokenizes the result. Doesn't register any {@link MakeVariableSupplier}. * * @param attributeName the name of the attribute to process * @return a list of strings containing the processed values for the attribute */ public ImmutableList<String> getExpandedStringListAttr(String attributeName, Tokenize tokenize) { + return getExpandedStringListAttr( + attributeName, tokenize, ImmutableList.<MakeVariableSupplier>of()); + } + + /** + * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags, and + * optionally tokenizes the result. + * + * @param attributeName the name of the attribute to process + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} + * @return a list of strings containing the processed values for the attribute + */ + public ImmutableList<String> getExpandedStringListAttr( + String attributeName, + Tokenize tokenize, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { if (!getRule().isAttrDefined(attributeName, Type.STRING_LIST)) { // TODO(bazel-team): This should be an error. return ImmutableList.of(); @@ -966,7 +996,7 @@ public final class RuleContext extends TargetContext new LocationExpander(this, LocationExpander.Options.ALLOW_DATA); for (String token : original) { - expandValue(tokens, attributeName, token, locationExpander, tokenize); + expandValue(tokens, attributeName, token, locationExpander, tokenize, makeVariableSuppliers); } return ImmutableList.copyOf(tokens); } @@ -974,42 +1004,53 @@ public final class RuleContext extends TargetContext /** * Expands make variables in value and tokenizes the result into tokens. * - * <p>This methods should be called only during initialization. + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} + * <p>This methods should be called only during initialization. */ - public void tokenizeAndExpandMakeVars(List<String> tokens, String attributeName, String value) { + public void tokenizeAndExpandMakeVars( + List<String> tokens, + String attributeName, + String value, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { LocationExpander locationExpander = new LocationExpander(this, Options.ALLOW_DATA, Options.EXEC_PATHS); - tokenizeAndExpandMakeVars(tokens, attributeName, value, locationExpander); + tokenizeAndExpandMakeVars( + tokens, attributeName, value, locationExpander, makeVariableSuppliers); } /** * Expands make variables and $(location) tags in value and tokenizes the result into tokens. * - * <p>This methods should be called only during initialization. + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} + * <p>This methods should be called only during initialization. */ public void tokenizeAndExpandMakeVars( List<String> tokens, String attributeName, String value, - @Nullable LocationExpander locationExpander) { - expandValue(tokens, attributeName, value, locationExpander, Tokenize.YES); + @Nullable LocationExpander locationExpander, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { + expandValue( + tokens, attributeName, value, locationExpander, Tokenize.YES, makeVariableSuppliers); } /** * Expands make variables and $(location) tags in value, and optionally tokenizes the result. * - * <p>This methods should be called only during initialization. + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} + * <p>This methods should be called only during initialization. */ public void expandValue( List<String> tokens, String attributeName, String value, @Nullable LocationExpander locationExpander, - Tokenize tokenize) { + Tokenize tokenize, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { if (locationExpander != null) { value = locationExpander.expandAttribute(attributeName, value); } - value = expandMakeVariables(attributeName, value); + value = expandMakeVariables(attributeName, value, makeVariableSuppliers); if (tokenize == Tokenize.YES) { try { ShellUtils.tokenize(tokens, value); @@ -1046,30 +1087,64 @@ public final class RuleContext extends TargetContext } /** - * Return a context that maps Make variable names (string) to values (string). + * Returns a (cached! read on) context that maps Make variable names (string) to values (string) + * without any extra {@link MakeVariableSupplier}. + * + * <p>Beware!!! {@link ConfigurationMakeVariableContext} instance is cached, so if you call it + * first with some list of {@link MakeVariableSupplier} and then with other list, you will always + * get the first instance back. TODO(hlopko): Extract Make variable expansion from RuleContext and + * fix all the callers * * @return a ConfigurationMakeVariableContext. - **/ + */ public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() { + return getConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of()); + } + + /** + * Returns a (cached! read on) context that maps Make variable names (string) to values (string). + * + * @see #getConfigurationMakeVariableContext() to understand how the instance is cached! + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} + * @return a ConfigurationMakeVariableContext. + */ + public ConfigurationMakeVariableContext getConfigurationMakeVariableContext( + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { if (configurationMakeVariableContext == null) { configurationMakeVariableContext = - new ConfigurationMakeVariableContext(this, getRule().getPackage(), getConfiguration()); + new ConfigurationMakeVariableContext( + this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers); } return configurationMakeVariableContext; } /** - * Returns the string "expression" after expanding all embedded references to - * "Make" variables. If any errors are encountered, they are reported, and - * "expression" is returned unchanged. + * Return a context that maps Make variable names (string) to values (string). * - * @param attributeName the name of the attribute from which "expression" comes; - * used for error reporting. + * <p>Uses {@NoopExpansionInterceptor}. + * + * @return a ConfigurationMakeVariableContext. + */ + public String expandMakeVariables(String attributeName, String expression) { + return expandMakeVariables(attributeName, expression, ImmutableList.<MakeVariableSupplier>of()); + } + + /** + * Returns the string "expression" after expanding all embedded references to "Make" variables. If + * any errors are encountered, they are reported, and "expression" is returned unchanged. + * + * @param attributeName the name of the attribute from which "expression" comes; used for error + * reporting. * @param expression the string to expand. + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} * @return the expansion of "expression". */ - public String expandMakeVariables(String attributeName, String expression) { - return expandMakeVariables(attributeName, expression, getConfigurationMakeVariableContext()); + public String expandMakeVariables( + String attributeName, + String expression, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { + return expandMakeVariables( + attributeName, expression, getConfigurationMakeVariableContext(makeVariableSuppliers)); } /** @@ -1100,24 +1175,29 @@ public final class RuleContext extends TargetContext public List<String> expandedMakeVariablesList(String attrName) { List<String> variables = new ArrayList<>(); for (String variable : attributes().get(attrName, Type.STRING_LIST)) { - variables.add(expandMakeVariables(attrName, variable)); + variables.add( + expandMakeVariables(attrName, variable, ImmutableList.<MakeVariableSupplier>of())); } return variables; } /** - * If the string consists of a single variable, returns the expansion of - * that variable. Otherwise, returns null. Syntax errors are reported. + * If the string consists of a single variable, returns the expansion of that variable. Otherwise, + * returns null. Syntax errors are reported. * - * @param attrName the name of the attribute from which "expression" comes; - * used for error reporting. + * @param attrName the name of the attribute from which "expression" comes; used for error + * reporting. * @param expression the string to expand. + * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext} * @return the expansion of "expression", or null. */ - public String expandSingleMakeVariable(String attrName, String expression) { + public String expandSingleMakeVariable( + String attrName, + String expression, + ImmutableList<? extends MakeVariableSupplier> makeVariableSuppliers) { try { return MakeVariableExpander.expandSingleVariable( - expression, getConfigurationMakeVariableContext()); + expression, getConfigurationMakeVariableContext(makeVariableSuppliers)); } catch (MakeVariableExpander.ExpansionException e) { attributeError(attrName, e.getMessage()); return expression; diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java index 3b9792cbcf..a7331ccd06 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java @@ -21,7 +21,6 @@ import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.SourceManifestAction.ManifestType; import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; import com.google.devtools.build.lib.analysis.actions.CommandLine; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.SymlinkTreeAction; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.RunUnder; @@ -87,13 +86,12 @@ public final class RunfilesSupport { * @param executable the executable for whose runfiles this runfiles support is responsible, may * be null * @param runfiles the runfiles - * @param appendingArgs to be added after the rule's args */ private RunfilesSupport( RuleContext ruleContext, Artifact executable, Runfiles runfiles, - CommandLine appendingArgs, + CommandLine args, boolean createSymlinks) { owningExecutable = Preconditions.checkNotNull(executable); this.createSymlinks = createSymlinks; @@ -127,8 +125,7 @@ public final class RunfilesSupport { ruleContext, artifactsMiddleman, runfilesManifest); sourcesManifest = createSourceManifest(ruleContext, runfiles); - ImmutableList<String> args = ruleContext.getTokenizedStringListAttr("args"); - this.args = CommandLine.concat(args, appendingArgs); + this.args = args; } /** @@ -323,7 +320,7 @@ public final class RunfilesSupport { } /** - * Creates an Artifact which writes the "sources only" manifest file. + * Creates an {@link Artifact} which writes the "sources only" manifest file. * * @param context the owner for the manifest action * @param runfiles the runfiles @@ -366,44 +363,51 @@ public final class RunfilesSupport { } /** - * Creates and returns a RunfilesSupport object for the given rule and executable. Note that this - * method calls back into the passed in rule to obtain the runfiles. + * Creates and returns a {@link RunfilesSupport} object for the given rule and executable. Note + * that this method calls back into the passed in rule to obtain the runfiles. */ - public static RunfilesSupport withExecutable(RuleContext ruleContext, Runfiles runfiles, - Artifact executable) { + public static RunfilesSupport withExecutable( + RuleContext ruleContext, Runfiles runfiles, Artifact executable) { return new RunfilesSupport( ruleContext, executable, runfiles, - CommandLine.EMPTY, + computeArgs(ruleContext, CommandLine.EMPTY, ImmutableList.<MakeVariableSupplier>of()), ruleContext.shouldCreateRunfilesSymlinks()); } /** - * Creates and returns a RunfilesSupport object for the given rule and executable. Note that this - * method calls back into the passed in rule to obtain the runfiles. + * Creates and returns a {@link RunfilesSupport} object for the given rule and executable. Note + * that this method calls back into the passed in rule to obtain the runfiles. */ - public static RunfilesSupport withExecutable(RuleContext ruleContext, Runfiles runfiles, - Artifact executable, boolean createSymlinks) { + public static RunfilesSupport withExecutable( + RuleContext ruleContext, Runfiles runfiles, Artifact executable, boolean createSymlinks) { return new RunfilesSupport( - ruleContext, executable, runfiles, CommandLine.EMPTY, createSymlinks); + ruleContext, + executable, + runfiles, + computeArgs(ruleContext, CommandLine.EMPTY, ImmutableList.<MakeVariableSupplier>of()), + createSymlinks); } /** - * Creates and returns a RunfilesSupport object for the given rule, executable, runfiles and args. + * Creates and returns a {@link RunfilesSupport} object for the given rule and executable. Note + * that this method calls back into the passed in rule to obtain the runfiles. */ - public static RunfilesSupport withExecutable(RuleContext ruleContext, Runfiles runfiles, - Artifact executable, List<String> appendingArgs) { + public static RunfilesSupport withExecutable( + RuleContext ruleContext, Runfiles runfiles, Artifact executable, List<String> appendingArgs) { return new RunfilesSupport( ruleContext, executable, runfiles, - CustomCommandLine.builder().add(appendingArgs).build(), + computeArgs( + ruleContext, CommandLine.of(appendingArgs), ImmutableList.<MakeVariableSupplier>of()), ruleContext.shouldCreateRunfilesSymlinks()); } /** - * Creates and returns a RunfilesSupport object for the given rule, executable, runfiles and args. + * Creates and returns a {@link RunfilesSupport} object for the given rule, executable, runfiles + * and args. */ public static RunfilesSupport withExecutable( RuleContext ruleContext, Runfiles runfiles, Artifact executable, CommandLine appendingArgs) { @@ -411,7 +415,29 @@ public final class RunfilesSupport { ruleContext, executable, runfiles, - appendingArgs, + computeArgs(ruleContext, appendingArgs, ImmutableList.<MakeVariableSupplier>of()), ruleContext.shouldCreateRunfilesSymlinks()); } + + public static RunfilesSupport withExecutable( + RuleContext ruleContext, + Runfiles runfiles, + Artifact executable, + boolean createSymlinks, + ImmutableList<? extends MakeVariableSupplier> makeVariableSuppliers) { + return new RunfilesSupport( + ruleContext, + executable, + runfiles, + computeArgs(ruleContext, CommandLine.EMPTY, makeVariableSuppliers), + createSymlinks); + } + + private static CommandLine computeArgs( + RuleContext ruleContext, + CommandLine additionalArgs, + ImmutableList<? extends MakeVariableSupplier> makeVariableSuppliers) { + return CommandLine.concat( + ruleContext.getTokenizedStringListAttr("args", makeVariableSuppliers), additionalArgs); + } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java index 1098e2aa81..44bcbc7857 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java @@ -2356,14 +2356,14 @@ public final class BuildConfiguration implements BuildEvent { * (Fragments, in particular the Google C++ support, can set variables through the * command line.) */ - public Map<String, String> getCommandLineBuildVariables() { + public ImmutableMap<String, String> getCommandLineBuildVariables() { return commandLineBuildVariables; } /** * Returns the global defaults for this configuration for the Make environment. */ - public Map<String, String> getGlobalMakeEnvironment() { + public ImmutableMap<String, String> getGlobalMakeEnvironment() { return globalMakeEnv; } diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java index 3e0ec37f1e..55f39fdd46 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/Package.java +++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java @@ -390,7 +390,7 @@ public class Package { /** * Returns all make variables for a given platform. */ - public Map<String, String> getAllMakeVariables(String platform) { + public ImmutableMap<String, String> getAllMakeVariables(String platform) { ImmutableMap.Builder<String, String> map = ImmutableMap.builder(); for (String var : makeEnv.getBindings().keySet()) { String value = makeEnv.lookup(var, platform); diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java index acd7e31332..565da4d942 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java @@ -1010,11 +1010,11 @@ public final class SkylarkRuleContext implements SkylarkValue { new ConfigurationMakeVariableContext( ruleContext, ruleContext.getRule().getPackage(), ruleContext.getConfiguration()) { @Override - public String lookupMakeVariable(String name) throws ExpansionException { - if (additionalSubstitutions.containsKey(name)) { - return additionalSubstitutions.get(name); + public String lookupMakeVariable(String variableName) throws ExpansionException { + if (additionalSubstitutions.containsKey(variableName)) { + return additionalSubstitutions.get(variableName); } else { - return super.lookupMakeVariable(name); + return super.lookupMakeVariable(variableName); } } }); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java index f5de614815..505d8e33b0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java @@ -13,7 +13,10 @@ // limitations under the License. package com.google.devtools.build.lib.rules.cpp; +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -21,6 +24,7 @@ import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.AnalysisEnvironment; import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.MakeVariableSupplier; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; @@ -32,6 +36,7 @@ import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.rules.apple.Platform; import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.SourceCategory; 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.CppConfiguration.DynamicMode; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode; import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector; @@ -50,6 +55,7 @@ import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import javax.annotation.Nullable; /** * Common parts of the implementation of cc rules. @@ -89,6 +95,7 @@ public final class CcCommon { CppRuleClasses.PIC, CppRuleClasses.PER_OBJECT_DEBUG_INFO, CppRuleClasses.PREPROCESSOR_DEFINES); + public static final String CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME = ":cc_toolchain"; /** C++ configuration */ private final CppConfiguration cppConfiguration; @@ -304,6 +311,62 @@ public final class CcCommon { return getHeaders(ruleContext); } + /** + * Supply CC_FLAGS Make variable value computed from FeatureConfiguration. Appends them to + * original CC_FLAGS, so FeatureConfiguration can override legacy values. + */ + public static class CcFlagsSupplier implements MakeVariableSupplier { + + private final RuleContext ruleContext; + + public CcFlagsSupplier(RuleContext ruleContext) { + this.ruleContext = Preconditions.checkNotNull(ruleContext); + } + + @Override + @Nullable + public String getMakeVariable(String variableName) { + if (!variableName.equals(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME)) { + return null; + } + + CcToolchainProvider toolchain = + CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext); + FeatureConfiguration featureConfiguration = + CcCommon.configureFeatures(ruleContext, toolchain); + if (!featureConfiguration.actionIsConfigured( + CppCompileAction.CC_FLAGS_MAKE_VARIABLE_ACTION_NAME)) { + return null; + } + + Variables buildVariables = new Variables.Builder() + .addAllStringVariables(toolchain.getBuildVariables()) + .build(); + String toolchainCcFlags = + Joiner.on(" ") + .join( + featureConfiguration.getCommandLine( + CppCompileAction.CC_FLAGS_MAKE_VARIABLE_ACTION_NAME, buildVariables)); + + ImmutableMap<String, String> currentMakeVariables = + ruleContext.getMakeVariables(ImmutableList.of(CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME)); + Preconditions.checkArgument( + currentMakeVariables.containsKey(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME)); + + return FluentIterable.of( + currentMakeVariables.get(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME)) + .append(toolchainCcFlags) + .join(Joiner.on(" ")); + } + + @Override + public ImmutableMap<String, String> getAllMakeVariables() { + return ImmutableMap.of( + CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME, + getMakeVariable(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME)); + } + } + private static ImmutableList<String> getPackageCopts(RuleContext ruleContext) { List<String> unexpanded = ruleContext.getRule().getPackage().getDefaultCopts(); return ImmutableList.copyOf(CppHelper.expandMakeVariables(ruleContext, "copts", unexpanded)); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java index 4f540224ff..abb218d4d0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java @@ -101,6 +101,7 @@ public final class CcLibraryHelper { CppFileTypes.ASSEMBLER, CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR), ImmutableSet.<String>of( + CppCompileAction.CC_FLAGS_MAKE_VARIABLE_ACTION_NAME, CppCompileAction.C_COMPILE, CppCompileAction.CPP_COMPILE, CppCompileAction.CPP_HEADER_PARSING, @@ -128,6 +129,7 @@ public final class CcLibraryHelper { CppFileTypes.ASSEMBLER, CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR), ImmutableSet.<String>of( + CppCompileAction.CC_FLAGS_MAKE_VARIABLE_ACTION_NAME, CppCompileAction.C_COMPILE, CppCompileAction.CPP_COMPILE, CppCompileAction.OBJC_COMPILE, @@ -147,9 +149,9 @@ public final class CcLibraryHelper { Link.LinkTargetType.EXECUTABLE.getActionName())); private final FileTypeSet sourceTypeSet; - private final Set<String> actionConfigSet; + private final ImmutableSet<String> actionConfigSet; - private SourceCategory(FileTypeSet sourceTypeSet, Set<String> actionConfigSet) { + private SourceCategory(FileTypeSet sourceTypeSet, ImmutableSet<String> actionConfigSet) { this.sourceTypeSet = sourceTypeSet; this.actionConfigSet = actionConfigSet; } 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 2d3231b177..ea3deb880e 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 @@ -464,9 +464,9 @@ public class CcToolchain implements RuleConfiguredTargetFactory { // Overwrite the CC_FLAGS variable to include sysroot, if it's available. if (sysroot != null) { String sysrootFlag = "--sysroot=" + sysroot; - String ccFlags = makeVariables.get("CC_FLAGS"); + String ccFlags = makeVariables.get(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME); ccFlags = ccFlags.isEmpty() ? sysrootFlag : ccFlags + " " + sysrootFlag; - makeVariables.put("CC_FLAGS", ccFlags); + makeVariables.put(CppConfiguration.CC_FLAGS_MAKE_VARIABLE_NAME, ccFlags); } return new MakeVariableProvider(ImmutableMap.copyOf(makeVariables)); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java index 5bc7e3647a..0fd33d0567 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java @@ -83,6 +83,7 @@ import javax.annotation.Nullable; @ThreadCompatible public class CppCompileAction extends AbstractAction implements IncludeScannable, ExecutionInfoSpecifier, CommandAction { + /** * Represents logic that determines if an artifact is a special input, meaning that it may require * additional inputs when it is compiled or may not be available to other actions. @@ -115,6 +116,10 @@ public class CppCompileAction extends AbstractAction private static final int VALIDATION_DEBUG = 0; // 0==none, 1==warns/errors, 2==all private static final boolean VALIDATION_DEBUG_WARN = VALIDATION_DEBUG >= 1; + /** A string constant used to compute CC_FLAGS make variable value */ + public static final java.lang.String CC_FLAGS_MAKE_VARIABLE_ACTION_NAME = + "cc-flags-make-variable"; + /** * A string constant for the c compilation action. */ 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 c9e148ca12..7fc17ec06f 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 @@ -88,6 +88,9 @@ public class CppConfiguration extends BuildConfiguration.Fragment { */ public static final String MAC_SYSTEM_NAME = "x86_64-apple-macosx"; + /** String constant for CC_FLAGS make variable name */ + public static final String CC_FLAGS_MAKE_VARIABLE_NAME = "CC_FLAGS"; + /** * An enumeration of all the tools that comprise a toolchain. */ @@ -576,7 +579,7 @@ public class CppConfiguration extends BuildConfiguration.Fragment { // 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", ""); + makeVariablesBuilder.put(CC_FLAGS_MAKE_VARIABLE_NAME, ""); for (CrosstoolConfig.MakeVariable variable : toolchain.getMakeVariableList()) { makeVariablesBuilder.put(variable.getName(), variable.getValue()); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java index 96ba0a6892..f1952e897d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java @@ -24,6 +24,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.MiddlemanFactory; import com.google.devtools.build.lib.analysis.AnalysisUtils; import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.MakeVariableSupplier; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleContext; @@ -37,6 +38,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.RuleErrorConsumer; +import com.google.devtools.build.lib.rules.cpp.CcCommon.CcFlagsSupplier; import com.google.devtools.build.lib.rules.cpp.CcLinkParams.Linkstamp; import com.google.devtools.build.lib.rules.cpp.CppCompilationContext.Builder; import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; @@ -136,17 +138,22 @@ public class CppHelper { !ruleContext.getFeatures().contains("no_copts_tokenization"); List<String> tokens = new ArrayList<>(); + ImmutableList<? extends MakeVariableSupplier> makeVariableSuppliers = + ImmutableList.of(new CcFlagsSupplier(ruleContext)); for (String token : input) { try { // Legacy behavior: tokenize all items. if (tokenization) { - ruleContext.tokenizeAndExpandMakeVars(tokens, attributeName, token); + ruleContext.tokenizeAndExpandMakeVars( + tokens, attributeName, token, makeVariableSuppliers); } else { - String exp = ruleContext.expandSingleMakeVariable(attributeName, token); + String exp = + ruleContext.expandSingleMakeVariable(attributeName, token, makeVariableSuppliers); if (exp != null) { ShellUtils.tokenize(tokens, exp); } else { - tokens.add(ruleContext.expandMakeVariables(attributeName, token)); + tokens.add( + ruleContext.expandMakeVariables(attributeName, token, makeVariableSuppliers)); } } } catch (ShellUtils.TokenizationException e) { @@ -178,7 +185,11 @@ public class CppHelper { ruleContext.attributeError(attrName, "could not resolve label '" + attrValue + "'"); } } else { - ruleContext.tokenizeAndExpandMakeVars(values, attrName, attrValue); + ruleContext.tokenizeAndExpandMakeVars( + values, + attrName, + attrValue, + ImmutableList.of(new CcFlagsSupplier(ruleContext))); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java index 5f0432ac4a..f35627b6eb 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java +++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.FileProvider; import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.MakeVariableExpander.ExpansionException; +import com.google.devtools.build.lib.analysis.MakeVariableSupplier; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleContext; @@ -40,6 +41,7 @@ import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.rules.cpp.CcCommon.CcFlagsSupplier; import com.google.devtools.build.lib.rules.cpp.CcToolchain; import com.google.devtools.build.lib.rules.cpp.CppHelper; import com.google.devtools.build.lib.rules.java.JavaHelper; @@ -56,7 +58,7 @@ import java.util.regex.Pattern; public abstract class GenRuleBase implements RuleConfiguredTargetFactory { private static final Pattern CROSSTOOL_MAKE_VARIABLE = - Pattern.compile("\\$\\((CC|AR|NM|OBJCOPY|STRIP|GCOVTOOL|CC_FLAGS)\\)"); + Pattern.compile("\\$\\((CC|CC_FLAGS|AR|NM|OBJCOPY|STRIP|GCOVTOOL)\\)"); private static final Pattern JDK_MAKE_VARIABLE = Pattern.compile("\\$\\((JAVABASE|JAVA)\\)"); @@ -278,7 +280,11 @@ public abstract class GenRuleBase implements RuleConfiguredTargetFactory { */ protected CommandResolverContext createCommandResolverContext(RuleContext ruleContext, NestedSet<Artifact> resolvedSrcs, NestedSet<Artifact> filesToBuild) { - return new CommandResolverContext(ruleContext, resolvedSrcs, filesToBuild); + return new CommandResolverContext( + ruleContext, + resolvedSrcs, + filesToBuild, + ImmutableList.of(new CcFlagsSupplier(ruleContext))); } /** @@ -297,11 +303,13 @@ public abstract class GenRuleBase implements RuleConfiguredTargetFactory { public CommandResolverContext( RuleContext ruleContext, NestedSet<Artifact> resolvedSrcs, - NestedSet<Artifact> filesToBuild) { + NestedSet<Artifact> filesToBuild, + Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) { super( ruleContext.getMakeVariables(makeVariableAttributes), ruleContext.getRule().getPackage(), - ruleContext.getConfiguration()); + ruleContext.getConfiguration(), + makeVariableSuppliers); this.ruleContext = ruleContext; this.resolvedSrcs = resolvedSrcs; this.filesToBuild = filesToBuild; @@ -312,16 +320,16 @@ public abstract class GenRuleBase implements RuleConfiguredTargetFactory { } @Override - public String lookupMakeVariable(String name) throws ExpansionException { - if (name.equals("SRCS")) { + public String lookupMakeVariable(String variableName) throws ExpansionException { + if (variableName.equals("SRCS")) { return Artifact.joinExecPaths(" ", resolvedSrcs); - } else if (name.equals("<")) { + } else if (variableName.equals("<")) { return expandSingletonArtifact(resolvedSrcs, "$<", "input file"); - } else if (name.equals("OUTS")) { + } else if (variableName.equals("OUTS")) { return Artifact.joinExecPaths(" ", filesToBuild); - } else if (name.equals("@")) { + } else if (variableName.equals("@")) { return expandSingletonArtifact(filesToBuild, "$@", "output file"); - } else if (name.equals("@D")) { + } else if (variableName.equals("@D")) { // The output directory. If there is only one filename in outs, // this expands to the directory containing that file. If there are // multiple filenames, this variable instead expands to the @@ -348,14 +356,14 @@ public abstract class GenRuleBase implements RuleConfiguredTargetFactory { ruleContext.getRule().getLabel().getPackageIdentifier().getSourceRoot(); return dir.getRelative(relPath).getPathString(); } - } else if (JDK_MAKE_VARIABLE.matcher("$(" + name + ")").find()) { + } else if (JDK_MAKE_VARIABLE.matcher("$(" + variableName + ")").find()) { return new ConfigurationMakeVariableContext( ruleContext.getMakeVariables(makeVariableAttributes), ruleContext.getTarget().getPackage(), ruleContext.getHostConfiguration()) - .lookupMakeVariable(name); + .lookupMakeVariable(variableName); } else { - return super.lookupMakeVariable(name); + return super.lookupMakeVariable(variableName); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java index 74fdc2fcd8..ab6df63379 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java @@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.rules.python; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; @@ -23,6 +24,7 @@ import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.RunfilesSupport; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.rules.cpp.CcCommon.CcFlagsSupplier; import com.google.devtools.build.lib.rules.cpp.CcLinkParams; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsStore; @@ -84,8 +86,13 @@ public abstract class PyBinary implements RuleConfiguredTargetFactory { semantics.collectDefaultRunfilesForBinary(ruleContext, defaultRunfilesBuilder); Runfiles defaultRunfiles = defaultRunfilesBuilder.build(); - RunfilesSupport runfilesSupport = RunfilesSupport.withExecutable(ruleContext, defaultRunfiles, - common.getExecutable(), ruleContext.shouldCreateRunfilesSymlinks()); + RunfilesSupport runfilesSupport = + RunfilesSupport.withExecutable( + ruleContext, + defaultRunfiles, + common.getExecutable(), + ruleContext.shouldCreateRunfilesSymlinks(), + ImmutableList.of(new CcFlagsSupplier(ruleContext))); if (ruleContext.hasErrors()) { return null; diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleCommandSubstitutionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleCommandSubstitutionTest.java index a17c2ebb92..2d57b3a10a 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleCommandSubstitutionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleCommandSubstitutionTest.java @@ -14,10 +14,12 @@ package com.google.devtools.build.lib.bazel.rules.genrule; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import com.google.common.base.Joiner; import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.util.AnalysisMock; import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -475,4 +477,31 @@ public class GenRuleCommandSubstitutionTest extends BuildViewTestCase { " outs = ['out'],", " cmd = '" + command + "')"); } -} + + @Test + public void testCcFlagsFromFeatureConfiguration() throws Exception { + AnalysisMock.get() + .ccSupport() + .setupCrosstool( + mockToolsConfig, + "action_config {", + " action_name: 'cc-flags-make-variable'", + " config_name: 'cc-flags-make-variable'", + " flag_set {", + " flag_group {", + " flag: 'foo'", + " flag: 'bar'", + " flag: 'baz'", + " }", + " }", + "}"); + useConfiguration(); + scratch.file( + "foo/BUILD", + "genrule(name = 'foo',", + " outs = ['out'],", + " cmd = '$(CC_FLAGS)')"); + String command = getGenruleCommand("//foo"); + assertThat(command).endsWith("foo bar baz"); + } +}
\ No newline at end of file |