From b439592cf8113f34240095dcd6d8b6196c7d87c7 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 16 Oct 2026 09:04:34 +0000 Subject: fix(build): build matching static LLD for macOS Build LLD from the installed LLVM version's official source release and install static archives into the local build prefix. Include the Mach-O unwind headers, preserve static library checks and document the setup. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/nightly-build.yml | 9 ++++--- AGENTS/ARCH.md | 14 +++++++--- cmake/NativeCompiler.cmake | 13 +++++----- doc/build.md | 17 +++++++++---- tools/build-static-lld.sh | 51 +++++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 tools/build-static-lld.sh diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 1f21821..048133d 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -123,13 +123,16 @@ jobs: - name: Install LLVM 23 and packaging dependencies run: | test "$(uname -m)" = arm64 - brew install llvm@23 lld pandoc zlib zstd ncurses python + brew install llvm@23 pandoc zlib zstd ncurses python test -x "$(brew --prefix llvm@23)/bin/clang++" + - name: Build matching static LLD libraries + run: | + sh tools/build-static-lld.sh "$(brew --prefix llvm@23)" "$PWD/build" 3 + - name: Build the embedded release package run: | llvm_prefix=$(brew --prefix llvm@23) - lld_prefix=$(brew --prefix lld) zlib_prefix=$(brew --prefix zlib) zstd_prefix=$(brew --prefix zstd) ncurses_prefix=$(brew --prefix ncurses) @@ -139,7 +142,7 @@ jobs: -DCMAKE_C_COMPILER="$llvm_prefix/bin/clang" \ -DCMAKE_CXX_COMPILER="$llvm_prefix/bin/clang++" \ -DLLVM_DIR="$llvm_prefix/lib/cmake/llvm" \ - -DCMAKE_PREFIX_PATH="$llvm_prefix;$lld_prefix;$zlib_prefix;$zstd_prefix;$ncurses_prefix" + -DCMAKE_PREFIX_PATH="$llvm_prefix;$zlib_prefix;$zstd_prefix;$ncurses_prefix" cmake --build build --target release --parallel 3 - name: Smoke test the packaged compiler diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md index 30e4f90..e78d872 100644 --- a/AGENTS/ARCH.md +++ b/AGENTS/ARCH.md @@ -67,8 +67,8 @@ selected executable changes. Platform modules relocate package paths only inside the extraction directory; Homebrew bottles also receive local Cellar/opt links and Mach-O relocation/signing. Package hashes skip unchanged extractions; a changed package set rebuilds the -managed root. Downloads belong to the package-manager commands in `doc/build.md`, -not to CMake. The Windows Pandoc ZIP is downloaded directly from its official +managed root. Downloads belong to the explicit dependency commands and static LLD +helper in `doc/build.md`, not to CMake. The Windows Pandoc ZIP is downloaded directly from its official release because MSYS2 has no Pandoc package. Only the Linux build is verified. Generated IR uses the C++ exception ABI; native compilation links its runtime @@ -143,6 +143,14 @@ headers or system runtime dylibs. No user development toolchain is required. Linux statically links non-system runtimes but dynamically links glibc; do not use global `-static` there. Generated binaries require a compatible host system runtime. +Homebrew's LLD package contains shared libraries. Run `tools/build-static-lld.sh` +with the selected LLVM prefix and cpsc build directory before configuring on macOS. +It builds matching LLD sources, installs static archives and tools into the build +prefix, and leaves LLVM itself installed. Source and build caches are versioned; +the resulting local `lib/cmake/lld` takes precedence over shared system packages. +The helper's build-time linker can use the installed LLVM dylib; cpsc still links +the LLD archives and static LLVM components. + Windows build instructions retain MSYS2 MINGW64. Its LLVM/Clang package names and compiler executable names are unversioned; CMake still requires major 23. The build guide explicitly selects `/mingw64/bin/clang.exe` and `clang++.exe` @@ -218,7 +226,7 @@ job uses a macOS 15 arm64 runner, and Windows uses Windows Server 2025 x86_64. All four check out the push SHA and run independently after cleanup. All three compiler jobs use LLVM/Clang/LLD 23, Python, Release and EMBEDDED settings, Pandoc, and the existing `release` target. Linux obtains its toolchain from apt.llvm.org; macOS -uses Homebrew's LLVM 23. Windows uses `msys2/setup-msys2@v2` with MINGW64, +uses Homebrew's LLVM 23 and builds matching static LLD with the helper above. Windows uses `msys2/setup-msys2@v2` with MINGW64, MSYS2 LLVM/Clang packages, explicit native compiler and LLVM paths, and the MinGW Makefiles generator. It downloads the official Pandoc 3.12.1 Windows x86_64 ZIP into `build/deps/packages/` for CMake to extract. Each compiler job diff --git a/cmake/NativeCompiler.cmake b/cmake/NativeCompiler.cmake index 29682ec..35c7f41 100644 --- a/cmake/NativeCompiler.cmake +++ b/cmake/NativeCompiler.cmake @@ -18,6 +18,13 @@ else() set(cpsc_linker_libraries lldELF) endif() +foreach(cpsc_native_library clangDriver ${cpsc_linker_libraries}) + get_target_property(cpsc_native_type ${cpsc_native_library} TYPE) + if(NOT cpsc_native_type STREQUAL "STATIC_LIBRARY") + message(FATAL_ERROR "Native output requires static ${cpsc_native_library}; found ${cpsc_native_type}. See doc/build.md for static dependency setup.") + endif() +endforeach() + set(cpsc_native_flags) get_filename_component(cpsc_lld_prefix "${LLD_DIR}/../../.." ABSOLUTE) if(APPLE) @@ -105,9 +112,3 @@ foreach(cpsc_import IN LISTS CLANG_EXPORTED_TARGETS LLD_EXPORTED_TARGETS LLVM_AV set_property(TARGET ${cpsc_import} PROPERTY INTERFACE_LINK_LIBRARIES "${cpsc_interface}") endif() endforeach() -foreach(cpsc_native_library clangDriver ${cpsc_linker_libraries}) - get_target_property(cpsc_native_type ${cpsc_native_library} TYPE) - if(NOT cpsc_native_type STREQUAL "STATIC_LIBRARY") - message(FATAL_ERROR "Native output requires static ${cpsc_native_library}") - endif() -endforeach() diff --git a/doc/build.md b/doc/build.md index a3b9cc3..7f702d3 100644 --- a/doc/build.md +++ b/doc/build.md @@ -133,10 +133,10 @@ The `clang-tools-extra` package is required because MSYS2's `ClangTargets.cmake` Install the Xcode Command Line Tools for the macOS SDK, make and package relocation tools with `xcode-select --install` if needed. The LLVM bottle below -provides Clang 23. Install CMake with Homebrew: +provides Clang 23. Install the build tools and LLVM SDK with Homebrew: ```bash -brew install cmake python +brew install cmake python llvm@23 ``` Recommended binary-bottle downloads to the build directory: @@ -144,16 +144,23 @@ Recommended binary-bottle downloads to the build directory: ```bash mkdir -p build/deps/packages HOMEBREW_CACHE="$PWD/build/deps/packages" brew fetch --force-bottle \ - llvm lld zlib zstd ncurses lz4 xz + llvm zlib zstd ncurses lz4 xz ``` [Homebrew's `llvm` formula](https://formulae.brew.sh/formula/llvm) currently provides 23; verify the downloaded version before configuring. This requires -binary bottles available for your macOS version and CPU; source -archives are not used. CMake extracts the bottles into a local `Cellar/`, creates +binary bottles available for your macOS version and CPU. CMake extracts the bottles into a local `Cellar/`, creates local `opt/` links and relocates their CMake and dynamic-library paths using the Command Line Tools. The macOS build has only been reviewed statically. +Homebrew's `lld` formula builds shared libraries, which cannot be embedded in the single-file compiler. Before configuring cpsc, build static LLD against the LLVM version selected for the compiler: + +```bash +sh tools/build-static-lld.sh "$(brew --prefix llvm@23)" "$PWD/build" 3 +``` + +The helper downloads the matching official LLVM source release, extracts LLD, its common CMake utilities and libunwind's Mach-O headers, and builds LLD using the installed LLVM SDK. It installs static LLD libraries, headers, tools and CMake configuration into `build/`, where cpsc's local dependency lookup finds them before system packages. It does not rebuild LLVM or libunwind. Use the same build directory for the helper and cpsc. For an already-extracted LLVM bottle, pass its `build/deps/root/opt/llvm` prefix instead; the LLVM versions must match. The helper uses the host architecture and defaults to a macOS 15.0 deployment target; set `MACOSX_DEPLOYMENT_TARGET` to override that target for both builds. + ## Build You must explicitly choose `-DCPSC_RUN_MODE=PATH`, `EMBEDDED`, or `NONE` on diff --git a/tools/build-static-lld.sh b/tools/build-static-lld.sh new file mode 100644 index 0000000..407e814 --- /dev/null +++ b/tools/build-static-lld.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# Build LLD against an installed LLVM SDK; install it in cpsc's build prefix. +set -eu + +if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then + echo "Usage: sh tools/build-static-lld.sh LLVM_PREFIX BUILD_DIRECTORY [JOBS]" >&2 + exit 1 +fi + +llvm_prefix=$(cd "$1" && pwd) +mkdir -p "$2" +build_root=$(cd "$2" && pwd) +jobs=${3:-3} +llvm_version=$("$llvm_prefix/bin/llvm-config" --version) +case "$llvm_version" in + 23.*) ;; + *) echo "Static LLD requires LLVM 23; found $llvm_version" >&2; exit 1 ;; +esac + +work="$build_root/static-lld-$llvm_version" +archive="$work/llvm-project-$llvm_version.src.tar.xz" +mkdir -p "$work/src/llvm" +if [ ! -f "$archive" ]; then + curl -fL --retry 3 \ + "https://github.com/llvm/llvm-project/releases/download/llvmorg-$llvm_version/llvm-project-$llvm_version.src.tar.xz" \ + -o "$archive.part" + mv "$archive.part" "$archive" +fi +if [ ! -f "$work/src/.extracted" ]; then + tar -xJf "$archive" -C "$work/src" --strip-components=1 \ + "llvm-project-$llvm_version.src/lld" "llvm-project-$llvm_version.src/cmake" \ + "llvm-project-$llvm_version.src/libunwind/include" + touch "$work/src/.extracted" +fi + +set -- +if [ "$(uname -s)" = Darwin ]; then + set -- "-DCMAKE_OSX_ARCHITECTURES=$(uname -m)" \ + "-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-15.0}" +fi +cmake -S "$work/src/lld" -B "$work/build" \ + -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ + -DLLVM_INCLUDE_TESTS=OFF -DLLVM_LINK_LLVM_DYLIB=ON \ + "-DLLVM_DIR=$llvm_prefix/lib/cmake/llvm" \ + "-DLLVM_MAIN_SRC_DIR=$work/src/llvm" \ + "-DCMAKE_C_COMPILER=$llvm_prefix/bin/clang" \ + "-DCMAKE_CXX_COMPILER=$llvm_prefix/bin/clang++" \ + "-DCMAKE_INSTALL_RPATH=$llvm_prefix/lib" \ + "-DCMAKE_INSTALL_PREFIX=$build_root" -DCMAKE_INSTALL_LIBDIR=lib "$@" +cmake --build "$work/build" --parallel "$jobs" +cmake --install "$work/build" -- cgit v1.3.1-4-g156e