# Klammertext source installation on macOS (Apple Silicon) Companion to `linux_source_install.md`. Verified on an Apple-Silicon Mac (arm64, macOS 26 "Tahoe"). Klammertext's core (engine, SKS, HTML/LaTeX, `@image`) builds and runs natively with Apple Clang; the cross-platform build environment (`env/makefile.env`) auto-detects the OS via `uname`. ## 1. Toolchain prerequisites ```sh xcode-select --install # Command Line Tools (clang, headers) — if not already present ``` Then install Python with a linkable `libpython` and `python3-config`, using whichever package manager you have — **Homebrew** or **MacPorts**. Both work; only the install prefix differs, and the build auto-detects it. ```sh # Homebrew (https://brew.sh): brew install python brew install gcc # OPTIONAL: a second compiler for a standards check # MacPorts (https://www.macports.org) — provisional, pending testing on a # MacPorts system: sudo port install python312 sudo port select --set python3 python312 # so python3 / python3-config resolve sudo port install gcc14 # OPTIONAL: a second compiler for a standards check ``` Notes: - The build embeds Python, which needs `python3-config` and a linkable `libpython`. Apple's `/usr/bin/python3` does **not** ship a usable `python3-config` and Apple discourages linking it — so a package-manager Python (Homebrew or MacPorts) is required. It coexists with Apple's; `python3-config` resolves to it when the manager's `bin` is early on `PATH` (`/opt/homebrew/bin` for Homebrew, `/opt/local/bin` for MacPorts — both set up by their installers). For MacPorts, `port select --set python3 python312` makes `python3` and `python3-config` resolve. - `makefile.env` gets all Python include/link flags from `python3-config` and auto-detects the package-manager prefix (`/opt/homebrew` or `/opt/local`, via `MACOS_PREFIX`), so either manager works without edits. Override with `make MACOS_PREFIX=...` if yours is installed elsewhere. ## 2. Image support (the `@image` klammer): OpenImageIO ```sh # Homebrew: /opt/homebrew/bin/pip3. install --break-system-packages OpenImageIO # e.g. pip3.14 — match your Python's version # MacPorts (matches the python312 installed above): sudo port install py312-openimageio ``` This provides the OpenImageIO Python bindings the embedded interpreter uses. With pip, the self-contained PyPI wheel goes into that Python's site-packages; `--break-system-packages` is needed because the Python is PEP-668 "externally managed". (Homebrew alternative: `brew install openimageio`, heavier — it pulls ffmpeg/openexr/etc.) ## 3. Clone and configure the environment ```sh git clone https://git.andykopra.com/ack/klammertext.git ~/projects/klammertext # Set up the runtime environment (KLAMMERTEXT_HOME, PATH); add to ~/.zprofile: echo 'source "$HOME/projects/klammertext/env/runtime.env"' >> ~/.zprofile ``` The single self-configuring `runtime.env` self-locates `KLAMMERTEXT_HOME` from its own path. On macOS it sets no `LD_LIBRARY_PATH`/`DYLD_LIBRARY_PATH` (`libklammertext.so` is found via the binaries' `@loader_path` rpath, and `document.so` is dlopen'd by absolute path under `$KLAMMERTEXT_HOME`) and no `LSAN_OPTIONS` (LeakSanitizer is unsupported on macOS). ## 4. Build (Apple Clang) Clang is the compiler you run on macOS, and it is the **default** here (`makefile.env` selects clang on Darwin), so no `COMPILER=` flag is needed. A single `make -C com` builds its prerequisites in `mac/` and `sks/` first, then the commands: ```sh cd "$KLAMMERTEXT_HOME" make -C com -j # optimized (-O3) by default; libklammertext.so + sks/*.so + bin/{ktext,kdesc,kdiag} ktext -s '@eval 1 + 1 @' -d # smoke test — prints 2 ``` (For a debug build with AddressSanitizer, intended for development, prefix `DEBUG=1`: `DEBUG=1 make -C com -j`.) For a document smoke test, create a small file and render it to HTML: ```sh cat > hello.kt <<'EOF' @document :structure article :title Hello :text @s1 Hello, Klammertext @ This document was built from source. @ EOF ktext hello.kt -t html # writes hello/index.html ``` (A PDF render needs TeX Live — see section 5.) ## 5. PDF target: TeX Live Build a complete Klammertext TeX Live tree with the bundled script, into `~/external/texlive/` — the location `runtime.env` auto-detects (`bin/universal-darwin`). macOS already has `curl`, `perl`, and `tar`, and `install-tl` self-provides `xz`, so nothing extra is needed: ```sh bash "$KLAMMERTEXT_HOME/doc/install/texlive_additional_packages.sh" ~/external/texlive/2026 ``` This installs `scheme-small` plus the SKS's additional packages and rebuilds all formats, fetching the `universal-darwin` binaries, and writes a `KLAMMERTEXT_BUILD_INFO.txt` provenance file into the tree. **This is the same command used on Linux**, so the TeX Live layout is identical across your machines. `runtime.env` then finds the tree automatically — open a new shell (or re-source it) and `xelatex` is on `PATH`; no manual `KLAMMERTEXT_TEXLIVE_BIN` is needed. If you already run BasicTeX/MacTeX and prefer to reuse it, point `runtime.env` at its bin directory from the gitignored escape hatch instead (and install the SKS's extra packages into it yourself — the list is in the script). Set the variable **and** prepend it to `PATH`, since `runtime.env.local` is sourced after the main `PATH` is built: ```sh cat >> "$KLAMMERTEXT_HOME/env/runtime.env.local" <<'EOF' export KLAMMERTEXT_TEXLIVE_BIN=/usr/local/texlive/2025basic/bin/universal-darwin export PATH="$KLAMMERTEXT_TEXLIVE_BIN:$PATH" EOF ``` Verify and test (reusing `hello.kt` from section 4): ```sh xelatex --version ktext hello.kt -t pdf # writes hello.pdf ``` ## 6. Updating To update an existing source installation to the latest version: ```sh cd "$KLAMMERTEXT_HOME" git pull make -C com -j # rebuild library, SKS components, and commands (optimized) ``` Rebuild the TeX Live tree only if the SKS's package requirements changed (rare); re-run the script from section 5. ## Compiler notes (macOS) - **Clang is the compiler you run, and the default here.** Apple Clang builds run correctly; `makefile.env` selects clang on Darwin automatically. - **Do not run gcc-built binaries on macOS.** GCC (Homebrew `g++-NN` or MacPorts `g++-mp-NN`) is useful only as an optional compile-time standards check (`make -C com COMPILER=gcc`); the resulting binaries **crash at runtime** on macOS because of a gcc/macOS codegen issue (for example `std::source_location` returning a bad pointer, so `Machine::Machine()` walks into `strlen` and SIGSEGVs). Always run the clang-built binary. (gcc-built binaries run fine on Linux.) - **Switching compilers requires a full clean** — `g++` and `clang++` objects must not be mixed (ABI). `make -C com redo` does a full clean rebuild across `mac`, `sks`, and `com`; a partial `make -C mac clean` does not.