From 869e99f69e1e315f4deb033b7e792373bbebc763 Mon Sep 17 00:00:00 2001 From: "Darryl L. Miles" Date: Thu, 23 Jul 2026 22:49:49 +0000 Subject: [PATCH] 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 --- scripts/magic_run_common.sh.in | 99 ++++++++++++++++++++++++++++++-- scripts/run_magic.sh.in | 29 ++++++++-- scripts/run_magic_gdb.sh.in | 22 ++++++- scripts/run_magic_valgrind.sh.in | 23 ++++++-- scripts/run_magicnull.sh.in | 27 +++++++-- 5 files changed, 180 insertions(+), 20 deletions(-) diff --git a/scripts/magic_run_common.sh.in b/scripts/magic_run_common.sh.in index 721d7a2c..7795cd74 100644 --- a/scripts/magic_run_common.sh.in +++ b/scripts/magic_run_common.sh.in @@ -10,16 +10,104 @@ # $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. +# +# --------------------------------------------------------------------------- +# Environment overrides (every value below can be pre-set in the environment; +# each is initialized with ${VAR:-} so the caller's value wins): +# +# CAD_ROOT Root of the staged runtime tree. Default: the build tree's +# own $builddir/CAD_DIR (a directory of symlinks, created on +# first run). Point it elsewhere to reuse a shared/installed +# tree instead of staging one. +# MAGIC_WISH The "wish" binary magic uses for the Tk console. Default: +# WISH, i.e. the wish detected by configure to match the Tcl/Tk +# this build linked against (--with-tk / --with-wish). A build +# against a non-standard Tk therefore uses the correct absolute +# wish automatically; override to force a different one. +# WISH Same as above; MAGIC_WISH defaults from it. Baked default is +# the configure-detected wish (may be empty on a --disable-tcl +# build -- the launchers use the self-contained magicexec and do +# not require an external wish). +# TCLSH tclsh matching this build's Tcl (--with-tcl). Provided for +# convenience/diagnostics; may be empty if configure found none. +# MAGIC_BUILDDIR Absolute build-tree top. Default: baked @abs_top_builddir@. +# MAGIC_SRCDIR Absolute source-tree top. Default: baked @abs_top_srcdir@. +# +# Any value that is inherited from the environment (or a baked default that no +# longer resolves) is sanity-checked below; problems are reported on stderr as +# non-fatal warnings to aid diagnosis -- see magic_check_env(). +# --------------------------------------------------------------------------- -MAGIC_BUILDDIR="@abs_top_builddir@" -MAGIC_SRCDIR="@abs_top_srcdir@" -SHDLIB_EXT="@SHDLIB_EXT@" +# Record which values the caller supplied (vs. the configure-baked default) so +# diagnostics can name the origin, then fall back to the baked-in defaults. +# ${VAR+x} is "x" only when VAR is already set -- safe under `set -u`. +_origin_MAGIC_BUILDDIR="build default"; [ -n "${MAGIC_BUILDDIR+x}" ] && _origin_MAGIC_BUILDDIR=environment +_origin_MAGIC_SRCDIR="build default"; [ -n "${MAGIC_SRCDIR+x}" ] && _origin_MAGIC_SRCDIR=environment +_origin_CAD_ROOT="build default"; [ -n "${CAD_ROOT+x}" ] && _origin_CAD_ROOT=environment +_origin_WISH="build default"; [ -n "${WISH+x}" ] && _origin_WISH=environment +_origin_MAGIC_WISH="build default"; [ -n "${MAGIC_WISH+x}" ] && _origin_MAGIC_WISH=environment +_origin_TCLSH="build default"; [ -n "${TCLSH+x}" ] && _origin_TCLSH=environment -CAD_ROOT="${MAGIC_BUILDDIR}/CAD_DIR" +MAGIC_BUILDDIR="${MAGIC_BUILDDIR:-@abs_top_builddir@}" +MAGIC_SRCDIR="${MAGIC_SRCDIR:-@abs_top_srcdir@}" +SHDLIB_EXT="${SHDLIB_EXT:-@SHDLIB_EXT@}" + +CAD_ROOT="${CAD_ROOT:-${MAGIC_BUILDDIR}/CAD_DIR}" export CAD_ROOT MAGIC_SYS="${CAD_ROOT}/magic/sys" MAGIC_TCL="${CAD_ROOT}/magic/tcl" +# wish/tclsh that match the Tcl/Tk this tree was configured against. +WISH="${WISH:-@WISH_EXE@}" +TCLSH="${TCLSH:-@TCLSH_EXE@}" +# tkcon.tcl launches the console via ${MAGIC_WISH:=wish}; hand it the matching one. +MAGIC_WISH="${MAGIC_WISH:-$WISH}" +[ -n "$MAGIC_WISH" ] && export MAGIC_WISH + +# One warning helper for all launchers. +magic_warn() { printf 'run_magic: warning: %s\n' "$*" >&2; } + +# _magic_check NAME KIND ORIGIN VALUE +# KIND: mustdir -- must exist and be a directory +# newdir -- may be absent (created later); if present must be a directory +# exec -- must exist, be a regular file, and be executable +# optexec -- empty is fine (feature not configured); else same as exec +_magic_check() { + _n="$1"; _k="$2"; _o="$3"; _v="$4" + case "$_k" in + optexec) [ -n "$_v" ] || return 0; _k=exec ;; + esac + case "$_k" in + mustdir) + [ -d "$_v" ] || magic_warn "\$$_n ($_o) = '$_v' is not a directory (build tree moved or removed?)" ;; + newdir) + { [ ! -e "$_v" ] || [ -d "$_v" ]; } || \ + magic_warn "\$$_n ($_o) = '$_v' exists but is not a directory" ;; + exec) + if [ ! -e "$_v" ]; then + magic_warn "\$$_n ($_o) = '$_v' does not exist" + elif [ ! -f "$_v" ]; then + magic_warn "\$$_n ($_o) = '$_v' is not a regular file" + elif [ ! -x "$_v" ]; then + magic_warn "\$$_n ($_o) = '$_v' is not executable" + fi ;; + esac +} + +# Validate the (possibly environment-inherited) configuration and warn -- never +# fail -- on anything that looks wrong, so a bad override is easy to spot. +magic_check_env() { + _magic_check MAGIC_BUILDDIR mustdir "$_origin_MAGIC_BUILDDIR" "$MAGIC_BUILDDIR" + _magic_check MAGIC_SRCDIR mustdir "$_origin_MAGIC_SRCDIR" "$MAGIC_SRCDIR" + _magic_check CAD_ROOT newdir "$_origin_CAD_ROOT" "$CAD_ROOT" + _magic_check WISH optexec "$_origin_WISH" "$WISH" + # MAGIC_WISH defaults from WISH; only check it separately when it diverges + # (an explicit MAGIC_WISH override) to avoid a duplicate warning. + [ "$MAGIC_WISH" = "$WISH" ] || \ + _magic_check MAGIC_WISH optexec "$_origin_MAGIC_WISH" "$MAGIC_WISH" + _magic_check TCLSH optexec "$_origin_TCLSH" "$TCLSH" +} + # (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() { @@ -58,3 +146,6 @@ magic_require_built() { exit 1 fi } + +# Validate the environment as soon as this file is sourced (warnings only). +magic_check_env diff --git a/scripts/run_magic.sh.in b/scripts/run_magic.sh.in index 1966232e..9882462e 100644 --- a/scripts/run_magic.sh.in +++ b/scripts/run_magic.sh.in @@ -1,12 +1,31 @@ #!/usr/bin/env bash # -# Launch magic (GUI) straight from the build tree -- no `make install` needed. +# run_magic.sh -- launch magic with its GUI straight from the build tree. # 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 +# PURPOSE +# Run the just-built magic *without* `make install`. On first run it stages +# ${builddir}/CAD_DIR (a tree of symlinks into the build and source trees) and +# exports CAD_ROOT so magic finds its tech/glyphs/styles and Tcl runtime there. +# Because it symlinks (never copies), a rebuild is picked up with no re-staging. +# +# USAGE +# ./run_magic.sh [magic-args...] # opens the default graphics device +# ./run_magic.sh -d XR foo.mag # pick a device / load a layout +# ./run_magic.sh -T scmos # start with a given technology +# (needs an X display; for batch/no-GUI use run_magicnull.sh instead.) +# +# This launches the self-contained "magicexec" (a wish replacement linked +# against this build's Tcl/Tk), so it needs no external wish. If magic opens +# its Tk console internally it uses $MAGIC_WISH (see below). +# +# ENVIRONMENT OVERRIDES (all optional; each wins over the baked default) +# CAD_ROOT reuse an alternate runtime tree instead of staging $builddir/CAD_DIR +# MAGIC_WISH wish for the Tk console (default: the configure-matched wish) +# WISH TCLSH wish/tclsh matching this build's Tcl/Tk (--with-tk / --with-tcl) +# MAGIC_BUILDDIR MAGIC_SRCDIR build/source tops (default: baked-in absolutes) +# Inherited values are sanity-checked; problems print as stderr warnings. +# See magic_run_common.sh for the authoritative list and defaults. set -eu here="$(cd "$(dirname "$0")" && pwd)" . "$here/magic_run_common.sh" diff --git a/scripts/run_magic_gdb.sh.in b/scripts/run_magic_gdb.sh.in index 876d9d7b..30d49136 100644 --- a/scripts/run_magic_gdb.sh.in +++ b/scripts/run_magic_gdb.sh.in @@ -1,10 +1,26 @@ #!/usr/bin/env bash # -# Run magic (GUI) under gdb, straight from the build tree. +# run_magic_gdb.sh -- 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 +# PURPOSE +# Debug the just-built magic without `make install`. Stages ${builddir}/CAD_DIR +# (symlinks) on first run, exports CAD_ROOT, then starts gdb on the self-contained +# "magicexec". Symbols come straight from the build tree. +# +# USAGE +# ./run_magic_gdb.sh [magic-args...] # then `run` at the (gdb) prompt +# For batch/no-GUI debugging (no X display needed, reproducible), debug the null +# binary instead: +# gdb --args "$MAGIC_TCL/magicdnull" -dnull -nowrapper +# +# ENVIRONMENT OVERRIDES (all optional; each wins over the baked default) +# CAD_ROOT reuse an alternate runtime tree instead of staging $builddir/CAD_DIR +# MAGIC_WISH wish for the Tk console (default: the configure-matched wish) +# WISH TCLSH wish/tclsh matching this build's Tcl/Tk (--with-tk / --with-tcl) +# MAGIC_BUILDDIR MAGIC_SRCDIR build/source tops (default: baked-in absolutes) +# Inherited values are sanity-checked; problems print as stderr warnings. +# See magic_run_common.sh for the authoritative list and defaults. set -eu here="$(cd "$(dirname "$0")" && pwd)" . "$here/magic_run_common.sh" diff --git a/scripts/run_magic_valgrind.sh.in b/scripts/run_magic_valgrind.sh.in index 55e90226..ba6c09a9 100644 --- a/scripts/run_magic_valgrind.sh.in +++ b/scripts/run_magic_valgrind.sh.in @@ -1,11 +1,26 @@ #!/usr/bin/env bash # -# Run magic under valgrind, straight from the build tree. +# run_magic_valgrind.sh -- 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 +# PURPOSE +# Memory-check the just-built magic without `make install`. Stages +# ${builddir}/CAD_DIR (symlinks) on first run, exports CAD_ROOT, then runs +# valgrind on the self-contained "magicexec". +# +# USAGE +# ./run_magic_valgrind.sh [magic-args...] +# This checks 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 +# +# ENVIRONMENT OVERRIDES (all optional; each wins over the baked default) +# CAD_ROOT reuse an alternate runtime tree instead of staging $builddir/CAD_DIR +# MAGIC_WISH wish for the Tk console (default: the configure-matched wish) +# WISH TCLSH wish/tclsh matching this build's Tcl/Tk (--with-tk / --with-tcl) +# MAGIC_BUILDDIR MAGIC_SRCDIR build/source tops (default: baked-in absolutes) +# Inherited values are sanity-checked; problems print as stderr warnings. +# See magic_run_common.sh for the authoritative list and defaults. set -eu here="$(cd "$(dirname "$0")" && pwd)" . "$here/magic_run_common.sh" diff --git a/scripts/run_magicnull.sh.in b/scripts/run_magicnull.sh.in index 90d7878b..f7ac9463 100644 --- a/scripts/run_magicnull.sh.in +++ b/scripts/run_magicnull.sh.in @@ -1,11 +1,30 @@ #!/usr/bin/env bash # -# Launch magic in batch / no-GUI mode (-dnull) straight from the build tree. +# run_magicnull.sh -- launch magic in batch / no-GUI mode (-dnull) 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 +# PURPOSE +# Run the just-built magic with the null graphics device -- no X display, fully +# scriptable -- without `make install`. Like run_magic.sh it stages +# ${builddir}/CAD_DIR (symlinks) on first run and exports CAD_ROOT so magic +# finds its sys files and Tcl runtime there. Uses the self-contained +# "magicdnull" (no external wish/Tk needed). +# +# USAGE +# ./run_magicnull.sh # interactive Tcl prompt +# ./run_magicnull.sh foo.mag # load a layout, batch +# Interactive (tty) use sources the Tcl startup (magic.tcl) automatically from +# CAD_ROOT. For a non-interactive script piped on stdin, source it yourself: +# printf 'source %s/magic.tcl\n\n' "$CAD_ROOT/magic/tcl" \ +# | ./run_magicnull.sh +# +# ENVIRONMENT OVERRIDES (all optional; each wins over the baked default) +# CAD_ROOT reuse an alternate runtime tree instead of staging $builddir/CAD_DIR +# TCLSH tclsh matching this build's Tcl (--with-tcl); for diagnostics +# MAGIC_BUILDDIR MAGIC_SRCDIR build/source tops (default: baked-in absolutes) +# (WISH/MAGIC_WISH are irrelevant here -- there is no Tk in -dnull mode.) +# Inherited values are sanity-checked; problems print as stderr warnings. +# See magic_run_common.sh for the authoritative list and defaults. set -eu here="$(cd "$(dirname "$0")" && pwd)" . "$here/magic_run_common.sh"