@@ -23,9 +23,11 @@ void create_archive_plan::archive(const build_env& env) const { | |||
; | |||
// Build up the archive command | |||
archive_spec ar; | |||
auto ar_cwd = env.output_root; | |||
ar.input_files = std::move(objects); | |||
ar.out_path = env.output_root / calc_archive_file_path(env.toolchain); | |||
auto ar_cmd = env.toolchain.create_archive_command(ar, fs::current_path(), env.knobs); | |||
auto ar_cmd = env.toolchain.create_archive_command(ar, ar_cwd, env.knobs); | |||
// `out_relpath` is purely for the benefit of the user to have a short name | |||
// in the logs | |||
@@ -43,7 +45,8 @@ void create_archive_plan::archive(const build_env& env) const { | |||
// Do it! | |||
dds_log(info, "[{}] Archive: {}", _qual_name, out_relpath); | |||
auto&& [dur_ms, ar_res] = timed<std::chrono::milliseconds>([&] { return run_proc(ar_cmd); }); | |||
auto&& [dur_ms, ar_res] = timed<std::chrono::milliseconds>( | |||
[&] { return run_proc(proc_options{.command = ar_cmd, .cwd = ar_cwd}); }); | |||
dds_log(info, "[{}] Archive: {} - {:L}ms", _qual_name, out_relpath, dur_ms.count()); | |||
// Check, log, and throw |
@@ -1,6 +1,7 @@ | |||
#pragma once | |||
#include <chrono> | |||
#include <filesystem> | |||
#include <optional> | |||
#include <string> | |||
#include <string_view> | |||
@@ -25,8 +26,8 @@ std::string quote_command(const Container& c) { | |||
} | |||
struct proc_result { | |||
int signal = 0; | |||
int retc = 0; | |||
int signal = 0; | |||
int retc = 0; | |||
bool timed_out = false; | |||
std::string output; | |||
@@ -36,6 +37,8 @@ struct proc_result { | |||
struct proc_options { | |||
std::vector<std::string> command; | |||
std::optional<std::filesystem::path> cwd = std::nullopt; | |||
/** | |||
* Timeout for the subprocess, in milliseconds. If zero, will wait forever | |||
*/ |
@@ -1,6 +1,7 @@ | |||
#ifndef _WIN32 | |||
#include "./proc.hpp" | |||
#include <dds/util/fs.hpp> | |||
#include <dds/util/log.hpp> | |||
#include <dds/util/signal.hpp> | |||
@@ -25,17 +26,18 @@ void check_rc(bool b, std::string_view s) { | |||
} | |||
} | |||
::pid_t | |||
spawn_child(const std::vector<std::string>& command, int stdout_pipe, int close_me) noexcept { | |||
::pid_t spawn_child(const proc_options& opts, int stdout_pipe, int close_me) noexcept { | |||
// We must allocate BEFORE fork(), since the CRT might stumble with malloc()-related locks that | |||
// are held during the fork(). | |||
std::vector<const char*> strings; | |||
strings.reserve(command.size() + 1); | |||
for (auto& s : command) { | |||
strings.reserve(opts.command.size() + 1); | |||
for (auto& s : opts.command) { | |||
strings.push_back(s.data()); | |||
} | |||
strings.push_back(nullptr); | |||
std::string workdir = opts.cwd.value_or(fs::current_path()).string(); | |||
auto child_pid = ::fork(); | |||
if (child_pid != 0) { | |||
return child_pid; | |||
@@ -46,6 +48,8 @@ spawn_child(const std::vector<std::string>& command, int stdout_pipe, int close_ | |||
check_rc(rc != -1, "Failed to dup2 stdout"); | |||
rc = dup2(stdout_pipe, STDERR_FILENO); | |||
check_rc(rc != -1, "Failed to dup2 stderr"); | |||
rc = ::chdir(workdir.data()); | |||
check_rc(rc != -1, "Failed to chdir() for subprocess"); | |||
::execvp(strings[0], (char* const*)strings.data()); | |||
@@ -73,7 +77,7 @@ proc_result dds::run_proc(const proc_options& opts) { | |||
int read_pipe = stdio_pipe[0]; | |||
int write_pipe = stdio_pipe[1]; | |||
auto child = spawn_child(opts.command, write_pipe, read_pipe); | |||
auto child = spawn_child(opts, write_pipe, read_pipe); | |||
::close(write_pipe); | |||
@@ -1,6 +1,7 @@ | |||
#ifdef _WIN32 | |||
#include "./proc.hpp" | |||
#include <dds/util/fs.hpp> | |||
#include <dds/util/log.hpp> | |||
#include <fmt/core.h> | |||
@@ -72,7 +73,7 @@ proc_result dds::run_proc(const proc_options& opts) { | |||
true, | |||
CREATE_NEW_PROCESS_GROUP, | |||
nullptr, | |||
nullptr, | |||
opts.cwd.value_or(fs::current_path()).c_str(), | |||
&startup_info, | |||
&proc_info); | |||
if (!okay) { |