Skip to content

Commit 5097ccf

Browse files
committed
fix(target): every object-format question reads the single answer, and two copies were searching for a vendor name
An audit of the 35 sites that derived the binary format from `os`. Twelve of them asked "which object format" and were converted to read `object_format()`; the rest ask a different question -- which payload to install, which loader variable a platform reads, which flag spelling a compiler wants -- and are unchanged. The classification mattered more than the count: a site that means "which OS" and is converted becomes wrong in a new way. WHAT EACH CONVERTED SITE ANSWERED FOR `aarch64-ios` BEFORE: -femulated-tls, -fvisibility-hidden not passed (Mach-O needs both) shared_library_link_flags $ORIGIN, which ld64 rejects shared_soname_flag -Wl,-soname, a BFD-only flag exports_file_contents / exports_flag a GNU version script debug_info_is_in_band true; Mach-O splits to dSYM dist::format_for the BUILD HOST's format Every one of those is the ELF branch reached by falling off the end of a two-valued test, which is the failure `ObjectFormat` was introduced to make impossible. Verified for every row in `kKnownTargets` that the answer changes only for `aarch64-ios` and `wasm32-emscripten`, and only toward correctness. TWO COPIES WERE SEARCHING FOR A VENDOR NAME IN THE WRONG STRING, AND ONE OF THEM AFFECTS AN ALREADY-VERIFIED ROW. `compute_flags`'s `linkIntentFlavor` and `resolution.json`'s `format` both derived the object format by looking for "apple" / "darwin" / "windows" / "mingw" in `plan.toolchain.targetTriple`. That string is mcpp's CANONICAL spelling, and `aarch64-macos` contains none of those words. The words live in the LLVM spelling, which is a different string -- the build report prints both, either side of an arrow: Target aarch64-macos → arm64-apple-macos14.0 ^ the identity ^ what clang is given So an explicit `--target aarch64-macos` linked and recorded as ELF. A NATIVE macOS build was right by a different branch -- an empty triple reaching the `needs_explicit_libcxx` rescue -- which is why nothing caught it: two paths through one function disagreed and only the exercised one was correct. Both now ask the parsed triple, and the substring test survives only for a spelling `parse` REJECTS, which is the `[target.<triple>]` escape hatch where an LLVM-shaped string is what an author actually wrote. `test_toolchain_triple.cpp` states this as a fact about the vocabulary rather than as a comment elsewhere: for `aarch64-macos`, `x86_64-macos` and `aarch64-ios` it asserts the canonical spelling contains neither "apple" nor "darwin", that the format is Mach-O anyway because it is asked of the fields, and that the LLVM spelling is where the vendor name lives. A second test takes its denominator from the table, so a row added without an answer cannot be covered by a test whose name says every row is. TWO GAPS ARE NAMED RATHER THAN GUESSED. `dist::Format` and `LinkIntentFlavor` have no `Wasm` member, so `wasm32-emscripten` still resolves to `Elf` in both. What "self-contained" and "link_lib" mean for an Emscripten link is a distribution-contract decision and the open half of #597, not a rename; the switch names the case so the gap is visible instead of reached by falling through. `mcpp::pack::run` now refuses a file that is neither ELF, PE nor Mach-O by name, where it previously handed anything not-PE-not-Mach-O to `LD_TRACE_LOADED_OBJECTS`. Docs: the design record's section 3.1 is corrected twice, because two of its guesses were measured wrong in the same direction -- a vendor had already done the work and nobody looked. NDK r30 ships the 133-file module surface itself (r27 shipped none), so for Android there is nothing to derive; and Apple's libc++ IS a build of a public revision (210106 -> llvmorg-21.1.6), the SDK ships no surface, and an `import std` Mach-O arm64 binary was linked from a Linux host. Section 8 names the pattern rather than only listing the facts. 109 unit tests pass.
1 parent 6163f86 commit 5097ccf

13 files changed

Lines changed: 328 additions & 44 deletions

.agents/docs/2026-09-11-distribution-plugins-and-platform-decomposition.md

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,39 @@ than the shipped state of either toolchain suggests: **`import std` works on
253253
both Android and Emscripten today, and neither needs a fork or a compiler
254254
upgrade.** What both need is a directory their vendor chose not to install.
255255

