Skip to content

Commit aa6d8dc

Browse files
committed
fix(workspace): anchor an inherited include_dirs to the workspace root
Found by re-reading the merge, not by a failure. `[workspace.build] include_dirs = ["shared/inc"]` was prepended to each member verbatim, so every member resolved it against its OWN directory — looking for `<member>/shared/inc` for a directory that lives at `<workspace>/shared/inc`. This is #224 for a new key. `[indices].path` and `[workspace.dependencies] path` are anchored to the workspace root for exactly this reason, and a third relative-path key that skipped it fails as a missing header three members deep, naming neither the manifest that declared it nor the root it was written against. Anchored rather than refused: `expandIncludeDirs` already accepts an absolute include directory, so the anchored form needs nothing downstream. 321 now includes a header from the workspace root, so the anchoring has an assertion rather than a comment.
1 parent 81cc84f commit aa6d8dc

2 files changed

Lines changed: 36 additions & 6 deletions

File tree

‎src/project.cppm‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,32 @@ export void inherit_workspace_config(mcpp::manifest::Manifest& member,
201201
prepend(b.ldflags, w.ldflags);
202202
prepend(b.defines, w.defines);
203203
prepend(b.dialectCxxflags, w.dialectCxxflags);
204-
prepend(b.includeDirs, w.includeDirs);
205-
prepend(b.includeDirsAfter, w.includeDirsAfter);
206-
prepend(b.privateIncludeDirs, w.privateIncludeDirs);
204+
// A RELATIVE INCLUDE DIRECTORY IN THE WORKSPACE MANIFEST WAS WRITTEN
205+
// AGAINST THE WORKSPACE ROOT, and every member would otherwise resolve
206+
// it against its own directory.
207+
//
208+
// This is #224 for a new key: `[indices].path` and
209+
// `[workspace.dependencies] path` are anchored for exactly this reason,
210+
// and a third relative-path key that skipped it would silently point at
211+
// `<member>/shared/inc` for a directory that lives at
212+
// `<workspace>/shared/inc`. The failure is a missing header, three
213+
// members deep, naming neither the manifest that declared it nor the
214+
// root it was declared against.
215+
//
216+
// Anchored rather than refused: an absolute include directory is
217+
// already accepted by `expandIncludeDirs`, so the anchored form needs
218+
// no new handling downstream.
219+
auto anchored = [&](const std::vector<std::filesystem::path>& src) {
220+
std::vector<std::filesystem::path> out;
221+
out.reserve(src.size());
222+
for (auto const& d : src)
223+
out.push_back(d.is_absolute() ? d
224+
: (wsRoot / d).lexically_normal());
225+
return out;
226+
};
227+
prepend(b.includeDirs, anchored(w.includeDirs));
228+
prepend(b.includeDirsAfter, anchored(w.includeDirsAfter));
229+
prepend(b.privateIncludeDirs, anchored(w.privateIncludeDirs));
207230
if (b.cStandard.empty()) b.cStandard = w.cStandard;
208231
if (b.linkage.empty()) b.linkage = w.linkage;
209232
if (b.target.empty()) b.target = w.target;

‎tests/e2e/321_workspace_inheritance.sh‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ TMP=$(mktemp -d)
2424
trap "rm -rf $TMP" EXIT
2525
cd "$TMP"
2626

27-
mkdir -p silent/src pinned/src adds/src
27+
mkdir -p silent/src pinned/src adds/src shared/inc
28+
printf '#define SHARED_HEADER_FOUND 1\n' > shared/inc/shared.h
2829

2930
cat > mcpp.toml <<'EOF'
3031
[workspace]
@@ -36,7 +37,8 @@ version = "0.4.2"
3637
license = "Apache-2.0"
3738
3839
[workspace.build]
39-
cxxflags = ["-DFROM_WORKSPACE=1"]
40+
cxxflags = ["-DFROM_WORKSPACE=1"]
41+
include_dirs = ["shared/inc"]
4042
EOF
4143

4244
# `version` is deliberately absent from every member: it is a required field,
@@ -46,7 +48,12 @@ printf '[package]\nname = "silent"\n' > silent/mcpp.toml
4648
printf '[package]\nname = "pinned"\nstandard = "c++23"\n' > pinned/mcpp.toml
4749
printf '[package]\nname = "adds"\n\n[build]\ncxxflags = ["-DFROM_MEMBER=1"]\n' > adds/mcpp.toml
4850
for m in silent pinned adds; do
49-
printf '#ifndef FROM_WORKSPACE\n#error "workspace [build] did not reach the member"\n#endif\nint main(){return 0;}\n' > "$m/src/main.cpp"
51+
# The include also proves the workspace-relative path was anchored to the
52+
# WORKSPACE ROOT and not to each member: `shared/inc` lives at
53+
# `<workspace>/shared/inc`, and resolving it per-member would look for
54+
# `<member>/shared/inc` and fail with a missing header three members deep,
55+
# naming neither the manifest that declared it nor the root it meant.
56+
printf '#include <shared.h>\n#if !defined(FROM_WORKSPACE) || !defined(SHARED_HEADER_FOUND)\n#error "workspace [build] did not reach the member"\n#endif\nint main(){return 0;}\n' > "$m/src/main.cpp"
5057
done
5158

5259
flags_of() { # $1 = member dir

0 commit comments

Comments
 (0)