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