Skip to content

Commit

Permalink
Keep exec-configured --run_under targets behind an incompatible flag.
Browse files Browse the repository at this point in the history
b03e4c5  is an incompatible change. Repo testing showed failures changing this
unconditionally. So adding `--incompatible_bazel_test_exec_run_under` to gate it.

Even though `$ bazel test --run_under=//foo` invokes `//foo` on exec machines, `//foo`'s build may still expect target configurations. For example:

 - custom toolchain settings
 - target-focused `select()`s
 - user-defined flags that don't propagate to the exec config

See #23179.

PiperOrigin-RevId: 658472773
Change-Id: I1bdf30432a6e3c74fc0355f1a96fee44ba2d453a
  • Loading branch information
gregestren authored and copybara-github committed Aug 1, 2024
1 parent bf4b42a commit 1ec4365
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory;
import com.google.devtools.build.lib.analysis.config.RunUnder;
import com.google.devtools.build.lib.analysis.constraints.ConstraintConstants;
import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
import com.google.devtools.build.lib.analysis.test.CoverageConfiguration;
Expand Down Expand Up @@ -162,15 +161,48 @@ public static LabelLateBoundDefault<CoverageConfiguration> getCoverageOutputGene
(rule, attributes, configuration) -> configuration.outputGenerator();

// TODO(b/65746853): provide a way to do this without passing the entire configuration
/** Implementation for the :run_under attribute. */
/**
* Resolves the latebound exec-configured :run_under label. This only exists if --run_under is set
* to a label and --incompatible_bazel_test_exec_run_under is true. Else it's null.
*
* <p>{@link RUN_UNDER_EXEC_CONFIG} and {@link RUN_UNDER_TARGET_CONFIG} cannot both be non-null in
* a build: if {@code --run_under} is set it must connect to a single dependency.
*/
@SerializationConstant @VisibleForSerialization
public static final LabelLateBoundDefault<?> RUN_UNDER =
public static final LabelLateBoundDefault<?> RUN_UNDER_EXEC_CONFIG =
LabelLateBoundDefault.fromTargetConfiguration(
BuildConfigurationValue.class,
null,
(rule, attributes, config) -> {
if (config.isExecConfiguration()
// This is the opposite of RUN_UNDER_TARGET_CONFIG, so both can't be non-null.
|| !config.runUnderExecConfigForTests()
|| config.getRunUnder() == null) {
return null;
}
return config.getRunUnder().getLabel();
});

