Skip to content

Commit bf455d1

Browse files
authored
Merge pull request #49 from mcpp-community/release/v0.0.17
release: v0.0.17 — macOS self-host via xlings
2 parents a6cd836 + 2b8f674 commit bf455d1

13 files changed

Lines changed: 174 additions & 62 deletions

.github/workflows/ci-macos.yml

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ jobs:
3333
uses: actions/cache@v4
3434
with:
3535
path: ~/.xlings
36-
key: xlings-macos15-arm64-${{ hashFiles('.xlings.json') }}
36+
key: xlings-macos15-arm64-v3-${{ hashFiles('.xlings.json') }}
3737
restore-keys: |
38-
xlings-macos15-arm64-
38+
xlings-macos15-arm64-v3-
3939
4040
- name: Bootstrap xlings
4141
env:
@@ -268,23 +268,50 @@ jobs:
268268
*) echo "FAIL: unexpected platform"; exit 1 ;;
269269
esac
270270
271-
- name: Install xmake (for bootstrap)
271+
- name: Bootstrap mcpp via xlings
272272
run: |
273-
brew install xmake
274-
xmake --version
273+
# Same pattern as Linux CI: xlings install mcpp
274+
xlings install mcpp -y
275+
MCPP="$HOME/.xlings/subos/default/bin/mcpp"
276+
test -x "$MCPP"
277+
"$MCPP" --version
278+
echo "MCPP=$MCPP" >> "$GITHUB_ENV"
279+
echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV"
280+
281+
- name: Build mcpp from source (self-host)
282+
run: |
283+
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
284+
"$MCPP" build
275285
276-
- name: Bootstrap mcpp from source (xmake)
286+
- name: Unit + integration tests via `mcpp test`
277287
run: |
278-
export LLVM_ROOT="$LLVM_ROOT"
279-
bash scripts/bootstrap-macos.sh "$LLVM_ROOT"
280-
./target/bootstrap/bin/mcpp --version
288+
# Use freshly-built mcpp (has --mirror support)
289+
MCPP=$(find target -path "*/bin/mcpp" | head -1)
290+
MCPP=$(cd "$(dirname "$MCPP")" && pwd)/$(basename "$MCPP")
291+
"$MCPP" self config --mirror GLOBAL
292+
"$MCPP" test
281293
282-
- name: Self-host (mcpp builds mcpp)
294+
- name: E2E suite
295+
run: |
296+
MCPP=$(find target -path "*/bin/mcpp" | head -1)
297+
MCPP=$(cd "$(dirname "$MCPP")" && pwd)/$(basename "$MCPP")
298+
test -x "$MCPP"
299+
export MCPP
300+
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
301+
test -x "$MCPP_VENDORED_XLINGS"
302+
export MCPP_E2E_TOOLCHAIN_MIRROR=GLOBAL
303+
"$MCPP" self config --mirror "$MCPP_E2E_TOOLCHAIN_MIRROR"
304+
"$MCPP" self config
305+
# macOS default toolchain is LLVM
306+
"$MCPP" toolchain default llvm@20.1.7
307+
bash tests/e2e/run_all.sh
308+
309+
- name: Self-host smoke (freshly-built mcpp builds itself again)
283310
run: |
284-
# Put bootstrapped mcpp on PATH so build.ninja can find it for dyndep
285-
export PATH="$PWD/target/bootstrap/bin:$PATH"
286-
mcpp build
287-
SELFHOST=$(find target -path "*/bin/mcpp" -not -path "*/bootstrap/*" -not -path "*/build/*" | head -1)
288-
test -x "$SELFHOST"
289-
"$SELFHOST" --version
290-
echo ":: Self-host successful!"
311+
MCPP=$(find target -path "*/bin/mcpp" | head -1)
312+
MCPP=$(cd "$(dirname "$MCPP")" && pwd)/$(basename "$MCPP")
313+
test -x "$MCPP"
314+
export PATH="$(dirname "$MCPP"):$PATH"
315+
"$MCPP" build
316+
"$MCPP" --version
317+
echo ":: Self-host smoke PASS"

