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>
This commit is contained in:
Darryl L. Miles 2026-07-23 22:06:28 +00:00 committed by R. Timothy Edwards
parent aab3361858
commit 201b27e4e9
8 changed files with 161 additions and 0 deletions

8
.gitignore vendored
View File

@ -10,6 +10,14 @@ scripts/defs.mak
# produced from Makefile.in, and config.status runs in the build directory.
/Makefile
/config.status
# Build-tree launch helpers (configure-generated) + the CAD_ROOT symlink tree they
# stage; in-tree these land in the source root.
/run_magic.sh
/run_magicnull.sh
/run_magic_gdb.sh
/run_magic_valgrind.sh
/magic_run_common.sh
/CAD_DIR/
install.log
make.log
reconfigure.sh

20
scripts/configure vendored
View File

@ -9509,6 +9509,17 @@ ac_config_files="$ac_config_files defs.mak:scripts/defs.mak.in"
ac_config_files="$ac_config_files scripts/makedbh:scripts/makedbh.in"
ac_config_files="$ac_config_files magic_run_common.sh:scripts/magic_run_common.sh.in"
ac_config_files="$ac_config_files run_magic.sh:scripts/run_magic.sh.in"
ac_config_files="$ac_config_files run_magicnull.sh:scripts/run_magicnull.sh.in"
ac_config_files="$ac_config_files run_magic_gdb.sh:scripts/run_magic_gdb.sh.in"
ac_config_files="$ac_config_files run_magic_valgrind.sh:scripts/run_magic_valgrind.sh.in"
ac_config_files="$ac_config_files tiles/Makefile:tiles/Makefile.in"
ac_config_files="$ac_config_files bplane/Makefile:bplane/Makefile.in"
@ -10327,6 +10338,11 @@ do
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile:Makefile.in" ;;
"defs.mak") CONFIG_FILES="$CONFIG_FILES defs.mak:scripts/defs.mak.in" ;;
"scripts/makedbh") CONFIG_FILES="$CONFIG_FILES scripts/makedbh:scripts/makedbh.in" ;;
"magic_run_common.sh") CONFIG_FILES="$CONFIG_FILES magic_run_common.sh:scripts/magic_run_common.sh.in" ;;
"run_magic.sh") CONFIG_FILES="$CONFIG_FILES run_magic.sh:scripts/run_magic.sh.in" ;;
"run_magicnull.sh") CONFIG_FILES="$CONFIG_FILES run_magicnull.sh:scripts/run_magicnull.sh.in" ;;
"run_magic_gdb.sh") CONFIG_FILES="$CONFIG_FILES run_magic_gdb.sh:scripts/run_magic_gdb.sh.in" ;;
"run_magic_valgrind.sh") CONFIG_FILES="$CONFIG_FILES run_magic_valgrind.sh:scripts/run_magic_valgrind.sh.in" ;;
"tiles/Makefile") CONFIG_FILES="$CONFIG_FILES tiles/Makefile:tiles/Makefile.in" ;;
"bplane/Makefile") CONFIG_FILES="$CONFIG_FILES bplane/Makefile:bplane/Makefile.in" ;;
"calma/Makefile") CONFIG_FILES="$CONFIG_FILES calma/Makefile:calma/Makefile.in" ;;
@ -10793,6 +10809,10 @@ which seems to be undefined. Please make sure it is defined" >&2;}
case $ac_file$ac_mode in
"scripts/makedbh":F) chmod +x scripts/makedbh ;;
"run_magic.sh":F) chmod +x run_magic.sh ;;
"run_magicnull.sh":F) chmod +x run_magicnull.sh ;;
"run_magic_gdb.sh":F) chmod +x run_magic_gdb.sh ;;
"run_magic_valgrind.sh":F) chmod +x run_magic_valgrind.sh ;;
esac
done # for ac_tag

View File

