Skip to content

Commit 200d5fe

Browse files
committed
feat(toolchain): one payload name, a payload that describes itself, and the SDK axis iOS needs
B1. WITHDRAW THE `ndk` ALIAS. It parsed and the capability gate then refused it, because that gate compares the declared spelling against the row's pin -- `android-ndk@30.0.16248370` -- and `ndk@30.0.16248370` does not contain it. So a name was good enough for the parser and not for the build, which reads as a defect rather than a naming choice. Withdrawn rather than completed: teaching the gate to normalise payload names would make two spellings work through a second mechanism, where one name keeps the comparison correct by construction. The name kept is the one the index uses. C1. `sdk_path(sdk)`. macOS located exactly one SDK because macOS was the only Apple target; the iOS rows need iPhoneOS and iPhoneSimulator, and the difference between the three is directory names. So it is a parameter over a table, not a second locator. Two pure pieces carry what can be wrong in it and are checked on any host: `sdk_layout` (the per-SDK directory names, and which a Command-Line-Tools install ships) and `sdkroot_answers` -- because `SDKROOT` names ONE SDK and there are now three questions. An override that names an SDK answers for that SDK alone; one that names none answers the default question only, which is what keeps today's three callers unchanged. C2. `.mcpp-toolchain.json`: A PAYLOAD DESCRIBES ITSELF. Three payload-specific facts lived in the engine -- the NDK's `toolchains/llvm/prebuilt/<host>/bin` layout, its API floor in `meta/platforms.json`, and the `-D__BIONIC_CTYPE_INLINE=` its libc++ module surface needs -- and each is a fact the installing recipe already computes for its own probes. The recipe now writes one file beside the payload and the engine reads it: `frontend`, `platform_floor`, `std_module_defines`. Three properties. Absence is compatibility: no descriptor means today's behaviour exactly, so a released payload keeps working and there is no flag day. Present and MALFORMED is refused naming the file -- otherwise a typo reads as "an older payload" and the engine uses a hardcoded path for a layout that has moved. And it is not a general flag channel: three keys, each answering a question the engine already asks, with `frontend` refused if it leaves the payload root and a define refused if it could begin an option. `payload_frontend` therefore returns `expected`, so no caller can express a malformed descriptor as "not found"; the eight call sites propagate it, and `toolchain list` and `doctor` report it rather than skipping the payload. D (partial). `ios_deployment_target` joins `macos_deployment_target` as the second Apple key: same single `minPlatformVersion` slot, different version space, since "14.0" is a macOS version and means nothing to an iOS SDK. The effective triple now carries it -- `arm64-apple-ios18.0` and `arm64-apple-ios18.0-simulator`, Apple's own spellings -- which is the one place that says it. `is_ios()` and `is_ios_simulator()` name the rows. A third copy of a false claim, corrected: `minApiLevel`'s comment still said an unset level "means the NDK's own default, which `clang -target aarch64-linux-android` normalises to". bionic refuses an unversioned triple. The two earlier copies were fixed in `min_platform_version` and `llvm_triple`; this one was written on another day and outlived both. THE FIFTH COPY OF THE TIER TABLE WAS IN A TEST. `aarch64-linux-android` became `verified`, the row and all four documents moved, `check_target_tiers.py` reported agreement -- and `test_toolchain_triple.cpp` went on asserting `preview`, because a literal in a test is in neither set. The test's tier claims are now one-line pairs and the checker reads it as a fifth document; removing the fix makes the checker fail, which is the only reason to add it. And a measurement, not yet a claim: ci-macos-ios.yml asks the runner what it actually provides -- both located SDKs, whether a simulator boots, whether `simctl spawn` takes a bare Mach-O, whether the SDK's libc++ or the payload's static archive links, and whether `import std` precompiles against the located SDK. The design record schedules the iOS rows on those answers; none of them can be reasoned out from a Linux desk.
1 parent 0995ea9 commit 200d5fe

23 files changed

Lines changed: 1205 additions & 90 deletions

.github/tools/check_target_tiers.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@
4040
ROOT / "docs/zh/21-the-target-triple.md",
4141
]
4242

