aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2025-12-31 13:10:20 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2025-12-31 18:51:13 +0000
commit1d52d5c5372a43655a252880d34088fa56aa2530 (patch)
treeff4a755a7099efcbdc0c194fa1bac1d39765af86
parent2c0e9a76c1cee8766245a0b5bdad73e995b790c6 (diff)
depend-cleanup: Force a clean build when options change
Similar to the build epoch check, cache a list of source options in the object tree, and force a clean build if the cached list does not match the current list, after filtering out options which are known not to affect the build (e.g. CLEAN, TESTS, WARNS). This also adds a DEPEND_CLEANUP option (which defaults to yes unless the CLEAN option is set) which can be used to skip depend-cleanup for faster incremental builds. MFC after: 1 week Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D52011
-rw-r--r--Makefile.inc16
-rw-r--r--share/man/man5/src.conf.514
-rw-r--r--share/mk/src.opts.mk5
-rwxr-xr-xtools/build/depend-cleanup.sh61
-rw-r--r--tools/build/options/WITHOUT_DEPEND_CLEANUP5
5 files changed, 79 insertions, 12 deletions
diff --git a/Makefile.inc1 b/Makefile.inc1
index c0bf42c3d008..8966f96de9b9 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -1071,10 +1071,12 @@ _sanity_check: .PHONY .MAKE
# tree changes, particularly with respect to removing source files and
# replacing generated files. Handle these cases here in an ad-hoc fashion.
_cleanobj_fast_depend_hack: .PHONY
+.if ${MK_DEPEND_CLEANUP} != "no"
@echo ">>> Deleting stale dependencies...";
MACHINE=${MACHINE} MACHINE_ARCH=${MACHINE_ARCH} \
- ALL_libcompats=${_ALL_libcompats:Q} \
+ ALL_libcompats=${_ALL_libcompats:Q} MAKE=${MAKE} \
sh ${.CURDIR}/tools/build/depend-cleanup.sh ${OBJTOP} ${SRCTOP}
+.endif
_cleanworldtmp: .PHONY
.if ${MK_CLEAN} == "yes"
@@ -1168,7 +1170,7 @@ _cleanobj:
.endfor
.else
${_+_}cd ${.CURDIR}; env CLEANMK="_NO_INCLUDE_COMPILERMK=t ${CLEANDIR}" \
- MAKE=${MAKE} ${WMAKE} _cleanobj_fast_depend_hack
+ ${WMAKE} _cleanobj_fast_depend_hack
.endif # ${MK_CLEAN} == "yes"
_obj:
@echo
diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5
index f028a3d1aac4..eaed8f9e3fb0 100644
--- a/share/man/man5/src.conf.5
+++ b/share/man/man5/src.conf.5
@@ -449,6 +449,14 @@ Clean before building world and/or kernel.
Note that recording a new epoch in
.Pa .clean_build_epoch
in the root of the source tree will also force a clean world build.
+When set, these options are also in effect:
+.Pp
+.Bl -inset -compact
+.It Va WITHOUT_DEPEND_CLEANUP
+(unless
+.Va WITH_DEPEND_CLEANUP
+is set explicitly)
+.El
.It Va WITHOUT_CPP
Do not build
.Xr cpp 1 .
@@ -537,6 +545,12 @@ amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc64 and powerpc/powerpc64le
.It Va WITHOUT_DEBUG_FILES
Avoid building or installing standalone debug files for each
executable binary and shared library.
+.It Va WITHOUT_DEPEND_CLEANUP
+Do not attempt to detect if the object tree needs cleaning in part or in
+whole before building.
+This speeds up incremental builds, especially when experimenting with
+build options, but may cause the build to inexplicably fail or produce
+non-functioning binaries.
.It Va WITH_DETECT_TZ_CHANGES
Make the time handling code detect changes to the timezone files.
.It Va WITH_DIALOG
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index 0d806702417f..68d48271d7bc 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -86,6 +86,7 @@ __DEFAULT_YES_OPTIONS = \
CRYPT \
CUSE \
CXGBETOOL \
+ DEPEND_CLEANUP \
DICT \
DMAGENT \
DTRACE \
@@ -515,6 +516,10 @@ MK_LLVM_CXXFILT:= yes
MK_LOADER_VERIEXEC_PASS_MANIFEST := no
.endif
+.if ${MK_CLEAN} == "yes"
+MK_DEPEND_CLEANUP:= no
+.endif
+
#
# MK_* options whose default value depends on another option.
#
diff --git a/tools/build/depend-cleanup.sh b/tools/build/depend-cleanup.sh
index f5d2fdac9dfd..ff7d4b2a5921 100755
--- a/tools/build/depend-cleanup.sh
+++ b/tools/build/depend-cleanup.sh
@@ -124,10 +124,8 @@ if [ ! -d "$SRCTOP" -o ! -f "$SRCTOP/Makefile.inc1" ]; then
fi
: ${CLEANMK=""}
-if [ -n "$CLEANMK" ]; then
- if [ -z "${MAKE+set}" ]; then
- err "MAKE not set"
- fi
+if [ -z "${MAKE+set}" ]; then
+ err "MAKE not set"
fi
if [ -z "${MACHINE+set}" ]; then
@@ -202,9 +200,41 @@ extract_epoch()
awk 'int($1) > 0 { epoch = $1 } END { print epoch }' "$1"
}
+# Regular expression matching the names of src.conf(5) options which
+# don't affect the build.
+#
+# This filter is applied to both the current options and the cached
+# options so we don't force a rebuild just because the filter itself
+# changed.
+IGNORED_OPTS="CLEAN|DEPEND_CLEANUP|EXAMPLES|MAN|TESTS|WARNS|WERROR"
+IGNORED_OPTS="${IGNORED_OPTS}|INSTALL.*|STAGING.*"
+# Also ignore TOOLCHAIN and the options it forces if set. It is
+# commonly used to speed up a build and is safe to toggle.
+IGNORED_OPTS="${IGNORED_OPTS}|TOOLCHAIN|CLANG.*|LLDB?|LLVM_(BIN|COV).*"
+
+extract_src_opts()
+{
+ $MAKE -C "$SRCTOP" -f "$SRCTOP"/Makefile.inc1 \
+ -V $'SRC_OPT_LIST:O:ts\n' |
+ egrep -v "^WITH(OUT)?_(${IGNORED_OPTS})="
+}
+
+extract_obj_opts()
+{
+ for fn; do
+ if [ -f "${fn}" ]; then
+ cat "${fn}"
+ else
+ echo "# ${fn}"
+ fi
+ done |
+ egrep -v "^WITH(OUT)?_(${IGNORED_OPTS})="
+}
+
clean_world()
{
local buildepoch="$1"
+ local srcopts="$2"
# The caller may set CLEANMK in the environment to make target(s) that
# should be invoked instead of just destroying everything. This is
@@ -227,34 +257,45 @@ clean_world()
mkdir -p "$OBJTOP"
echo "$buildepoch" > "$OBJTOP"/.clean_build_epoch
+ echo "$srcopts" > "$OBJTOP"/.src_opts
exit 0
}
-check_epoch()
+check_epoch_and_opts()
{
local srcepoch objepoch
+ local srcopts objopts
srcepoch=$(extract_epoch "$SRCTOP"/.clean_build_epoch)
if [ -z "$srcepoch" ]; then
err "Malformed .clean_build_epoch; please validate the last line"
fi
+ srcopts=$(extract_src_opts)
+ if [ -z "$srcopts" ]; then
+ err "Unable to extract source options"
+ fi
+
# We don't discriminate between the varying degrees of difference
# between epochs. If it went backwards we could be bisecting across
# epochs, in which case the original need to clean likely still stands.
objepoch=$(extract_epoch "$OBJTOP"/.clean_build_epoch)
if [ -z "$objepoch" ] || [ "$srcepoch" -ne "$objepoch" ]; then
- if [ "$VERBOSE" ]; then
- echo "Cleaning - src epoch: $srcepoch, objdir epoch: ${objepoch:-unknown}"
- fi
+ echo "Cleaning - src epoch: $srcepoch, objdir epoch: ${objepoch:-unknown}"
+ clean_world "$srcepoch" "$srcopts"
+ # NORETURN
+ fi
- clean_world "$srcepoch"
+ objopts=$(extract_obj_opts "$OBJTOP"/.src_opts)
+ if [ "$srcopts" != "$objopts" ]; then
+ echo "Cleaning - build options have changed"
+ clean_world "$srcepoch" "$srcopts"
# NORETURN
fi
}
-check_epoch
+check_epoch_and_opts
#### Typical dependency cleanup begins here.
diff --git a/tools/build/options/WITHOUT_DEPEND_CLEANUP b/tools/build/options/WITHOUT_DEPEND_CLEANUP
new file mode 100644
index 000000000000..6972ece98be7
--- /dev/null
+++ b/tools/build/options/WITHOUT_DEPEND_CLEANUP
@@ -0,0 +1,5 @@
+Do not attempt to detect if the object tree needs cleaning in part or in
+whole before building.
+This speeds up incremental builds, especially when experimenting with
+build options, but may cause the build to inexplicably fail or produce
+non-functioning binaries.