@ -2066,6 +2066,14 @@ dnl under build/scripts/ (matching ${SCRIPTS}/makedbh = ${MAGICDIR}/scripts).
AC_CONFIG_FILES([Makefile:Makefile.in])
AC_CONFIG_FILES([defs.mak:scripts/defs.mak.in])
AC_CONFIG_FILES([scripts/makedbh:scripts/makedbh.in], [chmod +x scripts/makedbh])
dnl Build-tree launch helpers: run magic straight from the build dir (no install)
dnl by staging a CAD_ROOT symlink tree and exec-ing the right variant.
AC_CONFIG_FILES([magic_run_common.sh:scripts/magic_run_common.sh.in])
AC_CONFIG_FILES([run_magic.sh:scripts/run_magic.sh.in], [chmod +x run_magic.sh])
AC_CONFIG_FILES([run_magicnull.sh:scripts/run_magicnull.sh.in], [chmod +x run_magicnull.sh])
AC_CONFIG_FILES([run_magic_gdb.sh:scripts/run_magic_gdb.sh.in], [chmod +x run_magic_gdb.sh])
AC_CONFIG_FILES([run_magic_valgrind.sh:scripts/run_magic_valgrind.sh.in], [chmod +x run_magic_valgrind.sh])
dnl rules.mak is included straight from the source tree (${MAGICSRC}/rules.mak),
dnl so it is NOT copied into the build top. Only defs.mak (which has @...@
dnl substitutions) is generated there.

View File

