Skip to content

Commit 9f79bf1

Browse files
committed
Always use a param file when calling into rustc.
The argument list seems to constantly overflow on Windows (for reasons that I don't really understand since `use_param_file` should dynamically switch to using a param file in these cases), so always generate a param file.
1 parent 8205991 commit 9f79bf1

File tree

6 files changed

+107
-38
lines changed

6 files changed

+107
-38
lines changed

rust/private/rustc.bzl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ def construct_arguments(
484484
force_all_deps_direct = False,
485485
force_link = False,
486486
stamp = False,
487-
remap_path_prefix = "."):
487+
remap_path_prefix = ".",
488+
use_param_file_for_rustc_args = True):
488489
"""Builds an Args object containing common rustc flags
489490
490491
Args:
@@ -510,6 +511,7 @@ def construct_arguments(
510511
stamp (bool, optional): Whether or not workspace status stamping is enabled. For more details see
511512
https://docs.bazel.build/versions/main/user-manual.html#flag--stamp
512513
remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to a falsey value, no prefix will be set.
514+
use_param_file_for_rustc_args(bool, optional): Whether Bazel should use a param file to pass the arguments to rustc.
513515
514516
Returns:
515517
tuple: A tuple of the following items
@@ -584,8 +586,11 @@ def construct_arguments(
584586

585587
# Rustc arguments
586588
rustc_flags = ctx.actions.args()
587-
rustc_flags.set_param_file_format("multiline")
588-
rustc_flags.use_param_file("@%s", use_always = False)
589+
590+
if use_param_file_for_rustc_args:
591+
rustc_flags.set_param_file_format("multiline")
592+
rustc_flags.use_param_file("@%s", use_always = True)
593+
589594
rustc_flags.add(crate_info.root)
590595
rustc_flags.add("--crate-name=" + crate_info.name)
591596
rustc_flags.add("--crate-type=" + crate_info.type)

rust/private/rustdoc.bzl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ def rustdoc_compile_action(
4848
toolchain,
4949
crate_info,
5050
output = None,
51-
rustdoc_flags = []):
51+
rustdoc_flags = [],
52+
use_param_file_for_rustc_args = True):
5253
"""Create a struct of information needed for a `rustdoc` compile action based on crate passed to the rustdoc rule.
5354
5455
Args:
@@ -57,6 +58,7 @@ def rustdoc_compile_action(
5758
crate_info (CrateInfo): The provider of the crate passed to a rustdoc rule.
5859
output (File, optional): An optional output a `rustdoc` action is intended to produce.
5960
rustdoc_flags (list, optional): A list of `rustdoc` specific flags.
61+
use_param_file_for_rustc_args(bool, optional): Whether Bazel should use a param file to pass the arguments to rustc.
6062
6163
Returns:
6264
struct: A struct of some `ctx.actions.run` arguments.
@@ -117,6 +119,7 @@ def rustdoc_compile_action(
117119
emit = [],
118120
remap_path_prefix = None,
119121
force_link = True,
122+
use_param_file_for_rustc_args = use_param_file_for_rustc_args,
120123
)
121124

122125
return struct(

rust/private/rustdoc_test.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ def _rust_doc_test_impl(ctx):
117117
toolchain = find_toolchain(ctx),
118118
crate_info = crate_info,
119119
rustdoc_flags = rustdoc_flags,
120+
# The arguments are written to a script file that is used to run the
121+
# tests and the args point to a param file outside of the `runfiles`.
122+
use_param_file_for_rustc_args = False,
120123
)
121124

122125
tools = action.tools + [ctx.executable._process_wrapper]

util/process_wrapper/process_wrapper.cc

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
3838

3939
System::EnvironmentBlock environment_file_block;
4040

41-
using Subst = std::pair<System::StrType, System::StrType>;
42-
4341
System::StrType exec_path;
4442
std::vector<Subst> subst_mappings;
4543
std::vector<Subst> stamp_mappings;
@@ -79,7 +77,8 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
7977
if (value == PW_SYS_STR("${pwd}")) {
8078
value = System::GetWorkingDirectory();
8179
}
82-
subst_mappings.push_back({std::move(key), std::move(value)});
80+
subst_mappings.push_back({PW_SYS_STR("${") + key + PW_SYS_STR("}"),
81+
std::move(value)});
8382
} else if (arg == PW_SYS_STR("--volatile-status-file")) {
8483
if (!volatile_status_file.empty()) {
8584
std::cerr << "process wrapper error: \"--volatile-status-file\" can "
@@ -143,24 +142,74 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
143142
for (++i; i < argc; ++i) {
144143
arguments.push_back(argv[i]);
145144
}
146-
// after we consume all arguments we append the files arguments
147-
for (const System::StrType& file_arg : file_arguments) {
148-
arguments.push_back(file_arg);
149-
}
150145
} else {
151146
std::cerr << "process wrapper error: unknow argument \"" << ToUtf8(arg)
152147
<< "\"." << '\n';
153148
return -1;
154149
}
155150
}
156151

