Skip to content

Commit d342503

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 f569827 commit d342503

File tree

6 files changed

+117
-45
lines changed

6 files changed

+117
-45
lines changed

rust/private/rustc.bzl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,8 @@ def construct_arguments(
474474
force_all_deps_direct = False,
475475
force_link = False,
476476
stamp = False,
477-
remap_path_prefix = "."):
477+
remap_path_prefix = ".",
478+
use_param_file_for_rustc_args = True):
478479
"""Builds an Args object containing common rustc flags
479480
480481
Args:
@@ -500,6 +501,7 @@ def construct_arguments(
500501
stamp (bool, optional): Whether or not workspace status stamping is enabled. For more details see
501502
https://docs.bazel.build/versions/main/user-manual.html#flag--stamp
502503
remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to a falsey value, no prefix will be set.
504+
use_param_file_for_rustc_args(bool, optional): Whether Bazel should use a param file to pass the arguments to rustc.
503505
504506
Returns:
505507
tuple: A tuple of the following items
@@ -574,8 +576,11 @@ def construct_arguments(
574576

575577
# Rustc arguments
576578
rustc_flags = ctx.actions.args()
577-
rustc_flags.set_param_file_format("multiline")
578-
rustc_flags.use_param_file("@%s", use_always = False)
579+
580+
if use_param_file_for_rustc_args:
581+
rustc_flags.set_param_file_format("multiline")
582+
rustc_flags.use_param_file("@%s", use_always = True)
583+
579584
rustc_flags.add(crate_info.root)
580585
rustc_flags.add("--crate-name=" + crate_info.name)
581586
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
@@ -49,7 +49,8 @@ def rustdoc_compile_action(
4949
crate_info,
5050
output = None,
5151
rustdoc_flags = [],
52-
is_test = False):
52+
is_test = False,
53+
use_param_file_for_rustc_args = True):
5354
"""Create a struct of information needed for a `rustdoc` compile action based on crate passed to the rustdoc rule.
5455
5556
Args:
@@ -59,6 +60,7 @@ def rustdoc_compile_action(
5960
output (File, optional): An optional output a `rustdoc` action is intended to produce.
6061
rustdoc_flags (list, optional): A list of `rustdoc` specific flags.
6162
is_test (bool, optional): If True, the action will be configured for `rust_doc_test` targets
63+
use_param_file_for_rustc_args(bool, optional): Whether Bazel should use a param file to pass the arguments to rustc.
6264
6365
Returns:
6466
struct: A struct of some `ctx.actions.run` arguments.
@@ -118,6 +120,7 @@ def rustdoc_compile_action(
118120
emit = [],
119121
remap_path_prefix = None,
120122
force_link = True,
123+
use_param_file_for_rustc_args = use_param_file_for_rustc_args,
121124
)
122125

123126
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
crate_info = crate_info,
118118
rustdoc_flags = rustdoc_flags,
119119
is_test = True,
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: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,41 @@
2121
#include "util/process_wrapper/system.h"
2222
#include "util/process_wrapper/utils.h"
2323

24-
using CharType = process_wrapper::System::StrType::value_type;
24+
using namespace process_wrapper;
25+
using CharType = System::StrType::value_type;
26+
27+
static int process_param_file(System::StrType& path,
28+
System::Arguments& collected_args,
29+
const std::vector<Subst>& subst_mappings) {
30+
System::StrVecType args;
31+
if (!ReadFileToVec(path, args)) {
32+
std::cerr << "Cannot read param file " << ToUtf8(path) << "\n";
33+
return -1;
34+
}
35+
for (System::StrType& arg : args) {
36+
// Expand tokens into each argument (since some paths might embed `${pwd}`
37+
// that we need to resolve from the subsitution mappings).
38+
ReplaceTokens(arg, subst_mappings);
39+
40+
// If this is a param file, expand it into the top-level arguments by
41+
// recursing into its content.
42+
if (arg.size() > 0 && arg.substr(0, 1) == PW_SYS_STR("@")) {
43+
System::StrType path = arg.substr(1);
44+
int res = process_param_file(path, collected_args, subst_mappings);
45+
if (res != 0) {
46+
return res;
47+
}
48+
} else {
49+
collected_args.push_back(arg);
50+
}
51+
}
52+
return 0;
53+
}
2554

2655
// Simple process wrapper allowing us to not depend on the shell to run a
2756
// process to perform basic operations like capturing the output or having
2857
// the $pwd used in command line arguments or environment variables
2958
int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
30-
using namespace process_wrapper;
31-
3259
System::EnvironmentBlock environment_block;
3360
// Taking all environment variables from the current process
3461
// and sending them down to the child process
@@ -38,8 +65,6 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
3865

3966
System::EnvironmentBlock environment_file_block;
4067

41-
using Subst = std::pair<System::StrType, System::StrType>;
42-
4368
System::StrType exec_path;
4469
std::vector<Subst> subst_mappings;
4570
std::vector<Subst> stamp_mappings;
@@ -53,7 +78,7 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
5378
System::Arguments file_arguments;
5479

5580
// Processing current process argument list until -- is encountered
56-
// everthing after gets sent down to the child process
81+
// everything after gets sent down to the child process
5782
for (int i = 1; i < argc; ++i) {
5883
System::StrType arg = argv[i];
5984
if (++i == argc) {
@@ -79,7 +104,8 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
79104
if (value == PW_SYS_STR("${pwd}")) {
80105
value = System::GetWorkingDirectory();
81106
}
82-
subst_mappings.push_back({std::move(key), std::move(value)});
107+
subst_mappings.push_back({PW_SYS_STR("${") + key + PW_SYS_STR("}"),
108+
std::move(value)});
83109
} else if (arg == PW_SYS_STR("--volatile-status-file")) {
84110
if (!volatile_status_file.empty()) {
85111
std::cerr << "process wrapper error: \"--volatile-status-file\" can "
@@ -90,11 +116,11 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
90116
return -1;
91117
}
92118
} else if (arg == PW_SYS_STR("--env-file")) {
93-
if (!ReadFileToArray(argv[i], environment_file_block)) {
119+
if (!ReadFileToVec(argv[i], environment_file_block)) {
94120
return -1;
95121
}
96122
} else if (arg == PW_SYS_STR("--arg-file")) {
97-
if (!ReadFileToArray(argv[i], file_arguments)) {
123+
if (!ReadFileToVec(argv[i], file_arguments)) {
98124
return -1;
99125
}
100126
} else if (arg == PW_SYS_STR("--touch-file")) {
@@ -143,7 +169,7 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
143169
for (++i; i < argc; ++i) {
144170
arguments.push_back(argv[i]);
145171
}
146-
// after we consume all arguments we append the files arguments
172+
// After we have consumed all arguments add the files arguments the them.
147173
for (const System::StrType& file_arg : file_arguments) {
148174
arguments.push_back(file_arg);
149175
}
@@ -154,13 +180,39 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
154180
}
155181
}
156182

183+
// Go through the arguments and make sure that we process param files so that
184+
// we can flatten potential recursive param files within them.
185+
for (System::StrType& arg : arguments) {
186+
if (arg.size() > 0 && arg.substr(0, 1) == PW_SYS_STR("@")) {
187+
// This is a param file, process it separately.
188+
System::StrType path = arg.substr(1);
189+
System::Arguments processed_args;
190+
if (process_param_file(path, processed_args, subst_mappings) != 0) {
191+
std::cerr << "Failure to process arguments list\n";
192+
return -1;
193+
}
194+
195+
// Create a new param file so that we don't need to edit the original one
196+
// that Bazel created.
197+
System::StrType new_path = path + PW_SYS_STR(".expanded");
198+
if (!WriteVecToFile(new_path, processed_args)) {
199+
std::cerr << "Cannot write params to file " << ToUtf8(new_path) << "\n";
200+
return -1;
201+
}
202+
203+
// Replace the params file arg with the new one.
204+
arg = PW_SYS_STR("@") + new_path;
205+
} else {
206+
// Expand tokens into each argument (since some paths might embed `${pwd}`
207+
// that we need to resolve from the subsitution mappings).
208+
ReplaceTokens(arg, subst_mappings);
209+
}
210+
}
211+
157212
// 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('}');
213+
if (stamp_mappings.size()) {
162214
for (System::StrType& env : environment_file_block) {
163-
ReplaceToken(env, token, stamp.second);
215+
ReplaceTokens(env, stamp_mappings);
164216
}
165217
}
166218

@@ -171,19 +223,9 @@ int PW_MAIN(int argc, const CharType* argv[], const CharType* envp[]) {
171223
environment_file_block.begin(),
172224
environment_file_block.end());
173225

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-
}
226+
// Expand tokens in environment
227+
for (System::StrType& env : environment_block) {
228+
ReplaceTokens(env, subst_mappings);
187229
}
188230

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

util/process_wrapper/utils.cc

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,17 @@ 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, const 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

52-
bool ReadFileToArray(const System::StrType& file_path,
53-
System::StrVecType& vec) {
53+
bool ReadFileToVec(const System::StrType& file_path,
54+
System::StrVecType& vec) {
5455
std::ifstream file(file_path);
5556
if (file.fail()) {
5657
std::cerr << "process wrapper error: failed to open file: "
@@ -101,12 +102,25 @@ bool ReadFileToArray(const System::StrType& file_path,
101102
return true;
102103
}
103104

105+
bool WriteVecToFile(const System::StrType& file_path, const 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 (const 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) {
107121
// Read each line of the stamp file and split on the first space
108122
System::StrVecType stamp_block;
109-
if (!ReadFileToArray(stamp_path, stamp_block)) {
123+
if (!ReadFileToVec(stamp_path, stamp_block)) {
110124
return false;
111125
}
112126

@@ -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: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@
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, const std::vector<Subst>& substs);
3132

3233
// Reads a file in text mode and feeds each line to item in the vec output
33-
bool ReadFileToArray(const System::StrType& file_path, System::StrVecType& vec);
34+
bool ReadFileToVec(const System::StrType& file_path, System::StrVecType& vec);
35+
36+
// Write the content of an array file as lines in a file
37+
bool WriteVecToFile(const System::StrType& file_path, const System::StrVecType& vec);
3438

3539
// Reads a workspace status stamp file to an array of key value pairs
3640
bool ReadStampStatusToArray(

0 commit comments

Comments
 (0)