.github/workflows/ci.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ jobs:
4949
uses: actions/cache@v4
5050
with:
5151
path: ~/.xlings
52-
key: xlings-${{ runner.os }}-${{ hashFiles('.xlings.json') }}
52+
key: xlings-${{ runner.os }}-v2-${{ hashFiles('.xlings.json') }}
5353
restore-keys: |
54-
xlings-${{ runner.os }}-
54+
xlings-${{ runner.os }}-v2-
5555
5656
- name: Bootstrap mcpp via xlings
5757
env:
@@ -88,13 +88,20 @@ jobs:
8888
restore-keys: |
8989
mcpp-target-${{ runner.os }}-
9090
91-
- name: Build mcpp from source (self-host)
91+
- name: Configure mirror + Build mcpp from source (self-host)
9292
run: |
93+
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
94+
# Set GLOBAL mirror via xlings directly (bootstrap mcpp may lack --mirror flag)
95+
"$XLINGS_BIN" config --mirror GLOBAL 2>/dev/null || true
96+
"$MCPP" self config --mirror GLOBAL 2>/dev/null || true
9397
"$MCPP" build
9498
9599
- name: Unit + integration tests via `mcpp test`
96100
run: |
97-
"$MCPP" test
101+
# Use freshly-built mcpp for test (it has --mirror support)
102+
MCPP_FRESH=$(realpath "$(find target -type f -name mcpp -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2)")
103+
"$MCPP_FRESH" self config --mirror GLOBAL
104+
"$MCPP_FRESH" test
98105
99106
- name: E2E suite
100107
run: |