152+
// Expand tokens into the file arguments (since some paths might embed
153+
// `${pwd}` that we need to resolve it from the subsitution mappings).
154+
for (System::StrType& file_arg : file_arguments) {
155+
ReplaceTokens(file_arg, subst_mappings);
156+
}
157+
158+
// Process the arguments, making sure that we don't have paths to param files
159+
// within another param file (that is an arg composed of `@` + a path), which
160+
// rustc doesn't support.
161+
// (We process them in reverse so that we can append the param files to the
162+
// front of `file_arguments` in the right order).
163+
for (auto arg_it = arguments.rbegin(); arg_it != arguments.rend(); arg_it++) {
164+
System::StrType& arg = *arg_it;
165+
ReplaceTokens(arg, subst_mappings);
166+
167+
// Check whether this is a regular argument or a path to a param file.
168+
if (arg.size() > 0 && arg.substr(0, 1) == PW_SYS_STR("@")) {
169+
System::StrType path = arg.substr(1);
170+
171+
// Read the actual params off the param file so that we can 1) extract
172+
// potential other param files inside and 2) substitute mappings.
173+
System::StrVecType params;
174+
if (!ReadFileToArray(path, params)) {
175+
std::cerr << "Cannot read param file " << ToUtf8(path) << "\n";
176+
return -1;
177+
}
178+
179+
for (auto par_it = params.rbegin(); par_it != params.rend(); par_it++) {
180+
System::StrType& param = *par_it;
181+
ReplaceTokens(param, subst_mappings);
182+
183+
// If we find a path to a param file, move it to the top-level file
184+
// arguments instead (we cannot have nested param files).
185+
if (param.size() > 0 && param.substr(0, 1) == PW_SYS_STR("@")) {
186+
file_arguments.insert(file_arguments.begin(), param);
187+
params.erase(std::next(par_it).base());
188+
}
189+
}
190+
191+
// Create a new param file so that we don't need to edit the original one
192+
// that Bazel created.
193+
System::StrType new_path = path + PW_SYS_STR(".expanded");
194+
if (!WriteArrayToFile(new_path, params)) {
195+
std::cerr << "Cannot write params to file " << ToUtf8(new_path) << "\n";
196+
return -1;
197+
}
198+
199+
arguments.erase(std::next(arg_it).base());
200+
file_arguments.insert(file_arguments.begin(), PW_SYS_STR("@") + new_path);
201+
}
202+
}
203+
204+
// after we consume all arguments we append the files arguments
205+
for (const System::StrType& file_arg : file_arguments) {
206+
arguments.push_back(file_arg);
207+
}
208+
157209
// Stamp any format string in an environment variable block
158-
for (const Subst& stamp : stamp_mappings) {
159-
System::StrType token = PW_SYS_STR("{");
160-
token += stamp.first;
161-
token.push_back('}');
210+
if (stamp_mappings.size()) {
162211
for (System::StrType& env : environment_file_block) {
163-
ReplaceToken(env, token, stamp.second);
212+
ReplaceTokens(env, stamp_mappings);
164213
}
165214
}
166215

@@ -171,19 +220,9 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
171220
environment_file_block.begin(),
172221
environment_file_block.end());
173222

