xref: /freebsd/contrib/bmake/mk/ldorder.mk (revision 3c4ba5f55438f7afd4f4b0b56f88f2bb505fd6a6)
1# $Id: ldorder.mk,v 1.26 2021/12/08 05:56:50 sjg Exp $
2#
3#	@(#) Copyright (c) 2015, Simon J. Gerraty
4#
5#	This file is provided in the hope that it will
6#	be of use.  There is absolutely NO WARRANTY.
7#	Permission to copy, redistribute or otherwise
8#	use this file is hereby granted provided that
9#	the above copyright notice and this notice are
10#	left intact.
11#
12#	Please send copies of changes and bug-fixes to:
13#	sjg@crufty.net
14#
15
16# Try to compute optimal link order.
17# When using only shared libs link order does not much matter,
18# but archive libs are a different matter.
19
20# We can construct a graph of .ldorder-lib${LIB*} dependencies
21# and associate each with _LDORDER_USE to output the relevant
22# ld flags.
23# Due to the nature of make, the result will be in the reverse order
24# that we want to feed to ld.
25# So we need to reverse it before use.
26
27.if !target(_LDORDER_USE)
28# does caller want to use ldorder?
29# yes for prog, normally no for lib
30.if ${.ALLTARGETS:Mldorder} != ""
31_ldorder_use:
32.endif
33
34# define this if we need a barrier between local and external libs
35# see below
36LDORDER_EXTERN_BARRIER ?= .ldorder-extern-barrier
37
38.-include <local.ldorder.mk>
39
40# convert /path/to/libfoo.a into _{LIBFOO}
41LDORDER_INC_FILTER += S,+,PLUS,g S,.so$$,,g
42LDORDER_LIBS_FILTER += O:u
43LDORDER_INC ?= ldorder.inc
44# for meta mode
45REFERENCE_FILE ?= :
46
47_LDORDER_USE: .ldorder-rm .USE .NOTMAIN
48	@echo depends: ${.ALLSRC:M.ldorder-lib*} > /dev/null
49	@echo ${LDADD_${.TARGET:T:S,.ldorder-,,}:U${.TARGET:T:S/.ldorder-lib/-l/}} >> .ldorder
50	@${META_COOKIE_TOUCH}
51
52# we need to truncate our working file
53.ldorder-rm: .NOTMAIN
54	@rm -f .ldorder ldorder-*
55	@${.ALLSRC:O:u:@f@${REFERENCE_FILE} < $f;@}
56	@${META_COOKIE_TOUCH}
57
58# make sure this exists
59.ldorder:	.NOTMAIN
60
61# and finally we need to reverse the order of content
62ldorder: .ldorder .NOTMAIN
63	@{ test ! -s .ldorder || cat -n .ldorder | sort -rn | \
64	sed '/ldorder-/d;s,^[[:space:]0-9]*,,'; } > ${.TARGET}
65
66# Initially we hook contents of DPLIBS and DPADD into our graph
67LDORDER_LIBS ?= ${DPLIBS} ${DPADD:M*/lib*} ${__dpadd_libs}
68# we need to remember this
69_LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}}
70
71.if empty(_LDORDER_LIBS)
72# don't use stale ldorder
73LDADD_LDORDER =
74.else
75# this is how you use it
76LDADD_LDORDER ?= `cat ldorder`
77.endif
78
79# for debug below
80_ldorder = ${RELDIR}.${TARGET_SPEC}
81
82# we make have some libs that exist outside of $SB
83# and want to insert a barrier
84.if target(${LDORDER_EXTERN_BARRIER})
85# eg. in local.ldorder.mk
86# ${LDORDER_EXTERN_BARRIER}:
87#	@test -z "${extern_ldorders}" || \
88#	echo -Wl,-Bdynamic >> .ldorder
89#
90# feel free to put more suitable version in local.ldorder.mk if needed
91# we do *not* count host libs in extern_ldorders
92extern_ldorders ?= ${__dpadd_libs:tA:N/lib*:N/usr/lib*:N${SB}/*:N${SB_OBJROOT:tA}*:T:${LDORDER_LIBS_FILTER:ts:}:R:C/\.so.*//:S,^,.ldorder-,:N.ldorder-}
93sb_ldorders ?= ${.ALLTARGETS:M.ldorder-*:N${LDORDER_EXTERN_BARRIER}:N.ldorder-rm:${extern_ldorders:${M_ListToSkip}}:N.ldorder-}
94
95# finally in Makefile after include of *.mk put
96# .ldorder ${sb_ldorders}: ${LDORDER_EXTERN_BARRIER}
97# ${LDORDER_EXTERN_BARRIER}: ${extern_ldorders}
98.endif
99
100.endif				# !target(_LDORDER_USE)
101
102.if !empty(LDORDER_LIBS) && target(_ldorder_use)
103# canonicalize - these are just tokens anyway
104LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}:R:C/\.so.*//}
105_ldorders := ${LDORDER_LIBS:T:Mlib*:S,^,.ldorder-,}
106
107.for t in ${_ldorders}
108.if !target($t)
109$t: _LDORDER_USE
110.endif
111.endfor
112
113# and this makes it all happen
114.ldorder: ${_ldorders}
115
116# this is how we get the dependencies
117.if ${.INCLUDEDFROMFILE:M*.${LDORDER_INC}} != ""
118_ldorder := .ldorder-${.INCLUDEDFROMFILE:S/.${LDORDER_INC}//}
119${_ldorder}: ${_ldorders}
120.ldorder-rm: ${.INCLUDEDFROMDIR}/${.INCLUDEDFROMFILE}
121.endif
122
123# set DEBUG_LDORDER to pattern[s] that match the dirs of interest
124.if ${DEBUG_LDORDER:Uno:@x@${RELDIR:M$x}@} != ""
125.info ${_ldorder}: ${_ldorders}
126.endif
127
128# now try to find more ...
129# each *.${LDORDER_INC} should set LDORDER_LIBS to what it needs
130# it can also add to CFLAGS etc.
131.for __inc in ${LDORDER_LIBS:S,$,.${LDORDER_INC},}
132.if !target(__${__inc}__)
133__${__inc}__: .NOTMAIN
134# make sure this is reset
135LDORDER_LIBS =
136_ldorders =
137.-include <${__inc}>
138.endif
139.endfor
140
141.endif				# !empty(LDORDER_LIBS)
142
143.ifdef LIB
144# you can make this depend on files (must match *ldorder*)
145# to add extra content - like CFLAGS
146libLDORDER_INC = lib${LIB}.${LDORDER_INC}
147.if !commands(${libLDORDER_INC})
148.if target(ldorder-header)
149${libLDORDER_INC}: ldorder-header
150.endif
151${libLDORDER_INC}:
152	@(cat /dev/null ${.ALLSRC:M*ldorder*}; \
153	echo 'LDORDER_LIBS= ${_LDORDER_LIBS:T:R:${LDORDER_INC_FILTER:ts:}:tu:C,.*,_{&},:N_{}}'; \
154	echo; echo '.include <ldorder.mk>' ) | sed 's,_{,$${,g' > ${.TARGET}
155.endif
156.endif
157