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>
This commit is contained in:
Darryl L. Miles 2026-07-23 13:55:20 +00:00 committed by R. Timothy Edwards
parent 465e946f2e
commit b3d6540f13
15 changed files with 89 additions and 40 deletions

View File

@ -208,7 +208,7 @@ Exttosim_Init(
{ {
/* Sanity checks! */ /* Sanity checks! */
if (interp == NULL) return TCL_ERROR; if (interp == NULL) return TCL_ERROR;
if (Tcl_PkgRequire(interp, "Tclmagic", MAGIC_VERSION, 0) == NULL) if (Tcl_PkgRequire(interp, "Tclmagic", MagicVersion, 0) == NULL)
return TCL_ERROR; return TCL_ERROR;
if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR; if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR;
@ -225,7 +225,7 @@ Exttosim_Init(
if (WindReplaceCommand(DBWclientID, "ext2sim", CmdExtToSim) < 0) if (WindReplaceCommand(DBWclientID, "ext2sim", CmdExtToSim) < 0)
return TCL_ERROR; return TCL_ERROR;
Tcl_PkgProvide(interp, "Exttosim", MAGIC_VERSION); Tcl_PkgProvide(interp, "Exttosim", MagicVersion);
return TCL_OK; return TCL_OK;
} }

View File

@ -206,7 +206,7 @@ Exttospice_Init(
{ {
/* Sanity checks! */ /* Sanity checks! */
if (interp == NULL) return TCL_ERROR; if (interp == NULL) return TCL_ERROR;
if (Tcl_PkgRequire(interp, "Tclmagic", MAGIC_VERSION, 0) == NULL) if (Tcl_PkgRequire(interp, "Tclmagic", MagicVersion, 0) == NULL)
return TCL_ERROR; return TCL_ERROR;
if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR; if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR;
@ -223,7 +223,7 @@ Exttospice_Init(
if (WindReplaceCommand(DBWclientID, "ext2spice", CmdExtToSpice) < 0) if (WindReplaceCommand(DBWclientID, "ext2spice", CmdExtToSpice) < 0)
return TCL_ERROR; return TCL_ERROR;
Tcl_PkgProvide(interp, "Exttospice", MAGIC_VERSION); Tcl_PkgProvide(interp, "Exttospice", MagicVersion);
return TCL_OK; return TCL_OK;
} }
#endif /* EXT2SPICE_AUTO */ #endif /* EXT2SPICE_AUTO */

View File

@ -52,7 +52,6 @@ char *EFArgTech = NULL; /* -T: Tech specified on command line */
/* Misc globals */ /* Misc globals */
float EFScale = 0.0; /* Uninitialized scale factor */ float EFScale = 0.0; /* Uninitialized scale factor */
char *EFVersion = MAGIC_VERSION;/* Version number of .ext format we read */
char *EFLibPath = NULL; /* Library search path for .ext files */ char *EFLibPath = NULL; /* Library search path for .ext files */
char *EFTech = NULL; char *EFTech = NULL;
char *EFStyle = NULL; /* Start with no extraction style */ char *EFStyle = NULL; /* Start with no extraction style */

View File

@ -575,7 +575,7 @@ resistChanged:
/* version version-number */ /* version version-number */
case VERSION: case VERSION:
if (strcmp(argv[1], EFVersion) != 0) if (strcmp(argv[1], MagicVersion) != 0)
{ {
efReadError( efReadError(
"Cell was extracted using version %s of the extractor.\n", argv[1]); "Cell was extracted using version %s of the extractor.\n", argv[1]);

View File

@ -32,7 +32,6 @@ extern char *EFTech; /* Technology of extracted circuit */
extern char *EFStyle; /* Extraction style of extracted circuit */ extern char *EFStyle; /* Extraction style of extracted circuit */
extern char *EFSearchPath; /* Path to search for .ext files */ extern char *EFSearchPath; /* Path to search for .ext files */
extern char *EFLibPath; /* Library search path */ extern char *EFLibPath; /* Library search path */
extern char *EFVersion; /* Version of extractor we work with */
extern char *EFArgTech; /* Tech file given as command line argument */ extern char *EFArgTech; /* Tech file given as command line argument */
extern bool EFCompat; /* Subtrate backwards-compatibility mode */ extern bool EFCompat; /* Subtrate backwards-compatibility mode */

View File

@ -41,7 +41,7 @@ Magiclef_Init(
{ {
/* Sanity checks! */ /* Sanity checks! */
if (interp == NULL) return TCL_ERROR; if (interp == NULL) return TCL_ERROR;
if (Tcl_PkgRequire(interp, "Tclmagic", MAGIC_VERSION, 0) == NULL) if (Tcl_PkgRequire(interp, "Tclmagic", MagicVersion, 0) == NULL)
return TCL_ERROR; return TCL_ERROR;
if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR; if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR;
@ -57,7 +57,7 @@ Magiclef_Init(
if (WindReplaceCommand(DBWclientID, "def", CmdLef) < 0) if (WindReplaceCommand(DBWclientID, "def", CmdLef) < 0)
return TCL_ERROR; return TCL_ERROR;
Tcl_PkgProvide(interp, "MagicLEF", MAGIC_VERSION); Tcl_PkgProvide(interp, "MagicLEF", MagicVersion);
return TCL_OK; return TCL_OK;
} }

View File

@ -55,18 +55,10 @@ main(int argc, char *argv[])
exit(0); exit(0);
} }
/* String containing the version number of magic. Don't change the string /* MagicVersion / MagicRevision / MagicCompileTime are defined once in
* here, nor its format. It is updated by the Makefile in this directory. * utils/buildinfo.c -- the single unit compiled with the version defines --
* * and declared in utils/magic_buildinfo.h. They used to be defined here (and,
* The version string originates at the top of scripts/config. * for the Tcl build, in tclmagic.c under a MAGIC_WRAPPER guard); consolidating
* * them removes the duplicate-symbol hazard and keeps the volatile build-date
* Under MAGIC_WRAPPER (Tcl-embedded builds), tclmagic.c owns these globals; * define off every compile command line.
* defining them here as well would produce duplicate-symbol errors when both
* objects end up in the same binary (as in the WASM build).
*/ */
#ifndef MAGIC_WRAPPER
char *MagicVersion = MAGIC_VERSION;
char *MagicRevision = MAGIC_REVISION;
char *MagicCompileTime = MAGIC_BUILDDATE;
#endif

View File

@ -44,7 +44,7 @@ Tclplot_Init(interp)
/* Sanity checks! */ /* Sanity checks! */
if (interp == NULL) return TCL_ERROR; if (interp == NULL) return TCL_ERROR;
if (Tcl_PkgRequire(interp, "Tclmagic", MAGIC_VERSION, 0) == NULL) if (Tcl_PkgRequire(interp, "Tclmagic", MagicVersion, 0) == NULL)
return TCL_ERROR; return TCL_ERROR;
if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR; if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR;
@ -67,7 +67,7 @@ Tclplot_Init(interp)
invplot = TechSectionGetMask("plot", NULL); invplot = TechSectionGetMask("plot", NULL);
if (!TechLoad(NULL, invplot)) return TCL_ERROR; if (!TechLoad(NULL, invplot)) return TCL_ERROR;
Tcl_PkgProvide(interp, "Plot", MAGIC_VERSION); Tcl_PkgProvide(interp, "Plot", MagicVersion);
return TCL_OK; return TCL_OK;
} }

View File

@ -51,7 +51,7 @@ Tclroute_Init(interp)
/* Sanity checks! */ /* Sanity checks! */
if (interp == NULL) return TCL_ERROR; if (interp == NULL) return TCL_ERROR;
if (Tcl_PkgRequire(interp, "Tclmagic", MAGIC_VERSION, 0) == NULL) if (Tcl_PkgRequire(interp, "Tclmagic", MagicVersion, 0) == NULL)
return TCL_ERROR; return TCL_ERROR;
if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR; if (Tcl_InitStubs(interp, Tclmagic_InitStubsVersion, 0) == NULL) return TCL_ERROR;
@ -88,7 +88,7 @@ Tclroute_Init(interp)
invsec &= TechSectionGetMask("router", NULL); invsec &= TechSectionGetMask("router", NULL);
if (!TechLoad(NULL, invsec)) return TCL_ERROR; if (!TechLoad(NULL, invsec)) return TCL_ERROR;
Tcl_PkgProvide(interp, "Route", MAGIC_VERSION); Tcl_PkgProvide(interp, "Route", MagicVersion);
return TCL_OK; return TCL_OK;
} }

View File

@ -163,9 +163,9 @@ ifeq (@MAKE_READLINE@,1)
CPPFLAGS += -I${MAGICSRC}/readline CPPFLAGS += -I${MAGICSRC}/readline
endif endif
DFLAGS_MAGICVERSION = -DMAGIC_VERSION=\"${MAGIC_VERSION}\" -DMAGIC_REVISION=\"${MAGIC_REVISION}\" -DMAGIC_COMMIT=\"${MAGIC_COMMIT}\" "-DMAGIC_BUILDDATE=\"${MAGIC_BUILDDATE}\"" DFLAGS_MAGICVERSION = -DMAGIC_VERSION=\"${MAGIC_VERSION}\" -DMAGIC_REVISION=\"${MAGIC_REVISION}\" -DMAGIC_COMMIT=\"${MAGIC_COMMIT}\" "-DMAGIC_BUILDDATE=\"${MAGIC_BUILDDATE}\""
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ ${DFLAGS_MAGICVERSION} -DGCORE=\"@GCORE@\" DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DGCORE=\"@GCORE@\"
DFLAGS += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" @NDEBUG_defs@ @DEBUG_defs@ ${FEATURE_FLAGS} DFLAGS += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" @NDEBUG_defs@ @DEBUG_defs@ ${FEATURE_FLAGS}
DFLAGS_NOSTUB = @extra_defs@ @DEFS@ ${DFLAGS_MAGICVERSION} -DGCORE=\"@GCORE@\" DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DGCORE=\"@GCORE@\"
DFLAGS_NOSTUB += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" @NDEBUG_defs@ @DEBUG_defs@ ${FEATURE_FLAGS} DFLAGS_NOSTUB += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" @NDEBUG_defs@ @DEBUG_defs@ ${FEATURE_FLAGS}
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@ CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@

View File

@ -48,14 +48,11 @@
#include "dbwind/dbwind.h" #include "dbwind/dbwind.h"
/* /*
* String containing the version number of magic. Don't change the string * MagicVersion / MagicRevision / MagicCompileTime are defined once in
* here, nor its format. It is updated by the Makefile in this directory. * utils/buildinfo.c and declared in utils/magic_buildinfo.h (included via
* utils/magic.h). They no longer need a MAGIC_WRAPPER-guarded definition here.
*/ */
char *MagicVersion = MAGIC_VERSION;
char *MagicRevision = MAGIC_REVISION;
char *MagicCompileTime = MAGIC_BUILDDATE;
#if TCL_MAJOR_VERSION < 9 #if TCL_MAJOR_VERSION < 9
const char *Tclmagic_InitStubsVersion = "8.5"; const char *Tclmagic_InitStubsVersion = "8.5";
#else #else
@ -1546,7 +1543,7 @@ Tclmagic_Init(interp)
Tcl_SetVar(interp, "CAD_ROOT", cadroot, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "CAD_ROOT", cadroot, TCL_GLOBAL_ONLY);
} }
Tcl_PkgProvide(interp, "Tclmagic", MAGIC_VERSION); Tcl_PkgProvide(interp, "Tclmagic", MagicVersion);
return TCL_OK; return TCL_OK;
} }

