Commit Graph

2762 Commits

Author SHA1 Message Date
R. Timothy Edwards c81b995266 Additional changes: Moved the halving of the sidewall capacitance
coefficient from the calculation to the tech file parser (done once
instead of done many times), and corrected the included (old) SCMOS
tech files to use the new "standard" coefficient values.
2026-08-02 11:34:41 -04:00
R. Timothy Edwards 51522d6889 Multiple changes:
(1) Corrections to the R-C extraction code to better handle nodes
    which have the recorded position at the corner of a split tile.
(2) Corrected "select area label" to prevent accidentally selecting
    unexpanded instances in the area.  Also corrects an issue with
    not being able to select labels that are attached to "space".
(3) Changed the way that magic interprets the "sidewall" coefficient
    so that it is entered into the tech file as the actual sidewall
    coefficient instead of being half the value to correct for
    magic's double counting of edges.  The correction is instead
    done when parsing the tech file.  This measure was taken because
    the open PDK values generated by "capiche" were not halving the
    value, so I either change magic or I change all the tech files.
2026-08-02 11:10:37 -04:00
R. Timothy Edwards 73620475d7 Updated the revision number to go along with the set of changes
committed by Darryl Miles in PR #546 and #547 (changes to enable
in-tree building, although there are numerous other changes here,
including removing the clunky Depend method and removing the copy
of readline source in the code base).
2026-07-26 14:54:35 -04:00
Darryl L. Miles fad955ce54 build: let run_magic_gdb/valgrind take tool options via a "--" separator
The gdb and valgrind launchers previously passed every argument straight to
magic, leaving no way to give the tool its own options.  Add a "--" split
(shared magic_split_args helper): arguments before "--" go to gdb/valgrind,
arguments after go to magic; with no "--", all arguments go to magic (the
common case).  Examples:

  ./run_magic_gdb.sh -tui -ex run -- -dnull foo.mag
  ./run_magic_valgrind.sh --tool=callgrind -- foo.mag

Also make the tool binary and its default options overridable from the
environment: GDB/GDB_OPTS and VALGRIND/VALGRIND_OPTS (valgrind defaults to
--leak-check=full --error-exitcode=0), and warn if the tool is not on PATH.

Smoke-tested against a live X display: gdb runs magic to a clean exit and
valgrind produces a Memcheck report; option routing verified (a bogus flag
after "--" is rejected by magic, not gdb), both headless (-dnull) and GUI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 869e99f69e build: document run_magic* launchers, template WISH/TCLSH, validate the env
Expand each run_magic*.sh header to state its purpose, usage, and the full set
of environment overrides.  Initialize every knob with ${VAR:-default} so a value
inherited from the environment always wins:

  - CAD_ROOT is now overridable (was hardwired to $builddir/CAD_DIR); point it at
    a shared/installed tree to skip staging.
  - WISH/TCLSH default to the wish/tclsh configure detected for this build's
    Tcl/Tk (@WISH_EXE@/@TCLSH_EXE@, matching --with-tk/--with-tcl), so a build
    against a non-standard Tcl/Tk automatically uses the correct absolute paths.
    MAGIC_WISH (what tkcon.tcl uses for the Tk console) defaults from WISH.

Add magic_check_env(): on source, sanity-check each value (directory / regular
file / executable, as appropriate) and print a non-fatal stderr warning naming
the offending variable and whether it came from the environment or the baked
default -- to make a bad override easy to diagnose.  Empty optional values
(e.g. no tclsh configured) and a not-yet-created CAD_ROOT are not flagged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 201b27e4e9 build: add run_magic*.sh launchers to run magic from the build tree
Four configure-generated launch scripts let you run magic straight from the
build directory without `make install`:

  * run_magic.sh          -- GUI magic (Cairo/X11)
  * run_magicnull.sh      -- batch / no-GUI (-dnull)
  * run_magic_gdb.sh      -- magic under gdb
  * run_magic_valgrind.sh -- magic under valgrind

magic resolves its runtime files through a single $CAD_ROOT root
($CAD_ROOT/magic/{sys,tcl}), but in the build tree they are scattered across
build/ (generated tech, .magicrc, magic.tcl, tclmagic, execs) and source/
(colormaps, dstyles, glyphs, fonts, tcl scripts).  On first run each launcher
self-stages ${builddir}/CAD_DIR as a symlink tree in that layout (no copies,
always current) via the shared scripts/magic_run_common.sh, exports
CAD_ROOT=${builddir}/CAD_DIR, and execs the right binary.  This pairs with the
preceding commit that made the C launchers honor CAD_ROOT.

magic_stage() is idempotent and re-runs on every launch.  Most staged entries
are files, but the bitmaps entry links a *directory*, so it uses `ln -sfn`
(--no-dereference; also accepted by BSD ln): a plain `ln -sf` would, on a second
run, dereference the existing symlink-to-directory and drop the new link *inside*
the target -- a magic/bitmaps/bitmaps self-loop in the source tree that trips up
find/tar/cp -r.

Verified: ./run_magicnull.sh self-stages (30 sys + 24 tcl symlinks) and runs --
`tech load scmos` reports 13 planes -- straight from the build dir.  gitignore
covers the generated scripts and the CAD_DIR tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles aab3361858 tcltk: honor CAD_ROOT for the Tcl runtime dir, not just the baked TCL_DIR
magicexec.c, magicdnull.c and tclmagic.c hardwired the compile-time TCL_DIR
(the install location) when locating magic.tcl (tcl_rcFileName) and the Tcl
auto_path.  So even with CAD_ROOT set -- the documented relocation knob, already
honored by the sys-file search and by tcltk/magic.sh's
TCL_MAG_DIR=${CAD_ROOT}/magic/tcl -- the C launchers still looked in the baked
install path, which is why magic could not source its startup from a relocated
install or a build tree.

Add tcltk/tcldir.h with a MagicTclDir() helper: $CAD_ROOT/magic/tcl when CAD_ROOT
is set and non-empty, else the compile-time TCL_DIR.  Use it in all three sites.
This makes the C side consistent with the shell wrappers and with how magic.tcl
itself already derives its own directory (from `info script`).

