Skip to content

Commit e133e66

Browse files
config doesn't error on duplicate --define values (bazelbuild#15473)
When `--define` flags are interpreted by other commands, the last one wins. Currently `bazel config` causes a server crash when interpreting duplicate `--define` values. This change makes `config` consistent with the other commands, and re-uses the same deduplication code across all call-sites. Closes bazelbuild#14760. PiperOrigin-RevId: 427266039 Co-authored-by: Daniel Wagner-Hall <[email protected]>
1 parent 1651b3b commit e133e66

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed

src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
import java.util.Map;
4747
import java.util.Objects;
4848
import java.util.Set;
49-
import java.util.TreeMap;
5049
import java.util.function.Supplier;
5150
import net.starlark.java.annot.StarlarkAnnotations;
5251
import net.starlark.java.annot.StarlarkBuiltin;
@@ -215,11 +214,8 @@ public BuildConfiguration(
215214
// We can't use an ImmutableMap.Builder here; we need the ability to add entries with keys that
216215
// are already in the map so that the same define can be specified on the command line twice,
217216
// and ImmutableMap.Builder does not support that.
218-
Map<String, String> commandLineDefinesBuilder = new TreeMap<>();
219-
for (Map.Entry<String, String> define : options.commandLineBuildVariables) {
220-
commandLineDefinesBuilder.put(define.getKey(), define.getValue());
221-
}
222-
commandLineBuildVariables = ImmutableMap.copyOf(commandLineDefinesBuilder);
217+
commandLineBuildVariables =
218+
ImmutableMap.copyOf(options.getNormalizedCommandLineBuildVariables());
223219

224220
this.actionEnv = actionEnvironment;
225221
this.testEnv = setupTestEnvironment();

src/main/java/com/google/devtools/build/lib/analysis/config/CoreOptions.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ public class CoreOptions extends FragmentOptions implements Cloneable {
8787
help = "If true, constraint settings from @bazel_tools are removed.")
8888
public boolean usePlatformsRepoForConstraints;
8989

90+
// Note: This value may contain conflicting duplicate values for the same define.
91+
// Use `getNormalizedCommandLineBuildVariables` if you wish for these to be deduplicated
92+
// (last-wins).
9093
@Option(
9194
name = "define",
9295
converter = Converters.AssignmentConverter.class,
@@ -878,16 +881,22 @@ public FragmentOptions getHost() {
878881
return host;
879882
}
880883

884+
/// Normalizes --define flags, preserving the last one to appear in the event of conflicts.
885+
public LinkedHashMap<String, String> getNormalizedCommandLineBuildVariables() {
886+
LinkedHashMap<String, String> flagValueByName = new LinkedHashMap<>();
887+
for (Map.Entry<String, String> entry : commandLineBuildVariables) {
888+
// If the same --define flag is passed multiple times we keep the last value.
889+
flagValueByName.put(entry.getKey(), entry.getValue());
890+
}
891+
return flagValueByName;
892+
}
893+
881894
@Override
882895
public CoreOptions getNormalized() {
883896
CoreOptions result = (CoreOptions) clone();
884897

885898
if (collapseDuplicateDefines) {
886-
LinkedHashMap<String, String> flagValueByName = new LinkedHashMap<>();
887-
for (Map.Entry<String, String> entry : result.commandLineBuildVariables) {
888-
// If the same --define flag is passed multiple times we keep the last value.
889-
flagValueByName.put(entry.getKey(), entry.getValue());
890-
}
899+
LinkedHashMap<String, String> flagValueByName = getNormalizedCommandLineBuildVariables();
891900

892901
// This check is an optimization to avoid creating a new list if the normalization was a
893902
// no-op.

src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,11 @@ private static ImmutableSortedMap<String, String> getOrderedUserDefinedOptions(
557557

558558
// --define:
559559
for (Map.Entry<String, String> entry :
560-
config.getOptions().get(CoreOptions.class).commandLineBuildVariables) {
560+
config
561+
.getOptions()
562+
.get(CoreOptions.class)
563+
.getNormalizedCommandLineBuildVariables()
564+
.entrySet()) {
561565
ans.put("--define:" + entry.getKey(), Verify.verifyNotNull(entry.getValue()));
562566
}
563567
return ans.build();

src/test/java/com/google/devtools/build/lib/runtime/commands/ConfigCommandTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,4 +427,29 @@ public void defineFlagsIndividuallyListedInUserDefinedFragment() throws Exceptio
427427
.collect(Collectors.toList()))
428428
.isEmpty();
429429
}
430+
431+
@Test
432+
public void conflictingDefinesLastWins() throws Exception {
433+
analyzeTarget("--define", "a=1", "--define", "a=2");
434+
435+
ConfigurationForOutput targetConfig = null;
436+
for (JsonElement configJson :
437+
JsonParser.parseString(callConfigCommand("--dump_all").outAsLatin1()).getAsJsonArray()) {
438+
ConfigurationForOutput config = new Gson().fromJson(configJson, ConfigurationForOutput.class);
439+
if (isTargetConfig(config)) {
440+
targetConfig = config;
441+
break;
442+
}
443+
}
444+
445+
assertThat(targetConfig).isNotNull();
446+
assertThat(getOptionValue(targetConfig, "user-defined", "--define:a")).isEqualTo("2");
447+
assertThat(
448+
targetConfig.fragmentOptions.stream()
449+
.filter(fragment -> fragment.name.endsWith("CoreOptions"))
450+
.flatMap(fragment -> fragment.options.keySet().stream())
451+
.filter(name -> name.equals("define"))
452+
.collect(Collectors.toList()))
453+
.isEmpty();
454+
}
430455
}

0 commit comments

Comments
 (0)