@@ -516,6 +516,55 @@ def _rust_test_impl(ctx):
516516 rust_flags = get_rust_test_flags (ctx .attr ),
517517 skip_expanding_rustc_env = True ,
518518 )
519+
520+ # If sharding is enabled and we're using libtest harness, wrap the test binary
521+ # with a script that handles test enumeration and shard partitioning
522+ if ctx .attr .experimental_enable_sharding and ctx .attr .use_libtest_harness :
523+ # Find DefaultInfo and CrateInfo in the providers list
524+ # DefaultInfo is first, CrateInfo follows (or TestCrateInfo for staticlib/cdylib)
525+ default_info = providers [0 ]
526+ default_info_index = 0
527+
528+ # Get the test binary from CrateInfo - it's the output of the compiled test
529+ crate_info_provider = None
530+ for p in providers :
531+ if hasattr (p , "output" ) and hasattr (p , "is_test" ):
532+ crate_info_provider = p
533+ break
534+
535+ if crate_info_provider :
536+ test_binary = crate_info_provider .output
537+
538+ # Select the appropriate wrapper template based on target OS
539+ if toolchain .target_os == "windows" :
540+ wrapper = ctx .actions .declare_file (ctx .label .name + "_sharding_wrapper.bat" )
541+ wrapper_template = ctx .file ._test_sharding_wrapper_windows
542+ else :
543+ wrapper = ctx .actions .declare_file (ctx .label .name + "_sharding_wrapper.sh" )
544+ wrapper_template = ctx .file ._test_sharding_wrapper_unix
545+
546+ # Generate wrapper script with test binary path substituted
547+ ctx .actions .expand_template (
548+ template = wrapper_template ,
549+ output = wrapper ,
550+ substitutions = {
551+ "{{TEST_BINARY}}" : test_binary .short_path ,
552+ },
553+ is_executable = True ,
554+ )
555+
556+ # Update runfiles to include both wrapper and test binary
557+ new_runfiles = default_info .default_runfiles .merge (
558+ ctx .runfiles (files = [test_binary ]),
559+ )
560+
561+ # Replace DefaultInfo with wrapper as executable
562+ providers [default_info_index ] = DefaultInfo (
563+ files = default_info .files ,
564+ runfiles = new_runfiles ,
565+ executable = wrapper ,
566+ )
567+
519568 data = getattr (ctx .attr , "data" , [])
520569
521570 env = expand_dict_value_locations (
@@ -918,6 +967,22 @@ _rust_test_attrs = {
918967 E.g. `bazel test //src:rust_test --test_arg=foo::test::test_fn`.
919968 """ ),
920969 ),
970+ "experimental_enable_sharding" : attr .bool (
971+ mandatory = False ,
972+ default = False ,
973+ doc = dedent ("""\
974+ If True, enable support for Bazel test sharding (shard_count attribute).
975+
976+ When enabled, tests are executed via a wrapper script that:
977+ 1. Enumerates tests using libtest's --list flag
978+ 2. Partitions tests across shards based on TEST_SHARD_INDEX/TEST_TOTAL_SHARDS
979+ 3. Runs only the tests assigned to the current shard
980+
981+ This attribute only has an effect when use_libtest_harness is True.
982+
983+ This is experimental and may change in future releases.
984+ """ ),
985+ ),
921986} | _coverage_attrs | _experimental_use_cc_common_link_attrs
922987
923988rust_library = rule (
@@ -1452,6 +1517,14 @@ rust_test = rule(
14521517 "_allowlist_function_transition" : attr .label (
14531518 default = "@bazel_tools//tools/allowlists/function_transition_allowlist" ,
14541519 ),
1520+ "_test_sharding_wrapper_unix" : attr .label (
1521+ default = Label ("//rust/private:test_sharding_wrapper.sh" ),
1522+ allow_single_file = True ,
1523+ ),
1524+ "_test_sharding_wrapper_windows" : attr .label (
1525+ default = Label ("//rust/private:test_sharding_wrapper.bat" ),
1526+ allow_single_file = True ,
1527+ ),
14551528 },
14561529 executable = True ,
14571530 fragments = ["cpp" ],
0 commit comments