1# $Id: dpadd.mk,v 1.34 2025/08/09 22:42:24 sjg Exp $ 2# 3# @(#) Copyright (c) 2004-2023, Simon J. Gerraty 4# 5# SPDX-License-Identifier: BSD-2-Clause 6# 7# Please send copies of changes and bug-fixes to: 8# sjg@crufty.net 9# 10 11## 12# DESCRIPTION: 13# This makefile manages a number of variables that simplify 14# dealing with libs in a build. 15# 16# Primary inputs are DPLIBS, DPADD and SRC_LIBS: 17# 18# DPLIBS 19# List of LIB* that we will actually link with 20# should be in correct link order. 21# DPLIBS is a short-cut to ensure that DPADD and LDADD are 22# kept in sync. 23# 24# DPADD List of LIB* that should already be built. 25# 26# SRC_LIBS 27# List of LIB* that we want headers from, we do *not* 28# require that such libs have been built. 29# 30# The above all get added to DPMAGIC_LIBS which is what we 31# process. 32# 33# We expect LIB* to be set to absolute path of a library - 34# suitable for putting in DPADD. 35# eg. 36# 37# LIBC ?= ${OBJTOP}/lib/libc/libc.a 38# 39# From such a path we can derrive a number of other variables 40# for which we can supply sensible default values. 41# We name all these variables for the basename of the library 42# (libc in our example above -- ${__lib:T:R} in below): 43# 44# LDADD_${__lib:T:R}: 45# What should be added to LDADD (eg -lc) 46# 47# OBJ_${__lib:T:R}: 48# This is trivial - just the dirname of the built library. 49# 50# SRC_${__lib:T:R}: 51# Where the src for ${__lib} is, if LIB* is set as above 52# we can simply substitute ${SRCTOP} for ${OBJTOP} in 53# the dirname. 54# 55# INCLUDES_${__lib:T:R}: 56# What should be added to CFLAGS 57# 58# If the directory ${SRC_${__lib:T:R}}/h exists we will 59# only add -I${SRC_${__lib:T:R}}/h on the basis that 60# this is where the public api is kept. 61# 62# Otherwise default will be -I${OBJ_${__lib:T:R}} 63# -I${SRC_${__lib:T:R}} 64# 65# Note much of the above is skipped for staged libs 66# eg. 67# LIBC ?= ${STAGE_OBJTOP}/usr/lib/libc.a 68# 69# Since we can safely assume that -I${STAGE_OBJTOP}/usr/include 70# and -L${STAGE_OBJTOP}/usr/lib are sufficient, and we should 71# have no need of anything else. 72# 73# Sometimes things are more complicated so allow for 74# DPLIBS to be qualified with each of the variables in 75# DPLIBS_QUALIFIER_LIST (default is VAR_QUALIFIER_LIST same as 76# init.mk) 77 78.if !target(__${.PARSEFILE}__) 79__${.PARSEFILE}__: .NOTMAIN 80 81# sometimes we play games with .CURDIR etc 82# _* hold the original values of .* 83_OBJDIR?= ${.OBJDIR} 84_CURDIR?= ${.CURDIR} 85 86.if ${_CURDIR} == ${SRCTOP} 87RELDIR=. 88RELTOP=. 89.else 90RELDIR?= ${_CURDIR:S,${SRCTOP}/,,} 91.if ${RELDIR} == ${_CURDIR} 92RELDIR?= ${_OBJDIR:S,${OBJTOP}/,,} 93.endif 94RELTOP?= ${RELDIR:C,[^/]+,..,g} 95.endif 96RELOBJTOP?= ${OBJTOP} 97RELSRCTOP?= ${SRCTOP} 98 99# we get included just about everywhere so this is handy... 100# C*DEBUG_XTRA are for defining on cmd line etc 101# so do not use in makefiles. 102.ifdef CFLAGS_DEBUG_XTRA 103CFLAGS_LAST += ${CFLAGS_DEBUG_XTRA} 104.endif 105.ifdef CXXFLAGS_DEBUG_XTRA 106CXXFLAGS_LAST += ${CXXFLAGS_DEBUG_XTRA} 107.endif 108 109.-include <local.dpadd.mk> 110 111# DPLIBS helps us ensure we keep DPADD and LDADD in sync 112DPLIBS_QUALIFIER_LIST ?= ${VAR_QUALIFIER_LIST} 113DPLIBS += ${DPLIBS_QUALIFIER_LIST:u:@Q@${DPLIBS.$Q:U}@} 114DPLIBS+= ${DPLIBS_LAST} ${DPLIBS_QUALIFIER_LIST:u:@Q@${DPLIBS_LAST.$Q:U}@} 115DPADD+= ${DPLIBS:N-*} 116.for __lib in ${DPLIBS} 117.if "${__lib:M-*}" != "" 118LDADD += ${__lib} 119.else 120LDADD += ${LDADD_${__lib:T:R}:U${__lib:T:R:S/lib/-l/:C/\.so.*//}} 121.endif 122.endfor 123 124# DPADD can contain things other than libs 125__dpadd_libs := ${DPADD:M*/lib*} 126 127.if defined(PROG) && ${MK_PROG_LDORDER_MK:Uno} != "no" 128# some libs have dependencies... 129# DPLIBS_* allows bsd.libnames.mk to flag libs which must be included 130# in DPADD for a given library. 131# Gather all such dependencies into __ldadd_all_xtras 132# dups will be dealt with later. 133# Note: libfoo_pic uses DPLIBS_libfoo 134__ldadd_all_xtras= 135.for __lib in ${__dpadd_libs:@d@${DPLIBS_${d:T:R:S,_pic,,}} ${DPLIBS_QUALIFIER_LIST:u:@Q@${DPLIBS_${d:T:R:S,_pic,,}.$Q:U}@}@} 136__ldadd_all_xtras+= ${LDADD_${__lib}:U${__lib:T:R:S/lib/-l/:C/\.so.*//}} 137.if "${DPADD:M${__lib}}" == "" 138DPADD+= ${__lib} 139.endif 140.endfor 141.endif 142# Last of all... for libc and libgcc 143DPADD+= ${DPADD_LAST} 144 145# de-dupuplicate __ldadd_all_xtras into __ldadd_xtras 146# in reverse order so that libs end up listed after all that needed them. 147__ldadd_xtras= 148.for __lib in ${__ldadd_all_xtras:[-1..1]} 149.if "${__ldadd_xtras:M${__lib}}" == "" || ${NEED_IMPLICIT_LDADD:tl:Uno} != "no" 150__ldadd_xtras+= ${__lib} 151.endif 152.endfor 153 154.if !empty(__ldadd_xtras) 155# now back to the original order 156__ldadd_xtras:= ${__ldadd_xtras:[-1..1]} 157LDADD+= ${__ldadd_xtras} 158.endif 159 160# Convert DPADD into -I and -L options and add them to CPPFLAGS and LDADD 161# For the -I's convert the path to a relative one. For separate objdirs 162# the DPADD paths will be to the obj tree so we need to subst anyway. 163 164# update this 165__dpadd_libs := ${DPADD:M*/lib*} 166 167# Order -L's to search ours first. 168# Avoids picking up old versions already installed. 169__dpadd_libdirs := ${__dpadd_libs:R:H:S/^/-L/g:O:u:N-L} 170LDADD += ${__dpadd_libdirs:M-L${OBJTOP}/*} 171LDADD += ${__dpadd_libdirs:N-L${OBJTOP}/*:N-L${HOST_LIBDIR:U/usr/lib}} 172.if defined(HOST_LIBDIR) && ${HOST_LIBDIR} != "/usr/lib" 173LDADD+= -L${HOST_LIBDIR} 174.endif 175 176.if !make(dpadd) 177.ifdef LIB 178# Each lib is its own src_lib, we want to include it in SRC_LIBS 179# so that the correct INCLUDES_* will be picked up automatically. 180SRC_LIBS+= ${_OBJDIR}/lib${LIB}.a 181.endif 182.endif 183 184# 185# This little bit of magic, assumes that SRC_libfoo will be 186# set if it cannot be correctly derrived from ${LIBFOO} 187# Note that SRC_libfoo and INCLUDES_libfoo should be named for the 188# actual library name not the variable name that might refer to it. 189# 99% of the time the two are the same, but the DPADD logic 190# only has the library name available, so stick to that. 191# 192 193SRC_LIBS?= 194# magic_libs includes those we want to link with 195# as well as those we might look at 196__dpadd_magic_libs += ${__dpadd_libs} ${SRC_LIBS} 197DPMAGIC_LIBS += ${__dpadd_magic_libs} \ 198 ${__dpadd_magic_libs:@d@${DPMAGIC_LIBS_${d:T:R}}@} 199 200# we skip this for staged libs 201.for __lib in ${DPMAGIC_LIBS:O:u:N${STAGE_OBJTOP:Unot}*/lib/*} 202# 203# if SRC_libfoo is not set, then we assume that the srcdir corresponding 204# to where we found the library is correct. 205# 206SRC_${__lib:T:R} ?= ${__lib:H:S,${OBJTOP},${RELSRCTOP},} 207# 208# This is a no-brainer but just to be complete... 209# 210OBJ_${__lib:T:R} ?= ${__lib:H:S,${OBJTOP},${RELOBJTOP},} 211# 212# If INCLUDES_libfoo is not set, then we'll use ${SRC_libfoo}/h if it exists, 213# else just ${SRC_libfoo}. 214# 215.if !empty(SRC_${__lib:T:R}) 216INCLUDES_${__lib:T:R} ?= -I${exists(${SRC_${__lib:T:R}}/h):?${SRC_${__lib:T:R}}/h:${SRC_${__lib:T:R}}} 217.endif 218.endfor 219 220# even for staged libs we sometimes 221# need to allow direct -I to avoid cicular dependencies 222.for __lib in ${DPMAGIC_LIBS:O:u:T:R} 223.if !empty(SRC_${__lib}) && empty(INCLUDES_${__lib}) 224# must be a staged lib 225.if exists(${SRC_${__lib}}/h) 226INCLUDES_${__lib} = -I${SRC_${__lib}}/h 227.else 228INCLUDES_${__lib} = -I${SRC_${__lib}} 229.endif 230.endif 231.endfor 232 233# when linking a shared lib, avoid non pic libs 234SHLDADD+= ${LDADD:N-[lL]*} 235.for __lib in ${__dpadd_libs:u} 236.if defined(SHLIB_NAME) && ${LDADD:M-l${__lib:T:R:S,lib,,}} != "" 237.if ${__lib:T:N*_pic.a:N*.so} == "" || exists(${__lib:R}.so) 238SHLDADD+= -l${__lib:T:R:S,lib,,} 239.elif exists(${__lib:R}_pic.a) 240SHLDADD+= -l${__lib:T:R:S,lib,,}_pic 241.else 242.warning ${RELDIR}.${TARGET_SPEC} needs ${__lib:T:R}_pic.a 243SHLDADD+= -l${__lib:T:R:S,lib,,} 244.endif 245SHLDADD+= -L${__lib:H} 246.endif 247.endfor 248 249# Now for the bits we actually need 250__dpadd_incs= 251.for __lib in ${__dpadd_libs:u} 252.if (make(${PROG:U}_p) || defined(NEED_GPROF)) && exists(${__lib:R}_p.a) 253__ldadd=-l${__lib:T:R:S,lib,,} 254LDADD := ${LDADD:S,^${__ldadd}$,${__ldadd}_p,g} 255.endif 256.endfor 257 258# 259# We take care of duplicate suppression later. 260# don't apply :T:R too early 261__dpadd_incs += ${__dpadd_magic_libs:u:@x@${INCLUDES_${x:T:R}}@} 262__dpadd_incs += ${__dpadd_magic_libs:O:u:@s@${SRC_LIBS_${s:T:R}:U}@:@x@${INCLUDES_${x:T:R}}@} 263 264__dpadd_last_incs += ${__dpadd_magic_libs:u:@x@${INCLUDES_LAST_${x:T:R}}@} 265__dpadd_last_incs += ${__dpadd_magic_libs:O:u:@s@${SRC_LIBS_${s:T:R}:U}@:@x@${INCLUDES_LAST_${x:T:R}}@} 266 267.if defined(HOSTPROG) || ${MACHINE:Nhost*} == "" 268# we want any -I/usr/* last 269__dpadd_last_incs := \ 270 ${__dpadd_last_incs:N-I/usr/*} \ 271 ${__dpadd_incs:M-I/usr/*} \ 272 ${__dpadd_last_incs:M-I/usr/*} 273__dpadd_incs := ${__dpadd_incs:N-I/usr/*} 274.endif 275 276# 277# eliminate any duplicates - but don't mess with the order 278# force evaluation now - to avoid giving make a headache 279# 280.for t in CFLAGS CXXFLAGS 281# avoid duplicates 282__$t_incs:=${$t:M-I*:O:u} 283.for i in ${__dpadd_incs} 284.if "${__$t_incs:M$i}" == "" 285$t+= $i 286__$t_incs+= $i 287.endif 288.endfor 289.endfor 290 291.for t in CFLAGS_LAST CXXFLAGS_LAST 292# avoid duplicates 293__$t_incs:=${$t:M-I*:u} 294.for i in ${__dpadd_last_incs} 295.if "${__$t_incs:M$i}" == "" 296$t+= $i 297__$t_incs+= $i 298.endif 299.endfor 300.endfor 301 302# This target is used to gather a list of 303# dir: ${DPADD} 304# entries 305.if make(*dpadd*) 306.if !target(dpadd) 307dpadd: .NOTMAIN 308.if defined(DPADD) && ${DPADD} != "" 309 @echo "${RELDIR}: ${DPADD:S,${OBJTOP}/,,}" 310.endif 311.endif 312.endif 313 314.ifdef SRC_PATHADD 315# We don't want to assume that we need to .PATH every element of 316# SRC_LIBS, but the Makefile cannot do 317# .PATH: ${SRC_libfoo} 318# since the value of SRC_libfoo must be available at the time .PATH: 319# is read - and we only just worked it out. 320# Further, they can't wait until after include of {lib,prog}.mk as 321# the .PATH is needed before then. 322# So we let the Makefile do 323# SRC_PATHADD+= ${SRC_libfoo} 324# and we defer the .PATH: until now so that SRC_libfoo will be available. 325.PATH: ${SRC_PATHADD} 326.endif 327 328# after all that, if doing -n we don't care 329.if ${.MAKEFLAGS:Ux:M-n} != "" 330DPADD = 331.elif ${.MAKE.MODE:Mmeta*} != "" && exists(${.MAKE.DEPENDFILE}) 332DPADD_CLEAR_DPADD ?= yes 333.if ${DPADD_CLEAR_DPADD} == "yes" 334# save this 335__dpadd_libs := ${__dpadd_libs} 336# we have made what use of it we can of DPADD 337DPADD = 338.endif 339.endif 340 341.endif 342