// TODO(b/65746853): provide a way to do this without passing the entire configuration
/**
* Resolves the latebound target-configured :run_under label. This only exists if --run_under is
* set to a label and --incompatible_bazel_test_exec_run_under is false. Else it's null.
*
* <p>{@link RUN_UNDER_EXEC_CONFIG} and {@link RUN_UNDER_TARGET_CONFIG} cannot both be non-null in
* a build: if {@code --run_under} is set it must connect to a single dependency.
*/
public static final LabelLateBoundDefault<?> RUN_UNDER_TARGET_CONFIG =
LabelLateBoundDefault.fromTargetConfiguration(
BuildConfigurationValue.class,
null,
(rule, attributes, configuration) -> {
RunUnder runUnder = configuration.getRunUnder();
return runUnder != null ? runUnder.getLabel() : null;
(rule, attributes, config) -> {
if (config.isExecConfiguration()
// This is the opposite of RUN_UNDER_EXEC_CONFIG, so both can't be non-null.
|| config.runUnderExecConfigForTests()
|| config.getRunUnder() == null) {
return null;
}
return config.getRunUnder().getLabel();
});

/**
Expand Down Expand Up @@ -255,22 +287,28 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env)
.value(
coverageReportGeneratorAttribute(
env.getToolsLabel(DEFAULT_COVERAGE_REPORT_GENERATOR_VALUE))))
// --run_under targets always run on exec machines:
// Bazel runs --run_under targets on exec machines:
// * For "$ bazel run", they run directly on the machine running bazel.
// * For "$ bazel test", they run on the build machine that executes tests.
//
// This may be different than the target platform. For example, if testing embedded device
// code where the test runner's job is to upload the target binary to the embedded device.
// This means they should be configured for the exec configuration.
// --incompatible_bazel_test_exec_run_under supports this. But we still need to support
// legacy invocations that incorrectly configure it with the target configuration. To
// support both modes, we define both an exec-configured and target-configured --run_under
// dep and have consuming logic choose the right one based on the flag.
//
// TODO: https://github.com/bazelbuild/bazel/discussions/21805 Setting cfg() here makes
// this work for "$ bazel test" but not "$ bazel run". Make this work for "$ bazel run"
// by updating RunCommand.java to self-transition --run_under to the exec configuration.
// TODO: https://github.com/bazelbuild/bazel/discussions/21805 this works for
// "$ bazel test" but not "$ bazel run". Make this work for "$ bazel run" by updating
// RunCommand.java to self-transition --run_under to the exec configuration.
.add(
attr(":run_under", LABEL)
attr(":run_under_exec_config", LABEL)
.cfg(ExecutionTransitionFactory.createFactory())
.value(RUN_UNDER)
.value(RUN_UNDER_EXEC_CONFIG)
.skipPrereqValidatorCheck())
.add(
attr(":run_under_target_config", LABEL)
.value(RUN_UNDER_TARGET_CONFIG)
.skipPrereqValidatorCheck());

env.getNetworkAllowlistForTests()
.ifPresent(
label ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,18 @@ public <T> T getPrerequisite(String attributeName, StarlarkProviderWrapper<T> ke
return getOwningPrerequisitesCollection(attributeName).getPrerequisite(attributeName, key);
}

/**
* Returns the {@code --run_under} prerequisite based on the value of {@code
* --incompatible_bazel_test_exec_run_under}.
*/
@Nullable
public TransitiveInfoCollection getRunUnderPrerequisite() {
return getPrerequisite(
getConfiguration().runUnderExecConfigForTests()
? ":run_under_exec_config"
: ":run_under_target_config");
}

/**
* Returns the list of transitive info collections that feed into this target through the
* specified attribute.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ private static RunfilesSupport create(
if (runUnder != null
&& runUnder.getLabel() != null
&& TargetUtils.isTestRule(ruleContext.getRule())) {
TransitiveInfoCollection runUnderTarget = ruleContext.getPrerequisite(":run_under");
TransitiveInfoCollection runUnderTarget = ruleContext.getRunUnderPrerequisite();
runfiles =
new Runfiles.Builder(
ruleContext.getWorkspaceName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -718,10 +718,16 @@ public boolean isCodeCoverageEnabled() {
return options.collectCodeCoverage;
}

@Nullable
public RunUnder getRunUnder() {
return options.runUnder;
}

/** Should the {@code --run_under} be configured in the exec configuration? */
public boolean runUnderExecConfigForTests() {
return options.bazelTestExecRunUnder;
}

/** Returns true if this is an execution configuration. */
public boolean isExecConfiguration() {
return options.isExec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,22 @@ public OutputPathsConverter() {
+ " When disabled, only the last flag is taken into account.")
public boolean additiveModifyExecutionInfo;

@Option(
name = "incompatible_bazel_test_exec_run_under",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.TOOLCHAIN,
effectTags = {
OptionEffectTag.AFFECTS_OUTPUTS,
},
metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE},
help =
"If enabled, \"bazel test --run_under=//:runner\" builds \"//:runner\" in the exec"
+ " configuration. If disabled, it builds \"//:runner\" in the target configuration."
+ " Bazel executes tests on exec machines, so the former is more correct. This"
+ " doesn't affect \"bazel run\", which always builds \"`--run_under=//foo\" in the"
+ " target configuration.")
public boolean bazelTestExecRunUnder;

@Option(
name = "include_config_fragments_provider",
defaultValue = "off",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.RUN_UNDER;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.RUN_UNDER_EXEC_CONFIG;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.RUN_UNDER_TARGET_CONFIG;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.TIMEOUT_DEFAULT;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.getTestRuntimeLabelList;
import static com.google.devtools.build.lib.analysis.test.ExecutionInfo.DEFAULT_TEST_RUNNER_EXEC_GROUP;
Expand Down Expand Up @@ -275,10 +276,16 @@ public static RuleClass getTestBaseRule(RuleDefinitionEnvironment env) {
labelCache.get(
toolsRepository
+ BaseRuleClasses.DEFAULT_COVERAGE_REPORT_GENERATOR_VALUE))))
// See similar definitions in BaseRuleClasses for context.
.add(
attr(":run_under", LABEL)
attr(":run_under_exec_config", LABEL)
.cfg(ExecutionTransitionFactory.createFactory())
.value(RUN_UNDER))
.value(RUN_UNDER_EXEC_CONFIG)
.skipPrereqValidatorCheck())
.add(
attr(":run_under_target_config", LABEL)
.value(RUN_UNDER_TARGET_CONFIG)
.skipPrereqValidatorCheck())
.addAttribute(
attr(Rule.IS_EXECUTABLE_ATTRIBUTE_NAME, BOOLEAN)
.value(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public final class TestTargetExecutionSettings {

@Nullable
private static Artifact getRunUnderExecutable(RuleContext ruleContext) {
TransitiveInfoCollection runUnderTarget = ruleContext.getPrerequisite(":run_under");
TransitiveInfoCollection runUnderTarget = ruleContext.getRunUnderPrerequisite();
return runUnderTarget == null
? null
: runUnderTarget.getProvider(FilesToRunProvider.class).getExecutable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ bazel_fragments["CoreOptions"] = fragment(
"//command_line_option:experimental_debug_selects_always_succeed",
"//command_line_option:incompatible_check_testonly_for_output_files",
"//command_line_option:incompatible_auto_exec_groups",
"//command_line_option:incompatible_bazel_test_exec_run_under",
"//command_line_option:experimental_writable_outputs",
"//command_line_option:build_runfile_manifests",
"//command_line_option:build_runfile_links",
Expand Down

0 comments on commit 1ec4365

Please sign in to comment.