256-
### The gap, stated once
256+
### The gap, stated once — and closed by one vendor since
257257

258258
An LLVM installation that supports `import std` carries a generated module
259-
surface beside its headers. Neither vendor ships it:
259+
surface beside its headers.
260+
261+
**The NDK ships one as of r30.** Measured 2026-09-11 against
262+
`android-ndk-r30-linux.zip` (`Pkg.Revision 30.0.16248370`, the current LTS):
263+
`share/libc++/v1/` holds `std.cppm`, `std.compat.cppm`, 110 `std/*.inc` and 21
264+
`std.compat/*.inc` — the same 133 files this section measured as **absent** on
265+
r27, generated by Google from the same AOSP checkout as the compiler. So the
266+
table below is r27's state, and for Android the remedy it describes is no
267+
longer needed: there is nothing to fetch from an `llvmorg-*` tag, nothing to
268+
substitute, and no second asset to publish.
269+
270+
Two things about r30 did **not** change, and both matter more than the file
271+
count:
272+
273+
- **`-D__BIONIC_CTYPE_INLINE=` is still required.** The bionic ctype defect
274+
reproduces verbatim on r30 / clang 21: 28 errors, confined to `cctype.inc`
275+
and `locale.inc`, `using declaration referring to 'isalnum' with internal
276+
linkage cannot be exported`. Google ships the surface without shipping a
277+
build of it that works out of the box.
278+
- **The version to match is still not derivable from the compiler.** r30's
279+
`_LIBCPP_VERSION` is `210000` from clang `21.0.0 (based on r574158c)` — an
280+
AOSP `toolchains/llvm-project` mirror revision, **not** a build of any public
281+
`llvmorg-21.1.x` tag. So the pairing check below cannot compare against an
282+
upstream tag for Android; it can only pin the value and refuse a change.
283+
284+
That is the second time a guess in this section was wrong in the same
285+
direction: **a vendor had already done the work and nobody looked.** The first
286+
was Apple (below). The table is kept as the r27 measurement it was, because the
287+
argument it supports — that a target row for a toolchain without the surface
288+
would be worse than its absence — is what motivated looking at all.
260289