View File

@ -9,7 +9,7 @@ srcdir = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
MAGICDIR = @top_builddir@ MAGICDIR = @top_builddir@
LIB_SRCS = LIBdbio.c LIBmain.c LIBtextio.c LIB_SRCS = LIBdbio.c LIBmain.c LIBtextio.c
SRCS = args.c child.c dqueue.c finddisp.c flock.c flsbuf.c fraction.c \ SRCS = args.c buildinfo.c child.c dqueue.c finddisp.c flock.c flsbuf.c fraction.c \
geometry.c getrect.c hash.c heap.c ihash.c list.c lookup.c \ geometry.c getrect.c hash.c heap.c ihash.c list.c lookup.c \
lookupany.c lookupfull.c macros.c main.c malloc.c match.c \ lookupany.c lookupfull.c macros.c main.c malloc.c match.c \
maxrect.c netlist.c niceabort.c parser.c path.c pathvisit.c \ maxrect.c netlist.c niceabort.c parser.c path.c pathvisit.c \
@ -23,3 +23,9 @@ DFLAGS += ${GR_DFLAGS}
CFLAGS += ${GR_CFLAGS} CFLAGS += ${GR_CFLAGS}
include ${MAGICSRC}/rules.mak include ${MAGICSRC}/rules.mak
# buildinfo.c is the ONLY unit that consumes the version defines; they are no
# longer on the global DFLAGS (that kept the ever-changing MAGIC_BUILDDATE off
# every other compile command line, so ccache/sccache keys stay stable). Apply
# them just here, target-specifically.
buildinfo.o: DFLAGS += ${DFLAGS_MAGICVERSION}