@ -0,0 +1,60 @@
# Shared setup for the run_magic* launchers -- sourced, not run directly.
#
# Generated by configure from scripts/magic_run_common.sh.in. It stages a
# CAD_ROOT directory of *symlinks* into the build (generated) and source trees --
# the same layout `make install` copies, but instantly and always reflecting the
# latest build -- and exports the environment magic needs to start straight from
# the build tree without `make install`.
#
# See magic's runtime file discovery: MAGIC_SYS_PATH = ". $CAD_ROOT/magic/sys
# $CAD_ROOT/magic/sys/current" (utils/paths.h) for tech/glyphs/fonts/styles, the
# system .magicrc at $CAD_ROOT/magic/sys/.magicrc, and (since tcltk/tcldir.h)
# magic.tcl / tclmagic / auto_path at $CAD_ROOT/magic/tcl.
MAGIC_BUILDDIR="@abs_top_builddir@"
MAGIC_SRCDIR="@abs_top_srcdir@"
SHDLIB_EXT="@SHDLIB_EXT@"
CAD_ROOT="${MAGIC_BUILDDIR}/CAD_DIR"
export CAD_ROOT
MAGIC_SYS="${CAD_ROOT}/magic/sys"
MAGIC_TCL="${CAD_ROOT}/magic/tcl"
# (Re)build the symlink layout. Idempotent; `ln -sf` relinks so a rebuilt target
# is always current. Missing globs (a partial build) are tolerated.
magic_stage() {
local b="$MAGIC_BUILDDIR" s="$MAGIC_SRCDIR"
mkdir -p "$MAGIC_SYS" "$MAGIC_TCL"
# --- sys/ : generated tech (build) + display files/glyphs/fonts (source) ---
ln -sf "$b"/scmos/*.tech "$MAGIC_SYS"/ 2>/dev/null || :
ln -sf "$s"/scmos/*.cmap "$s"/scmos/*dstyle "$MAGIC_SYS"/ 2>/dev/null || :
ln -sf "$s"/windows/*.glyphs "$s"/windows/vfont.* "$MAGIC_SYS"/ 2>/dev/null || :
ln -sf "$s"/graphics/*.glyphs "$s"/graphics/*.pt3 "$MAGIC_SYS"/ 2>/dev/null || :
ln -sf "$b"/magic/proto.magicrc "$MAGIC_SYS"/.magicrc 2>/dev/null || :
ln -sf "$b"/magic/proto.initrc "$MAGIC_SYS"/.initrc 2>/dev/null || :
if [ -f "$b"/magic/magicps.pro ]; then
ln -sf "$b"/magic/magicps.pro "$MAGIC_SYS"/ 2>/dev/null || :
else
ln -sf "$s"/magic/magicps.pro "$MAGIC_SYS"/ 2>/dev/null || :
fi
# --- tcl/ : source scripts + generated magic.tcl + .so + execs + bitmaps ---
ln -sf "$s"/tcltk/*.tcl "$MAGIC_TCL"/ 2>/dev/null || :
ln -sf "$b"/tcltk/magic.tcl "$MAGIC_TCL"/ 2>/dev/null || :
ln -sf "$b"/magic/tclmagic${SHDLIB_EXT} "$MAGIC_TCL"/ 2>/dev/null || :
ln -sf "$b"/tcltk/magicexec "$b"/tcltk/magicdnull "$MAGIC_TCL"/ 2>/dev/null || :
# bitmaps is a *directory*: use -n so a re-stage replaces the existing
# symlink instead of dereferencing it and dropping a self-link *inside* the
# source tree (magic/bitmaps/bitmaps -> .../magic/bitmaps).
ln -sfn "$s"/magic/bitmaps "$MAGIC_TCL"/bitmaps 2>/dev/null || :
}
# Fail early with a clear message if the build has not produced the binaries yet.
magic_require_built() {
if [ ! -x "$MAGIC_BUILDDIR/tcltk/magicexec" ] && \
[ ! -x "$MAGIC_BUILDDIR/tcltk/magicdnull" ]; then
echo "error: magic is not built yet -- run 'make' in ${MAGIC_BUILDDIR} first." >&2
exit 1
fi
}

17
scripts/run_magic.sh.in Normal file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
#
# Launch magic (GUI) straight from the build tree -- no `make install` needed.
# Generated by configure from scripts/run_magic.sh.in.
#
# On first run it stages ${builddir}/CAD_DIR (symlinks into the build and source
# trees), then exports CAD_ROOT so magic finds its sys files and Tcl runtime
# there. This is a Cairo/X11 GUI build; magic picks its default device, and you
# can override on the command line, e.g.: ./run_magic.sh -d XR foo.mag
set -eu
here="$(cd "$(dirname "$0")" && pwd)"
. "$here/magic_run_common.sh"
magic_require_built
magic_stage
exec "$MAGIC_TCL/magicexec" -- "$@"

View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
#
# Run magic (GUI) under gdb, straight from the build tree.
# Generated by configure from scripts/run_magic_gdb.sh.in.
#
# For batch/no-GUI debugging (no X needed, reproducible), point gdb at magicdnull
# instead: gdb --args "$MAGIC_TCL/magicdnull" -dnull -nowrapper
set -eu
here="$(cd "$(dirname "$0")" && pwd)"
. "$here/magic_run_common.sh"
magic_require_built
magic_stage
exec gdb --args "$MAGIC_TCL/magicexec" -- "$@"

View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
#
# Run magic under valgrind, straight from the build tree.
# Generated by configure from scripts/run_magic_valgrind.sh.in.
#
# This debugs the GUI binary (magicexec); Tk/X allocations make the output noisy,
# so for real leak hunting prefer the batch binary (fewer moving parts):
# valgrind --leak-check=full "$MAGIC_TCL/magicdnull" -dnull -nowrapper
set -eu
here="$(cd "$(dirname "$0")" && pwd)"
. "$here/magic_run_common.sh"
magic_require_built
magic_stage
exec valgrind --leak-check=full --error-exitcode=0 \
"$MAGIC_TCL/magicexec" -- "$@"

View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
#
# Launch magic in batch / no-GUI mode (-dnull) straight from the build tree.
# Generated by configure from scripts/run_magicnull.sh.in.
#
# Interactive use sources the Tcl startup (magic.tcl) automatically from CAD_ROOT.
# For a non-interactive script piped on stdin, source magic.tcl yourself first:
# printf 'source %s/magic.tcl\n<commands>\n' "$CAD_ROOT/magic/tcl" | ./run_magicnull.sh
set -eu
here="$(cd "$(dirname "$0")" && pwd)"
. "$here/magic_run_common.sh"
magic_require_built
magic_stage
exec "$MAGIC_TCL/magicdnull" -dnull -nowrapper "$@"