xref: /freebsd/contrib/bmake/mk/dpadd.mk (revision c60f6422ffae3ea85e7b10bad950ad27c463af18)
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