#!/bin/sh1#2#3# Our current make(1)-based approach to dependency tracking cannot cope with4# certain source tree changes, including:5#6# - removing source files7# - replacing generated files with files committed to the tree8# - changing file extensions (e.g. a C source file rewritten in C++)9# - moving a file from one directory to another10#11# Note that changing extensions or moving files may occur in effect as a result12# of switching from a generic machine-independent (MI) implementation file to a13# machine-dependent (MD) one.14#15# We handle those cases here in an ad-hoc fashion by looking for the known-16# bad case in the main .depend file, and if found deleting all of the related17# .depend files (including for example the lib32 version).18#19# These tests increase the build time (albeit by a small amount), so they20# should be removed once enough time has passed and it is extremely unlikely21# anyone would try a NO_CLEAN build against an object tree from before the22# related change. One year should be sufficient.23#24# Groups of cleanup rules begin with a comment including the date and git hash25# of the affected commit, and a description. The clean_dep function (below)26# handles common dependency cleanup cases. See the comment above the function27# for its arguments.28#29# Examples of each of the special cases:30#31# - Removing a source file (including changing a file's extension). The path,32# file, and extension are passed to clean_dep.33#34# # 20231031 0527c9bdc718 Remove forward compat ino64 stuff35# clean_dep lib/libc fstat c36#37# # 20221115 42d10b1b56f2 move from rs.c to rs.cc38# clean_dep usr.bin/rs rs c39#40# - Moving a file from one directory to another. Note that a regex is passed to41# clean_dep, as the default regex is derived from the file name (strncat.c in42# this example) does not change. The regex matches the old location, does not43# match the new location, and does not match any dependency shared between44# them. The `/`s are replaced with `.` to avoid awkward escaping.45#46# # 20250110 3dc5429158cf add strncat SIMD implementation47# clean_dep lib/libc strncat c "libc.string.strncat.c"48#49# - Replacing generated files with files committed to the tree. This is special50# case of moving from one directory to another. The stale generated file also51# needs to be deleted, so that it isn't found in make's .PATH. Note the52# unconditional `rm -fv`: there's no need for an extra call to first check for53# the file's existence.54#55# # 20250110 3863fec1ce2d add strlen SIMD implementation56# clean_dep lib/libc strlen S arm-optimized-routines57# run rm -fv "$OBJTOP"/lib/libc/strlen.S58#59# A rule may be required for only one architecture:60#61# # 20220326 fbc002cb72d2 move from bcmp.c to bcmp.S62# if [ "$MACHINE_ARCH" = "amd64" ]; then63# clean_dep lib/libc bcmp c64# fi65#66# We also have a big hammer at the top of the tree, .clean_build_epoch, to be67# used in severe cases where we can't surgically remove just the parts that68# need rebuilt. This should be used sparingly.6970set -e71set -u7273warn()74{75echo "$(basename "$0"):" "$@" >&276}7778err()79{80warn "$@"81exit 182}8384usage()85{86echo "usage: $(basename $0) [-v] [-n] objtop srctop" >&287}8889VERBOSE=90PRETEND=91while getopts vn o; do92case "$o" in93v)94VERBOSE=195;;96n)97PRETEND=198;;99*)100usage101exit 1102;;103esac104done105shift $((OPTIND-1))106107if [ $# -ne 2 ]; then108usage109exit 1110fi111112OBJTOP=$1113shift114SRCTOP=$1115shift116117if [ ! -d "$OBJTOP" ]; then118err "$OBJTOP: Not a directory"119fi120121if [ ! -d "$SRCTOP" -o ! -f "$SRCTOP/Makefile.inc1" ]; then122err "$SRCTOP: Not the root of a src tree"123fi124125: ${CLEANMK=""}126if [ -n "$CLEANMK" ]; then127if [ -z "${MAKE+set}" ]; then128err "MAKE not set"129fi130fi131132if [ -z "${MACHINE+set}" ]; then133err "MACHINE not set"134fi135136if [ -z "${MACHINE_ARCH+set}" ]; then137err "MACHINE_ARCH not set"138fi139140if [ -z "${ALL_libcompats+set}" ]; then141err "ALL_libcompats not set"142fi143144run()145{146if [ "$VERBOSE" ]; then147echo "$@"148fi149if ! [ "$PRETEND" ]; then150"$@"151fi152}153154# Clean the depend and object files for a given source file if the155# depend file matches a regex (which defaults to the source file156# name). This is typically used if a file was renamed, especially if157# only its extension was changed (e.g. from .c to .cc).158#159# $1 directory160# $2 source filename w/o extension161# $3 source extension162# $4 optional regex for egrep -w163clean_dep()164{165for libcompat in "" $ALL_libcompats; do166dirprfx=${libcompat:+obj-lib${libcompat}/}167if egrep -qw "${4:-$2\.$3}" "$OBJTOP"/$dirprfx$1/.depend.$2.*o 2>/dev/null; then168echo "Removing stale ${libcompat:+lib${libcompat} }dependencies and objects for $2.$3"169run rm -fv \170"$OBJTOP"/$dirprfx$1/.depend.$2.* \171"$OBJTOP"/$dirprfx$1/$2.*o172fi173done174}175176# Clean the object file for a given source file if it exists and177# matches a regex. This is typically used if a a change in CFLAGS or178# similar caused a change in the generated code without a change in179# the sources.180#181# $1 directory182# $2 source filename w/o extension183# $3 source extension184# $4 regex for egrep -w185clean_obj()186{187for libcompat in "" $ALL_libcompats; do188dirprfx=${libcompat:+obj-lib${libcompat}/}189if strings "$OBJTOP"/$dirprfx$1/$2.*o 2>/dev/null | egrep -qw "${4}"; then190echo "Removing stale ${libcompat:+lib${libcompat} }objects for $2.$3"191run rm -fv \192"$OBJTOP"/$dirprfx$1/$2.*o193fi194done195}196197extract_epoch()198{199[ -s "$1" ] || return 0200201awk 'int($1) > 0 { epoch = $1 } END { print epoch }' "$1"202}203204clean_world()205{206local buildepoch="$1"207208# The caller may set CLEANMK in the environment to make target(s) that209# should be invoked instead of just destroying everything. This is210# generally used after legacy/bootstrap tools to avoid over-cleansing211# since we're generally in the temporary tree's ancestor.212if [ -n "$CLEANMK" ]; then213echo "Cleaning up the object tree"214run $MAKE -C "$SRCTOP" -f "$SRCTOP"/Makefile.inc1 $CLEANMK215else216echo "Cleaning up the temporary build tree"217run rm -rf "$OBJTOP"218fi219220# We don't assume that all callers will have grabbed the build epoch, so221# we'll do it here as needed. This will be useful if we add other222# non-epoch reasons to force clean.223if [ -z "$buildepoch" ]; then224buildepoch=$(extract_epoch "$SRCTOP"/.clean_build_epoch)225fi226227mkdir -p "$OBJTOP"228echo "$buildepoch" > "$OBJTOP"/.clean_build_epoch229230exit 0231}232233check_epoch()234{235local srcepoch objepoch236237srcepoch=$(extract_epoch "$SRCTOP"/.clean_build_epoch)238if [ -z "$srcepoch" ]; then239err "Malformed .clean_build_epoch; please validate the last line"240fi241242# We don't discriminate between the varying degrees of difference243# between epochs. If it went backwards we could be bisecting across244# epochs, in which case the original need to clean likely still stands.245objepoch=$(extract_epoch "$OBJTOP"/.clean_build_epoch)246if [ -z "$objepoch" ] || [ "$srcepoch" -ne "$objepoch" ]; then247if [ "$VERBOSE" ]; then248echo "Cleaning - src epoch: $srcepoch, objdir epoch: ${objepoch:-unknown}"249fi250251clean_world "$srcepoch"252# NORETURN253fi254}255256check_epoch257258#### Typical dependency cleanup begins here.259260# Date Rev Description261262# 20220326 fbc002cb72d2 move from bcmp.c to bcmp.S263if [ "$MACHINE_ARCH" = "amd64" ]; then264clean_dep lib/libc bcmp c265fi266267# 20220524 68fe988a40ca kqueue_test binary replaced shell script268if stat "$OBJTOP"/tests/sys/kqueue/libkqueue/*kqtest* \269"$OBJTOP"/tests/sys/kqueue/libkqueue/.depend.kqtest* >/dev/null 2>&1; then270echo "Removing old kqtest"271run rm -fv "$OBJTOP"/tests/sys/kqueue/libkqueue/.depend.* \272"$OBJTOP"/tests/sys/kqueue/libkqueue/*273fi274275# 20221115 42d10b1b56f2 move from rs.c to rs.cc276clean_dep usr.bin/rs rs c277278# 20230110 bc42155199b5 usr.sbin/zic/zic -> usr.sbin/zic279if [ -d "$OBJTOP"/usr.sbin/zic/zic ] ; then280echo "Removing old zic directory"281run rm -rf "$OBJTOP"/usr.sbin/zic/zic282fi283284# 20230208 29c5f8bf9a01 move from mkmakefile.c to mkmakefile.cc285clean_dep usr.sbin/config mkmakefile c286# 20230209 83d7ed8af3d9 convert to main.cc and mkoptions.cc287clean_dep usr.sbin/config main c288clean_dep usr.sbin/config mkoptions c289290# 20230401 54579376c05e kqueue1 from syscall to C wrapper291clean_dep lib/libc kqueue1 S292293# 20230623 b077aed33b7b OpenSSL 3.0 update294if [ -f "$OBJTOP"/secure/lib/libcrypto/aria.o ]; then295echo "Removing old OpenSSL 1.1.1 tree"296for libcompat in "" $ALL_libcompats; do297dirprfx=${libcompat:+obj-lib${libcompat}/}298run rm -rf "$OBJTOP"/${dirprfx}secure/lib/libcrypto \299"$OBJTOP"/${dirprfx}secure/lib/libssl300done301fi302303# 20230714 ee8b0c436d72 replace ffs/fls implementations with clang builtins304clean_dep lib/libc ffs S305clean_dep lib/libc ffsl S306clean_dep lib/libc ffsll S307clean_dep lib/libc fls S308clean_dep lib/libc flsl S309clean_dep lib/libc flsll S310311# 20230815 28f6c2f29280 GoogleTest update312if [ -e "$OBJTOP"/tests/sys/fs/fusefs/mockfs.o ] && \313grep -q '_ZN7testing8internal18g_linked_ptr_mutexE' "$OBJTOP"/tests/sys/fs/fusefs/mockfs.o; then314echo "Removing stale fusefs GoogleTest objects"315run rm -rf "$OBJTOP"/tests/sys/fs/fusefs316fi317318# 20231031 0527c9bdc718 Remove forward compat ino64 stuff319clean_dep lib/libc fstat c320clean_dep lib/libc fstatat c321clean_dep lib/libc fstatfs c322clean_dep lib/libc getdirentries c323clean_dep lib/libc getfsstat c324clean_dep lib/libc statfs c325326# 20240308 e6ffc7669a56 Remove pointless MD syscall(2)327# 20240308 0ee0ae237324 Remove pointless MD syscall(2)328# 20240308 7b3836c28188 Remove pointless MD syscall(2)329if [ ${MACHINE} != i386 ]; then330libcompats=331for libcompat in $ALL_libcompats; do332if [ $MACHINE = amd64 ] && [ $libcompat = 32 ]; then333continue334fi335libcompats="${libcompats+$libcompats }$libcompat"336done337ALL_libcompats="$libcompats" clean_dep lib/libsys syscall S ".*/syscall\.S"338ALL_libcompats="$libcompats" clean_dep lib/libc syscall S ".*/syscall\.S"339fi340341# 20240416 2fda3ab0ac19 WITH_NVME: Remove from broken342if [ -f "$OBJTOP"/rescue/rescue/rescue.mk ] && \343! grep -q 'nvme_util.o' "$OBJTOP"/rescue/rescue/rescue.mk; then344echo "removing rescue.mk without nvme_util.o"345run rm -fv "$OBJTOP"/rescue/rescue/rescue.mk346fi347348# 20240910 e2df9bb44109349clean_dep cddl/lib/libzpool abd_os c "linux/zfs/abd_os\.c"350351# 20241007352clean_dep cddl/lib/libzpool zfs_debug c "linux/zfs/zfs_debug\.c"353354# 20241011355clean_dep cddl/lib/libzpool arc_os c "linux/zfs/arc_os\.c"356357# 20241018 1363acbf25de libc/csu: Support IFUNCs on riscv358if [ ${MACHINE} = riscv ]; then359for f in "$OBJTOP"/lib/libc/.depend.libc_start1.*o; do360if [ ! -f "$f" ]; then361continue362fi363if ! grep -q 'lib/libc/csu/riscv/reloc\.c' "$f"; then364echo "Removing stale dependencies and objects for libc_start1.c"365run rm -fv \366"$OBJTOP"/lib/libc/.depend.libc_start1.* \367"$OBJTOP"/lib/libc/libc_start1.*o368break369fi370done371fi372373# 20241018 5deeebd8c6ca Merge llvm-project release/19.x llvmorg-19.1.2-0-g7ba7d8e2f7b6374p="$OBJTOP"/lib/clang/libclang/clang/Basic375f="$p"/arm_mve_builtin_sema.inc376if [ -e "$f" ]; then377if grep -q SemaBuiltinConstantArgRange "$f"; then378echo "Removing pre-llvm19 clang-tblgen output"379run rm -fv "$p"/*.inc380fi381fi382383# 20241025 cb5e41b16083 Unbundle hash functions fom lib/libcrypt384clean_obj lib/libcrypt crypt-md5 c __MD5Init385clean_obj lib/libcrypt crypt-nthash c __MD4Init386clean_obj lib/libcrypt crypt-sha256 c __SHA256Init387clean_obj lib/libcrypt crypt-sha512 c __SHA512Init388389# 20241213 b55f5e1c4ae3 jemalloc: Move generated jemalloc.3 into lib/libc tree390if [ -h "$OBJTOP"/lib/libc/jemalloc.3 ]; then391# Have to cleanup the jemalloc.3 in the obj tree since make gets392# confused and won't use the one in lib/libc/malloc/jemalloc/jemalloc.3393echo "Removing stale jemalloc.3 object"394run rm -fv "$OBJTOP"/lib/libc/jemalloc.3395fi396397if [ $MACHINE_ARCH = aarch64 ]; then398# 20250110 5e7d93a60440 add strcmp SIMD implementation399ALL_libcompats= clean_dep lib/libc strcmp S arm-optimized-routines400run rm -fv "$OBJTOP"/lib/libc/strcmp.S401402# 20250110 b91003acffe7 add strspn optimized implementation403ALL_libcompats= clean_dep lib/libc strspn c404405# 20250110 f2bd390a54f1 add strcspn optimized implementation406ALL_libcompats= clean_dep lib/libc strcspn c407408# 20250110 89b3872376cb add optimized strpbrk & strsep implementations409ALL_libcompats= clean_dep lib/libc strpbrk c "libc.string.strpbrk.c"410411# 20250110 79287d783c72 strcat enable use of SIMD412ALL_libcompats= clean_dep lib/libc strcat c "libc.string.strcat.c"413414# 20250110 756b7fc80837 add strlcpy SIMD implementation415ALL_libcompats= clean_dep lib/libc strlcpy c416417# 20250110 25c485e14769 add strncmp SIMD implementation418ALL_libcompats= clean_dep lib/libc strncmp S arm-optimized-routines419run rm -fv "$OBJTOP"/lib/libc/strncmp.S420421# 20250110 bad17991c06d add memccpy SIMD implementation422ALL_libcompats= clean_dep lib/libc memccpy c423424# 20250110 3dc5429158cf add strncat SIMD implementation425ALL_libcompats= clean_dep lib/libc strncat c "libc.string.strncat.c"426427# 20250110 bea89d038ac5 add strlcat SIMD implementation, and move memchr428ALL_libcompats= clean_dep lib/libc strlcat c "libc.string.strlcat.c"429ALL_libcompats= clean_dep lib/libc memchr S "[[:space:]]memchr.S"430run rm -fv "$OBJTOP"/lib/libc/memchr.S431432# 20250110 3863fec1ce2d add strlen SIMD implementation433ALL_libcompats= clean_dep lib/libc strlen S arm-optimized-routines434run rm -fv "$OBJTOP"/lib/libc/strlen.S435436# 20250110 79e01e7e643c add bcopy & bzero wrapper437ALL_libcompats= clean_dep lib/libc bcopy c "libc.string.bcopy.c"438ALL_libcompats= clean_dep lib/libc bzero c "libc.string.bzero.c"439440# 20250110 f2c98669fc1b add ASIMD-enhanced timingsafe_bcmp implementation441ALL_libcompats= clean_dep lib/libc timingsafe_bcmp c442443# 20250110 3f224333af16 add timingsafe_memcmp() assembly implementation444ALL_libcompats= clean_dep lib/libc timingsafe_memcmp c445fi446447# 20250402 839d0755fea8 ctld converted to C++448clean_dep usr.sbin/ctld ctld c449clean_dep usr.sbin/ctld conf c450clean_dep usr.sbin/ctld discovery c451clean_dep usr.sbin/ctld isns c452clean_dep usr.sbin/ctld kernel c453clean_dep usr.sbin/ctld login c454clean_dep usr.sbin/ctld uclparse c455456# 20250425 2e47f35be5dc libllvm, libclang and liblldb became shared libraries457if [ -f "$OBJTOP"/lib/clang/libllvm/libllvm.a ]; then458echo "Removing old static libllvm library"459run rm -fv "$OBJTOP"/lib/clang/libllvm/libllvm.a460fi461if [ -f "$OBJTOP"/lib/clang/libclang/libclang.a ]; then462echo "Removing old static libclang library"463run rm -fv "$OBJTOP"/lib/clang/libclang/libclang.a464fi465if [ -f "$OBJTOP"/lib/clang/liblldb/liblldb.a ]; then466echo "Removing old static liblldb library"467run rm -fv "$OBJTOP"/lib/clang/liblldb/liblldb.a468fi469470# 20250813 4f766afc1ca0 tcopy converted to C++471clean_dep usr.bin/tcopy tcopy c472473# 20250904 aef807876c30 moused binary to directory474if [ -f "$OBJTOP"/usr.sbin/moused/moused ]; then475echo "Removing old moused binary"476run rm -fv "$OBJTOP"/usr.sbin/moused/moused477fi478479480