174-
if (subst_mappings.size()) {
175-
for (const Subst& subst : subst_mappings) {
176-
System::StrType token = PW_SYS_STR("${");
177-
token += subst.first;
178-
token.push_back('}');
179-
for (System::StrType& arg : arguments) {
180-
ReplaceToken(arg, token, subst.second);
181-
}
182-
183-
for (System::StrType& env : environment_block) {
184-
ReplaceToken(env, token, subst.second);
185-
}
186-
}
223+
// Expand tokens in environment
224+
for (System::StrType& env : environment_block) {
225+
ReplaceTokens(env, subst_mappings);
187226
}
188227

189228
// Have the last values added take precedence over the first.

util/process_wrapper/utils.cc

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ std::string ToUtf8(const System::StrType& string) {
4141
#endif // defined(PW_WIN_UNICODE)
4242
}
4343

44-
void ReplaceToken(System::StrType& str, const System::StrType& token,
45-
const System::StrType& replacement) {
46-
std::size_t pos = str.find(token);
47-
if (pos != std::string::npos) {
48-
str.replace(pos, token.size(), replacement);
44+
void ReplaceTokens(System::StrType& str, std::vector<Subst>& substs) {
45+
for (const Subst& subst : substs) {
46+
std::size_t pos = str.find(subst.first);
47+
if (pos != std::string::npos) {
48+
str.replace(pos, subst.first.size(), subst.second);
49+
}
4950
}
5051
}
5152

@@ -101,6 +102,19 @@ bool ReadFileToArray(const System::StrType& file_path,
101102
return true;
102103
}
103104

105+
bool WriteArrayToFile(const System::StrType& file_path, System::StrVecType& vec) {
106+
std::ofstream file(file_path, std::ofstream::out | std::ofstream::trunc);
107+
if (file.fail()) {
108+
std::cerr << "process wrapper error: failed to open file: "
109+
<< ToUtf8(file_path) << '\n';
110+
return false;
111+
}
112+
for (System::StrType& line : vec) {
113+
file << ToUtf8(line) << std::endl;
114+
}
115+
return true;
116+
}
117+
104118
bool ReadStampStatusToArray(
105119
const System::StrType& stamp_path,
106120
std::vector<std::pair<System::StrType, System::StrType>>& vec) {
@@ -118,7 +132,8 @@ bool ReadStampStatusToArray(
118132
<< ToUtf8(stamp_block[i]) << "\".\n";
119133
return false;
120134
}
121-
System::StrType key = stamp_block[i].substr(0, space_pos);
135+
System::StrType key =
136+
PW_SYS_STR("{") + stamp_block[i].substr(0, space_pos) + PW_SYS_STR("}");
122137
System::StrType value =
123138
stamp_block[i].substr(space_pos + 1, stamp_block[i].size());
124139
vec.push_back({std::move(key), std::move(value)});

util/process_wrapper/utils.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,21 @@
2121

2222
namespace process_wrapper {
2323

24+
using Subst = std::pair<System::StrType, System::StrType>;
25+
2426
// Converts to and frin the system string format
2527
System::StrType FromUtf8(const std::string& string);
2628
std::string ToUtf8(const System::StrType& string);
2729

28-
// Replaces a token in str by replacement
29-
void ReplaceToken(System::StrType& str, const System::StrType& token,
30-
const System::StrType& replacement);
30+
// Replaces tokens in str by replacement
31+
void ReplaceTokens(System::StrType& str, std::vector<Subst>& substs);
3132

3233
// Reads a file in text mode and feeds each line to item in the vec output
3334
bool ReadFileToArray(const System::StrType& file_path, System::StrVecType& vec);
3435

36+
// Write the content of an array file as lines in a file
37+
bool WriteArrayToFile(const System::StrType& file_path, System::StrVecType& vec);
38+
3539
// Reads a workspace status stamp file to an array of key value pairs
3640
bool ReadStampStatusToArray(
3741
const System::StrType& stamp_path,

0 commit comments

Comments
 (0)