From 201b27e4e9f2c10583828e258da01ee0dd48b624 Mon Sep 17 00:00:00 2001 From: "Darryl L. Miles" Date: Thu, 23 Jul 2026 22:06:28 +0000 Subject: [PATCH] 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) --- .gitignore | 8 +++++ scripts/configure | 20 +++++++++++ scripts/configure.in | 8 +++++ scripts/magic_run_common.sh.in | 60 ++++++++++++++++++++++++++++++++ scripts/run_magic.sh.in | 17 +++++++++ scripts/run_magic_gdb.sh.in | 15 ++++++++ scripts/run_magic_valgrind.sh.in | 17 +++++++++ scripts/run_magicnull.sh.in | 16 +++++++++ 8 files changed, 161 insertions(+) create mode 100644 scripts/magic_run_common.sh.in create mode 100644 scripts/run_magic.sh.in create mode 100644 scripts/run_magic_gdb.sh.in create mode 100644 scripts/run_magic_valgrind.sh.in create mode 100644 scripts/run_magicnull.sh.in diff --git a/.gitignore b/.gitignore index f7bc87ae..6f623e06 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/scripts/configure b/scripts/configure index caf93eaf..c0f274c7 100755 --- a/scripts/configure +++ b/scripts/configure @@ -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 diff --git a/scripts/configure.in b/scripts/configure.in index 94ee0c8c..cf93cd69 100644 --- a/scripts/configure.in +++ b/scripts/configure.in @@ -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. diff --git a/scripts/magic_run_common.sh.in b/scripts/magic_run_common.sh.in new file mode 100644 index 00000000..721d7a2c --- /dev/null +++ b/scripts/magic_run_common.sh.in @@ -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 +} diff --git a/scripts/run_magic.sh.in b/scripts/run_magic.sh.in new file mode 100644 index 00000000..1966232e --- /dev/null +++ b/scripts/run_magic.sh.in @@ -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" -- "$@" diff --git a/scripts/run_magic_gdb.sh.in b/scripts/run_magic_gdb.sh.in new file mode 100644 index 00000000..876d9d7b --- /dev/null +++ b/scripts/run_magic_gdb.sh.in @@ -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" -- "$@" diff --git a/scripts/run_magic_valgrind.sh.in b/scripts/run_magic_valgrind.sh.in new file mode 100644 index 00000000..55e90226 --- /dev/null +++ b/scripts/run_magic_valgrind.sh.in @@ -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" -- "$@" diff --git a/scripts/run_magicnull.sh.in b/scripts/run_magicnull.sh.in new file mode 100644 index 00000000..90d7878b --- /dev/null +++ b/scripts/run_magicnull.sh.in @@ -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\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 "$@"