# 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.<N> 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/<year>` — 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. Optional: the `mdpdf` command (Markdown to PDF)

Klammertext ships a second, independent route in `sks/tns/`: `mdpdf` renders
a **Markdown** file to PDF through a headless browser, bypassing Klammertext
entirely. It is for a document that is not written in Klammertext — one you
have not converted yet, or one whose Markdown is not worth converting.

The command is a shell function that `env/runtime.env` defines, so if you
source that file (section 3) you already have it — **in shells started after
the installation**. In a shell that was already running, source it again:

```sh
source "$KLAMMERTEXT_HOME/env/runtime.env"
type mdpdf                    # mdpdf is a shell function
```

Two things it needs that the distribution does not install:

```sh
# 1. The Markdown renderer, in a virtual environment of its own.  PEP 668
#    forbids installing it into the system Python, so this is not optional
#    and not a system package.
python3 "$KLAMMERTEXT_HOME/sks/tns/md_to_pdf.py" --setup

# 2. A Chromium-based browser -- Brave, Chrome or Chromium -- which is the
#    renderer.  Any one of them will do, and an .app in /Applications is
#    found without being told where it is.
brew install --cask chromium
```

Then:

```sh
mdpdf notes.md                # writes notes.pdf beside it
mdpdf notes                   # the .md may be left off
```

It supplies the fonts, the size matching and the code wrapping, and completes
on `*.md` at the TAB key. Each default is a variable you may set in
`~/.zprofile` — `MDPDF_SERIF`, `MDPDF_SANS`, `MDPDF_MONO`, `MDPDF_MATCH`,
`MDPDF_WRAP`, and `MDPDF_BROWSER` for a browser installed somewhere the
command does not look. Any option of the underlying `md_to_pdf.py` may also
be given on the command line, where it overrides the default:

```sh
mdpdf notes.md --paper letter --margin 0.75
```

The stylesheet it applies is `sks/tns/markdown.css`; copy it, edit the copy,
and pass `--css yourcopy.css` to render to your own taste.

## 7. 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.