31
utils/buildinfo.c Normal file
View File

@ -0,0 +1,31 @@
/*
* buildinfo.c --
*
* The single translation unit that captures the build-information defines.
*
* This is the ONLY file compiled with -DMAGIC_VERSION / -DMAGIC_REVISION /
* -DMAGIC_COMMIT / -DMAGIC_BUILDDATE (see the buildinfo.o recipe in
* utils/Makefile.in). Isolating them here keeps those defines -- especially the
* ever-changing MAGIC_BUILDDATE -- off every other compile command line, so
* ccache/sccache keys stay stable and the version/date/commit baked into the
* binary are consistent rather than smeared across whenever each object last
* recompiled.
*
* Consumers include "utils/magic_buildinfo.h" and read these externs.
*/
#include "utils/magic_buildinfo.h"
char *MagicVersion = MAGIC_VERSION;
char *MagicRevision = MAGIC_REVISION;
char *MagicCommit = MAGIC_COMMIT;
/*
* MAGIC_BUILDDATE may be disabled at configure time (--disable-magic-builddate)
* for reproducible builds; when it is, MagicCompileTime reports the empty string.
*/
#ifdef MAGIC_NO_BUILDDATE
char *MagicCompileTime = "";
#else
char *MagicCompileTime = MAGIC_BUILDDATE;
#endif

