Artifact a79b16aa18cfa615da74e5e236cc70aea2a283e8c46d8aebd8d1a0c4e6950a28:
- File revival/doc/quickstart.md — part of check-in [4379605690] at 2026-08-12 21:30:16 on branch trunk — quickstart.md: document config/Makefile's BASEDIR as a second hardcoded path alongside site.h (reported by an outside builder) (user: wdc size: 16520)
AUIS Revival: Running ez on macOS/Darwin
This guide covers getting the source, building, and running ez and
other AUIS applications on macOS with XQuartz. See roadmap.md for
current status and porting-changelog.md for the history behind each
decision.
For getting messages/cui working against a real IMAP/SMTP mail
account, see mail-quickstart.md.
Getting the source
Two mirrors exist; either works. Both track trunk, so a plain clone
lands you on the active revival tree with no branch flag needed. The
checkout can live anywhere and be named anything — nothing below
assumes a specific directory name — but the tree does contain one
hardcoded absolute path that has to match wherever you put it (fixed
in Site configuration, below).
GitHub (mirror, easiest for a one-off checkout):
git clone https://github.com/poetnerd/auis.git
cd auis
Fossil (canonical repo, needed if you intend to contribute changes back):
mkdir auis && cd auis
fossil clone https://poetnerd.com/wdc/auis auis.fossil
fossil open auis.fossil
fossil clone downloads the whole repository (history included) into
the auis.fossil file; fossil open checks out trunk's tip into
the current directory.
Either way, you should now be in a checkout directory containing
src/, revival/, patches/, and bison/. Everything below assumes
you're starting from there — examples show /path/to/your/checkout/,
substitute your actual path.
Prerequisites
XQuartz — the X11 server for macOS. Install via:
brew install --cask xquartz
Or download from xquartz.org. XQuartz must be running for any AUIS
application to open a window. Modern XQuartz sets $DISPLAY
automatically via a launchd socket (/private/tmp/com.apple.launchd.*/
org.xquartz:0); you do not normally need to set it by hand.
Build tools — Xcode Command Line Tools, plus:
brew install bison flex imake makedepend
- bison and flex: the build uses system versions (the vendored Andrew
bison hangs on Darwin/arm64 — see porting-changelog.md 2026-06-29)
- imake: required to regenerate Makefiles on a fresh checkout
- makedepend: required for the make depend phase
Site configuration — required before your first build
src/config/site.h hardcodes DEFAULT_ANDREWDIR_ENV, a path compiled
into every AUIS binary as the fallback location for its own resource
tree (fonts, etc/AndrewSetup, help files — everything under build/)
whenever the ANDREWDIR environment variable isn't set at runtime. As
checked in, it points at the original developer's own checkout path.
If your checkout isn't at that exact path, edit it before building:
#define DEFAULT_ANDREWDIR_ENV /path/to/your/checkout/build
This only needs doing once, before the first make World — the value
gets compiled in, so changing it later means rebuilding. (If you'd
rather not touch a tracked file, setting the ANDREWDIR environment
variable to the same path at runtime overrides this default without a
rebuild — but you'd need to set it in every shell session that runs an
AUIS binary, so editing site.h once is usually less friction.)
A second, separate hardcoded path to check: BASEDIR in
src/config/Makefile. This is a different file from site.h above,
and a different mechanism — config/Makefile is generated by imake
(Step 2 below), which reads DEFAULT_ANDREWDIR_ENV out of site.h at
generation time and bakes the same path into every subdirectory
Makefile as BASEDIR, the install destination for everything the
build produces. If you edit site.h before config/Makefile exists
(i.e. before you've ever run Step 2), this happens automatically and
there's nothing more to do. But if config/Makefile already exists —
you tried a build first, hit an error, and are now fixing site.h
after the fact — its BASEDIR is already baked in with the old value
and does not pick up the site.h edit on its own. In principle GNU
make's own Makefile-remake-on-dependency-change should catch this and
regenerate it automatically; in practice, don't rely on that here —
fossil checkouts don't reliably preserve mtimes (see "Fossil checkout
timestamps..." below), so the automatic check can silently not fire.
After editing site.h, if config/Makefile already exists, rerun
Step 2 by hand to be sure:
imake -I. -I./config -Timake.tmpl -s Makefile -DTOPDIR=.
Safe to run any time — it just regenerates config/Makefile fresh
from the current site.h.
Building
First build (fresh checkout)
From the checkout root, run all three steps below in
order — the first is easy to miss because its symptom is a fatal
compile error (classproc.c:12:10: fatal error: 'class.h' file not
found) that shows up two steps later, in a part of the build that
looks unrelated:
cd src
# Step 1: class.h must exist in build/include/ before machdep can build
# against it. On a brand-new checkout nothing has been installed yet,
# so this has to run first, by hand, exactly once.
../revival/tools/prime-class-header
# Step 2: generate the top-level Makefile via imake. Bakes site.h's
# DEFAULT_ANDREWDIR_ENV into this Makefile's BASEDIR -- if you're
# re-running this after fixing site.h, this is the step that actually
# picks up the fix. See "Site configuration" above.
imake -I. -I./config -Timake.tmpl -s Makefile -DTOPDIR=.
# Step 3: World = regenerate all subdirectory Makefiles + full build + install
make World 2>&1 | tee ../dependInstall.log
make World regenerates all subdirectory Makefiles via imake, creates
the build/ directory tree, builds all libraries and binaries,
generates .ih/.eh headers from .ch class specs, and installs
everything. Expect it to take a few minutes. A clean build produces
278 .do files and 602 headers with zero errors.
Expect thousands of makedepend "cannot find include file" warnings
along the way — that's normal, not a sign anything is missing.
make World runs as two full tree-wide passes, depend then
install (config/imake.tmpl's world:: target) — every directory's
dependency scan happens before any directory's generated .ih/.eh
headers are actually installed into build/include/. So makedepend
routinely can't find a sibling directory's generated header yet and
prints warning: ... cannot find include file "foo.ih"; a known-good
build log here has over 5,000 of these. They're warnings, not errors —
make continues past them, and the header shows up once its own
directory reaches the install pass later in the same run. This is a
different problem from Step 1's class.h issue above (that one is a
hard compile failure, not a makedepend warning). If a wall of these
warnings scrolls by, that's expected; what tells you whether the build
actually worked is whether the run ends with the zero-errors success
line above, not whether these warnings appeared.
Why step 1 is needed: overhead/class/Imakefile builds machdep
before lib, but lib is what installs class.h into
build/include/ — machdep/darwin/classproc.c needs it already
there, and on a truly empty build/ nothing has installed it yet.
This only bites the very first build; every build after this one
already has class.h in place. See porting-assessment.md → "Primary
build environment" for the full writeup. (The same three steps apply
any time build/ is deliberately wiped from scratch, e.g. to bisect
an old revision — not just on a fresh checkout. Full recipe for
testing a specific historical revision, since fossil's mtimes make
incremental rebuilds untrustworthy across checkouts:
porting-assessment.md → "Fossil checkout timestamps make incremental
rebuilds untrustworthy...".)
Check for LP64 warnings before running new code paths:
grep "warning: cast to '.*\*' from smaller integer type" ../dependInstall.log
Any hit is a real bug (pointer-returning function called without a
prototype, return value truncated to 32 bits). Fix with a local
extern TYPE FunctionName(); declaration. See porting-changelog.md
and porting-assessment.md §LP64 for the full pattern.
If you're going to run messages or cui, also run this now —
build/ doesn't come with it, and skipping it doesn't fail loudly:
../revival/tools/write-andrewsetup
Without it, mail silently defaults to AMS_OnlyMail: Yes, which
collapses the startup folder view down to just mail regardless of
subscription status — no error, it just looks like nothing is
subscribed. See "AndrewSetup settings" below for what this creates and
why (ThisDomain matters too, for outgoing mail). Safe to (re-)run
after any clean rebuild.
Incremental rebuilds (after the first build)
Once build/ exists and the first make World has succeeded, day-to-day
rebuilds are simpler. From your checkout's src/:
make dependInstall 2>&1 | tee ../dependInstall.log
-k is not needed; the tree is clean. Do not run concurrent builds.
AndrewSetup settings
build/etc/AndrewSetup is a hand-authored site-config file, read at
runtime by every AMS/ATK client (GetConfiguration, searching a fixed
list of paths ending in ${ANDREWDIR}/etc/AndrewSetup — this
revival's site.h points ANDREWDIR at the build tree, so no root
access is needed and no other candidate path on this list exists). It
is not a build artifact — no Imakefile creates, installs, or
regenerates it — but it lives inside build/, so make Clean (or any
other wipe of build/) deletes it silently along with everything
else, with no error or warning that it's gone.
Run revival/tools/write-andrewsetup any time after a clean to
recreate it (refuses to overwrite an existing file; pass -f to
force). Current contents:
# AUIS revival local configuration
ThisDomain: fastmail.com
AMS_OnlyMail: No
ThisDomain— the domain AMS stamps into outgoingFrom:headers (<unix-login>@<ThisDomain>; any From you type is replaced). Without it, mail goes out asyou@your-machine.lan, which real SMTP providers refuse to relay externally. Seemail-quickstart.mdstep 3.AMS_OnlyMail— boolean (Yes/No/1/0), defaults toYesunless the tree is built withRUN_AMDS_ENV(this revival never defines it — seeallsys.h).Yeshard-restricts the default "Expose New" startup folder view to$HOME/.MESSAGESonly, excluding every other mspath root (e.g. an IMAP mirror) regardless of subscription status — the check happens before subscription is ever consulted. Sites that actually want bboards suppressed should leave thisYes; a personal single-user setup wantsNo. Full trace of how this was found:claude-history/ folder-visibility-REPORT.md.
Terminal setup — important
Always run AUIS binaries from native Terminal.app or iTerm2, not from a VS Code integrated terminal or any VS Code-attached shell.
VS Code's terminal inherits a Mach exception-port relationship that
intercepts crash signals from child processes and never services them.
Any AUIS binary that crashes while launched from a VS Code terminal will
enter an unkillable UE (uninterruptible zombie) state that survives
kill -9 and requires a reboot to clear. The same bug hides real crashes
behind an apparently-hung process, making debugging impossible. Running
from native Terminal.app, the same crash exits normally and can be caught
by lldb. See porting-changelog.md 2026-06-30 for the full diagnosis.
Font path setup
AUIS needs its compiled fonts to be visible to the X server. The build
places 40 PCF font files in build/X11fonts/. Add this directory to
XQuartz's font path once per XQuartz session (it is lost when XQuartz
quits):
xset fp+ /path/to/your/checkout/build/X11fonts
xset fp rehash
Why this is still needed even with Xft text rendering: the revival uses a hybrid font approach:
| Rendering path | Font mechanism |
|---|---|
| Body text | Xft / fontconfig (client-side, no X font path needed) |
| Menus | Xft (phase 2, in progress as of 2026-07) |
| Symbol characters (bullets, math marks) | Andy symba*.pcf — X font path required |
| Cursor shapes | Andy cursor PCF — X font path required |
The fonts.alias file in build/X11fonts/ maps Andy text font names
(andysans, andytype) to standard Adobe Helvetica/Courier XLFD names
already present in XQuartz, so no Andy text bitmap fonts need to be
installed. The symba*.pcf files (5 sizes: 8, 10, 12, 16, 22 point) are
custom CMU symbol fonts with no standard substitute — without them,
bullet characters render as 7 and other symbol characters are wrong.
A future setup step may automate the xset fp+ call, either via a
wrapper script or by installing the PCF files into XQuartz's default font
path (/opt/X11/share/fonts/).
con10/con12 (console-app icon fonts) are not among the 40 PCF
files make World installs, because MK_CONSOLE gates out all of
atk/console (including console/fonts) and this revival leaves it
off intentionally. These two fonts are referenced by things outside
console too — e.g. ams/demo/d10's fad (animation) inset (see Test
documents below) uses con10 for an icon — so their absence isn't
just "the console app doesn't work," it silently breaks icon rendering
elsewhere. Run
../revival/tools/install-console-fonts once per fresh/wiped build/
to build and install just these two fonts, without building the rest
of console. See porting-assessment.md → "MK_CONSOLE being off
silently breaks con10/con12..." for the full story.
Running ez
Change to the build/ directory and run:
cd /path/to/your/checkout/build
bin/ez -d # open a blank document
bin/ez -d doc/README.ez # open an existing .ez file
bin/ez -d ~/src/AUIS/NEWSLETTERS/EZ/95Summer.ez # richer test document
The -d flag prevents ez from forking to background, which is useful
during development. Without -d, ez daemonizes and the shell returns
immediately; crash output goes nowhere visible.
ez is a symlink to runapp, the generic AUIS application launcher. All
ATK applications (help, bush, figure, table, etc.) are symlinks
to the same binary.
Running help
cd /path/to/your/checkout/build
bin/helpa -d
Note the argument order: application name before flags (helpa -d, not
-d helpa). The -d flag is parsed by app.c's ParseArgs after
runapp has identified the target application; flags before the app name
are not seen by the application.
Known issues
Status of individual applications and insets, open bugs, and active
work all live in roadmap.md — see its "Applications and insets" and
"Open issues" sections, which stay current. This file used to
duplicate that list; it drifted stale, so it doesn't anymore.
Debugging crashes
Use lldb from native Terminal.app:
cd /path/to/your/checkout/build
lldb bin/ez -- -d path/to/file.ez
(lldb) run
... wait for crash ...
(lldb) bt
(lldb) frame select N
(lldb) frame variable
When a new crash is encountered, check dependInstall.log for a
-Wint-to-pointer-cast warning at the crashing function before assuming
a new bug type — it is likely an LP64 missing-prototype truncation, the
most common crash class in this codebase. See porting-assessment.md
for all known LP64 bug patterns.
Test documents
Good ez test files, in order of increasing complexity. The last
three rows are historical CMU AUIS newsletters/papers, not part of
this checkout — useful if you have a copy, skippable if you don't:
| File | What it tests |
|---|---|
revival/testing.ez |
text, note, calc, eq, table insets; used for the Media-menu regression-test checklist in claude-history/roadmap-old.md ("ez application (menus)") |
ams/demo/d10 |
fad (animation) inset; exercises the con10 console icon font — see Font path setup |
doc/README.ez |
Basic text, page break insets (bp/bpv) |
src/contrib/mit/rtf2/test.ez |
Rich paragraph styles, no insets |
src/FAQ.ez |
Long document, footnote insets |
src/contrib/mit/neos/doc/history.ez |
Raster image insets |
src/contrib/mit/neos/doc/NEOS_stud.ez |
6 rasters + zip inset |
~/src/AUIS/NEWSLETTERS/EZ/95Summer.ez |
Figure insets |
~/src/AUIS/NEWSLETTERS/EZ/92Sep.ez |
Raster + footnote insets |
~/src/AUIS/PAPERS/atk/Boren.CACM |
Non-.ez format; full justification, multiple font sizes |