xref: /freebsd/contrib/bmake/mk/ldorder.mk (revision 4f52dfbb)
1# $Id: ldorder.mk,v 1.18 2018/02/11 18:27:59 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_ldorder_use := ${.ALLTARGETS:Mldorder}
31
32.-include <local.ldorder.mk>
33
34# convert /path/to/libfoo.a into _{LIBFOO}
35LDORDER_INC_FILTER += S,+,PLUS,g S,.so$$,,g
36LDORDER_LIBS_FILTER += O:u
37LDORDER_INC ?= ldorder.inc
38REFERENCE_FILE ?= :
39
40_LDORDER_USE: .ldorder-rm .USE .NOTMAIN
41	@echo depends: ${.ALLSRC:M.ldorder-lib*} > /dev/null
42	@echo ${LDADD_${.TARGET:T:S,.ldorder-,,}:U${.TARGET:T:S/.ldorder-lib/-l/}} >> .ldorder
43	@${META_COOKIE_TOUCH}
44
45# we need to truncate our working file
46.ldorder-rm: .NOTMAIN
47	@rm -f .ldorder ldorder-*
48	@${.ALLSRC:O:u:@f@${REFERENCE_FILE} < $f;@}
49	@${META_COOKIE_TOUCH}
50
51# make sure this exists
52.ldorder:	.NOTMAIN
53
54# and finally we need to reverse the order of content
55ldorder: .ldorder .NOTMAIN
56	@{ test ! -s .ldorder || cat -n .ldorder | sort -rn | \
57	sed '/ldorder-/d;s,^[[:space:]0-9]*,,'; } > ${.TARGET}
58
59# Initially we hook contents of DPLIBS and DPADD into our graph
60LDORDER_LIBS ?= ${DPLIBS} ${DPADD:M*/lib*} ${__dpadd_libs}
61# we need to remember this
62_LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}}
63
64.if empty(_LDORDER_LIBS)
65# don't use stale ldorder
66LDADD_LDORDER =
67.else
68# this is how you use it
69LDADD_LDORDER ?= `cat ldorder`
70.endif
71
72# for debug below
73_ldorder = ${RELDIR}.${TARGET_SPEC}
74
75.endif				# !target(_LDORDER_USE)
76
77.if !empty(LDORDER_LIBS) && !empty(_ldorder_use)
78# canonicalize - these are just tokens anyway
79LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}:R:C/\.so.*//}
80_ldorders := ${LDORDER_LIBS:T:Mlib*:S,^,.ldorder-,}
81
82.for t in ${_ldorders}
83.if !target($t)
84$t: _LDORDER_USE
85.endif
86.endfor
87
88# and this makes it all happen
89.ldorder: ${_ldorders}
90
91# this is how we get the dependencies
92.if ${.INCLUDEDFROMFILE:M*.${LDORDER_INC}} != ""
93_ldorder := .ldorder-${.INCLUDEDFROMFILE:S/.${LDORDER_INC}//}
94${_ldorder}: ${_ldorders}
95.ldorder-rm: ${.INCLUDEDFROMDIR}/${.INCLUDEDFROMFILE}
96.endif
97
98# set DEBUG_LDORDER to pattern[s] that match the dirs of interest
99.if ${DEBUG_LDORDER:Uno:@x@${RELDIR:M$x}@} != ""
100.info ${_ldorder}: ${_ldorders}
101.endif
102
103# now try to find more ...
104# each *.${LDORDER_INC} should set LDORDER_LIBS to what it needs
105# it can also add to CFLAGS etc.
106.for __inc in ${LDORDER_LIBS:S,$,.${LDORDER_INC},}
107.if !target(__${__inc}__)
108__${__inc}__:
109# make sure this is reset
110LDORDER_LIBS =
111.-include <${__inc}>
112.endif
113.endfor
114
115.endif				# !empty(LDORDER_LIBS)
116
117.ifdef LIB
118# you can make this depend on files (must match *ldorder*)
119# to add extra content - like CFLAGS
120libLDORDER_INC = lib${LIB}.${LDORDER_INC}
121.if !commands(${libLDORDER_INC})
122${libLDORDER_INC}:
123	@(cat /dev/null ${.ALLSRC:M*ldorder*}; \
124	echo 'LDORDER_LIBS= ${_LDORDER_LIBS:T:R:${LDORDER_INC_FILTER:ts:}:tu:C,.*,_{&},}'; \
125	echo; echo '.include <ldorder.mk>' ) | sed 's,_{,$${,g' > ${.TARGET}
126.endif
127.endif
128