Verified: default (no CAD_ROOT) resolves to TCL_DIR as before (build rc=0); with
CAD_ROOT pointed at a staged build tree, `magicdnull -dnull` sources magic.tcl
from there and runs (tech load scmos -> 13 planes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 293c111bc3 build: remove the bundled readline/ subdirectory (Patch 3)
Delete readline/ (the vendored GNU readline 4.3, ~104 files / 2 MB) now that
configure requires the system readline (Patch 1) and the Makefiles no longer
wire the bundled build (Patch 2).  Sweep the remaining references:

  * commands/Makefile.in: drop the `module: ${MAGICDIR}/readline/readline` rule
    and the readline-create-symlinks delegation (bundled-only; commands now uses
    the default `module: libcommands.o`).
  * commands/CmdFI.c, textio/txMain.c, textio/txInput.c: the readline includes
    had a `#ifdef HAVE_READLINE <system> #else "readline/readline/*.h" (bundled)`
    split.  HAVE_READLINE/NEED_READLINE are used nowhere else and USE_READLINE now
    always implies the system library, so collapse to the plain
    `#include <readline/readline.h>` / `<history.h>`.
  * CI: main.yml's non-Tcl job installs libreadline-dev (was relying on bundled);
    canary-matrix drops the now-invalid no_tk_tcl_brl / --enable-readline-bundled
    variant.
  * .gitignore: drop the "readline/ intentionally not converted" note.

Verified: Tcl -j12 builds+installs 375 files (commands builds, no readline-dir
references); --without-tcl --disable-readline -j12 builds (x2); --without-tcl with
no readline dev package still errors with the guidance message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 5e8b81cbcc build: remove bundled-readline wiring from the Makefiles (Patch 2)
With the bundled fallback gone (Patch 1) the readline/ special-casing is dead
machinery.  Remove it:

  * Makefile.in: $(submake) drops the `= readline` `-f`/mkdir branch and is now
    plain `$(MAKE) -C <dir> <goal>`; the clean loop drops its matching branch;
    `readline` is removed from BUNDLED_MODULES.
  * scripts/defs.mak.in: remove the `ifeq (@MAKE_READLINE@,1) -I${MAGICSRC}/
    readline` block (system readline headers are on the standard search path) and
    the MAKE_READLINE variable; tidy the srcdir-fallback comment (only the
    top-level Makefile uses it now).
  * scripts/configure.in: drop AC_SUBST(MAKE_READLINE); regenerate configure.

The system readline link flags (rl_libs = -lreadline via READLINE_LIBS) are
unchanged.  readline/ itself is deleted in the next patch.

Verified: no unsubstituted @MAKE_READLINE@; Tcl -j12 builds+installs 375 files
with readline/ not built; --without-tcl --disable-readline -j12 builds (x2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 5d6c9899d4 build: serialize module@X/lib@X per directory to fix a -j race
main@ depends on both `modules` and `libs`, so `module@X` (`make -C X module`)
and `lib@X` (`make -C X lib`) could run in the same directory concurrently under
-j and race on X's shared objects -- each %.o recipe does `rm $*.o; cc -c`, so
one make would delete/rebuild an object while the other was linking it, e.g.
`ld: cannot find touchtypes.o` while linking libutils.o.  It was rare (timing
dependent) but real; it surfaced on a --without-tcl --disable-readline -j12 build.

Make `lib@%` depend on its own `module@%`: module@X builds the objects, lib@X
then only archives them, so the two never touch X's *.o at the same time.
Cross-directory parallelism is unchanged (lib@X waits only on module@X, not the
whole modules phase).

Verified: 4/4 clean --without-tcl -j12 builds pass (previously intermittently
failed); Tcl -j12 still builds 375 files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles c05ac60851 build: require system readline (or Tcl); drop the bundled fallback (Patch 1)
configure already preferred the system readline (AC_CHECK_LIB → -lreadline) and
only fell back to the bundled readline/ copy.  Remove that fallback: a non-Tcl
interactive build now requires the *system* GNU readline -- both its header
(AC_CHECK_HEADER readline/readline.h, so configure fails cleanly instead of deep
in compilation) and the library -- and if neither Tcl nor readline is available
configure errors with a clear explanation of the three ways forward (build with
Tcl, install libreadline-dev, or --disable-readline).

Also drop the now-meaningless --enable-readline-bundled, and substitute
MAKE_READLINE=0 unconditionally so the Makefiles' bundled-readline path goes
inert.  readline/ and all Makefiles are left untouched here (cleaned up and
removed in the following patches).

--disable-readline stays as the escape hatch: it just tells configure to ignore
the system readline and build the existing no-line-editing variant.

Verified: Tcl build rc=0 (readline off, 375 files, readline/ not built); non-Tcl
--disable-readline builds (serial); non-Tcl default with no readline dev package
now errors with the guidance message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 39b9b528cb doc: note coreutils/gdate is optional on macOS (INSTALL_MacOS.md)
The build's SOURCE_DATE_EPOCH date handling auto-detects gdate/GNU date and
falls back to native BSD `date -r`, so coreutils is not a prerequisite (unlike
gnu-sed).  Add an optional note so the reproducible-build audience knows it is
available but not needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 0aacd546c9 build: compute version/commit/date once, not per sub-make recursion
MAGIC_VERSION/REVISION/COMMIT/BUILDDATE used `?=` with `$(shell ...)`, which
makes them recursively-expanded.  Because they are exported, make re-evaluated
(re-spawned git/date/cat) every time it built a child's environment -- so a
no-op recursive `make` spawned git and date ~624 times each.

Guard each with `ifndef` and assign with `:=` (simply-expanded) so the value is
computed once at the top and exported as a plain string; sub-makes inherit it
and the ifndef skips recomputation.  This was the last "fold in" item from the
buildinfo/ccache plan.

Verified: a no-op `make` now spawns git and date once each (was 624); a full
clean build spawns 1 git / 2 date / 10 cat; the commit is still embedded
correctly and builds are reproducible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 92d13c9894 build: enforce LF on build inputs via .gitattributes; drop sed CR-stripping
npm/build.sh stripped CRs from configure and every scripts/ file before each
WASM build.  Its purpose was purely to survive a Windows checkout with
core.autocrlf=true (which rewrites LF->CRLF, and bash/make then reject CRLF) --
not reproducible packaging.  No tracked build input is CRLF today
(`git ls-files --eol` shows only the incidental appimage/rsc/magic.svg), so it
never fired on a normal checkout, and it mutated the source tree to do it.

Add .gitattributes `eol=lf` for configure, scripts/**, *.sh, *.mak, *.mak.in
and Makefile.in.  Attributes override core.autocrlf, so git always checks these
out as LF regardless of platform -- the authoritative fix -- and the source tree
is never rewritten by the build.  Remove sed_strip_cr and its call sites.

Verified: git check-attr reports eol=lf for configure/scripts/*/*.sh/rules.mak/
Makefile.in; build.sh parses cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 25fa181200 build: detect GNU/BSD date at configure time for SOURCE_DATE_EPOCH
The SOURCE_DATE_EPOCH -> date conversion previously relied on a runtime
`date -u -d @EPOCH 2>/dev/null || date -u -r EPOCH` fallback.  That is
unreliable on macOS/*BSD: BSD `date -d` reads -d as a DST flag and silently
prints the wrong time (exit 0), so the `-r` fallback is never reached.

Decide at configure time instead: prefer coreutils `gdate` (GNU date, e.g.
installed on macOS), else a native `date` that really is GNU (verified by the
epoch-0 output containing 1970), else BSD `date -r`.  configure substitutes the
chosen invocation as @SOURCE_DATE_CMD@ and defs.mak appends the epoch.

Verified on Linux (no gdate -> GNU `date -u -d @`): a fixed SOURCE_DATE_EPOCH
yields a byte-identical buildinfo.o across builds; the no-epoch path still
stamps the current local time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 67d6a2ff5a build: address code-review findings (low-risk cleanups)
From an independent review of the branch:

* Makefile.in: `tcltk` is in both INSTALL_CAD_DIRS and PROGRAMS (Tcl build),
  so install@tcltk / install-tcl@tcltk were defined twice -> "given more than
  once" warnings on every command.  Wrap both install lists in $(sort ...) to
  dedup (as CLEAN_TARGETS already does).  Also fix a stale comment (module@ now
  waits for ${DATABASE_H}, not a `depend` phase).

* toolchains/emscripten/defs.mak: the scmos display-file embed globbed
  `mos.*.dstyle`, which misses mos.7bit.mraster_dstyle (an underscore, not a
  dot) -- so the mono-raster style was not embedded in WASM, and the comment
  wrongly called that file non-existent.  Glob `mos.*dstyle` to cover both.

* npm/build.sh: sed_strip_cr wrote the file back unconditionally, bumping the
  mtimes of configure and every scripts/ file on each WASM build (contradicting
  the "source never mutated" guarantee and able to force a coexisting native
  rebuild).  Only write back when a CR was actually stripped.

* graphics/Makefile.in: remove the dead DEPSRCS block left behind by retiring
  the Depend machinery (it also referenced an undefined ${THREE_D_SRCS}).

* scripts/defs.mak.in: clarify that only the SOURCE_DATE_EPOCH branch is UTC.

Verified: 0 duplicate-target warnings, wildcard now lists mos.7bit.mraster_dstyle,
full Tcl build+install rc=0 (375 files), graphics lib builds, build.sh syntax OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles eaf42fab01 build: remove the depend phase/barrier from the top Makefile
With per-file dependencies now generated during compilation (previous commit),
the serial `depend` phase and its barrier are obsolete.  Drop SUBDIRS_DEPEND and
the `<dir>/Depend: ${DATABASE_H}` rule, and replace the `module@/lib@/tech@ %:
depend` prerequisite with `: ${DATABASE_H}` -- the only real ordering constraint
is the generated header, not a whole dependency-scanning pass.  Modules therefore
start compiling in parallel immediately instead of waiting for every subdir's
deps to be scanned first.

`make depend` is kept as a top-level no-op (the WASM build script still calls
`emmake make depend`).

Verified out-of-tree serial and -j12 and in-tree -j12: rc=0, 375 files, serial
and -j installs byte-identical, zero Depend files, source tree clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 1bc8537b5d build: per-file automatic dependencies (.deps), retire the Depend/sed machinery
Replace the monolithic per-directory `Depend` file -- generated by a separate,
serial `make depend` pass (one `gcc -MM` over all sources) and post-processed by
sed -- with automake-style per-file dependency fragments produced as a side
effect of each compile.

rules.mak's %.o rule now adds, when the compiler supports it,
  -MMD -MP -MF .deps/<stem>.d
so every object records the (non-system) headers it used.  Those fragments are
`-include`d best-effort: absent on a first build, present and correct after.
Benefits:
  * self-maintaining -- no explicit depend step; deps refresh on every compile;
  * parallel -- generated during the (already parallel) compile, no barrier;
  * -MMD already drops system headers (what the sed did) and -MP tolerates a
    removed/renamed header, so the sed post-processing is gone;
  * fixes out-of-tree incremental header tracking: with an absolute srcdir the
    old sed stripped the now-absolute *local* header paths too, silently losing
    them; the .d files keep them.

configure probes `-MMD -MP` (AUTODEP_FLAGS; empty and best-effort-skipped if the
compiler cannot).  clean/distclean remove .deps (rm -r); .gitignore replaces the
obsolete */Depend with .deps/.  `make depend` is kept as a no-op for callers that
still invoke it (e.g. the WASM build script).

Verified out-of-tree (--disable-ccache): 324 .d files, 0 Depend files, a header
touch recompiles its dependents, no-op rebuild is idle, clean clears .deps.  (The
top-level depend phase still runs here as a no-op; removed next.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles c27ef5fab1 doc: document --disable-magic-builddate and the ccache options in INSTALL
Add three configure options to the INSTALL option list:
  * --disable-magic-builddate -- omit the build date for reproducible builds
    (byte-identical objects for a given commit) and full ccache effectiveness.
  * --disable-ccache -- opt out of the auto-detected ccache.
  * --enable-ccache-prefix-map -- relativize embedded source paths for
    cross-tree ccache sharing (off by default; note the debugger and
    CCACHE_BASEDIR implications).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 64614da7a0 build: --enable-ccache-prefix-map for cross-tree ccache sharing
The out-of-tree build puts absolute source-root paths on the command line
(-I${MAGICSRC}, -I${srcdir}, the source file itself), which are part of
ccache's key -- so same-tree rebuilds hit (proven) but different checkouts /
build dirs do not share cache.

New opt-in configure --enable-ccache-prefix-map adds
  -ffile-prefix-map=${MAGICSRC}=.
to CFLAGS (requires ccache; the flag is probed for GCC-8+/clang support and
skipped with a warning otherwise).  This relativizes the source paths embedded
in the compiled output (__FILE__, debug info) so a cached object is valid
regardless of which tree produced it.

Off by default: it makes debug paths relative, so gdb then needs
`set substitute-path . <srcdir>`.  It is only for cross-tree *correctness* and
must be paired with CCACHE_BASEDIR=<build top> in the environment for cross-tree
*hits* (that half normalizes the command-line paths in the hash; this half keeps
the cached output tree-neutral).  Same-tree caching needs neither.

Verified: default/--disable-ccache carry no -ffile-prefix-map;
--enable-ccache-prefix-map (probe "yes") adds it, and with --disable-ccache it
warns and is ignored.  Full build rc=0 (375 files); the installed tclmagic.so
contains zero absolute /work/magic paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 5719a536e8 build: autodetect ccache (configure --disable-ccache to opt out)
When ccache is on PATH, prefix CC/CXX with it so every compile goes through
ccache -- no Makefile change, since rules.mak already runs `${CC} ... -c` and
defs.mak substitutes @CC@/@CXX@.  Autodetected on by default; --disable-ccache
opts out.

Placed after the AC_PROG_C* checks so configure's own feature tests use the
plain compiler and only the build picks up the prefix.  Pairs with the
build-info isolation (utils/buildinfo.c): with the volatile MAGIC_BUILDDATE on
only that one unit, a full rebuild hits the cache for every other unit.

Measured (default Tcl build, all objects deleted then rebuilt): 323/324 hits
with the date enabled (only buildinfo.o misses), 324/324 with
--disable-magic-builddate.

Verified: default configure -> CC="ccache gcc", CXX="ccache g++";
--disable-ccache -> CC="gcc".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles a9edf1a97d build: add --disable-magic-builddate (reproducible, ccache-stable builds)
New configure option --disable-magic-builddate omits the build date from the
binary.  It is wired via an AC_SUBST'd MAGIC_BUILDDATE_DEFS (not AC_DEFINE), so
it reaches only buildinfo.o rather than @DEFS@ / every command line:

  * enabled (default): buildinfo.o gets -DMAGIC_BUILDDATE="<date>" and defs.mak
    computes the date (SOURCE_DATE_EPOCH-aware);
  * disabled: buildinfo.o gets -DMAGIC_NO_BUILDDATE instead, defs.mak skips the
    date computation entirely (no parse-time `date` spawn), and buildinfo.c
    reports an empty MagicCompileTime.

This gives a fully reproducible build whose one volatile input (the date) is
gone; what remains in buildinfo.o is commit/version/revision, which do not
change second-to-second -- the intended pairing with ccache for day-to-day
development.

Verified both configs: default bakes the date + commit; --disable-magic-builddate
compiles buildinfo.o with -DMAGIC_NO_BUILDDATE (no date), commit still present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 20911acc49 build: honor SOURCE_DATE_EPOCH for the build date; graceful git fallback
MAGIC_BUILDDATE now derives from SOURCE_DATE_EPOCH (UTC) when it is set,
falling back to the current local time otherwise.  This makes the date baked
into buildinfo.o reproducible for the appimage/npm tarballs (cf. npm/pack.sh,
which already normalizes mtimes).

Also add `2>/dev/null` to the MAGIC_COMMIT git call so a source tarball or a
non-work-tree ${MAGICSRC} yields an empty commit rather than a git error.

Only buildinfo.o consumes these (see the prior commit), so the shell still
runs at defs.mak parse time but affects just that one unit's define.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles b3d6540f13 build: isolate build-info defines into utils/buildinfo.c (ccache-friendly)
MAGIC_VERSION / MAGIC_REVISION / MAGIC_COMMIT / MAGIC_BUILDDATE were on the
global DFLAGS, so every object's compile command line carried them.  Because
the command line is part of ccache/sccache's hash key and MAGIC_BUILDDATE
changes every second, that meant a cache miss on every unit on every build;
it also smeared the baked-in date/commit across "whenever each file last
recompiled".

Move the four values into a single translation unit:
  * utils/magic_buildinfo.h -- extern MagicVersion/MagicRevision/MagicCommit/
    MagicCompileTime (MagicCommit is new; the other three moved here from
    utils/magic.h, which now includes this header).
  * utils/buildinfo.c -- the ONLY unit compiled with the version defines
    (target-specific `buildinfo.o: DFLAGS += ${DFLAGS_MAGICVERSION}` in
    utils/Makefile.in); it defines the four globals.  ${DFLAGS_MAGICVERSION}
    is removed from the global DFLAGS/DFLAGS_NOSTUB.

Consumers updated to read the runtime symbol instead of the compile-time
macro:
  * magicTop.c / tclmagic.c no longer define the globals (the MAGIC_WRAPPER
    duplicate-symbol guard is gone -- buildinfo.o owns them for every variant,
    including WASM, which links both mains).
  * Tcl_PkgProvide/PkgRequire in router/ext2spice/lef/ext2sim/plot/tclmagic
    now pass MagicVersion.
  * extflat: EFVersion (a static-initialized copy of MAGIC_VERSION) is dropped;
    EFread.c compares the .ext version against MagicVersion directly -- the same
    value ExtCell.c already *writes* into .ext files, so read and write are now
    consistent.

Verified: only buildinfo.o carries -DMAGIC_* (hash/DBio/windCmdSZ carry none);
Tcl (375 files) and --without-tcl builds rc=0, version/commit/date embedded in
tclmagic.so, magicTop.o no longer defines MagicVersion; in-tree source clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 465e946f2e gitignore: ignore npm/examples/output-tcl/ (tcl smoke-test output)
The tcl smoke test writes generated artifacts to npm/examples/output-tcl/,
mirroring the already-ignored notcl npm/examples/output/.  Ignore it too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 1adce493eb wasm: embed scmos display styles/colour maps (fix out-of-source init)
The WASM link embeds ${MAGICDIR}/scmos (the build tree) at the VFS sys dir,
which out of source holds only the *generated* tech files.  A technology's
"styles" section (styletype mos) also needs the display styles and colour
maps -- scmos ${FILES}: mos.*.dstyle / mos.*.cmap -- which are *source*
files absent from the build tree.  So magic_wasm_init failed:

  Couldn't open color map file "mos.7bit.std.cmap"
  ... minimum.tech ... [styles] ... Cannot load technology "minimum"

(In-tree this never showed because build == source.  It was also masked
until now behind the wasmBinary/INCOMING_MODULE_JS_API abort.)

Embed each display file from the source tree into the same VFS dir via
$(wildcard), which matches only files that exist -- so a stale/typo'd name
in ${FILES} (e.g. the non-existent mos.7bit.mraster_dstyle) can't break the
link.

Verified on emsdk 6.0.3, both variants: smoke tests now pass 4/4 (notcl)
and 5/5 (tcl).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 752d80ba01 wasm: pin INCOMING_MODULE_JS_API (fixes wasmBinary abort on emsdk 6.x)
Emscripten's default INCOMING_MODULE_JS_API list dropped `wasmBinary`
(present through ~4.x, gone by 6.0.x).  With -sASSERTIONS=1 a caller that
sets Module.wasmBinary — as the npm harness and the documented API do —
then aborts at instantiation:

  Aborted(`Module.wasmBinary` was supplied but `wasmBinary` not included
          in INCOMING_MODULE_JS_API)

Set the list explicitly so the build no longer depends on Emscripten's
default (which drifts between emsdk versions).  Allow the properties that
matter for embedding/consuming the .wasm across node/web/worker:

  print, printErr             stdout/stderr callbacks
  wasmBinary, wasm            supply the module as bytes / a compiled Module
  instantiateWasm, locateFile custom instantiation (streaming/caching/
                              bundlers) and .wasm URL resolution

`arguments` is intentionally omitted: main() is defined but never run
(magic is driven through the magic_wasm_* exports), so argv is inert here.

Verified on emsdk 6.0.2 and 6.0.3: the wasmBinary abort is gone and the
module instantiates (0 INCOMING aborts in the smoke run on either).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles b2c35f8249 build: make the psfigures symlink source-safe and -j-safe
Out-of-tree, doc/latexfiles points a build-tree ../psfigures at the source
copy so latex/dvips resolve ../psfigures/*.ps.  The old
`test -e ../psfigures || ln -s ... ../psfigures` had two defects:

  * Under a parallel docs build two .ps jobs could both see ../psfigures
    absent and both run `ln -s`.  The second `ln -s DIR symlink-to-dir`
    nests the link *inside* the target, writing a stray
    doc/psfigures/psfigures INTO THE SOURCE TREE -- an out-of-tree build
    must never modify source.
  * (An order-only make prerequisite is not a fix here: VPATH makes make
    "find" ../psfigures in the source tree and skip creating the build link
    latex actually needs.)

Use a shell test (VPATH-immune) that is both idempotent and race/nest safe:
`test -d ../psfigures || ln -sfn ${MAGICSRC}/doc/psfigures ../psfigures`.
`test -d` is true in-tree (real source dir) and once the build symlink
exists; `ln -sfn` (force + no-dereference) replaces an existing symlink in
place instead of nesting inside it.

Verified in/out of tree under -j12: 28/28 docs, correct single-level build
symlink, source tree never touched (in-tree psfigures stays a real dir).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 145e7cb8ad doc: fix maint1.tex LaTeX errors so it compiles (docs 28/28)
maint1.tex failed to build -- it was the one document that never
regenerated -- because of three source-level LaTeX errors, each masked by
the one before it:

  * `gdb program $pid`: a bare `$` opens math mode (meant literally), which
    was never closed, so `\endi` hit "Missing $ inserted" / Emergency stop.
    Escaped to `\$pid`.
  * `{\itshape process_ID}` (x2): a bare `_` is a math-mode subscript in
    text.  Escaped to `process\_ID`.
  * a tabbing block (`\ii ps -C wish` before `\ii gdb ...`, and the
    `gdb wish / run / set argc / set argv / source` block) was missing its
    `\\` row separators, so multiple `\ii` (= \>\>\>) accumulated in one row
    and overran the 4 tab stops -> "Undefined tab position".  Added the
    missing `\\`.

maint1 now compiles cleanly (two-pass, 0 errors) and `make all` in
doc/latexfiles produces 28/28 PostScript files instead of 27/28.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 9bd4957fa9 build: -j correctness — database archive edge + serial docs
Two fixes make a parallel `make -jN` deterministic:

1. lib@database: module@tiles module@utils.  libdatabase.a physically
   archives tiles/libtiles.o and utils/libutils.o (database/Makefile.in
   LIB_OBJS +=), so lib@database must wait for those module objects.  A
   serial build got this from prerequisite order; under -j it was a latent
   race (it happened to win most of the time because tiles/utils are quick).
   Audited all Makefile.in: no other default-built module archives another
   module's objects (magic's EXTRA_LIBS is covered by main@: modules libs;
   the ext2*/router tools are not in the default build).

2. docs runs the doc/latexfiles sub-make with -j1.  Those rules share
   per-run .aux/.log files in one directory and are not parallel-safe;
   under an inherited jobserver they raced and dropped documents (5-9 of 28
   failed under -j vs 1 serial).  Doc regeneration is best-effort (pre-built
   PostScript is the install fallback), so forcing it serial costs nothing.

Verified: 5x clean out-of-tree `make -j12` all rc=0 with zero core-build
errors and a stable 27/28 docs; in-tree -j12 installs 375 files;
--without-tcl -j12 builds readline + magic.  Serial behaviour unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles e84e353a40 build: declarative subdir recursion, no for-loops/FORCE
Replace the shell `for dir` loops and the FORCE pattern-rule hack with a
uniform per-directory PHONY target scheme: each (phase, dir) is a target
"<phase>@<dir>" that recurses into <dir> with that phase's goal via
$(submake), and each phase aggregate (depend, modules, libs, techs,
install, install-tcl, clean, mains, tcllibrary) is just the list of its
per-dir targets as prerequisites.

Inter-phase ordering moves from the aggregate onto the per-dir targets
(module@/lib@/tech@ each require `depend`; main@ requires modules+libs),
so the dependency graph is correct under `make -jN`, not only in a
left-to-right serial build.  '@' is a safe namespace char (never in a real
target name).  readline/ still takes the -f path inside $(submake).

The `depend` rule is left as real file targets (<dir>/Depend) so Depend is
still regenerated incrementally, not on every build.  clean-mains loses its
one-iteration shell loop too.

The one cross-module edge (libdatabase.a needs tiles/utils modules first)
is preserved by prerequisite order for serial builds here; its explicit
-j edge is fixed in the following commit.

Verified serial rc=0, 375 files, identical installs in-tree and
out-of-tree; --without-tcl builds readline + magic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 2b4fcf5968 build: include rules.mak from source, drop the build-top copy
rules.mak has no @...@ substitutions, so there is no reason to copy it into
the build top.  Point all 38 subdir Makefile.in includes at the source copy
directly -- ${MAGICSRC}/rules.mak instead of ${MAGICDIR}/rules.mak -- and
remove AC_CONFIG_FILES([rules.mak:rules.mak]) from configure.  defs.mak (the
one make fragment with substitutions) remains the only generated file in the
build top.  readline/ and the top Makefile never included rules.mak, so they
are unaffected; AC_CONFIG_SRCDIR(rules.mak) (the srcdir sentinel) is kept.

Now editing rules.mak in the source tree takes effect without reconfiguring.

Verified rc=0, 375 files, both in-tree and out-of-tree; out-of-tree build
top has no rules.mak; distclean rc=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 69dff2aaa8 build: reduce the srcdir derivation to a minimal fallback
Every converted module sets srcdir=@srcdir@ and VPATH=@srcdir@
before including defs.mak, so the full srcdir derivation is now reached
only by readline/ (never converted) and the top-level Makefile.  Neither
compiles magic sources through the pattern rules, so neither needs VPATH.

Drop the MODULE_SUBPATH variable and the VPATH derivation; keep just a
one-line srcdir fallback so CPPFLAGS (-I${srcdir}) stays well-formed for
those two.  BUILD_TOP is retained (GENINC still needs it).

Verified rc=0: out-of-tree Tcl (375) + in-tree Tcl (375, header present) +
out-of-tree --without-tcl (readline/libreadline.a + magic/magic built
through the fallback).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 79e6863aa8 build: make the -f recursion path readline-specific
Every module is now a configure-generated Makefile, so the
generic "use -f if there is no build Makefile" fallback in $(submake) and
in the clean loop is only ever reached by readline/ (the one module that
is intentionally never converted).

Replace the generic `test -f $dir/Makefile` probe with an explicit
`$dir = readline` check: recurse natively everywhere, take the -f path
(against the source Makefile, creating the build subdir on demand) only
for readline.  A converted module whose build Makefile is somehow missing
now fails loudly instead of silently falling back to -f.

Verified out-of-tree: default (Tcl) make+install+clean rc=0 (375 files);
--without-tcl make+clean rc=0 with readline/libreadline.a + magic/magic
built through the readline -f path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 54a5a919bb build: doc/html install ships only content, not build files
The doc/html install tar'd the whole $(srcdir), so it shipped Makefile.in
(always) and, for an in-tree build, the config.status-generated Makefile,
into $CAD_ROOT/magic/doc/html/.  That also made the install differ
in-tree (377 files) vs out-of-tree (376).

Exclude ./Makefile and ./Makefile.in from the tar.  The install now
contains only the 148 HTML files (+ subdirs) and is identical in-tree and
out-of-tree (375 files).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles f2c77ad927 build: nested-child Makefile.in use @srcdir@
Switch the 5 nested children (scmos/cif_template, doc/man, doc/tutcells,
doc/html, doc/latexfiles) to configure-provided substitution:
  srcdir   = @srcdir@
  VPATH    = @srcdir@
  MAGICDIR = @top_builddir@   (resolves to ../.. for these nested dirs)

Verified out-of-tree: full `make` rc=0; cif_template gets
srcdir=<src>/scmos/cif_template, doc/latexfiles MAGICDIR=../..; scmos
techs + 27/28 docs build.

With this, every module except readline/ is a configure-generated
Makefile.in using @srcdir@ substitution.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles d2650e4833 build: convert nested children + rewire parent recursion to native
Convert the last nested children to Makefile.in and switch their parents
from the -f fallback to native recursion (they now have generated build
Makefiles).  Rename and rewire are one unit: a pure rename would break the
parent's -f path to the (now-.in) child.

Converted (5): scmos/cif_template, doc/man, doc/tutcells, doc/html,
doc/latexfiles.  Pure renames -- still build via the srcdir derivation;
@srcdir@ substitution follows.

Rewired to native `make -C <child>` (config.status now creates the child
build dirs + Makefiles):
* scmos/Makefile.in: cif_template build + clean.
* doc/Makefile.in: install/install-tcl over man/tutcells/html/latexfiles.
* Makefile.in: the docs: target -> `make -k -C doc/latexfiles all`.
The `mkdir -p` and `-f ${MAGICSRC}/.../Makefile` are dropped in each.

* configure.in: AC_CONFIG_FILES for the 5 children; regenerated configure.
* .gitignore: ignore each generated child Makefile, same commit.

Verified out-of-tree: full `make && make install` rc=0, 376 files --
scmos recurses natively into cif_template (8 objs), docs regenerate via
native doc/latexfiles (27/28), man pages install via native doc/man.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 162db537d8 build: magic/tcltk/scmos/doc/lisp Makefile.in use @srcdir@
Switch the 5 top-level outlier modules to configure-provided substitution
(same template as the rest):
  srcdir   = @srcdir@
  VPATH    = @srcdir@
  MAGICDIR = @top_builddir@
Their custom rules and ${MAGICDIR}/${MAGICSRC} references keep working:
${MAGICDIR} = @top_builddir@ (build top), $(srcdir) now from @srcdir@.
scmos/doc still recurse into their (static) children via -f.

Verified out-of-tree: full `make` rc=0 -- magic gets srcdir=<src>/magic,
tclmagic.so + scmos techs + 27/28 docs build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 887eca61fe build: generate magic/tcltk/scmos/doc/lisp Makefiles from Makefile.in (rename unit)
Fourth batch of the Makefile.in migration: the top-level complex outliers
  magic tcltk scmos doc lisp
Pure renames -- content unchanged, so each still builds via the defs.mak
srcdir derivation; the @srcdir@ substitution follows.

Their nested children (scmos/cif_template and doc/{man,tutcells,html,
latexfiles}) are intentionally NOT converted here: scmos and doc recurse
into them with `-f ${MAGICSRC}/.../Makefile`, which keeps working only
while those children remain static Makefiles.  They convert in a later
step together with the parent-recursion updates.

* git mv <dir>/Makefile -> <dir>/Makefile.in (5 modules)
* configure.in: AC_CONFIG_FILES for each; regenerated configure.
* .gitignore: ignore each generated <dir>/Makefile, same commit.

Verified out-of-tree: full `make` rc=0 -- tclmagic.so, scmos techs (scmos
recurses into the static cif_template via -f, 8 objs), 27/28 docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles a560226757 build: near-standard + outlier Makefile.in use @srcdir@
Switch the 13 near-standard/outlier modules to configure-provided
substitution (same template as the standard modules):
  srcdir   = @srcdir@
  VPATH    = @srcdir@
  MAGICDIR = @top_builddir@
Their sibling-object refs (${MAGICDIR}/<mod>/lib*.o) and custom rules are
unchanged: ${MAGICDIR} = @top_builddir@ (the build top) so the sibling
objects resolve into the build tree, and $(srcdir) now comes from
@srcdir@ instead of the derivation.

Verified out-of-tree: `make modules libs` builds all 33 module libraries;
the five Tcl auto-load libraries (magiclef.so, tclplot.so, tclroute.so,
exttospice.so, exttosim.so) link (sibling refs resolve to the build top).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles fe70666b0c build: generate near-standard + outlier Makefiles from Makefile.in (rename unit)
Third batch of the Makefile.in migration: near-standard modules
(utils windows commands database) and the program/.so outliers
(lef plot router ext2spice ext2sim extcheck net2ir graphics oa).
Pure renames -- content unchanged, so each still builds via the defs.mak
srcdir derivation; the @srcdir@ substitution follows.

* git mv <dir>/Makefile -> <dir>/Makefile.in (13 modules)
* configure.in: AC_CONFIG_FILES for each; regenerated configure.
* .gitignore: ignore each generated <dir>/Makefile, same commit.

These modules carry sibling-object refs (${MAGICDIR}/<mod>/lib*.o) and
custom rules; those keep working unchanged (${MAGICDIR} = the build top,
$(srcdir) from the derivation).  readline/ remains on the -f path.

Verified out-of-tree: config.status writes 35 module Makefiles (22 + 13);
`make modules libs` builds all 33 module libraries (rc=0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 4fd85ee844 build: standard-module Makefile.in use @srcdir@ substitution
Switch the 21 standard modules from the defs.mak srcdir derivation to
configure-provided substitution (same template as tiles):
  srcdir   = @srcdir@
  VPATH    = @srcdir@
  MAGICDIR = @top_builddir@
defs.mak's dual-mode guard sees `srcdir` already set (origin=file) and
skips the srcdir derivation for these modules.

Verified out-of-tree: config.status writes srcdir=<src>/<mod> into each
build/<mod>/Makefile; `make modules libs` builds all 33 module libraries
(lib*.o + lib*.a, rc=0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 02d2147753 build: generate 21 standard-module Makefiles from Makefile.in (rename unit)
Second batch of the Makefile.in migration: the remaining standard modules
  bplane calma cif cmwind dbwind debug drc extflat extract garouter gcr
  grouter irouter mzrouter netmenu plow resis select sim textio wiring
Pure renames -- content unchanged, so each still builds via the defs.mak
srcdir derivation (dual mode); the @srcdir@ substitution follows.

* git mv <dir>/Makefile -> <dir>/Makefile.in (21 modules)
* configure.in: AC_CONFIG_FILES for each; regenerated configure.  Their
  build subdirs + Makefiles are now created by config.status, so
  $(submake) recurses natively (make -C <dir>), no -f.
* .gitignore: ignore each generated <dir>/Makefile, in this same commit.

Verified out-of-tree: config.status writes 22 module Makefiles (these 21 +
tiles); `make modules` builds all 33 module libraries (rc=0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 2ee689084a build: tiles/Makefile.in uses @srcdir@ substitution
Switch tiles from the defs.mak srcdir *derivation* to configure-provided
substitution:
  srcdir   = @srcdir@
  VPATH    = @srcdir@
  MAGICDIR = @top_builddir@
defs.mak's dual-mode guard now sees `srcdir` already set (origin=file) and
skips the $(abspath)/$(patsubst) srcdir computation for this module.

Verified: config.status writes srcdir=<src>/tiles into build/tiles/Makefile;
make -C tiles module compiles from that srcdir (libtiles.o, rc=0) with the
derivation bypassed.  This is the template the remaining modules follow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 214cc43f4a build: generate tiles/Makefile from tiles/Makefile.in (rename unit)
First module of the Makefile.in migration (proof).  Pure rename: the
Makefile content is unchanged, so config.status just copies it and the
module still builds via the defs.mak srcdir *derivation* (dual mode from
phase 1) -- the @srcdir@ substitution is a separate follow-up.

* git mv tiles/Makefile -> tiles/Makefile.in
* configure.in: AC_CONFIG_FILES([tiles/Makefile:tiles/Makefile.in]);
  regenerated configure.  config.status now creates build/tiles/Makefile,
  so $(submake) recurses into tiles natively (make -C tiles), no -f.
* .gitignore: ignore the generated tiles/Makefile (in-tree it lands in the
  source tree) -- added in this same commit so it can never be committed.

Verified out-of-tree: config.status writes build/tiles/Makefile,
make -C tiles module builds libtiles.o (rc=0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 242d415788 build: accept @srcdir@-substituted subdir Makefiles
Enabler for the Makefile -> Makefile.in migration.  No module is
converted yet; behaviour is identical.

* scripts/defs.mak.in: dual-mode.  A module converted to Makefile.in will
  set `srcdir` (and VPATH) from @srcdir@ before including defs.mak; only
  derive them (the $(abspath)/$(patsubst) srcdir computation) when it
  did not -- `ifeq ($(origin srcdir),undefined)`.  BUILD_TOP (needed by
  GENINC) is computed either way.

* Makefile.in: route every subdir recursion through a single helper,
      $(call submake,<dir>,<goal>)
  which uses the generated build Makefile if config.status made one there
  (a converted Makefile.in) and otherwise falls back to the source
  Makefile with -f.  Today nothing is converted, so out-of-tree always
  takes the -f path and in-tree uses the (identical) static Makefile
  natively.  clean/ keeps its own no-mkdir variant.  readline/ is
  intentionally never converted and always takes -f.

* .gitignore: document the migration policy -- each converted module adds
  its generated "<dir>/Makefile" here in the same commit so an in-tree
  build can never commit a generated Makefile.  (None converted yet.)

Verified in-tree and out-of-tree: `configure && make && make install`
each produce 376 files with the header in the right place (database/
database.h in-tree, include/database/database.h relocated), 27/28 docs,
source tree clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 64d2ad8df7 build: generate <magic/autoconf/config.h> from configure
Emit an autoconf config header carrying every autoconf define -- at least
all the -D options that appear on the compiler command lines, plus
anything else configure knows -- available to the tree as
    #include <magic/autoconf/config.h>

It is built directly from confdefs.h just before AC_OUTPUT (which removes
that file), NOT via AC_CONFIG_HEADERS.  This is deliberate:

  * AC_CONFIG_HEADERS would rewrite @DEFS@ to -DHAVE_CONFIG_H and move the
    defines into the header, changing every compiler command line and
    breaking the build until sources #include it.  Building from confdefs.h
    leaves @DEFS@ (and the whole build) exactly as-is, so the header is a
    pure additional artifact with no consumers yet.
  * confdefs.h already holds every AC_DEFINE, including the many that have
    no autoheader template (CALMA_MODULE, HAVE_READLINE, ...), which
    AC_CONFIG_HEADERS/autoheader would have dropped.

Location mirrors the generated database.h (defs.mak GENINC): magic/autoconf/
config.h at the build top when in-tree (build dir == source dir), else
include/magic/autoconf/config.h so the clean -I include/ rule finds it and
the raw build dir stays off the search path.  The directory is created on
demand and the header is rewritten on every ./configure.  No defs.mak.in
change is needed -- the existing -I${GENINC} already resolves it.

.gitignore: ignore the in-tree magic/autoconf/config.h (out-of-tree it is
under the build dir and already ignored).

Verified: out-of-tree writes include/magic/autoconf/config.h, in-tree
writes magic/autoconf/config.h; both contain the command-line defines
(SIZEOF_VOID_P, CALMA_MODULE, HAVE_*, ...); #include <magic/autoconf/
config.h> resolves via -I${GENINC} from a subdir; @DEFS@ is unchanged
(-DHAVE_CONFIG_H absent) and modules still build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles b21b20364b build: add "make prepare" and use it in docs/CI instead of database.h path
The generated header's path now depends on in-tree vs relocated builds
(database/database.h vs include/database/database.h), so instructions
that named it directly ("make database/database.h") are brittle.

Add a stable, path-independent top-level target:

    .PHONY: prepare
    prepare: ${DATABASE_H}

Being .PHONY the name is always valid, but its prerequisite is the real
file target ${DATABASE_H}, so the header is still regenerated only when
out of date -- same result, no exposed path.

Convert every "make database/database.h" in the docs, appimage
Dockerfiles, and CI workflows to "make prepare".

Verified: relocated `make prepare` generates include/database/database.h;
re-running is a no-op; touching database.h.in triggers regeneration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 1bdc3fa12a build: put the generated header under include/ for relocated builds
Previously the generated database/database.h was written to the build
top and exposed with -I${MAGICDIR}.  Out-of-tree that placed the raw
build directory on the compiler's include search path.

Introduce ${GENINC}, the single include dir for generated headers:
  * in-tree  (build top == source top): ${MAGICDIR}, so the header stays
    at $(builddir)/database/database.h and -I${GENINC} is exactly the old
    -I${MAGICDIR} -- behaviour is unchanged.
  * relocated (out-of-tree): ${MAGICDIR}/include, so the header is written
    to $(builddir)/include/database/database.h and only that clean
    include/ dir is on the search path; the raw build top never is.

* scripts/defs.mak.in: derive GENINC from BUILD_TOP vs MAGICSRC; add
  DATABASE_H = ${GENINC}/database/database.h; CPPFLAGS uses -I${GENINC}.
* Makefile.in: the makedbh rule targets ${DATABASE_H} (mkdir its dir);
  every prereq and the distclean use ${DATABASE_H}.
* database/Makefile: the fallback delegate targets ${DATABASE_H}.

Verified: relocated `make modules` builds all 33 module libraries with
the header at build/include/database/database.h and no raw build-top on
any -I line; in-tree the header stays at database/database.h and the
-I set is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00
Darryl L. Miles 955a61aeda ci: build the Tcl auto-load modules and add a non-Tcl build job
Extend the Linux CI so consumers exercise more of what is buildable:

* In the Tcl job, after the default build, also build the per-module Tcl
  auto-load shared libraries (lef/plot/router/ext2spice/ext2sim
  tcl-main -> magiclef.so, tclplot.so, tclroute.so, exttospice.so,
  exttosim.so).  These are real products the default target never builds,
  so building them in CI keeps them from bit-rotting.

* Add a standard_build_linux job for the non-Tcl configuration
  (./configure --without-tcl): the native magic binary + bundled GNU
  readline -- code paths the Tcl build does not cover, and which only
  build now that the bundled-readline out-of-tree fixes landed.

NB: the standard job's apt package set is not validated on the runner;
adjust if a library is not found.  Docs remain best-effort in both jobs.

Not changed here: whether the five auto-load .so should also be shipped
by the default "make install" (they currently are not) -- left as a
separate decision.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:54:11 -04:00