.github/workflows/release.yml

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ jobs:
295295
xlings-macos15-release-
296296
xlings-macos15-arm64-
297297
298-
- name: Bootstrap xlings + LLVM
298+
- name: Bootstrap mcpp via xlings
299299
env:
300300
XLINGS_NON_INTERACTIVE: '1'
301301
XLINGS_VERSION: '0.4.30'
@@ -310,42 +310,37 @@ jobs:
310310
fi
311311
export PATH="$HOME/.xlings/subos/default/bin:$PATH"
312312
xlings --version
313-
# Install LLVM
314-
xlings install llvm -y || xlings install llvm@20.1.7 -y
315-
LLVM_ROOT=$(find "$HOME/.xlings" -path "*/xpkgs/xim-x-llvm/*/bin/clang++" | head -1 | xargs dirname | xargs dirname)
316-
echo "LLVM_ROOT=$LLVM_ROOT" >> "$GITHUB_ENV"
317-
318-
- name: Install xmake (for bootstrap)
319-
run: brew install xmake
320-
321-
- name: Bootstrap-compile mcpp (xmake + LLVM)
322-
run: |
323-
export LLVM_ROOT="$LLVM_ROOT"
324-
bash scripts/bootstrap-macos.sh "$LLVM_ROOT"
325-
./target/bootstrap/bin/mcpp --version
313+
xlings install mcpp -y
314+
MCPP="$HOME/.xlings/subos/default/bin/mcpp"
315+
test -x "$MCPP"
316+
"$MCPP" --version
317+
echo "MCPP=$MCPP" >> "$GITHUB_ENV"
318+
echo "XLINGS_BIN=$HOME/.xlings/subos/default/bin/xlings" >> "$GITHUB_ENV"
326319
327-
- name: Self-host rebuild (mcpp builds mcpp)
320+
- name: Build mcpp from source (self-host)
328321
run: |
329-
# Put bootstrapped mcpp on PATH so build.ninja can find it for dyndep
330-
export PATH="$PWD/target/bootstrap/bin:$PATH"
331-
mcpp build
332-
# Find the self-hosted binary
333-
SELFHOST=$(find target -path "*/bin/mcpp" -not -path "*/bootstrap/*" -not -path "*/build/*" | head -1)
334-
test -x "$SELFHOST"
335-
"$SELFHOST" --version
336-
echo "SELFHOST=$SELFHOST" >> "$GITHUB_ENV"
322+
export PATH="$HOME/.xlings/subos/default/bin:$PATH"
323+
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
324+
"$MCPP" build
325+
MCPP_BIN=$(find target -path "*/bin/mcpp" | head -1)
326+
MCPP_BIN=$(cd "$(dirname "$MCPP_BIN")" && pwd)/$(basename "$MCPP_BIN")
327+
test -x "$MCPP_BIN"
328+
file "$MCPP_BIN"
329+
otool -L "$MCPP_BIN"
330+
"$MCPP_BIN" --version
331+
echo "MCPP_BIN=$MCPP_BIN" >> "$GITHUB_ENV"
337332
338333
- name: Package macOS release
339334
id: stage
340335
run: |
341336
VERSION="${{ steps.resolve.outputs.version }}"
342-
TARBALL_NAME="mcpp-${VERSION}-darwin-arm64.tar.gz"
343-
WRAPPER="mcpp-${VERSION}-darwin-arm64"
337+
TARBALL_NAME="mcpp-${VERSION}-macosx-arm64.tar.gz"
338+
WRAPPER="mcpp-${VERSION}-macosx-arm64"
344339
345340
# Create release layout
346341
STAGING=$(mktemp -d)
347342
mkdir -p "$STAGING/$WRAPPER/bin"
348-
cp "$SELFHOST" "$STAGING/$WRAPPER/bin/mcpp"
343+
cp "$MCPP_BIN" "$STAGING/$WRAPPER/bin/mcpp"
349344
# Strip (Mach-O)
350345
strip "$STAGING/$WRAPPER/bin/mcpp" 2>/dev/null || true
351346
# Copy metadata
@@ -371,10 +366,10 @@ jobs:
371366
mkdir -p dist
372367
(cd "$STAGING" && tar -czf "$GITHUB_WORKSPACE/dist/${TARBALL_NAME}" "$WRAPPER")
373368
# Versionless alias
374-
cp "dist/${TARBALL_NAME}" "dist/mcpp-darwin-arm64.tar.gz"
369+
cp "dist/${TARBALL_NAME}" "dist/mcpp-macosx-arm64.tar.gz"
375370
# SHA256
376371
(cd dist && shasum -a 256 "${TARBALL_NAME}" > "${TARBALL_NAME}.sha256")
377-
(cd dist && shasum -a 256 "mcpp-darwin-arm64.tar.gz" > "mcpp-darwin-arm64.tar.gz.sha256")
372+
(cd dist && shasum -a 256 "mcpp-macosx-arm64.tar.gz" > "mcpp-macosx-arm64.tar.gz.sha256")
378373
379374
echo "tarball=${TARBALL_NAME}" >> "$GITHUB_OUTPUT"
380375
ls -la dist/
@@ -394,7 +389,7 @@ jobs:
394389
with:
395390
tag_name: ${{ steps.resolve.outputs.tag }}
396391
files: |
397-
dist/mcpp-${{ steps.resolve.outputs.version }}-darwin-arm64.tar.gz
398-
dist/mcpp-${{ steps.resolve.outputs.version }}-darwin-arm64.tar.gz.sha256
399-
dist/mcpp-darwin-arm64.tar.gz
400-
dist/mcpp-darwin-arm64.tar.gz.sha256
392+
dist/mcpp-${{ steps.resolve.outputs.version }}-macosx-arm64.tar.gz
393+
dist/mcpp-${{ steps.resolve.outputs.version }}-macosx-arm64.tar.gz.sha256
394+
dist/mcpp-macosx-arm64.tar.gz
395+
dist/mcpp-macosx-arm64.tar.gz.sha256

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 = "0.0.16"
3+
version = "0.0.17"
44
description = "Modern C++ build & package management tool"
55
license = "Apache-2.0"
66
authors = ["mcpp-community"]

src/build/flags.cppm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,22 @@ CompileFlags compute_flags(const BuildPlan& plan) {
161161
runtime_dirs += " -L" + escape_path(dir);
162162
runtime_dirs += " -Wl,-rpath," + escape_path(dir);
163163
}
164+
165+
#if defined(__APPLE__)
166+
// macOS linking strategy:
167+
// - No --sysroot: SDK .tbd stubs miss libc++abi exports.
168+
// - No -L<llvm>/lib: xlings LLVM's libc++.dylib doesn't pull in
169+
// libc++abi. System /usr/lib/libc++ does (and is ABI-compatible
170+
// with LLVM 20 headers since macOS ships a recent libc++).
171+
// - No -rpath for LLVM lib: binary should use system libc++ at runtime.
172+
// - Explicit -lc++: clang++.cfg's -nostdinc++ suppresses implicit linkage.
173+
// Result: compile with LLVM headers, link with system libc++ + libc++abi.
174+
f.ld = std::format("{}{}{} -lc++", full_static, static_stdlib, b_flag);
175+
#else
176+
// Linux: sysroot + runtime dirs needed (glibc/libc++ live in sandbox)
164177
f.ld = std::format("{}{}{}{}{}", full_static, static_stdlib, sysroot_flag, b_flag,
165178
runtime_dirs);
179+
#endif
166180

