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
This commit is contained in:
Dag-Erling Smørgrav
2025-12-31 14:10:20 +01:00
parent 2c0e9a76c1
commit 1d52d5c537
5 changed files with 79 additions and 12 deletions
+4 -2
View File
@@ -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
+14
View File
@@ -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
+5
View File
@@ -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.
#
+48 -7
View File
@@ -124,10 +124,8 @@ if [ ! -d "$SRCTOP" -o ! -f "$SRCTOP/Makefile.inc1" ]; then
fi
: ${CLEANMK=""}
if [ -n "$CLEANMK" ]; then
if [ -z "${MAKE+set}" ]; then
if [ -z "${MAKE+set}" ]; then
err "MAKE not set"
fi
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}"
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.
@@ -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.