1# SPDX-License-Identifier: BSD-2-Clause 2# 3# $Id: meta.autodep.mk,v 1.70 2025/05/28 20:03:00 sjg Exp $ 4 5# 6# @(#) Copyright (c) 2010-2025, Simon J. Gerraty 7# 8# This file is provided in the hope that it will 9# be of use. There is absolutely NO WARRANTY. 10# Permission to copy, redistribute or otherwise 11# use this file is hereby granted provided that 12# the above copyright notice and this notice are 13# left intact. 14# 15# Please send copies of changes and bug-fixes to: 16# sjg@crufty.net 17# 18 19_this ?= ${.PARSEFILE} 20.if !target(__${_this}__) 21__${_this}__: .NOTMAIN 22 23.-include <local.autodep.mk> 24 25.if ${DEBUG_AUTODEP:Uno:@m@${RELDIR:M$m}@} != "" 26_debug.autodep = 1 27.else 28_debug.autodep = 0 29.endif 30 31PICO?= .pico 32 33.if defined(SRCS) 34.if ${MAKE_VERSION:U0} >= 20211212 35OBJ_SUFFIXES += ${.SUFFIXES:M*o} 36.else 37# it would be nice to be able to query .SUFFIXES 38OBJ_SUFFIXES += .o .po .lo ${PICO} 39.endif 40 41# explicit dependencies help short-circuit .SUFFIX searches 42SRCS_DEP_FILTER+= N*.[hly] 43.for s in ${SRCS:${SRCS_DEP_FILTER:O:u:ts:}} 44.for e in ${OBJ_SUFFIXES:O:u} 45.if !target(${s:T:R}$e) 46${s:T:R}$e: $s 47.endif 48.endfor 49.endfor 50.endif 51 52.if make(gendirdeps) 53# you are supposed to know what you are doing! 54UPDATE_DEPENDFILE = yes 55.elif !empty(.TARGETS) && !make(all) 56# do not update the *depend* files 57# unless we are building the entire directory or the default target. 58# NO means don't update .depend - or Makefile.depend* 59# no means update .depend but not Makefile.depend* 60UPDATE_DEPENDFILE = NO 61.elif ${.MAKEFLAGS:M-k} != "" 62# it is a bad idea to update anything 63UPDATE_DEPENDFILE = NO 64.endif 65 66_CURDIR ?= ${.CURDIR} 67_OBJDIR ?= ${.OBJDIR} 68_OBJTOP ?= ${OBJTOP} 69_OBJROOT ?= ${OBJROOT:U${_OBJTOP}} 70_DEPENDFILE := ${_CURDIR}/${.MAKE.DEPENDFILE:T} 71 72.if ${.MAKE.LEVEL} > 0 73# do not allow auto update if we ever built this dir without filemon 74NO_FILEMON_COOKIE = .nofilemon 75CLEANFILES += ${NO_FILEMON_COOKIE} 76.if ${.MAKE.MODE:Uno:Mnofilemon} != "" 77UPDATE_DEPENDFILE = NO 78all: ${NO_FILEMON_COOKIE} 79${NO_FILEMON_COOKIE}: .NOMETA 80 @echo UPDATE_DEPENDFILE=NO > ${.TARGET} 81.elif exists(${NO_FILEMON_COOKIE}) 82UPDATE_DEPENDFILE = NO 83.warning ${RELDIR} built with nofilemon; UPDATE_DEPENDFILE=NO 84.endif 85.endif 86 87.if ${.MAKE.LEVEL} == 0 88UPDATE_DEPENDFILE = NO 89.endif 90.if !exists(${_DEPENDFILE}) 91_bootstrap_dirdeps = yes 92.endif 93_bootstrap_dirdeps ?= no 94UPDATE_DEPENDFILE ?= ${MK_UPDATE_DEPENDFILE:Uyes} 95 96.if ${_debug.autodep} 97.info ${_DEPENDFILE:S,${SRCTOP}/,,} update=${UPDATE_DEPENDFILE} 98.endif 99 100.if !empty(XMAKE_META_FILE) 101.if exists(${.OBJDIR}/${XMAKE_META_FILE}) 102# we cannot get accurate dependencies from an update build 103UPDATE_DEPENDFILE = NO 104.else 105META_XTRAS += ${XMAKE_META_FILE} 106.endif 107.endif 108 109.if ${_bootstrap_dirdeps} == "yes" || exists(${_DEPENDFILE}) 110# if it isn't supposed to be touched by us the Makefile should have 111# UPDATE_DEPENDFILE = no 112WANT_UPDATE_DEPENDFILE ?= yes 113.endif 114 115.if ${WANT_UPDATE_DEPENDFILE:Uno:tl} != "no" 116.if ${.MAKE.MODE:Uno:Mmeta*} == "" || ${.MAKE.MODE:Uno:M*read*} != "" 117UPDATE_DEPENDFILE = no 118.endif 119 120.if ${_debug.autodep} 121.info ${_DEPENDFILE:S,${SRCTOP}/,,} update=${UPDATE_DEPENDFILE} 122.endif 123 124.if ${UPDATE_DEPENDFILE:tl} == "yes" 125# sometimes we want .meta files generated to aid debugging/error detection 126# but do not want to consider them for dependencies 127# for example the result of running configure 128# just make sure this is not empty 129META_FILE_FILTER ?= N.meta 130# never consider these 131META_FILE_FILTER += Ndirdeps.cache* 132 133.if !empty(DPADD) 134# if we have any non-libs in DPADD, 135# they probably need to be paid attention to 136.if !empty(DPLIBS) 137FORCE_DPADD = ${DPADD:${DPLIBS:${M_ListToSkip}}:${DPADD_LAST:${M_ListToSkip}}} 138.else 139_nonlibs := ${DPADD:T:Nlib*:N*include} 140.if !empty(_nonlibs) 141FORCE_DPADD += ${_nonlibs:@x@${DPADD:M*/$x}@} 142.endif 143.endif 144.endif 145 146.if !make(gendirdeps) 147.END: gendirdeps 148.endif 149 150.if ${LOCAL_DEPENDS_GUARD:U} == "no" 151.depend: 152.endif 153 154# if we don't have OBJS, then .depend isn't useful 155.if !target(.depend) && (!empty(OBJS) || ${.ALLTARGETS:M*.o} != "") 156# some makefiles and/or targets contain 157# circular dependencies if you dig too deep 158# (as meta mode is apt to do) 159# so we provide a means of suppressing them. 160# the input to the loop below is target: dependency 161# with just one dependency per line. 162# Also some targets are not really local, or use random names. 163# Use local.autodep.mk to provide local additions! 164SUPPRESS_DEPEND += \ 165 ${SB:S,/,_,g}* \ 166 *:y.tab.c \ 167 *.c:*.c \ 168 *.h:*.h 169 170.NOPATH: .depend 171# we use ${.MAKE.META.CREATED} to trigger an update but 172# we process using ${.MAKE.META.FILES} 173# the double $$ defers initial evaluation 174# if necessary, we fake .po dependencies, just so the result 175# in Makefile.depend* is stable 176# The current objdir may be referred to in various ways 177OBJDIR_REFS += ${.OBJDIR} ${.OBJDIR:tA} ${_OBJDIR} ${RELOBJTOP}/${RELDIR} 178_depend = .depend 179# it would be nice to be able to get .SUFFIXES as ${.SUFFIXES} 180# we actually only care about the .SUFFIXES of files that might be 181# generated by tools like yacc. 182.if ${MAKE_VERSION:U0} >= 20211212 183DEPEND_SUFFIXES += ${.SUFFIXES:N.sh:N*[0-9aFfglopmnrSsty]} 184.else 185DEPEND_SUFFIXES += .c .h .cpp .hpp .cxx .hxx .cc .hh 186.endif 187.depend: .NOMETA $${.MAKE.META.CREATED} ${_this} 188 @echo "Updating $@: ${.OODATE:T:[1..8]}" 189 @${EGREP:Uegrep} -i '^R .*\.(${DEPEND_SUFFIXES:tl:O:u:S,^.,,:ts|})$$' /dev/null ${.MAKE.META.FILES:T:O:u:${META_FILE_FILTER:ts:}:M*o.meta} | \ 190 sed -e 's, \./, ,${OBJDIR_REFS:O:u:@d@;s, $d/, ,@};/\//d' \ 191 -e 's,^\([^/][^/]*\).meta...[0-9]* ,\1: ,' | \ 192 sort -u | \ 193 while read t d; do \ 194 case "$$d:" in $$t) continue;; esac; \ 195 case "$$t$$d" in ${SUPPRESS_DEPEND:U.:O:u:ts|}) continue;; esac; \ 196 echo $$t $$d; \ 197 done > $@.${.MAKE.PID} 198 @case "${.MAKE.META.FILES:T:M*.po.*}" in \ 199 *.po.*) mv $@.${.MAKE.PID} $@;; \ 200 *) { cat $@.${.MAKE.PID}; \ 201 sed ${OBJ_SUFFIXES:N.o:N.po:@o@-e 's,\$o:,.o:,'@} \ 202 -e 's,\.o:,.po:,' $@.${.MAKE.PID}; } | sort -u > $@; \ 203 rm -f $@.${.MAKE.PID};; \ 204 esac 205.else 206# make sure this exists 207.depend: 208# do _not_ assume that .depend is in any fit state for us to use 209CAT_DEPEND = /dev/null 210.if ${.MAKE.LEVEL} > 0 211.export CAT_DEPEND 212.endif 213_depend = 214.endif 215 216.if ${_debug.autodep} 217.info ${_DEPENDFILE:S,${SRCTOP}/,,} _depend=${_depend} 218.endif 219 220.if ${UPDATE_DEPENDFILE} == "yes" 221gendirdeps: beforegendirdeps .WAIT ${_DEPENDFILE} 222beforegendirdeps: 223.endif 224 225.if !target(${_DEPENDFILE}) 226.if ${_bootstrap_dirdeps} == "yes" 227# We are boot-strapping a new directory 228# Use DPADD to seed DIRDEPS 229.if !empty(DPADD) 230# anything which matches ${_OBJROOT}* but not ${_OBJTOP}* 231# needs to be qualified in DIRDEPS 232# The pseudo machine "host" is used for HOST_TARGET 233DIRDEPS += \ 234 ${DPADD:M${_OBJTOP}*:H:C,${_OBJTOP}[^/]*/,,:N.:O:u} \ 235 ${DPADD:M${_OBJROOT}*:N${_OBJTOP}*:N${STAGE_ROOT:U${_OBJTOP}}/*:H:S,${_OBJROOT},,:C,^([^/]+)/(.*),\2.\1,:S,${HOST_TARGET}$,host,:N.*:O:u} 236 237.endif 238.endif 239 240_gendirdeps_mutex = 241.if defined(NEED_GENDIRDEPS_MUTEX) 242# If a src dir gets built with multiple object dirs, 243# we need a mutex. Obviously, this is best avoided. 244# Note if .MAKE.DEPENDFILE is common for all ${MACHINE} 245# you either need to mutex, or ensure only one machine builds at a time! 246# lockf is an example of a suitable tool 247LOCKF ?= /usr/bin/lockf 248.if exists(${LOCKF}) 249GENDIRDEPS_MUTEXER ?= ${LOCKF} -k 250.endif 251.if empty(GENDIRDEPS_MUTEXER) 252.error NEED_GENDIRDEPS_MUTEX defined, but GENDIRDEPS_MUTEXER not set 253.else 254_gendirdeps_mutex = ${GENDIRDEPS_MUTEXER} ${GENDIRDEPS_MUTEX:U${_CURDIR}/Makefile} 255.endif 256.endif 257 258# If we have META_XTRAS we most likely did not create them 259# but we need to behave as if we did. 260# Avoid adding glob patterns to .MAKE.META.CREATED though. 261.MAKE.META.CREATED += ${META_XTRAS:N*\**:O:u} 262OPTIMIZE_OBJECT_META_FILES ?= no 263 264.if ${OPTIMIZE_OBJECT_META_FILES} == "yes" 265# If we have lots of .o.meta, ${PICO}.meta etc we need only look at one set. 266# If META_FILE_OBJ_FILTER is not already set, we default it to a 267# .SUFFIX which matches the first *o.meta. 268# There is no guarantee it will be just .o or .So etc, 269META_FILE_OBJ_FILTER ?= \ 270 ${.SUFFIXES:M*o:@o@${"${.MAKE.META.FILES:T:M*$o.meta:[1]}":?M*$o.meta:}@:[1]} 271.endif 272 273# parent may have set META_FILE_OBJ_FILTER 274.if ${OPTIMIZE_OBJECT_META_FILES} == "yes" || !empty(META_FILE_OBJ_FILTER) 275META_FILES = \ 276 ${.MAKE.META.FILES:N.depend*:N*o.meta} \ 277 ${.MAKE.META.FILES:${META_FILE_OBJ_FILTER}} 278.else 279META_FILES = ${.MAKE.META.FILES:N.depend*} 280.endif 281# ensure this is not empty (this will sort after any M and N 282# we use S,${_OBJDIR}/,, rather than :T since some makefiles have 283# objects in subdirs 284META_FILE_FILTER += S,${_OBJDIR}/,,:O:u 285# we have to defer evaluation until the target script runs 286GENDIRDEPS_ENV += META_FILES="${META_FILES:${META_FILE_FILTER:O:u:ts:}}}" 287 288.if ${_debug.autodep} 289.info ${_DEPENDFILE:S,${SRCTOP}/,,}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} xtras=${META_XTRAS} 290.endif 291 292.if ${.MAKE.LEVEL} > 0 293.if ${UPDATE_DEPENDFILE} == "yes" 294.-include <${.CURDIR}/${.MAKE.DEPENDFILE_PREFIX}.options> 295.endif 296.if !empty(GENDIRDEPS_FILTER) 297.export GENDIRDEPS_FILTER 298.endif 299.endif 300 301_this_dir := ${_PARSEDIR} 302.if ${MAKE_VERSION} < 20230123 303# we might have .../ in MAKESYSPATH 304_makesyspath := ${MAKESYSPATH:U${_this_dir}} 305.if ${.MAKEFLAGS:M-m} != "" 306_makesyspath := ${.MAKEFLAGS:S,-m ,-m,gW:M-m*:S,-m, ,:ts:}:${_makesyspath} 307.endif 308_makesyspath := ${_makesyspath:C,\.\.\./[^:]*,${_this_dir},} 309GENDIRDEPS_ENV += MAKESYSPATH=${_makesyspath} 310.else 311# add this if not already there 312.SYSPATH: ${_this_dir} 313GENDIRDEPS_ENV += MAKESYSPATH=${.SYSPATH:ts:} 314.endif 315 316${_DEPENDFILE}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} $${.MAKE.META.CREATED} 317 @echo Checking $@: ${.OODATE:T:[1..8]} 318 @(cd . && ${GENDIRDEPS_ENV} \ 319 SKIP_GENDIRDEPS='${SKIP_GENDIRDEPS:O:u}' \ 320 DPADD='${FORCE_DPADD:O:u}' ${_gendirdeps_mutex} \ 321 ${.MAKE} -B -f gendirdeps.mk RELDIR=${RELDIR} _DEPENDFILE=${_DEPENDFILE}) 322 @test -s $@ && touch $@; : 323.endif 324 325.endif 326.endif 327 328.if ${_bootstrap_dirdeps} == "yes" 329DIRDEPS+= ${RELDIR}.${TARGET_SPEC:U${MACHINE}} 330# make sure this is included at least once 331.include <dirdeps.mk> 332.else 333${_DEPENDFILE}: .PRECIOUS 334.endif 335 336CLEANFILES += *.meta filemon.* *.db 337 338# these make it easy to gather some stats 339now_utc ?= ${%s:L:localtime} 340.if !defined(start_utc) 341start_utc := ${now_utc} 342.endif 343 344meta_stats= meta=${empty(.MAKE.META.FILES):?0:${.MAKE.META.FILES:[#]}} \ 345 created=${empty(.MAKE.META.CREATED):?0:${.MAKE.META.CREATED:[#]}} 346 347.if !target(_reldir_finish) 348#.END: _reldir_finish 349.if target(gendirdeps) 350_reldir_finish: gendirdeps 351.endif 352_reldir_finish: .NOMETA 353 @echo "${TIME_STAMP} Finished ${RELDIR}.${TARGET_SPEC} seconds=$$(( ${now_utc} - ${start_utc} )) ${meta_stats}" 354.endif 355 356.if !target(_reldir_failed) 357#.ERROR: _reldir_failed 358_reldir_failed: .NOMETA 359 @echo "${TIME_STAMP} Failed ${RELDIR}.${TARGET_SPEC} seconds=$$(( ${now_utc} - ${start_utc} )) ${meta_stats}" 360.endif 361 362.if !defined(WITHOUT_META_STATS) && ${.MAKE.LEVEL} > 0 363.END: _reldir_finish 364.ERROR: _reldir_failed 365.endif 366 367.-include <ccm.dep.mk> 368 369.endif 370