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>
This commit is contained in:
Darryl L. Miles 2026-07-23 14:27:18 +00:00 committed by R. Timothy Edwards
parent 5719a536e8
commit 64614da7a0
3 changed files with 77 additions and 0 deletions

42
scripts/configure vendored
View File

@ -691,6 +691,7 @@ ALLOCA
EGREP
GREP
PERL
CCACHE_PREFIX_MAP_FLAG
CCACHE
SED
RANLIB
@ -762,6 +763,7 @@ ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_ccache
enable_ccache_prefix_map
with_gnu_ld
enable_assertions
enable_debug
@ -1428,6 +1430,7 @@ Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-ccache do not use ccache even if it is installed
--enable-ccache-prefix-map relativize embedded source paths for cross-tree ccache (needs ccache; makes debug paths relative)
--enable-assertions build with fatal assertions enabled
--enable-debug build with fatal debug enabled
--disable-compression disable file compression
@ -4289,6 +4292,45 @@ $as_echo "$as_me: using ccache: CC=\"$CC\"" >&6;}
fi
fi
CCACHE_PREFIX_MAP_FLAG=""
# Check whether --enable-ccache-prefix-map was given.
if test "${enable_ccache_prefix_map+set}" = set; then :
enableval=$enable_ccache_prefix_map;
if test "x$CCACHE" = "x"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-ccache-prefix-map ignored: ccache is not in use" >&5
$as_echo "$as_me: WARNING: --enable-ccache-prefix-map ignored: ccache is not in use" >&2;}
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -ffile-prefix-map" >&5
$as_echo_n "checking whether $CC accepts -ffile-prefix-map... " >&6; }
magic_save_cflags="$CFLAGS"
CFLAGS="$CFLAGS -ffile-prefix-map=/nonexistent=."
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }; CCACHE_PREFIX_MAP_FLAG="-ffile-prefix-map"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: compiler lacks -ffile-prefix-map; not relativizing paths" >&5
$as_echo "$as_me: WARNING: compiler lacks -ffile-prefix-map; not relativizing paths" >&2;}
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$magic_save_cflags"
fi
fi
# Extract the first word of "perl", so it can be a program name with args.
set dummy perl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5

View File

@ -49,6 +49,32 @@ if test "x$enable_ccache" = "xyes"; then
fi
fi
dnl Optional: normalize the absolute source-root prefix embedded in compiled
dnl output (__FILE__, debug info) so a cached object is valid regardless of which
dnl checkout / build dir produced it -- needed for *correct* cross-tree ccache
dnl sharing (which also wants CCACHE_BASEDIR=<build top> in the environment at
dnl build time; see the README). Off by default: it relativizes debug paths, so
dnl gdb then needs `set substitute-path . <srcdir>`. Requires GCC 8+/clang, so
dnl the flag is probed before use. Same-tree cache hits do NOT need this (the
dnl command-line paths already match); it is purely for cross-tree correctness.
CCACHE_PREFIX_MAP_FLAG=""
AC_ARG_ENABLE(ccache-prefix-map,
[ --enable-ccache-prefix-map relativize embedded source paths for cross-tree ccache (needs ccache; makes debug paths relative)],
[
if test "x$CCACHE" = "x"; then
AC_MSG_WARN([--enable-ccache-prefix-map ignored: ccache is not in use])
else
AC_MSG_CHECKING([whether $CC accepts -ffile-prefix-map])
magic_save_cflags="$CFLAGS"
CFLAGS="$CFLAGS -ffile-prefix-map=/nonexistent=."
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
[AC_MSG_RESULT([yes]); CCACHE_PREFIX_MAP_FLAG="-ffile-prefix-map"],
[AC_MSG_RESULT([no]); AC_MSG_WARN([compiler lacks -ffile-prefix-map; not relativizing paths])])
CFLAGS="$magic_save_cflags"
fi
])
AC_SUBST(CCACHE_PREFIX_MAP_FLAG)
AC_PATH_PROG(PERL, perl, no)
AC_SUBST(PERL)

View File

@ -186,6 +186,15 @@ DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DGCORE=\"@GCORE@\"
DFLAGS_NOSTUB += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" @NDEBUG_defs@ @DEBUG_defs@ ${FEATURE_FLAGS}
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@
# Set only by configure --enable-ccache-prefix-map (empty otherwise). Maps the
# absolute source root to "." in the compiled output so a cached object carries
# no tree-specific paths -- required for correct cross-tree ccache sharing (pair
# with CCACHE_BASEDIR=<build top> in the environment for cross-tree *hits*).
CCACHE_PREFIX_MAP_FLAG = @CCACHE_PREFIX_MAP_FLAG@
ifneq (${CCACHE_PREFIX_MAP_FLAG},)
CFLAGS += ${CCACHE_PREFIX_MAP_FLAG}=${MAGICSRC}=.
endif
LDFLAGS = @LDFLAGS@
READLINE_DEFS = @rl_defs@