43+
# THE FIFTH COPY WAS IN A TEST, AND A CHECK OVER DOCUMENTS CANNOT SEE IT.
44+
#
45+
# `aarch64-linux-android` became `verified`; the row moved, all four documents
46+
# moved, this script reported "OK: 29 target tiers agree across 4 documents"
47+
# -- and `test_toolchain_triple.cpp` went on asserting `preview`, because a
48+
# literal in a test is in neither set. It was caught by running the suite,
49+
# which is luck rather than a check.
50+
#
51+
# So the test file is a fifth document here. Its tier claims are written as
52+
# `std::pair{"<target>", "<tier>"}` for exactly this reason: one line carrying
53+
# both halves is a shape this script can read, and the alternative -- a target
54+
# named on one line and its tier asserted three lines below -- is not.
55+
tests = [
56+
ROOT / "tests/unit/test_toolchain_triple.cpp",
57+
]
58+
4359
fail = False
4460
for doc in docs:
4561
if not doc.exists():
@@ -75,6 +91,37 @@
7591
fail = True
7692
print(f" {doc.relative_to(ROOT)}: {len(seen)} of {len(rows)} rows")
7793

94+
# The test file, by the one-line rule described above. Unlike a document it is
95+
# not required to name every row: a test states the claims it has evidence for,
96+
# and a row with no assertion is not a row asserted wrongly. What IS required
97+
# is that every claim it does make agrees.
98+
for t in tests:
99+
if not t.exists():
100+
print(f"ERROR: {t.relative_to(ROOT)} is missing")
101+
fail = True
102+
continue
103+
claimed = {}
104+
for line in t.read_text().splitlines():
105+
lits = re.findall(r'"([A-Za-z0-9_.+-]+)"', line)
106+
tier = next((l for l in lits if l in TIERS), None)
107+
if tier is None:
108+
continue
109+
for name in lits:
110+
if name in rows:
111+
claimed[name] = tier
112+
if not claimed:
113+
print(f"ERROR: {t.relative_to(ROOT)} is listed here but claims no "
114+
f"tier; either its assertions changed shape or this list is stale")
115+
fail = True
116+
continue
117+
for name, tier in sorted(claimed.items()):
118+
if rows[name] != tier:
119+
print(f"ERROR: {t.relative_to(ROOT)}: {name} asserted as "
120+
f"'{tier}', the table says '{rows[name]}'")
121+
fail = True
122+
print(f" {t.relative_to(ROOT)}: {len(claimed)} row(s) claimed")
123+
78124
if fail:
79125
sys.exit(1)
80-
print(f"OK: {len(rows)} target tiers agree across {len(docs)} documents")
126+
print(f"OK: {len(rows)} target tiers agree across {len(docs)} documents "
127+
f"and {len(tests)} test file(s)")

