Skip to content

Commit da44e99

Browse files
committed
deps: the Linux GCC row keeps vcpkg's detection; the MSBuild refusal reads the call stack
- mcpp runs its GCC payload with a sysroot, a binutils directory and a link model that only its own command lines carry, so the driver alone is not a complete handover: vcpkg's compiler detection failed with it on CI. On that row the host compiler's libstdc++ is the program's C++ library, and `resolved` answers `detected`, stating why. The clang payloads are complete through their `.cfg` files and stay `chain`. - The MSBuild watch matched the current file, which inside a function is the caller's (the portfile), so it never fired; it now matches the helper in the call stack, by its own directory and file names (measured with CMake 4.4: the helper is refused, a CMake helper's read is not).
1 parent eee568f commit da44e99

5 files changed

Lines changed: 91 additions & 41 deletions

File tree

‎.github/scripts/check-deps-and-qt.sh‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,25 @@ vcpkg_consumer() {
7272

7373
# THE MECHANISM (0.17.0). On the Visual Studio row the instance mcpp
7474
# resolved is selected and the standard triplet is used, so the ABI hash is
75-
# the one vcpkg computes by itself; on the other rows a derived triplet
76-
# names the resolved tools.
75+
# the one vcpkg computes by itself. On the Linux GCC row (this job's
76+
# default) vcpkg's own detection is kept: the payload driver runs with
77+
# flags only mcpp's command lines carry. On the clang rows (macOS here) a
78+
# derived triplet names the resolved tools.
7779
if is_windows; then
7880
grep -rqs 'VCPKG_VISUAL_STUDIO_PATH=' target --include=build.ninja ||
7981
fail "the installation does not select the Visual Studio instance mcpp resolved"
8082
[ -d target/vcpkg_installed/x64-windows/x64-windows ] || fail "the instance mechanism did not use x64-windows"
8183
echo "ok: the installation selects the Visual Studio instance and keeps the standard triplet"
82-
else
84+
elif is_macos; then
8385
ls -d target/vcpkg_installed/*-mcpp-*/*-mcpp-* > /dev/null 2>&1 ||
8486
fail "no derived <base>-mcpp-<hash> prefix under target/vcpkg_installed"
8587
grep -rqs 'MCPP_VCPKG_CXX=' target --include=build.ninja || fail "the installation does not hand vcpkg the resolved compiler"
8688
echo "ok: the installation names the resolved compiler in a derived triplet"
89+
else
90+
ls -d target/vcpkg_installed/*-linux/*-linux > /dev/null 2>&1 ||
91+
fail "the GCC row did not keep the standard <arch>-linux triplet"
92+
! grep -rqs 'MCPP_VCPKG_CXX=' target --include=build.ninja || fail "the GCC row named its compiler to vcpkg"
93+
echo "ok: the GCC row keeps vcpkg's detection and the standard triplet"
8794
fi
8895

8996
if is_windows; then
@@ -126,8 +133,8 @@ vcpkg_libcxx() {
126133
"$MCPP" run | tee target/ci/default-run.log
127134
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/default-run.log || fail "the default toolchain's program did not print through fmt"
128135
[ -f "$lib" ] || fail "the default toolchain's installation removed the $gen prefix"
129-
[ "$(ls -d target/vcpkg_installed/*-mcpp-* | wc -l)" -ge 2 ] ||
130-
fail "the default toolchain did not derive a triplet of its own"
136+
[ "$(ls -d target/vcpkg_installed/*/ | wc -l)" -ge 2 ] ||
137+
fail "the default toolchain did not install a prefix of its own"
131138
local stamp; stamp=$(find target -path '*deps-vcpkg*' -name "$gen.stamp" | head -1)
132139
[ -n "$stamp" ] || fail "no $gen installation stamp"
133140
touch -r "$stamp" target/ci/before-switch-back
@@ -455,7 +462,7 @@ vcpkg_msbuild_refused() {
455462
if "$MCPP" build --toolchain "$MSVC_MANAGED" > target/ci/build.log 2>&1; then
456463
cat target/ci/build.log; fail "an MSBuild port built without Visual Studio"
457464
fi
458-
grep -q "builds with MSBuild, which needs a Visual Studio instance" target/ci/build.log ||
465+
grep -q "builds with MSBuild" target/ci/build.log ||
459466
{ tail -60 target/ci/build.log; fail "the MSBuild port failed without the plugin's reason"; }
460467
echo "ok: an MSBuild port is refused by name without Visual Studio"
461468
}

‎deps/vcpkg.cppm‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,17 +267,24 @@ inline std::string chain_toolchain_text() {
267267
}
268268

269269
// What an MSBuild port meets under `chain`: vcpkg runs MSBuild with
270-
// `/p:PlatformToolset=external` and fails without naming the cause. The
271-
// MSBuild helpers read `VCPKG_PLATFORM_TOOLSET` to build that argument; the
272-
// watch stops the port there and says why.
270+
// `/p:PlatformToolset=external` and fails without naming the cause ("msbuild:
271+
// no such file or directory" when no Visual Studio exists). The MSBuild
272+
// helpers read `VCPKG_PLATFORM_TOOLSET` to build that argument; the watch
273+
// stops the port there and says why. The helper is recognised in the watch's
274+
// CALL STACK, not its current file: a read inside a function reports the
275+
// caller's file (the portfile), and the stack names the file that defines the
276+
// function (measured with CMake 4.4). The pattern names the helper's own
277+
// directory and files, so a project whose path contains "msbuild" is not
278+
// refused.
273279
inline std::string msbuild_refusal_text(std::string_view identity) {
274280
return std::format(
275281
"# mcpp.deps.vcpkg: a port that builds with MSBuild needs a Visual Studio\n"
276282
"# instance, and this toolset comes from none.\n"
277283
"if(PORT AND NOT DEFINED Z_MCPP_MSBUILD_WATCH)\n"
278284
" set(Z_MCPP_MSBUILD_WATCH 1)\n"
279-
" function(z_mcpp_msbuild_watch variable access value current_file)\n"
280-
" if(access STREQUAL \"READ_ACCESS\" AND current_file MATCHES \"msbuild\")\n"
285+
" function(z_mcpp_msbuild_watch variable access value current_file stack)\n"
286+
" if(access STREQUAL \"READ_ACCESS\" AND stack MATCHES "
287+
"\"/vcpkg-msbuild/|vcpkg_install_msbuild\\\\.cmake|vcpkg_build_msbuild\\\\.cmake\")\n"
281288
" message(FATAL_ERROR \"mcpp.deps.vcpkg: the port '${{PORT}}' builds with MSBuild, which "
282289
"needs a Visual Studio instance; the toolset mcpp resolved ({}) comes from none. Build with "
283290
"the toolchain msvc@system on a machine with Visual Studio, or set the deps-vcpkg option "

‎docs/deps.md‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,18 @@ vcpkg follows where the toolset came from:
108108
| mechanism | when | what vcpkg receives | port kinds that build |
109109
|---|---|---|---|
110110
| `instance` | an MSVC toolset from a Visual Studio instance (`msvc@system`, the default on a machine with Visual Studio) | `VCPKG_VISUAL_STUDIO_PATH` naming that instance; the standard triplet, or a derived one with `VCPKG_PLATFORM_TOOLSET_VERSION` when the resolved toolset is not the instance's default | CMake, make and MSBuild |
111-
| `chain` | any other toolset: a managed MSVC toolset (`xim:msvc@<version>`), and the toolsets of the Linux and macOS rows | a derived triplet `<base>-mcpp-<hash>` that chain-loads a toolchain naming the tools, and the tools' environment | CMake and make; an MSBuild port is refused by name |
112-
| `detected` | `options.toolset.toolset = detected` | nothing: vcpkg finds its own toolset, as in 0.16.0 | as vcpkg's own detection allows |
111+
| `chain` | a managed MSVC toolset (`xim:msvc@<version>`), and the clang toolsets of the Linux and macOS rows | a derived triplet `<base>-mcpp-<hash>` that chain-loads a toolchain naming the tools, and the tools' environment | CMake and make; an MSBuild port is refused by name |
112+
| `detected` | `options.toolset.toolset = detected`; and, under `resolved`, the Linux GCC row | nothing: vcpkg finds its own toolset, as in 0.16.0 | as vcpkg's own detection allows |
113+
114+
**The Linux GCC row.** mcpp runs its GCC payload with a sysroot, a binutils
115+
directory and a link model (the payload's dynamic linker and C library) that
116+
its own command lines add; the driver alone is not a complete toolset, and
117+
vcpkg's compiler detection fails with it on a machine whose host compiler does
118+
not fill the gaps (measured on the plugins' CI). The clang payloads carry their
119+
configuration in their own `.cfg` files and are complete. On the GCC row the
120+
host compiler's libstdc++ is the program's C++ library, so `resolved` keeps
121+
vcpkg's detection there and the member states why in `mcpp.plugins.toolset`'s
122+
`reason`.
113123

114124
**The derived triplet.** The base triplet's text is copied into it, not
115125
included, because vcpkg hashes a triplet file's content and not the files it
@@ -145,14 +155,15 @@ a second C++ runtime into the process without a word. `crt_linkage` states the
145155
ports' linkage explicitly and wins.
146156

147157
**Linux.** Linux has two C++ standard libraries that do not link with each
148-
other. The derived triplet names the program's compiler, so the ports use the
149-
program's library on every row: libc++ under mcpp's clang (`std::__1::`), and
150-
the GCC payload's libstdc++ under mcpp's GCC.
151-
152-
**Upgrading from 0.16.0.** On Linux and macOS, and on Windows with a managed
153-
toolset, the installation moves to a derived triplet, so each port is built once
154-
more (or restored from a binary cache that already holds it); the prefixes of
155-
0.16.0 (`<arch>-linux-libcxx`, `x64-linux`) are left where they are. With
158+
other. Under mcpp's clang the derived triplet names that clang, so the ports
159+
use libc++ (`std::__1::`) as the program does; under mcpp's GCC the host
160+
compiler's libstdc++ is the program's library, and vcpkg's detection is kept.
161+
162+
**Upgrading from 0.16.0.** On the clang rows of Linux and macOS, and on Windows
163+
with a managed toolset, the installation moves to a derived triplet, so each
164+
port is built once more (or restored from a binary cache that already holds
165+
it); the prefixes of 0.16.0 (`<arch>-linux-libcxx`) are left where they are. The
166+
Linux GCC row is unchanged. With
156167
Visual Studio and the dynamic C runtime nothing changes: the standard triplet
157168
and the instance vcpkg selects by itself give the same ABI hash. A program that
158169
links the C runtime statically moves to `x64-windows-static`.

‎src/toolset.cppm‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
// toolset loading stays in place, pointed at the instance mcpp
1515
// resolved, so MSBuild is present and every kind of project
1616
// builds.
17-
// chain Any other toolset -- a managed MSVC toolset, and every toolset
18-
// on the other rows -- is named: absolute tool paths, the
17+
// chain Any other toolset -- a managed MSVC toolset, and the clang
18+
// toolsets of the other rows -- is named: absolute tool paths, the
1919
// environment they run with, and the directories that go first
2020
// on PATH. On the MSVC ABI without an instance no MSBuild exists.
21-
// detected `source::detected`: nothing is named, and the foreign system
22-
// finds its own toolset, as the deps members did before 0.17.0.
23-
// Kept by `src/compat/detected_toolset.cppm` until 2027-03-28.
21+
// detected Nothing is named, and the foreign system finds its own
22+
// toolset. `source::detected` asks for it (kept by
23+
// `src/compat/detected_toolset.cppm` until 2027-03-28); `resolved`
24+
// answers it on the Linux GCC row, whose payload driver is not a
25+
// complete handover (see `resolve`).
2426
//
2527
// NONE OF THIS NAMES A FOREIGN SYSTEM. vcpkg's triplet and CMake's generator
2628
// are written by the plugins that drive them (`mcpp.deps.vcpkg`,
@@ -73,6 +75,9 @@ struct resolved_tools {
7375
std::string identity; // toolset_identity(): "msvc 14.44.35207; sdk 10.0.26100.0", "clang 22.1.8"
7476
std::string crt; // msvc_crt_linkage(): "static", "dynamic", or empty off the MSVC ABI
7577
bool msvc_abi = false;
78+
// Why `resolved` answered `detected`: empty unless the resolved toolset
79+
// cannot be handed over by its tools alone.
80+
std::string reason;
7681
};
7782

7883
inline bool msvc_abi() {
@@ -216,6 +221,22 @@ inline std::expected<resolved_tools, std::string> resolve(const choice& c = {})
216221
"arrived in mcpp 2026.9.28.3 (protocol 14). Pin \"mcpp\": \"2026.9.28.3\" or newer "
217222
"in .xlings.json, or set the plugin's `toolset` option to `detected`."));
218223

224+
// THE GCC PAYLOAD IS NOT A COMPLETE HANDOVER. mcpp runs it with a sysroot,
225+
// a binutils directory and a link model (`--sysroot`, `-B`, the payload's
226+
// dynamic linker and C library) that its own command lines add and a
227+
// foreign build system does not receive; given the driver alone, vcpkg's
228+
// compiler detection failed on CI while it passed on a machine whose host
229+
// compiler filled the gaps. The clang payloads carry their configuration in
230+
// their own `.cfg` files and are complete. On the GCC row the host
231+
// compiler's libstdc++ is the same C++ library, so the foreign system's
232+
// detection agrees with the program, as it did before 0.17.0.
233+
if (!r.msvc_abi && std::string_view(mcpp::compiler()) == "gcc") {
234+
r.how = mechanism::detected;
235+
r.reason = "the GCC payload runs with a sysroot, binutils and a link model that only mcpp's "
236+
"own command lines carry; the host compiler's libstdc++ is the program's C++ library";
237+
return r;
238+
}
239+
219240
const std::string instance = forward(mcpp::msvc_instance_dir());
220241
if (r.msvc_abi && !instance.empty() && c.cc == compiler::abi_native) {
221242
r.how = mechanism::instance;

‎tests/plugin-logic/build.mcpp‎

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -176,41 +176,45 @@ int main(int argc, char** argv) {
176176
"the compatibility note is printed");
177177
} },
178178

179-
{ "vcpkg: the Linux GCC row is chained with vcpkg's linux.cmake",
179+
{ "vcpkg: the Linux GCC row keeps vcpkg's detection, and says why",
180180
with_vcpkg(t::row::linux_gcc()),
181+
[] {
182+
const auto r = ts::resolve();
183+
std::printf("reason=%s\n", r ? r->reason.c_str() : "");
184+
return vcpkg_use();
185+
},
186+
[](const t::result& r, t::checker& c) {
187+
c.expect(r.has_line("mcpp:action=", {"deps-vcpkg:install:x64-linux\""}),
188+
"the standard triplet x64-linux is used");
189+
c.expect(!r.has_line("mcpp:action=", {"MCPP_VCPKG_CXX="}), "no compiler is named");
190+
c.expect(r.has_line("reason=", {"GCC payload"}), "the resolution states why");
191+
} },
192+
193+
{ "vcpkg: the Linux libc++ row hands over mcpp's clang through linux.cmake",
194+
with_vcpkg(t::row::linux_libcxx()),
181195
[] { return vcpkg_use(); },
182196
[](const t::result& r, t::checker& c) {
183-
const auto f = derived_triplet(r);
184-
const auto name = stem(f);
197+
const auto name = stem(derived_triplet(r));
185198
c.expect(name.starts_with("x64-linux-mcpp-"), "the derived triplet is x64-linux-mcpp-<hash>");
186199
c.expect(r.file("out/deps-vcpkg/triplets/mcpp-chain-linux.cmake")
187200
.find("/scripts/toolchains/linux.cmake\")") != std::string::npos,
188201
"the toolchain includes vcpkg's linux.cmake");
189202
const auto a = r.line("mcpp:action=", {"deps-vcpkg:install:" + name});
190-
c.expect(a.find("MCPP_VCPKG_CXX=") != std::string::npos && a.find("gcc/bin/g++") != std::string::npos,
191-
"the row's g++ is handed to vcpkg");
203+
c.expect(a.find("MCPP_VCPKG_CXX=") != std::string::npos && a.find("llvm/bin/clang++") != std::string::npos,
204+
"clang++ is handed to vcpkg");
192205
c.expect(a.find("--host-triplet") == std::string::npos, "host tools keep vcpkg's host triplet");
193206
c.expect(a.find("\"PATH=") == std::string::npos, "PATH is left alone off the MSVC ABI");
194207
first_linux_name = name;
195208
} },
196209

197210
{ "vcpkg: the derived triplet's name does not depend on where the tools are",
198-
with_vcpkg(t::row::linux_gcc()),
211+
with_vcpkg(t::row::linux_libcxx()),
199212
[] { return vcpkg_use(); },
200213
[](const t::result& r, t::checker& c) {
201214
c.expect(!first_linux_name.empty() && stem(derived_triplet(r)) == first_linux_name,
202215
"the same toolset under another root derives the same triplet");
203216
} },
204217

205-
{ "vcpkg: the Linux libc++ row hands over mcpp's clang",
206-
with_vcpkg(t::row::linux_libcxx()),
207-
[] { return vcpkg_use(); },
208-
[](const t::result& r, t::checker& c) {
209-
c.expect(r.has_line("mcpp:action=", {"MCPP_VCPKG_CXX=", "llvm/bin/clang++"}),
210-
"clang++ is handed to vcpkg");
211-
c.expect(stem(derived_triplet(r)) != first_linux_name, "the two toolsets derive two triplets");
212-
} },
213-
214218
// ── deps-cmake ──────────────────────────────────────────────────────
215219
{ "cmake: a Visual Studio toolset keeps the Visual Studio generator on that instance",
216220
with_subproject(t::row::windows_visual_studio("14.43.34808", "14.44.35207")),

0 commit comments

Comments
 (0)