in tools/worker/work_processor.cc [49:197]
void WorkProcessor::ProcessWorkRequest(
const blaze::worker::WorkRequest &request,
blaze::worker::WorkResponse *response) {
std::vector<std::string> processed_args(universal_args_);
// Bazel's worker spawning strategy reads the arguments from the params file
// and inserts them into the proto. This means that if we just try to pass
// them verbatim to swiftc, we might end up with a command line that's too
// long. Rather than try to figure out these limits (which is very
// OS-specific and easy to get wrong), we unconditionally write the processed
// arguments out to a params file.
auto params_file = TempFile::Create("swiftc_params.XXXXXX");
std::ofstream params_file_stream(params_file->GetPath());
OutputFileMap output_file_map;
std::string output_file_map_path;
bool is_wmo = false;
bool is_dump_ast = false;
std::string prev_arg;
for (auto arg : request.arguments()) {
auto original_arg = arg;
// Peel off the `-output-file-map` argument, so we can rewrite it if
// necessary later.
if (arg == "-output-file-map") {
arg.clear();
} else if (arg == "-dump-ast") {
is_dump_ast = true;
} else if (prev_arg == "-output-file-map") {
output_file_map_path = arg;
arg.clear();
} else if (ArgumentEnablesWMO(arg)) {
is_wmo = true;
}
if (!arg.empty()) {
params_file_stream << arg << '\n';
}
prev_arg = original_arg;
}
bool is_incremental = !is_wmo && !is_dump_ast;
if (!output_file_map_path.empty()) {
if (is_incremental) {
output_file_map.ReadFromPath(output_file_map_path);
// Rewrite the output file map to use the incremental storage area and
// pass the compiler the path to the rewritten file.
auto new_path =
ReplaceExtension(output_file_map_path, ".incremental.json");
output_file_map.WriteToPath(new_path);
params_file_stream << "-output-file-map\n";
params_file_stream << new_path << '\n';
// Pass the incremental flags only if WMO is disabled. WMO would overrule
// incremental mode anyway, but since we control the passing of this flag,
// there's no reason to pass it when it's a no-op.
params_file_stream << "-incremental\n";
} else {
// If WMO or -dump-ast is forcing us out of incremental mode, just put the
// original output file map back so the outputs end up where they should.
params_file_stream << "-output-file-map\n";
params_file_stream << output_file_map_path << '\n';
}
}
processed_args.push_back("@" + params_file->GetPath());
params_file_stream.close();
std::ostringstream stderr_stream;
if (is_incremental) {
for (const auto &expected_object_pair :
output_file_map.incremental_outputs()) {
// Bazel creates the intermediate directories for the files declared at
// analysis time, but we need to manually create the ones for the
// incremental storage area.
auto dir_path = Dirname(expected_object_pair.second);
if (!MakeDirs(dir_path, S_IRWXU)) {
stderr_stream << "swift_worker: Could not create directory " << dir_path
<< " (errno " << errno << ")\n";
FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
return;
}
}
// Copy some input files from the incremental storage area to the locations
// where Bazel will generate them.
for (const auto &expected_object_pair :
output_file_map.incremental_inputs()) {
if (FileExists(expected_object_pair.second)) {
if (!CopyFile(expected_object_pair.second,
expected_object_pair.first)) {
stderr_stream << "swift_worker: Could not copy "
<< expected_object_pair.second << " to "
<< expected_object_pair.first << " (errno " << errno
<< ")\n";
FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
return;
}
}
}
}
SwiftRunner swift_runner(processed_args, /*force_response_file=*/true);
int exit_code = swift_runner.Run(&stderr_stream, /*stdout_to_stderr=*/true);
if (is_incremental) {
// Copy the output files from the incremental storage area back to the
// locations where Bazel declared the files.
for (const auto &expected_object_pair :
output_file_map.incremental_outputs()) {
if (!CopyFile(expected_object_pair.second, expected_object_pair.first)) {
stderr_stream << "swift_worker: Could not copy "
<< expected_object_pair.second << " to "
<< expected_object_pair.first << " (errno " << errno
<< ")\n";
FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
return;
}
}
// Copy the replaced input files back to the incremental storage for the
// next run.
for (const auto &expected_object_pair :
output_file_map.incremental_inputs()) {
if (FileExists(expected_object_pair.first)) {
if (FileExists(expected_object_pair.second)) {
// CopyFile fails if the file already exists
RemoveFile(expected_object_pair.second);
}
if (!CopyFile(expected_object_pair.first,
expected_object_pair.second)) {
stderr_stream << "swift_worker: Could not copy "
<< expected_object_pair.first << " to "
<< expected_object_pair.second << " (errno " << errno
<< ")\n";
FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
return;
}
}
}
}
FinalizeWorkRequest(request, response, exit_code, stderr_stream);
}