Skip to content

Commit 7e5e4e8

Browse files
committed
fix(build.mcpp): run with cwd = project root (capture_exec cwd param)
build.mcpp wrote its generated sources relative to the CHILD's cwd = mcpp's invocation dir, which is the project root only by coincidence. Running it via 'mcpp test -p <member>' (or any invocation from another dir) wrote the files to the wrong place -> 'declared generated source does not exist'. Add an optional cwd to platform::process::capture_exec (Linux: posix_spawn_file_actions_addchdir_np; else: 'cd <cwd> && ' prefix) and run/ compile build.mcpp with cwd = project root. Also unblocks the future typed import-mcpp module (GCC gcm.cache staging needs a controllable cwd). e2e 89 extended: build from a nested subdir, assert the generated source lands in the project root.
1 parent 40c4873 commit 7e5e4e8

3 files changed

Lines changed: 50 additions & 4 deletions

File tree

src/build/build_program.cppm

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,15 +299,17 @@ std::expected<void, std::string> run_build_program(
299299
compileArgv.push_back(src.string());
300300
compileArgv.push_back("-o"); compileArgv.push_back(bin.string());
301301
mcpp::ui::info("build.mcpp", "compiling");
302-
auto cres = mcpp::platform::process::capture_exec(compileArgv);
302+
auto cres = mcpp::platform::process::capture_exec(compileArgv, {}, root.string());
303303
if (cres.exit_code != 0) {
304304
return std::unexpected(std::format(
305305
"build.mcpp failed to compile (exit {}):\n{}", cres.exit_code, cres.output));
306306
}
307307

308308
// ── Run it; capture stdout(+stderr) and parse directives ────────────────
309+
// Run with cwd = project root so the program's relative file writes (e.g.
310+
// mcpp:generated sources) land in the project, not in mcpp's invocation dir.
309311
mcpp::ui::info("build.mcpp", "running");
310-
auto rres = mcpp::platform::process::capture_exec({bin.string()});
312+
auto rres = mcpp::platform::process::capture_exec({bin.string()}, {}, root.string());
311313
if (rres.exit_code != 0) {
312314
return std::unexpected(std::format(
313315
"build.mcpp exited with {} (build aborted):\n{}", rres.exit_code, rres.output));

src/platform/process.cppm

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
// Callers are responsible for shell-quoting arguments (see platform.shell).
2020

2121
module;
22+
#ifndef _GNU_SOURCE
23+
#define _GNU_SOURCE // for posix_spawn_file_actions_addchdir_np (glibc)
24+
#endif
2225
#include <cstdio>
2326
#include <cstdlib>
2427
#if defined(_WIN32)
@@ -77,7 +80,8 @@ int run_exec(const std::vector<std::string>& argv,
7780
// is_stale_ninja_failure / filter_ninja_output. No shell → no quoting/injection.
7881
RunResult capture_exec(
7982
const std::vector<std::string>& argv,
80-
const std::vector<std::pair<std::string, std::string>>& extraEnv = {});
83+
const std::vector<std::pair<std::string, std::string>>& extraEnv = {},
84+
std::string_view cwd = {});
8185

8286
// Run `command` silently (discard stdout/stderr).
8387
// On POSIX, stdin is automatically redirected from /dev/null.
@@ -325,7 +329,8 @@ int run_exec(const std::vector<std::string>& argv,
325329

326330
RunResult capture_exec(
327331
const std::vector<std::string>& argv,
328-
const std::vector<std::pair<std::string, std::string>>& extraEnv)
332+
const std::vector<std::pair<std::string, std::string>>& extraEnv,
333+
std::string_view cwd)
329334
{
330335
RunResult result;
331336
if (argv.empty()) { result.exit_code = 127; return result; }
@@ -345,6 +350,11 @@ RunResult capture_exec(
345350

346351
posix_spawn_file_actions_t fa;
347352
::posix_spawn_file_actions_init(&fa);
353+
// Run the child in `cwd` when requested (e.g. build.mcpp, whose relative
354+
// file writes must land in the project root regardless of mcpp's own cwd).
355+
std::string cwdStore(cwd);
356+
if (!cwdStore.empty())
357+
::posix_spawn_file_actions_addchdir_np(&fa, cwdStore.c_str());
348358
::posix_spawn_file_actions_adddup2(&fa, fds[1], 1); // stdout → pipe
349359
::posix_spawn_file_actions_adddup2(&fa, fds[1], 2); // stderr → same pipe
350360
::posix_spawn_file_actions_addclose(&fa, fds[0]);
@@ -367,6 +377,8 @@ RunResult capture_exec(
367377
return result;
368378
#else
369379
std::string cmd = command_from_argv(argv) + " 2>&1";
380+
if (!cwd.empty())
381+
cmd = "cd " + mcpp::platform::shell::quote(cwd) + " && " + cmd;
370382
return capture_with_env(cmd, extraEnv);
371383
#endif
372384
}

tests/e2e/89_build_mcpp.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,36 @@ touch src/main.cpp
6767
MCPP_TEST_TOGGLE=1 "$MCPP" build > b3.log 2>&1 || { cat b3.log; echo "FAIL: build 3 errored"; exit 1; }
6868
grep -qi "build.mcpp.*\(running\|compiling\)" b3.log || { cat b3.log; echo "FAIL: changed env did not force build.mcpp re-run"; exit 1; }
6969

70+
# ── CWD independence: build.mcpp must run with cwd = project root, so its
71+
# relative file writes (the generated source) land in the project even when
72+
# mcpp is invoked from a SUBDIRECTORY (e.g. workspace -p, or `cd src && mcpp`).
73+
cd "$TMP"
74+
mkdir -p sub/src
75+
cat > sub/mcpp.toml <<'EOF'
76+
[package]
77+
name = "sub"
78+
version = "0.1.0"
79+
EOF
80+
cat > sub/src/main.cpp <<'EOF'
81+
#ifndef FROM_BUILD_MCPP
82+
#error "define missing"
83+
#endif
84+
int gen();
85+
int main() { return gen() == 7 ? 0 : 1; }
86+
EOF
87+
cat > sub/build.mcpp <<'EOF'
88+
#include <fstream>
89+
#include <cstdio>
90+
int main() {
91+
std::ofstream("src/gen.cpp") << "int gen(){return 7;}\n";
92+
std::puts("mcpp:generated=src/gen.cpp");
93+
std::puts("mcpp:cxxflag=-DFROM_BUILD_MCPP=1");
94+
return 0;
95+
}
96+
EOF
97+
# Invoke from the nested src/ dir — mcpp walks up to the project; build.mcpp must
98+
# still write src/gen.cpp into the project root, not into the cwd.
99+
( cd sub/src && "$MCPP" build > "$TMP/sub.log" 2>&1 ) || { cat "$TMP/sub.log"; echo "FAIL: build from subdir errored (cwd not project root?)"; exit 1; }
100+
[ -f sub/src/gen.cpp ] || { echo "FAIL: generated source not written to project root"; exit 1; }
101+
70102
echo "OK"

0 commit comments

Comments
 (0)