View File

@ -145,9 +145,10 @@ extern char *SysLibPath; /* Path for finding system
/* ------------ Globally-used strings. -------------------------------- */ /* ------------ Globally-used strings. -------------------------------- */
extern char *MagicVersion; /* Build-info globals (MagicVersion / MagicRevision / MagicCommit /
extern char *MagicRevision; * MagicCompileTime) are defined in utils/buildinfo.c -- the one unit compiled
extern char *MagicCompileTime; * with the version defines -- and declared here: */
#include "utils/magic_buildinfo.h"
extern char AbortMessage[]; extern char AbortMessage[];
/* ------------ zlib (compression) support -------------------------------- */ /* ------------ zlib (compression) support -------------------------------- */

24
utils/magic_buildinfo.h Normal file
View File

@ -0,0 +1,24 @@
/*
* magic_buildinfo.h --
*
* Public declarations for the build-information globals: magic's version,
* revision, git commit, and compile date/time.
*
* These are the ONLY symbols initialized from the -DMAGIC_VERSION /
* -DMAGIC_REVISION / -DMAGIC_COMMIT / -DMAGIC_BUILDDATE command-line defines.
* They are defined in exactly one translation unit, utils/buildinfo.c, which is
* the only unit compiled with those defines. Every other unit reads the values
* through these externs, so the volatile build-date/commit values stay off every
* other compile command line (which keeps ccache/sccache keys stable and the
* baked-in date/commit consistent across the whole binary).
*/
#ifndef _MAGIC_BUILDINFO_H
#define _MAGIC_BUILDINFO_H
extern char *MagicVersion; /* e.g. "8.3" (major.minor) */
extern char *MagicRevision; /* e.g. "670" (patch/revision) */
extern char *MagicCommit; /* git commit SHA, or "" if unavailable */
extern char *MagicCompileTime; /* build date/time, or "" if disabled */
#endif /* _MAGIC_BUILDINFO_H */