@@ -631,6 +631,7 @@ def construct_arguments(
631
631
- all (list): A list of all `Args` objects in the order listed above.
632
632
This is to be passed to the `arguments` parameter of actions
633
633
- (dict): Common rustc environment variables
634
+ - (list): Extra input files for the compile action
634
635
"""
635
636
output_dir = getattr (crate_info .output , "dirname" , None )
636
637
linker_script = getattr (file , "linker_script" , None )
@@ -764,7 +765,7 @@ def construct_arguments(
764
765
_add_native_link_flags (rustc_flags , dep_info , linkstamp_outs , ambiguous_libs , crate_info .type , toolchain , cc_toolchain , feature_configuration )
765
766
766
767
# These always need to be added, even if not linking this crate.
767
- add_crate_link_flags (rustc_flags , dep_info , force_all_deps_direct )
768
+ extra_link_inputs = add_crate_link_flags (ctx , toolchain , rustc_flags , crate_info , dep_info , force_all_deps_direct )
768
769
769
770
needs_extern_proc_macro_flag = "proc-macro" in [crate_info .type , crate_info .wrapped_crate_type ] and \
770
771
crate_info .edition != "2015"
@@ -810,7 +811,7 @@ def construct_arguments(
810
811
all = [process_wrapper_flags , rustc_path , rustc_flags ],
811
812
)
812
813
813
- return args , env
814
+ return args , env , extra_link_inputs
814
815
815
816
def rustc_compile_action (
816
817
ctx ,
@@ -867,7 +868,7 @@ def rustc_compile_action(
867
868
stamp = stamp ,
868
869
)
869
870
870
- args , env_from_args = construct_arguments (
871
+ args , env_from_args , extra_link_inputs = construct_arguments (
871
872
ctx = ctx ,
872
873
attr = attr ,
873
874
file = ctx .file ,
@@ -887,6 +888,7 @@ def rustc_compile_action(
887
888
force_all_deps_direct = force_all_deps_direct ,
888
889
stamp = stamp ,
889
890
)
891
+ compile_inputs = depset (extra_link_inputs , transitive = [compile_inputs ])
890
892
891
893
env = dict (ctx .configuration .default_shell_env )
892
894
env .update (env_from_args )
@@ -1179,16 +1181,71 @@ def _get_dir_names(files):
1179
1181
dirs [f .dirname ] = None
1180
1182
return dirs .keys ()
1181
1183
1182
- def add_crate_link_flags (args , dep_info , force_all_deps_direct = False ):
1184
+ def _symlink_transitive_crates_if_needed (ctx , toolchain , crate_info , dep_info ):
1185
+ """Collect and symlink the transitive crates into a single directory.
1186
+
1187
+ The reason for this is that when passing a large (350+) number of `-Ldependency=` arguments to rustc on
1188
+ Windows, we seem to be getting some obscure errors such as "failure to call `LoadLibraryExW` that results
1189
+ on some transitive dependencies not being picked up and the build to fail.
1190
+
1191
+ If we detect a large number of transitive dependencies we symlink them all into a single directory that
1192
+ we can pass to rustc in a single `-Ldependency=` argument.
1193
+
1194
+ Args:
1195
+ ctx (ctx): The rule's context object
1196
+ toolchain (rust_toolchain): The current `rust_toolchain`
1197
+ crate_info (CrateInfo): The CrateInfo provider of the target crate
1198
+ dep_info (DepInfo): The current target's dependency info
1199
+
1200
+ Returns:
1201
+ tuple: A tuple of the following items
1202
+ - (File): Optional - the output directory containing all transitive crates that this crate depends on.
1203
+ - (list): The list of transitive crates files that should be used as input to the build action.
1204
+ """
1205
+ if toolchain .os != "windows" :
1206
+ return None , []
1207
+
1208
+ deps = dep_info .transitive_crates .to_list ()
1209
+
1210
+ # Only symlink if we are about to pass a large (350+) number of transitive dependencies to rustc.
1211
+ if not deps or len (deps ) < 350 :
1212
+ return None , []
1213
+
1214
+ output_dirname = crate_info .output .basename + ".transitive_crates"
1215
+ links = []
1216
+
1217
+ # Keep a list of the crates that were currently added so that we can uniquify them.
1218
+ names = {}
1219
+
1220
+ for dep in deps :
1221
+ name = dep .output .basename
1222
+ if name in names :
1223
+ continue
1224
+
1225
+ link = ctx .actions .declare_file (output_dirname + "/" + name )
1226
+ ctx .actions .symlink (output = link , target_file = dep .output , is_executable = True )
1227
+
1228
+ names [name ] = True
1229
+ links .append (link )
1230
+
1231
+ return links [0 ].dirname , links
1232
+
1233
+ def add_crate_link_flags (ctx , toolchain , args , crate_info , dep_info , force_all_deps_direct = False ):
1183
1234
"""Adds link flags to an Args object reference
1184
1235
1185
1236
Args:
1237
+ ctx (ctx): The rule's context object
1238
+ toolchain (rust_toolchain): The current `rust_toolchain`
1186
1239
args (Args): An arguments object reference
1240
+ crate_info (CrateInfo): The CrateInfo provider for the current target.
1187
1241
dep_info (DepInfo): The current target's dependency info
1242
+ If this argument is set, only it will be added as a `-Ldependency=` flag, otherwise all rlibs will be set individually.
1188
1243
force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern
1189
1244
to the commandline as opposed to -L.
1190
- """
1191
1245
1246
+ Returns:
1247
+ - (list): A list of extra inputs that should be added to the rustc compile action.
1248
+ """
1192
1249
if force_all_deps_direct :
1193
1250
args .add_all (
1194
1251
depset (
@@ -1203,12 +1260,21 @@ def add_crate_link_flags(args, dep_info, force_all_deps_direct = False):
1203
1260
else :
1204
1261
# nb. Direct crates are linked via --extern regardless of their crate_type
1205
1262
args .add_all (dep_info .direct_crates , map_each = _crate_to_link_flag )
1206
- args .add_all (
1207
- dep_info .transitive_crates ,
1208
- map_each = _get_crate_dirname ,
1209
- uniquify = True ,
1210
- format_each = "-Ldependency=%s" ,
1211
- )
1263
+
1264
+ transitive_crates_dir , transitive_crates_links = _symlink_transitive_crates_if_needed (ctx , toolchain , crate_info , dep_info )
1265
+
1266
+ # If transitive rlibs have been collected into this single directory, only set this directory
1267
+ if transitive_crates_dir :
1268
+ args .add ("-Ldependency={}" .format (transitive_crates_dir ))
1269
+ else :
1270
+ args .add_all (
1271
+ dep_info .transitive_crates ,
1272
+ map_each = _get_crate_dirname ,
1273
+ uniquify = True ,
1274
+ format_each = "-Ldependency=%s" ,
1275
+ )
1276
+
1277
+ return transitive_crates_links
1212
1278
1213
1279
def _crate_to_link_flag (crate ):
1214
1280
"""A helper macro used by `add_crate_link_flags` for adding crate link flags to a Arg object
0 commit comments