.github/workflows/ci-macos-ios.yml

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
name: ci-macos-ios
2+
3+
# The iOS rows, measured on the only machine that can answer for them.
4+
#
5+
# iOS needs an ecosystem compiler and a LOCATED SDK: `xim:llvm` emits arm64
6+
# Mach-O for an iOS deployment target, and only the machine's Xcode can supply
7+
# the iPhoneOS / iPhoneSimulator headers and stub libraries, which are not
8+
# redistributable. The simulator runtime is the same category. So every claim
9+
# about these three rows is a claim about a macOS runner, and this job is where
10+
# they are made.
11+
#
12+
# Kept out of ci-macos.yml deliberately: that job asserts mcpp's default quiet
13+
# output shape and tacking a differently-shaped leg onto it has broken that
14+
# assertion before.
15+
16+
on:
17+
push:
18+
branches: [ main ]
19+
pull_request:
20+
branches: [ main ]
21+
workflow_dispatch:
22+
23+
concurrency:
24+
group: ci-macos-ios-${{ github.ref }}
25+
cancel-in-progress: true
26+
27+
jobs:
28+
ios-host-surface:
29+
name: iOS - what this runner actually provides
30+
runs-on: macos-15
31+
timeout-minutes: 30
32+
steps:
33+
- uses: actions/checkout@v4
34+
- uses: ./.github/actions/setup-macos-llvm
35+
36+
# THE PREMISE, STATED AND THEN MEASURED. The design record schedules the
37+
# iOS rows on one assumption: that a GitHub macOS runner ships both an
38+
# iOS SDK and a bootable simulator. If it ships the SDK but no simulator,
39+
# the device row is still verifiable here and the two simulator rows
40+
# become a local-only claim -- which changes the tier they can reach and
41+
# nothing else. This step is the difference between those two worlds.
42+
- name: "Host surface: the two located SDKs and the simulator runtime"
43+
run: |
44+
set -x
45+
xcode-select -p
46+
xcrun --sdk iphoneos --show-sdk-path
47+
xcrun --sdk iphoneos --show-sdk-version
48+
xcrun --sdk iphonesimulator --show-sdk-path
49+
xcrun --sdk iphonesimulator --show-sdk-version
50+
set +x
51+
echo "--- runtimes ---"
52+
xcrun simctl list runtimes
53+
echo "--- devices available ---"
54+
xcrun simctl list devices available
55+
56+
# WHETHER A BARE MACH-O CAN BE RUN AT ALL, which decides how much the
57+
# runner program has to do. `simctl launch` needs an installed .app
58+
# bundle; `simctl spawn` takes an executable. If spawn works, the
59+
# `simctl-run` program is a boot-and-spawn wrapper; if it does not, it
60+
# has to synthesise a bundle, sign it and install it. Measuring this is
61+
# cheaper than designing for the harder case.
62+
- name: "Device: is one bootable, and does spawn take a bare executable"
63+
run: |
64+
set -uo pipefail
65+
UDID=$(xcrun simctl list devices available \
66+
| grep -A50 -- '-- iOS' \
67+
| grep -m1 -oE '[0-9A-F]{8}-[0-9A-F-]{27}' || true)
68+
echo "udid=[$UDID]"
69+
if [ -z "$UDID" ]; then
70+
echo "NO-IOS-SIMULATOR-DEVICE"
71+
exit 0
72+
fi
73+
xcrun simctl boot "$UDID" || true
74+
xcrun simctl bootstatus "$UDID" -b || true
75+
cat > /tmp/hello.cpp << 'CPP'
76+
#include <cstdio>
77+
int main() { std::puts("1-2-3"); return 0; }
78+
CPP
79+
SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
80+
"$LLVM_ROOT/bin/clang++" -std=c++23 \
81+
-target arm64-apple-ios18.0-simulator \
82+
-isysroot "$SDK" -o /tmp/hello /tmp/hello.cpp
83+
file /tmp/hello
84+
otool -l /tmp/hello | grep -A5 LC_BUILD_VERSION || true
85+
echo "--- simctl spawn on a bare Mach-O ---"
86+
if xcrun simctl spawn "$UDID" /tmp/hello; then
87+
echo "SPAWN-OK"
88+
else
89+
echo "SPAWN-FAILED exit=$?"
90+
fi
91+
92+
# THE DEVICE ROW'S ARTEFACT. Nothing runs it here -- that needs a
93+
# signature the developer owns -- so the claim is about the ARTEFACT:
94+
# arm64 Mach-O naming the iOS platform in LC_BUILD_VERSION. An artefact
95+
# that says MACOS there is the failure this leg exists to catch, and it
96+
# is invisible to a build that merely succeeds.
97+
- name: "Device: the artefact names the iOS platform"
98+
run: |
99+
set -euo pipefail
100+
cat > /tmp/dev.cpp << 'CPP'
101+
#include <cstdio>
102+
int main() { std::puts("1-2-3"); return 0; }
103+
CPP
104+
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
105+
"$LLVM_ROOT/bin/clang++" -std=c++23 -target arm64-apple-ios18.0 \
106+
-isysroot "$SDK" -o /tmp/dev /tmp/dev.cpp
107+
file /tmp/dev
108+
otool -l /tmp/dev | grep -A5 LC_BUILD_VERSION
109+
110+
# THE C++ RUNTIME QUESTION, WHICH IS THE ONE THAT CAN SINK THIS. macOS
111+
# links the PAYLOAD's static libc++ so that mcpp's deployment floor is
112+
# real. That archive is built for macOS, and ld64 refuses an object built
113+
# for one platform in a link for another -- so iOS may have to take
114+
# libc++ from the SDK instead. Both are tried here, because "which one
115+
# works" is the fact the flag builder needs and neither answer can be
116+
# reasoned out from a Linux desk.
117+
- name: "C++ runtime: SDK libc++ versus the payload static archive"
118+
run: |
119+
set -x
120+
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
121+
cat > /tmp/cxx.cpp << 'CPP'
122+
#include <string>
123+
#include <cstdio>
124+
int main() { std::string s = "1-2-3"; std::puts(s.c_str()); return 0; }
125+
CPP
126+
echo "--- (a) SDK libc++, dynamic ---"
127+
if "$LLVM_ROOT/bin/clang++" -std=c++23 -target arm64-apple-ios18.0 \
128+
-isysroot "$SDK" -o /tmp/cxx-sdk /tmp/cxx.cpp; then
129+
otool -L /tmp/cxx-sdk
130+
echo "SDK-LIBCXX-OK"
131+
else
132+
echo "SDK-LIBCXX-FAILED"
133+
fi
134+
echo "--- (b) payload static libc++ ---"
135+
if "$LLVM_ROOT/bin/clang++" -std=c++23 -target arm64-apple-ios18.0 \
136+
-isysroot "$SDK" -nostdlib++ \
137+
"$LLVM_ROOT/lib/libc++.a" "$LLVM_ROOT/lib/libc++abi.a" \
138+
-o /tmp/cxx-static /tmp/cxx.cpp; then
139+
echo "PAYLOAD-STATIC-OK"
140+
else
141+
echo "PAYLOAD-STATIC-FAILED"
142+
fi
143+
set +x
144+
145+
# `import std` FOR iOS, which is mcpp's default and therefore the real
146+
# bar. The module is precompiled from the PAYLOAD's libc++ headers
147+
# against the LOCATED SDK's C library -- the same split macOS already
148+
# uses, with a second SDK. If this cannot be made to work the iOS rows
149+
# are a non-module tier and the documentation has to say so.
150+
- name: "import std: precompile against the located SDK"
151+
run: |
152+
set -x
153+
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
154+
STD_CPPM=$(find "$LLVM_ROOT" -name 'std.cppm' | head -1)
155+
echo "std.cppm=$STD_CPPM"
156+
MODDIR=$(dirname "$STD_CPPM")
157+
if "$LLVM_ROOT/bin/clang++" -std=c++23 -target arm64-apple-ios18.0 \
158+
-isysroot "$SDK" -Wno-reserved-module-identifier \
159+
-Xclang -emit-reduced-module-interface \
160+
--precompile -o /tmp/std.pcm "$STD_CPPM" -I"$MODDIR"; then
161+
echo "PRECOMPILE-OK"
162+
else
163+
echo "PRECOMPILE-FAILED"
164+
fi
165+
cat > /tmp/mod.cpp << 'CPP'
166+
import std;
167+
int main() { std::println("1-2-3"); return 0; }
168+
CPP
169+
if "$LLVM_ROOT/bin/clang++" -std=c++23 -target arm64-apple-ios18.0 \
170+
-isysroot "$SDK" -fmodule-file=std=/tmp/std.pcm \
171+
-o /tmp/mod /tmp/mod.cpp /tmp/std.pcm; then
172+
echo "MODULE-LINK-OK"
173+
else
174+
echo "MODULE-LINK-FAILED"
175+
fi
176+
file /tmp/mod || true
177+
set +x

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ list` reports for this machine):
421421
| `riscv64-linux-musl` · `aarch64-linux-gnu` · `x86_64-macos` || planned |
422422
| `wasm32-emscripten` | `emsdk@6.0.9` — Emscripten ships its own sysroot and its own libc++ module surface; `mcpp run` executes the module with `node` | verified |
423423
| `x86_64-linux-android` | `android-ndk@30.0.16248370` — bionic from the NDK, one payload for both ABIs; ran on an API 24 x86_64 emulator image | verified |
424-
| `aarch64-linux-android` | the same payload and the same build; no execution path from an x86_64 host, because Google's emulator refuses a foreign guest | preview |
424+
| `aarch64-linux-android` | the same payload and the same build; ran under qemu-user over the system image's own bionic, which the platform emulator cannot do from an x86_64 host | verified |
425425
| `aarch64-ios` · `aarch64-ios-sim` · `x86_64-ios-sim` | the iPhoneOS and iPhoneSimulator SDKs ship inside Xcode and are not redistributable, so the blocker is a licence rather than a payload | planned |
426426

427427
`verified` an image has been built **and run** for the row, qemu and wine

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ mcpp 的身份模型是两条正交轴:**工具链** = `family@version`(family
408408
| `riscv64-linux-musl` · `aarch64-linux-gnu` · `x86_64-macos` || planned |
409409
| `wasm32-emscripten` | `emsdk@6.0.9` —— Emscripten 自带 sysroot 和它自己的 libc++ 模块面;`mcpp run``node` 把模块跑起来 | verified |
410410
| `x86_64-linux-android` | `android-ndk@30.0.16248370` —— bionic 来自 NDK,一个载荷服务两个 ABI;在 API 24 的 x86_64 模拟器镜像上跑过 | verified |
411-
| `aarch64-linux-android` | 同一个载荷、同样的构建;从 x86_64 宿主没有执行路径,因为 Google 的模拟器直接拒绝异构 guest | preview |
411+
| `aarch64-linux-android` | 同一个载荷、同样的构建;在 qemu-user 上、配系统镜像自带的 bionic 跑过 —— 这是平台模拟器从 x86_64 宿主做不到的 | verified |
412412
| `aarch64-ios` · `aarch64-ios-sim` · `x86_64-ios-sim` | iPhoneOS 与 iPhoneSimulator 的 SDK 在 Xcode 里且不可再分发,所以阻塞项是许可而不是载荷 | planned |
413413

414414
`verified` 该行的镜像已被构建**并运行**过,qemu 与 wine 都算 · `preview` 可构建

docs/21-the-target-triple.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ other's rows.
485485
| `thumbv8m.main-none-eabihf` | preview | `llvm@22.1.8` | payload | payload | payload | payload |
486486
| `armv7a-none-eabi` | verified | `llvm@22.1.8` | payload | payload | payload | payload |
487487
| `armv7a-none-eabihf` | verified | `llvm@22.1.8` | payload | payload | payload | payload |
488-
| `aarch64-linux-android` | preview | `android-ndk@30.0.16248370` | payload | payload | payload ||
488+
| `aarch64-linux-android` | verified | `android-ndk@30.0.16248370` | payload | payload | payload ||
489489
| `x86_64-linux-android` | verified | `android-ndk@30.0.16248370` | payload | payload | payload ||
490490
| `aarch64-ios` | planned || planned | planned | planned | planned |
491491
| `aarch64-ios-sim` | planned || planned | planned | planned | planned |
@@ -526,12 +526,12 @@ constant stating it here is what the wasm row's own history shows going stale.
526526
A Windows user therefore sees the row, the pin resolves, and xim refuses with
527527
`no payload for this platform` before anything is fetched, naming the package.
528528

529-
**The two Android rows differ in tier because one of them was run.** An
530-
x86_64 Android artefact executes on the platform's own emulator, and a
531-
`verified` row means exactly that was done. The device row builds identically
532-
and has no execution path from an x86_64 host: the emulator refuses a foreign
533-
guest (`QEMU2 emulator does not support arm64 CPU architecture`), so it needs
534-
an arm64 host or the qemu-user route.
529+
**Both Android rows are `verified`, by different vehicles.** An x86_64
530+
artefact executes on the platform's own emulator. The device row's artefact runs
531+
under qemu-user over the system image's own bionic, which is the route that
532+
works from an x86_64 host -- the platform emulator refuses a foreign guest
533+
(`QEMU2 emulator does not support arm64 CPU architecture`). A tier states that
534+
an artefact was built and RUN; it does not state which emulator ran it.
535535

536536
### And CI measures every one of them
537537

docs/zh/21-the-target-triple.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ CRT;图供给时是 `musl`。一个目标字符串,两个不同的 C 库 ——
435435
| `thumbv8m.main-none-eabihf` | preview | `llvm@22.1.8` | 载荷 | 载荷 | 载荷 | 载荷 |
436436
| `armv7a-none-eabi` | verified | `llvm@22.1.8` | 载荷 | 载荷 | 载荷 | 载荷 |
437437
| `armv7a-none-eabihf` | verified | `llvm@22.1.8` | 载荷 | 载荷 | 载荷 | 载荷 |
438-
| `aarch64-linux-android` | preview | `android-ndk@30.0.16248370` | payload | payload | payload ||
438+
| `aarch64-linux-android` | verified | `android-ndk@30.0.16248370` | payload | payload | payload ||
439439
| `x86_64-linux-android` | verified | `android-ndk@30.0.16248370` | payload | payload | payload ||
440440
| `aarch64-ios` | planned || planned | planned | planned | planned |
441441
| `aarch64-ios-sim` | planned || planned | planned | planned | planned |
@@ -472,11 +472,11 @@ CRT;图供给时是 `musl`。一个目标字符串,两个不同的 C 库 ——
472472
一行自己的历史所展示的会变陈旧的东西。因此 Windows 用户会看到这一行、钉能解析,
473473
而 xim 在任何东西被下载之前以 `no payload for this platform` 拒绝,并点名那个包。
474474

475-
**两个 Android 行层级不同,是因为其中一个被运行过** 一个 x86_64 的 Android 产物
476-
在平台自己的模拟器上执行得起来,而 `verified` 这个层级断言的正是「做过这件事」。
477-
真机那一行构建方式完全相同,而从一台 x86_64 宿主没有执行路径:模拟器直接拒绝异构
478-
guest(`QEMU2 emulator does not support arm64 CPU architecture`),所以它需要一台
479-
arm64 宿主,或者 qemu-user 那条路
475+
**两个 Android 行都是 `verified`,而载具不同** x86_64 的产物在平台自己的模拟器上
476+
执行。真机那一行的产物在 qemu-user 上、配系统镜像自带的 bionic 跑起来 —— 这是从一台
477+
x86_64 宿主行得通的路线,而平台模拟器会直接拒绝异构 guest
478+
(`QEMU2 emulator does not support arm64 CPU architecture`)。一个层级断言的是产物
479+
被构建**并运行**过,它不断言是哪个模拟器运行的
480480

481481
### 而 CI 把每一台都测了
482482

mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcpp"
3-
version = "2026.9.11.3"
3+
version = "2026.9.11.4"
44
description = "Modern C++ build & package management tool"
55
license = "Apache-2.0"
66
authors = ["mcpp-community"]

modules/manifest/src/toml.cppm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,6 +1936,8 @@ std::expected<Manifest, ManifestError> parse_string(std::string_view content,
19361936
"and a SubOS's by that SubOS."));
19371937
if (auto v = doc->get_string("build.macos_deployment_target"))
19381938
m.buildConfig.macosDeploymentTarget = *v;
1939+
if (auto v = doc->get_string("build.ios_deployment_target"))
1940+
m.buildConfig.iosDeploymentTarget = *v;
19391941

19401942
// Surface unsupported [build] keys instead of silently dropping them.
19411943
// #296 is #131's footgun one section over: `[build] defines` on an mcpp
@@ -1953,6 +1955,7 @@ std::expected<Manifest, ManifestError> parse_string(std::string_view content,
19531955
"dependency_linkage",
19541956
"dialect_cxxflags", "flags", "include_dirs", "include_dirs_after",
19551957
"private_include_dirs",
1958+
"ios_deployment_target",
19561959
"jobs", "ldflags", "macos_deployment_target", "module_extensions", "profile",
19571960
"sources", "static_stdlib", "target",
19581961
// #540: read a few hundred lines above and, until now, absent here —
@@ -3028,6 +3031,8 @@ std::expected<Manifest, ManifestError> parse_string(std::string_view content,
30283031
b.dependencyLinkage = *v;
30293032
if (auto v = doc->get_string("workspace.build.macos_deployment_target"))
30303033
b.macosDeploymentTarget = *v;
3034+
if (auto v = doc->get_string("workspace.build.ios_deployment_target"))
3035+
b.iosDeploymentTarget = *v;
30313036
static constexpr std::string_view kKnown[] = {
30323037
"cflags", "cxxflags", "ldflags", "defines", "dialect_cxxflags",
30333038
"include_dirs", "include_dirs_after", "private_include_dirs",

0 commit comments

Comments
 (0)