Skip to content

Commit 82d4db2

Browse files
ulrfacopybara-github
authored andcommitted
Same transition dirs when only cmd line options differs
Ignore user defined build settings only set on command line and not affected by any transition, when calculating transitionDirectoryNameFragment output directory. Native options on command line already have this behavior, and this commit provides the same also for user defined build settings. This allows reducing transition scalability issues, by combining transitions with command line options: a) Setting a limited number of common options via transitions, which affects large parts of the code base, but with limited number of variants. b) When needed, *also* setting a few of many specific options, each of them affecting only their parts of the code base, but with many variants. Resolves #12731 Closes #13580. PiperOrigin-RevId: 396689438
1 parent 331e19a commit 82d4db2

File tree

3 files changed

+122
-49
lines changed

3 files changed

+122
-49
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,11 @@ public String getTypeDescription() {
261261
}
262262

263263
/**
264-
* This internal option is a *set* of names (e.g. "cpu") of *native* options that have been
265-
* changed by starlark transitions at any point in the build at the time of accessing. This is
266-
* used to regenerate {@code transitionDirectoryNameFragment} after each starlark transition.
264+
* This internal option is a *set* of names of options that have been changed by starlark
265+
* transitions at any point in the build at the time of accessing. It contains both native and
266+
* starlark options in label form. e.g. "//command_line_option:cpu" for native options and
267+
* "//myapp:foo" for starlark options. This is used to regenerate {@code
268+
* transitionDirectoryNameFragment} after each starlark transition.
267269
*/
268270
@Option(
269271
name = "affected by starlark transition",

src/main/java/com/google/devtools/build/lib/analysis/starlark/FunctionTransitionUtil.java

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static java.util.stream.Collectors.joining;
2020

2121
import com.google.common.base.Joiner;
22+
import com.google.common.base.VerifyException;
2223
import com.google.common.collect.ImmutableList;
2324
import com.google.common.collect.ImmutableMap;
2425
import com.google.common.collect.ImmutableSet;
@@ -289,13 +290,13 @@ private static BuildOptions applyTransition(
289290

290291
if (!optionName.startsWith(COMMAND_LINE_OPTION_PREFIX)) {
291292
// The transition changes a Starlark option.
292-
Object oldValue =
293-
fromOptions.getStarlarkOptions().get(Label.parseAbsoluteUnchecked(optionName));
293+
Label optionLabel = Label.parseAbsoluteUnchecked(optionName);
294+
Object oldValue = fromOptions.getStarlarkOptions().get(optionLabel);
294295
if ((oldValue == null && optionValue != null)
295296
|| (oldValue != null && optionValue == null)
296297
|| (oldValue != null && !oldValue.equals(optionValue))) {
297-
changedStarlarkOptions.put(Label.parseAbsoluteUnchecked(optionName), optionValue);
298-
convertedNewValues.add(optionName);
298+
changedStarlarkOptions.put(optionLabel, optionValue);
299+
convertedNewValues.add(optionLabel.toString());
299300
}
300301
} else {
301302
// The transition changes a native option.
@@ -398,9 +399,10 @@ private static BuildOptions applyTransition(
398399
}
399400

400401
/**
401-
* Compute the output directory name fragment corresponding to the new BuildOptions based on (1)
402-
* the names and values of all native options previously transitioned anywhere in the build by
403-
* starlark transitions, (2) names and values of all entries in the starlark options map.
402+
* Compute the output directory name fragment corresponding to the new BuildOptions based on the
403+
* names and values of all options (both native and Starlark) previously transitioned anywhere in
404+
* the build by Starlark transitions. Options only set on command line are not affecting the
405+
* computation.
404406
*
405407
* @param changedOptions the names of all options changed by this transition in label form e.g.
406408
* "//command_line_option:cpu" for native options and "//myapp:foo" for starlark options.
@@ -421,38 +423,34 @@ private static void updateOutputDirectoryNameFragment(
421423
}
422424

423425
CoreOptions buildConfigOptions = toOptions.get(CoreOptions.class);
424-
Set<String> updatedAffectedByStarlarkTransition =
425-
new TreeSet<>(buildConfigOptions.affectedByStarlarkTransition);
426-
// Add newly changed native options to overall list of changed native options
427-
for (String option : changedOptions) {
428-
if (option.startsWith(COMMAND_LINE_OPTION_PREFIX)) {
429-
updatedAffectedByStarlarkTransition.add(
430-
option.substring(COMMAND_LINE_OPTION_PREFIX.length()));
431-
}
432-
}
433-
buildConfigOptions.affectedByStarlarkTransition =
434-
ImmutableList.sortedCopyOf(updatedAffectedByStarlarkTransition);
435426

436-
// hash all relevant native option values;
427+
updateAffectedByStarlarkTransition(buildConfigOptions, changedOptions);
428+
437429
TreeMap<String, Object> toHash = new TreeMap<>();
438-
for (String nativeOption : updatedAffectedByStarlarkTransition) {
439-
Object value;
440-
try {
441-
value =
442-
optionInfoMap
443-
.get(nativeOption)
444-
.getDefinition()
445-
.getField()
446-
.get(toOptions.get(optionInfoMap.get(nativeOption).getOptionClass()));
447-
} catch (IllegalAccessException e) {
448-
throw new RuntimeException(
449-
"IllegalAccess for option " + nativeOption + ": " + e.getMessage());
430+
for (String optionName : buildConfigOptions.affectedByStarlarkTransition) {
431+
if (optionName.startsWith(COMMAND_LINE_OPTION_PREFIX)) {
432+
String nativeOptionName = optionName.substring(COMMAND_LINE_OPTION_PREFIX.length());
433+
Object value;
434+
try {
435+
value =
436+
optionInfoMap
437+
.get(nativeOptionName)
438+
.getDefinition()
439+
.getField()
440+
.get(toOptions.get(optionInfoMap.get(nativeOptionName).getOptionClass()));
441+
} catch (IllegalAccessException e) {
442+
throw new VerifyException(
443+
"IllegalAccess for option " + nativeOptionName + ": " + e.getMessage());
444+
}
445+
toHash.put(optionName, value);
446+
} else {
447+
Object value = toOptions.getStarlarkOptions().get(Label.parseAbsoluteUnchecked(optionName));
448+
if (value != null) {
449+
toHash.put(optionName, value);
450+
}
450451
}
451-
toHash.put(nativeOption, value);
452452
}
453453

454-
// hash all starlark options in map.
455-
toOptions.getStarlarkOptions().forEach((opt, value) -> toHash.put(opt.toString(), value));
456454
ImmutableList.Builder<String> hashStrs = ImmutableList.builderWithExpectedSize(toHash.size());
457455
for (Map.Entry<String, Object> singleOptionAndValue : toHash.entrySet()) {
458456
String toAdd = singleOptionAndValue.getKey() + "=" + singleOptionAndValue.getValue();
@@ -462,6 +460,19 @@ private static void updateOutputDirectoryNameFragment(
462460
transitionDirectoryNameFragment(hashStrs.build());
463461
}
464462

463+
/**
464+
* Extend the global build config affectedByStarlarkTransition, by adding any new option names
465+
* from changedOptions
466+
*/
467+
private static void updateAffectedByStarlarkTransition(
468+
CoreOptions buildConfigOptions, Set<String> changedOptions) {
469+
Set<String> mutableCopyToUpdate =
470+
new TreeSet<>(buildConfigOptions.affectedByStarlarkTransition);
471+
mutableCopyToUpdate.addAll(changedOptions);
472+
buildConfigOptions.affectedByStarlarkTransition =
473+
ImmutableList.sortedCopyOf(mutableCopyToUpdate);
474+
}
475+
465476
public static String transitionDirectoryNameFragment(Iterable<String> opts) {
466477
Fingerprint fp = new Fingerprint();
467478
for (String opt : opts) {

src/test/java/com/google/devtools/build/lib/analysis/StarlarkAttrTransitionProviderTest.java

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,10 +1137,59 @@ public void testTransitionOnBuildSetting_fromCommandLine() throws Exception {
11371137
.isEqualTo(StarlarkInt.of(42));
11381138
}
11391139

1140+
@Test
1141+
public void testTransitionOnBuildSetting_onlyTransitionsAffectsDirectory() throws Exception {
1142+
writeAllowlistFile();
1143+
writeBuildSettingsBzl();
1144+
writeRulesWithAttrTransitionBzl();
1145+
scratch.file(
1146+
"test/starlark/BUILD",
1147+
"load('//test/starlark:rules.bzl', 'my_rule')",
1148+
"load('//test/starlark:build_settings.bzl', 'int_flag')",
1149+
"my_rule(name = 'test', dep = ':dep')",
1150+
"my_rule(name = 'dep')",
1151+
"int_flag(name = 'the-answer', build_setting_default = 0)",
1152+
"int_flag(name = 'cmd-line-option', build_setting_default = 0)");
1153+
1154+
useConfiguration(ImmutableMap.of("//test/starlark:cmd-line-option", 100), "--cpu=FOO");
1155+
1156+
ConfiguredTarget test = getConfiguredTarget("//test/starlark:test");
1157+
1158+
@SuppressWarnings("unchecked")
1159+
ConfiguredTarget dep =
1160+
Iterables.getOnlyElement(
1161+
(List<ConfiguredTarget>) getMyInfoFromTarget(test).getValue("dep"));
1162+
1163+
// Assert starlark option set via transition.
1164+
assertThat(getStarlarkOption(dep, "//test/starlark:the-answer")).isEqualTo(StarlarkInt.of(42));
1165+
1166+
// Assert starlark option set via command line.
1167+
assertThat(getStarlarkOption(dep, "//test/starlark:cmd-line-option")).isEqualTo(100);
1168+
1169+
// Assert native option set via command line.
1170+
assertThat(getCoreOptions(dep).cpu).isEqualTo("FOO");
1171+
1172+
// Assert that transitionDirectoryNameFragment is only affected by options
1173+
// set via transitions. Not by native or starlark options set via command line,
1174+
// never touched by any transition.
1175+
assertThat(getCoreOptions(dep).transitionDirectoryNameFragment)
1176+
.isEqualTo(
1177+
FunctionTransitionUtil.transitionDirectoryNameFragment(
1178+
ImmutableList.of("//test/starlark:the-answer=42")));
1179+
}
1180+
11401181
private CoreOptions getCoreOptions(ConfiguredTarget target) {
11411182
return getConfiguration(target).getOptions().get(CoreOptions.class);
11421183
}
11431184

1185+
private ImmutableMap<Label, Object> getStarlarkOptions(ConfiguredTarget target) {
1186+
return getConfiguration(target).getOptions().getStarlarkOptions();
1187+
}
1188+
1189+
private Object getStarlarkOption(ConfiguredTarget target, String absName) {
1190+
return getStarlarkOptions(target).get(Label.parseAbsoluteUnchecked(absName));
1191+
}
1192+
11441193
@Test
11451194
public void testOutputDirHash_multipleNativeOptionTransitions() throws Exception {
11461195
writeAllowlistFile();
@@ -1182,7 +1231,7 @@ public void testOutputDirHash_multipleNativeOptionTransitions() throws Exception
11821231

11831232
List<String> affectedOptions = getCoreOptions(test).affectedByStarlarkTransition;
11841233

1185-
assertThat(affectedOptions).containsExactly("foo");
1234+
assertThat(affectedOptions).containsExactly("//command_line_option:foo");
11861235

11871236
@SuppressWarnings("unchecked")
11881237
ConfiguredTarget dep =
@@ -1191,17 +1240,19 @@ public void testOutputDirHash_multipleNativeOptionTransitions() throws Exception
11911240

11921241
affectedOptions = getCoreOptions(dep).affectedByStarlarkTransition;
11931242

1194-
assertThat(affectedOptions).containsExactly("foo", "bar");
1243+
assertThat(affectedOptions)
1244+
.containsExactly("//command_line_option:foo", "//command_line_option:bar");
11951245

11961246
assertThat(getCoreOptions(test).transitionDirectoryNameFragment)
11971247
.isEqualTo(
11981248
FunctionTransitionUtil.transitionDirectoryNameFragment(
1199-
ImmutableList.of("foo=foosball")));
1249+
ImmutableList.of("//command_line_option:foo=foosball")));
12001250

12011251
assertThat(getCoreOptions(dep).transitionDirectoryNameFragment)
12021252
.isEqualTo(
12031253
FunctionTransitionUtil.transitionDirectoryNameFragment(
1204-
ImmutableList.of("bar=barsball", "foo=foosball")));
1254+
ImmutableList.of(
1255+
"//command_line_option:bar=barsball", "//command_line_option:foo=foosball")));
12051256
}
12061257

12071258
// Test that a no-op starlark transition to an already starlark transitioned configuration
@@ -1523,8 +1574,7 @@ public void testOutputDirHash_multipleStarlarkTransitions() throws Exception {
15231574
List<String> affectedOptions =
15241575
getConfiguration(dep).getOptions().get(CoreOptions.class).affectedByStarlarkTransition;
15251576

1526-
// Assert that affectedOptions is empty but final fragment is still different.
1527-
assertThat(affectedOptions).isEmpty();
1577+
assertThat(affectedOptions).containsExactly("//test:bar", "//test:foo");
15281578
assertThat(getCoreOptions(test).transitionDirectoryNameFragment)
15291579
.isEqualTo(
15301580
FunctionTransitionUtil.transitionDirectoryNameFragment(
@@ -1611,12 +1661,12 @@ public void testOutputDirHash_multipleMixedTransitions() throws Exception {
16111661
List<String> affectedOptionsTop =
16121662
getConfiguration(top).getOptions().get(CoreOptions.class).affectedByStarlarkTransition;
16131663

1614-
assertThat(affectedOptionsTop).containsExactly("foo");
1664+
assertThat(affectedOptionsTop).containsExactly("//command_line_option:foo");
16151665
assertThat(getConfiguration(top).getOptions().getStarlarkOptions()).isEmpty();
16161666
assertThat(getCoreOptions(top).transitionDirectoryNameFragment)
16171667
.isEqualTo(
16181668
FunctionTransitionUtil.transitionDirectoryNameFragment(
1619-
ImmutableList.of("foo=foosball")));
1669+
ImmutableList.of("//command_line_option:foo=foosball")));
16201670

16211671
// test:middle (foo_transition, zee_transition, bar_transition)
16221672
@SuppressWarnings("unchecked")
@@ -1626,14 +1676,20 @@ public void testOutputDirHash_multipleMixedTransitions() throws Exception {
16261676
List<String> affectedOptionsMiddle =
16271677
getConfiguration(middle).getOptions().get(CoreOptions.class).affectedByStarlarkTransition;
16281678

1629-
assertThat(affectedOptionsMiddle).containsExactly("foo", "bar");
1679+
assertThat(affectedOptionsMiddle)
1680+
.containsExactly("//command_line_option:foo", "//command_line_option:bar", "//test:zee");
1681+
16301682
assertThat(getConfiguration(middle).getOptions().getStarlarkOptions().entrySet())
16311683
.containsExactly(
16321684
Maps.immutableEntry(Label.parseAbsoluteUnchecked("//test:zee"), "zeesball"));
1685+
16331686
assertThat(getCoreOptions(middle).transitionDirectoryNameFragment)
16341687
.isEqualTo(
16351688
FunctionTransitionUtil.transitionDirectoryNameFragment(
1636-
ImmutableList.of("//test:zee=zeesball", "bar=barsball", "foo=foosball")));
1689+
ImmutableList.of(
1690+
"//command_line_option:bar=barsball",
1691+
"//command_line_option:foo=foosball",
1692+
"//test:zee=zeesball")));
16371693

16381694
// test:bottom (foo_transition, zee_transition, bar_transition, xan_transition)
16391695
@SuppressWarnings("unchecked")
@@ -1644,7 +1700,10 @@ public void testOutputDirHash_multipleMixedTransitions() throws Exception {
16441700
List<String> affectedOptionsBottom =
16451701
getConfiguration(bottom).getOptions().get(CoreOptions.class).affectedByStarlarkTransition;
16461702

1647-
assertThat(affectedOptionsBottom).containsExactly("foo", "bar");
1703+
assertThat(affectedOptionsBottom)
1704+
.containsExactly(
1705+
"//command_line_option:foo", "//command_line_option:bar", "//test:xan", "//test:zee");
1706+
16481707
assertThat(getConfiguration(bottom).getOptions().getStarlarkOptions().entrySet())
16491708
.containsExactly(
16501709
Maps.immutableEntry(Label.parseAbsoluteUnchecked("//test:zee"), "zeesball"),
@@ -1653,7 +1712,8 @@ public void testOutputDirHash_multipleMixedTransitions() throws Exception {
16531712
.isEqualTo(
16541713
FunctionTransitionUtil.transitionDirectoryNameFragment(
16551714
ImmutableList.of(
1656-
"//test:xan=xansball", "//test:zee=zeesball", "bar=barsball", "foo=foosball")));
1715+
"//command_line_option:bar=barsball", "//command_line_option:foo=foosball",
1716+
"//test:xan=xansball", "//test:zee=zeesball")));
16571717
}
16581718

16591719
@Test

0 commit comments

Comments
 (0)