261290
| | `xim:llvm` 20.1.7 | NDK r27 | Emscripten 4.0.19 |
262291
|---|---|---|---|
@@ -389,14 +418,61 @@ $ node app.js
389418
half is open: **the standard library story is answered**, and what remains is
390419
[#597](https://github.com/mcpp-community/mcpp/issues/597)'s target model.
391420

392-
### Apple: not measured, and the recipe may not transfer
421+
### Apple: measured after all, and every guess in this section was wrong
393422

394-
iOS cannot be measured on a Linux host. Unlike the other two, the remedy may not
395-
exist: Apple's libc++ is not a build of a public revision, so there is no
396-
matching `libcxx/modules/` to take a surface from, and the `_LIBCPP_VERSION`
397-
check that makes the other two recipes safe has nothing to compare against.
398-
Two honest possibilities, and which holds is a measurement not taken — Xcode's
399-
toolchain already ships the surface, or iOS waits on Apple.
423+
This section first said iOS could not be measured on a Linux host, that Apple's
424+
libc++ is not a build of a public revision, and that the remedy might therefore
425+
not exist. **All three are false**, measured 2026-09-11 against
426+
`iPhoneOS26.5.sdk` (49 MB, from a public mirror) and `xim:llvm@22.1.8`:
427+
428+
| | |
429+
|---|---|
430+
| `_LIBCPP_VERSION` | **210106** — a public revision, and `llvmorg-21.1.6` exists upstream |
431+
| `_LIBCPP_ABI_NAMESPACE` | `__1` — upstream's own default, not a vendor-private namespace like the NDK's `__ndk1` |
432+
| `_LIBCPP_HAS_NO_STD_MODULES` | `/* #undef */` — Apple does **not** disable std modules, unlike the NDK |
433+
| `std.cppm` in the SDK | **0 files**, exactly as on Android and Emscripten |
434+
435+
So the recipe is the same recipe: take `libcxx/modules/` from the tag matching
436+
`_LIBCPP_VERSION`, perform the `@LIBCXX_MODULE_STD_INCLUDE_SOURCES@`
437+
substitution, and get 133 files and 620 KB — the same count and size the other
438+
two produce, and the same the vendor ships where it ships one at all.
439+
440+
Carried end to end, from a Linux host:
441+
442+
```
443+
$ clang++ --no-default-config --target=arm64-apple-ios18.0 -isysroot <sdk> \
444+
-nostdinc++ -isystem <sdk>/usr/include/c++/v1 -std=c++23 \
445+
--precompile surface/std.cppm -o std.pcm # 34 MB BMI
446+
$ clang++ ... -fmodule-file=std=std.pcm -c app.cpp # import std; OK
447+
$ clang++ ... -fuse-ld=lld app.o std.pcm -lc++ -o app
448+
$ file app
449+
app: Mach-O 64-bit arm64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|…|PIE>
450+
```
451+
452+
The binary was not executed — no device and no simulator on a Linux host — so
453+
this is "compiles and links", which is what the `preview` tier means.
454+
455+
**`--no-default-config` is load-bearing, and the reason generalises past iOS.**
456+
`xim:llvm`'s payload ships a `bin/clang++.cfg` that injects the host's glibc and
457+
libc++ unconditionally:
458+
459+
```
460+
-isystem <xim:llvm>/include/c++/v1
461+
-isystem <xim:glibc>/include
462+
-Wl,--dynamic-linker=<xim:glibc>/lib64/ld-linux-x86-64.so.2
463+
```
464+
465+
Those apply to **every** target the driver is pointed at, so a cross target that
466+
is not Linux/glibc silently gets the host's C and C++ standard library ahead of
467+
its own. `-nostdinc++` does not displace them — measured: with `-isysroot` and
468+
`-nostdinc++` both given, the search list still began with the host's
469+
`include/c++/v1` and the compile failed inside the host's `stdint.h` on
470+
`gnu/stubs-32.h`. The criterion is `clang -v`'s search list, not whether the
471+
compile succeeds, because a compile that reads the wrong standard library
472+
usually succeeds.
473+
474+
That is a property of the payload rather than of iOS, and it applies to any
475+
non-Linux target driven through it.
400476

401477
### What this means for xim-pkgindex
402478

@@ -574,14 +650,18 @@ answered it by adding a separate package whose `tests/` selects instead of
574650
discovering. This is unrelated to plugins and is noted because it is the second
575651
thing an ecosystem library hits.
576652

577-
**Apple was not measured, and its recipe may not exist.** Android and
578-
Emscripten were carried to a running or linking artifact; iOS cannot be
579-
measured on a Linux host, and 3.1 states the two possibilities rather than
580-
choosing one. The other two results are the argument for not guessing: every
581-
intermediate guess along the way was wrong — that the gap was one file (it is
582-
133), that a mismatched surface fails obscurely (it names the missing header),
583-
that the blocker was libc++ (it was bionic's `static inline` ctype), and that
584-
Emscripten's libc++ version follows its clang version (it does not).
653+
**Every guess along the way was wrong, including the ones this document made
654+
about Apple.** That the gap was one file (it is 133); that a mismatched surface
655+
fails obscurely (it names the missing header); that the blocker was libc++ (it
656+
was bionic's `static inline` ctype); that Emscripten's libc++ version follows
657+
its clang version (it does not); that iOS could not be measured from Linux (it
658+
can); that Apple's libc++ is not a public revision (it is, 210106); and that
659+
Xcode might already ship the surface (it does not, and the SDK carries none).
660+
661+
The pattern is worth naming rather than just recording: **each wrong guess was
662+
about what a vendor had done, and each was cheap to check and was not checked.**
663+
The section that guessed least — Emscripten, where the version was read rather
664+
than inferred — is the only one that needed no correction.
585665

586666
**Neither working recipe was carried to a released payload.** Both were built
587667
and exercised in a scratch directory. Turning each into an xim recipe — the

modules/toolchain-model/src/model.cppm

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -497,10 +497,15 @@ std::vector<std::string> graph_runtime_compile_flags(const Toolchain& tc) {
497497
// defect was invisible until a second architecture was built.
498498
if (t->arch == "aarch64") out.emplace_back("--rtlib=compiler-rt");
499499
if (t->is_pe()) out.emplace_back("-fdwarf-exceptions");
500-
if (t->is_pe() || t->os == "macos") out.emplace_back("-femulated-tls");
500+
// OBJECT FORMAT, NOT OS: `is_mach_o()` covers iOS along with macOS, which
501+
// `os == "macos"` used to miss. Both need the emulated-TLS model for the
502+
// same reason PE does -- `_tlv_bootstrap` is loader-bootstrapped there
503+
// exactly as `_tls_index` is on PE.
504+
if (t->is_pe() || t->is_mach_o()) out.emplace_back("-femulated-tls");
501505
// MACH-O ONLY, AND THE REASON IS THAT WEAK-DEF IS A RUN-TIME MECHANISM
502-
// THERE. See the note on this function for the measurement.
503-
if (t->os == "macos") {
506+
// THERE. See the note on this function for the measurement. `is_mach_o()`
507+
// rather than `os == "macos"`: the mechanism is ld64's, which iOS shares.
508+
if (t->is_mach_o()) {
504509
out.emplace_back("-fvisibility=hidden");
505510
out.emplace_back("-fvisibility-inlines-hidden");
506511
}
@@ -524,8 +529,11 @@ bool target_supports_full_static(std::string_view targetTriple, bool hostCapabil
524529
// false is what keeps the two mechanisms from both emitting the flag.
525530
if (t->is_pe()) return false;
526531

527-
// macOS cannot fully static-link: libSystem must stay dynamic.
528-
if (t->os == "macos") return false;
532+
// Mach-O cannot fully static-link: libSystem (macOS) / the Apple
533+
// equivalent (iOS) must stay dynamic. `is_mach_o()`, paired with `is_pe()`
534+
// above, so this reads as "for each object format" rather than leaving
535+
// iOS to fall through to the `linux` line below by accident.
536+
if (t->is_mach_o()) return false;
529537

530538
// Linux ELF — glibc or musl, native or cross. This is the line that was
531539
// previously gated on the HOST being Linux.

src/build/distribution.cppm

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,22 @@ enum class Format { Elf, MachO, Pe };
129129
Format format_for(std::string_view targetTriple, Format hostFallback) {
130130
if (auto parsed = mcpp::toolchain::triple::parse(targetTriple)) {
131131
if (parsed->is_pe()) return Format::Pe;
132-
if (parsed->os == "macos") return Format::MachO;
132+
// `is_mach_o()`, not `os == "macos"`: the latter answered the
133+
// opposite-hosts defect above for macOS and would still get iOS
134+
// wrong the same way, since iOS's `os` is `ios`.
135+
if (parsed->is_mach_o()) return Format::MachO;
133136
if (parsed->os == "linux"
134137
|| parsed->os == "none") return Format::Elf;
138+
// THIS `Format` HAS NO FOURTH MEMBER YET. A wasm32-emscripten
139+
// triple parses here and falls out of every branch above (`is_pe()`
140+
// and `is_mach_o()` are both false, and its `os` is `emscripten`,
141+
// neither `linux` nor `none`) to the substring fallback below, which
142+
// also does not name it, and then to `hostFallback` -- so today this
143+
// function still answers the machine's own format for wasm rather
144+
// than the target's, the same defect class its own header measured
145+
// for macOS. Adding `Format::Wasm` is deferred to whoever gives this
146+
// module a Mach-O-shaped mechanism for it (see `resolve`'s `switch`),
147+
// not attempted here.
135148
}
136149
if (targetTriple.find("windows") != std::string_view::npos
137150
|| targetTriple.find("mingw") != std::string_view::npos)

src/build/flags.cppm

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,40 @@ CompileFlags compute_flags(const BuildPlan& plan) {
691691
const auto linkIntentFlavor = [&] {
692692
if (isMingwTc) return LinkIntentFlavor::PeGnu;
693693
if (isMsvcDialect) return LinkIntentFlavor::PeMsvc;
694+
// THE OBJECT FORMAT IS ASKED OF THE PARSED TRIPLE, AND THE SUBSTRING
695+
// TEST BELOW IS NOW ONLY THE ESCAPE HATCH.
696+
//
697+
// `plan.toolchain.targetTriple` is mcpp's CANONICAL spelling, and
698+
// `aarch64-macos` contains neither "apple" nor "darwin" -- so an
699+
// explicit `--target aarch64-macos`, a verified row, fell through to
700+
// `Elf`. Only a NATIVE macOS build was right, and by a different
701+
// branch: an empty triple reaching the `needs_explicit_libcxx` rescue
702+
// below. That is why nothing caught it -- the two paths through this
703+
// function disagreed and only one of them was exercised.
704+
//
705+
// The substring test is kept for a triple `parse` REJECTS, which is
706+
// the `[target.<triple>]` escape hatch: an author may name a spelling
707+
// outside the canonical vocabulary, and it is then an LLVM-shaped
708+
// string where "apple" and "windows" do appear.
709+
if (auto t = mcpp::toolchain::triple::parse(plan.toolchain.targetTriple)) {
710+
switch (t->object_format()) {
711+
case mcpp::toolchain::triple::ObjectFormat::MachO:
712+
return LinkIntentFlavor::MachO;
713+
case mcpp::toolchain::triple::ObjectFormat::Pe:
714+
return LinkIntentFlavor::PeGnu;
715+
case mcpp::toolchain::triple::ObjectFormat::Wasm:
716+
// No `LinkIntentFlavor::Wasm` exists, and inventing one
717+
// here would be a link-contract decision rather than a
718+
// format question -- what `link_lib` and a search path
719+
// even mean for an Emscripten link is the open half of
720+
// #597. `Elf` is the wrong answer and is the one this
721+
// returns; it is named here so the gap is visible rather
722+
// than reached by falling off the end of a switch.
723+
return LinkIntentFlavor::Elf;
724+
case mcpp::toolchain::triple::ObjectFormat::Elf:
725+
return LinkIntentFlavor::Elf;
726+
}
727+
}
694728
auto triple = plan.toolchain.targetTriple;
695729
std::ranges::transform(triple, triple.begin(),
696730
[](unsigned char c) { return std::tolower(c); });

src/build/ninja_backend.cppm

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,18 @@ std::string pe_link_flag(const BuildPlan& plan, bool sep,
260260
std::string shared_soname_flag(const LinkUnit& lu, const BuildPlan& plan) {
261261
if (lu.kind != LinkUnit::SharedLibrary) return "";
262262
const auto t = mcpp::toolchain::triple::parse(plan.toolchain.targetTriple);
263-
const std::string os = t ? t->os
264-
: (mcpp::platform::is_macos ? "macos"
265-
: mcpp::platform::is_windows ? "windows" : "linux");
263+
// WHICH FLAG SPELLING, ASKED OF THE OBJECT FORMAT DIRECTLY rather than of
264+
// an `os` string: the prior `os == "macos"` fell through to the ELF
265+
// branch (`-Wl,-soname`, a GNU ld/BFD flag ld64 does not accept) for
266+
// iOS, whose `os` is `ios`.
267+
const bool pe = t ? t->is_pe() : bool(mcpp::platform::is_windows);
268+
const bool macho = t ? t->is_mach_o() : bool(mcpp::platform::is_macos);
266269
// PE records no such name: a DLL is found by the filename in the importing
267270
// module's import table, and there is nothing to override.
268-
if (os == "windows") return "";
271+
if (pe) return "";
269272
const std::string name = lu.soname.empty()
270273
? lu.output.filename().string() : lu.soname;
271-
if (os == "macos") return "-Wl,-install_name,@rpath/" + name;
274+
if (macho) return "-Wl,-install_name,@rpath/" + name;
272275
return lu.soname.empty() ? "" : "-Wl,-soname," + lu.soname;
273276
}
274277

@@ -291,7 +294,11 @@ std::string shared_soname_flag(const LinkUnit& lu, const BuildPlan& plan) {
291294
// script's syntax is not what the author wrote.
292295
std::string exports_file_contents(const LinkUnit& lu, std::string_view os) {
293296
std::string out;
294-
if (os == "macos") {
297+
// Which SYMBOL-TABLE SYNTAX, which is a property of the object format:
298+
// iOS links with the same ld64 and the same leading-underscore Mach-O
299+
// symbol table as macOS, so it takes this branch too rather than the
300+
// GNU version-script one below, which ld64 does not parse.
301+
if (os == "macos" || os == "ios") {
295302
// One symbol per line. Mach-O symbols carry a leading underscore that
296303
// the C++ source never writes, so it is added here -- the author names
297304
// the symbol, not the object format's spelling of it.
@@ -316,7 +323,10 @@ std::string exports_flag(const LinkUnit& lu, std::string_view os,
316323
const std::filesystem::path& file) {
317324
if (lu.kind != LinkUnit::SharedLibrary || lu.exportPatterns.empty()) return "";
318325
if (os == "windows") return "";
319-
if (os == "macos")
326+
// iOS alongside macOS, matching `exports_file_contents`: same linker,
327+
// same flag. Leaving it out sent an iOS shared-library link a GNU
328+
// `--version-script` for a Mach-O symbol list, which ld64 rejects.
329+
if (os == "macos" || os == "ios")
320330
return "-Wl,-exported_symbols_list," + file.generic_string();
321331
return "-Wl,--version-script=" + file.generic_string();
322332
}

src/build/plan.cppm

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,12 @@ std::vector<std::string> shared_library_link_flags(
555555
const mcpp::toolchain::triple::Triple& target) {
556556
std::vector<std::string> flags;
557557
const bool pe = n.sharedNeedsImportLib;
558+
// WHICH RPATH SYNTAX, ASKED OF THE OBJECT FORMAT. `target.os == "macos"`
559+
// used to answer this and missed iOS, which links with the same ld64 and
560+
// wants the same `@loader_path` -- `os == "ios"` would otherwise take the
561+
// ELF branch below and hand `$ORIGIN` to a linker that has no such token.
558562
const bool macho = target.empty() ? bool(mcpp::platform::is_macos)
559-
: target.os == "macos";
563+
: target.is_mach_o();
560564
if (pe) {
561565
flags.push_back(import_library_for(t, n).generic_string());
562566
} else {
@@ -810,9 +814,16 @@ std::vector<mcpp::platform::search::Dir> runtime_search_closure(
810814
auto t = mcpp::toolchain::triple::parse(plan.toolchain.targetTriple);
811815
return t ? *t : mcpp::toolchain::triple::Triple{};
812816
}();
817+
// `!= "macos" && != "windows"` READ AS "ELF" BY EXCLUSION, WHICH IS THE
818+
// ONE ANSWER THAT MUST NEVER BE REACHED BY EXCLUDING EVERYTHING ELSE:
819+
// iOS and wasm32-emscripten both satisfy that double negative (their `os`
820+
// is `ios` / `emscripten`, neither string), so this line called an iOS
821+
// Mach-O and a wasm module ELF and would have handed both a DT_RPATH
822+
// mechanism neither format has. Asked of `object_format()` directly, the
823+
// single derivation, instead.
813824
const bool elfTarget = triple.empty()
814825
? bool(mcpp::platform::is_linux)
815-
: (triple.os != "macos" && triple.os != "windows");
826+
: (triple.object_format() == mcpp::toolchain::triple::ObjectFormat::Elf);
816827

817828
// THE ARTIFACT'S OWN DIRECTORY — `$ORIGIN` (#415).
818829
//
@@ -1059,10 +1070,13 @@ make_plan(const mcpp::manifest::Manifest& manifest,
10591070

10601071
// The loader-tag contract exists only where DT_RPATH/DT_RUNPATH do.
10611072
// Mach-O and PE have neither, so they get no flag rather than a branch in
1062-
// every consumer.
1073+
// every consumer. Asked of `object_format()`: the exclusion form this
1074+
// used to be (`!= "macos" && != "windows"`) answers "ELF" for any `os` it
1075+
// does not name, which is wrong the same way for iOS and for
1076+
// wasm32-emscripten — see the sibling derivation earlier in this file.
10631077
const bool elfTarget = targetTriple.empty()
10641078
? bool(mcpp::platform::is_linux)
1065-
: (targetTriple.os != "macos" && targetTriple.os != "windows");
1079+
: (targetTriple.object_format() == mcpp::toolchain::triple::ObjectFormat::Elf);
10661080
auto loader_tag_flag = [&](LinkUnit::Kind kind) -> std::string {
10671081
if (!elfTarget) return {};
10681082
using mcpp::build::loader::Form;

0 commit comments

Comments
 (0)