167181
return f;
168182
}

src/build/ninja_backend.cppm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
module;
1515
#include <cstdio>
1616
#include <cstdlib>
17+
#if defined(__APPLE__)
18+
#include <mach-o/dyld.h> // _NSGetExecutablePath
19+
#endif
1720

1821
export module mcpp.build.ninja;
1922

@@ -113,9 +116,19 @@ bool dyndep_mode_enabled() {
113116

114117
std::filesystem::path mcpp_exe_path() {
115118
std::error_code ec;
119+
#if defined(__APPLE__)
120+
// macOS: use _NSGetExecutablePath
121+
char buf[4096];
122+
uint32_t size = sizeof(buf);
123+
if (_NSGetExecutablePath(buf, &size) == 0) {
124+
auto p = std::filesystem::canonical(buf, ec);
125+
if (!ec) return p;
126+
}
127+
#else
116128
auto p = std::filesystem::read_symlink("/proc/self/exe", ec);
117129
if (!ec)
118130
return p;
131+
#endif
119132
return "mcpp"; // fall back to PATH lookup
120133
}
121134

src/config.cppm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
module;
1717
#include <cstdio>
1818
#include <cstdlib>
19+
#if defined(__APPLE__)
20+
#include <mach-o/dyld.h> // _NSGetExecutablePath
21+
#endif
1922

2023
export module mcpp.config;
2124

@@ -161,7 +164,15 @@ std::filesystem::path home_dir() {
161164
return std::filesystem::path(e);
162165

163166
std::error_code ec;
167+
#if defined(__APPLE__)
168+
char _exe_buf[4096];
169+
uint32_t _exe_size = sizeof(_exe_buf);
170+
std::filesystem::path exe;
171+
if (_NSGetExecutablePath(_exe_buf, &_exe_size) == 0)
172+
exe = std::filesystem::canonical(_exe_buf, ec);
173+
#else
164174
auto exe = std::filesystem::canonical("/proc/self/exe", ec);
175+
#endif
165176
if (!ec && exe.parent_path().filename() == "bin") {
166177
// Dev builds emit binaries at target/<triple>/<fp>/bin/<exe>,
167178
// matching the bin/ shape. Any ancestor literally named

tests/e2e/05_errors.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ out=$("$MCPP" build 2>&1) && { echo "expected failure"; exit 1; }
6060
cd "$TMP"
6161
"$MCPP" new naming-ok > /dev/null
6262
cd naming-ok
63-
sed -i 's/name = "naming-ok"/name = "myorg.something"/' mcpp.toml
63+
sed -i.bak 's/name = "naming-ok"/name = "myorg.something"/' mcpp.toml && rm -f mcpp.toml.bak
6464
cat > src/foo.cppm <<'EOF'
6565
export module differentprefix;
6666
import std;

tests/e2e/09_path_dependency.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ grep -q 'mcpp.cache/mylibA.greet.gcm\|gcm.cache/mylibA.greet.gcm' "$ninja_file"
8181
# Path-resolution error reporting: declared name mismatch
8282
TMP2=$(mktemp -d)
8383
cp -r "$TMP/mylibA" "$TMP2/wrongname"
84-
sed -i 's/name = "mylibA"/name = "differentname"/' "$TMP2/wrongname/mcpp.toml"
84+
sed -i.bak 's/name = "mylibA"/name = "differentname"/' "$TMP2/wrongname/mcpp.toml" && rm -f "$TMP2/wrongname/mcpp.toml.bak"
8585
cat > mcpp.toml <<EOF
8686
[package]
8787
name = "myappB"

tests/e2e/22_doctor_cache_publish.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ out=$("$MCPP" cache list 2>&1)
3131
cd "$TMP"
3232
"$MCPP" new myapp >/dev/null
3333
cd myapp
34-
sed -i 's|^repo[[:space:]]*=.*|repo = "https://github.com/example/myapp"|' mcpp.toml
34+
sed -i.bak 's|^repo[[:space:]]*=.*|repo = "https://github.com/example/myapp"|' mcpp.toml && rm -f mcpp.toml.bak
3535
grep -q '^repo' mcpp.toml || cat >> mcpp.toml <<'EOF'
3636
3737
[package]

0 commit comments

Comments
 (0)