1330258Ssjg# $Id: ldorder.mk,v 1.18 2018/02/11 18:27:59 sjg Exp $
2330258Ssjg#
3330258Ssjg#	@(#) Copyright (c) 2015, Simon J. Gerraty
4330258Ssjg#
5330258Ssjg#	This file is provided in the hope that it will
6330258Ssjg#	be of use.  There is absolutely NO WARRANTY.
7330258Ssjg#	Permission to copy, redistribute or otherwise
8330258Ssjg#	use this file is hereby granted provided that 
9330258Ssjg#	the above copyright notice and this notice are
10330258Ssjg#	left intact. 
11330258Ssjg#      
12330258Ssjg#	Please send copies of changes and bug-fixes to:
13330258Ssjg#	sjg@crufty.net
14330258Ssjg#
15330258Ssjg
16330258Ssjg# Try to compute optimal link order.
17330258Ssjg# When using only shared libs link order does not much matter,
18330258Ssjg# but archive libs are a different matter.
19330258Ssjg
20330258Ssjg# We can construct a graph of .ldorder-lib${LIB*} dependencies
21330258Ssjg# and associate each with _LDORDER_USE to output the relevant
22330258Ssjg# ld flags.
23330258Ssjg# Due to the nature of make, the result will be in the reverse order
24330258Ssjg# that we want to feed to ld.
25330258Ssjg# So we need to reverse it before use.
26330258Ssjg
27330258Ssjg.if !target(_LDORDER_USE)
28330258Ssjg# does caller want to use ldorder?
29330258Ssjg# yes for prog, normally no for lib
30330258Ssjg_ldorder_use := ${.ALLTARGETS:Mldorder}
31330258Ssjg
32330258Ssjg.-include <local.ldorder.mk>
33330258Ssjg
34330258Ssjg# convert /path/to/libfoo.a into _{LIBFOO}
35330258SsjgLDORDER_INC_FILTER += S,+,PLUS,g S,.so$$,,g
36330258SsjgLDORDER_LIBS_FILTER += O:u
37330258SsjgLDORDER_INC ?= ldorder.inc
38330258SsjgREFERENCE_FILE ?= :
39330258Ssjg
40330258Ssjg_LDORDER_USE: .ldorder-rm .USE .NOTMAIN
41330258Ssjg	@echo depends: ${.ALLSRC:M.ldorder-lib*} > /dev/null
42330258Ssjg	@echo ${LDADD_${.TARGET:T:S,.ldorder-,,}:U${.TARGET:T:S/.ldorder-lib/-l/}} >> .ldorder
43330258Ssjg	@${META_COOKIE_TOUCH}
44330258Ssjg
45330258Ssjg# we need to truncate our working file
46330258Ssjg.ldorder-rm: .NOTMAIN
47330258Ssjg	@rm -f .ldorder ldorder-*
48330258Ssjg	@${.ALLSRC:O:u:@f@${REFERENCE_FILE} < $f;@}
49330258Ssjg	@${META_COOKIE_TOUCH}
50330258Ssjg
51330258Ssjg# make sure this exists
52330258Ssjg.ldorder:	.NOTMAIN
53330258Ssjg
54330258Ssjg# and finally we need to reverse the order of content
55330258Ssjgldorder: .ldorder .NOTMAIN
56330258Ssjg	@{ test ! -s .ldorder || cat -n .ldorder | sort -rn | \
57330258Ssjg	sed '/ldorder-/d;s,^[[:space:]0-9]*,,'; } > ${.TARGET}
58330258Ssjg
59330258Ssjg# Initially we hook contents of DPLIBS and DPADD into our graph
60330258SsjgLDORDER_LIBS ?= ${DPLIBS} ${DPADD:M*/lib*} ${__dpadd_libs}
61330258Ssjg# we need to remember this
62330258Ssjg_LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}}
63330258Ssjg
64330258Ssjg.if empty(_LDORDER_LIBS)
65330258Ssjg# don't use stale ldorder
66330258SsjgLDADD_LDORDER =
67330258Ssjg.else
68330258Ssjg# this is how you use it
69330258SsjgLDADD_LDORDER ?= `cat ldorder`
70330258Ssjg.endif
71330258Ssjg
72330258Ssjg# for debug below
73330258Ssjg_ldorder = ${RELDIR}.${TARGET_SPEC}
74330258Ssjg
75330258Ssjg.endif				# !target(_LDORDER_USE)
76330258Ssjg
77330258Ssjg.if !empty(LDORDER_LIBS) && !empty(_ldorder_use)
78330258Ssjg# canonicalize - these are just tokens anyway
79330258SsjgLDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}:R:C/\.so.*//}
80330258Ssjg_ldorders := ${LDORDER_LIBS:T:Mlib*:S,^,.ldorder-,}
81330258Ssjg
82330258Ssjg.for t in ${_ldorders}
83330258Ssjg.if !target($t)
84330258Ssjg$t: _LDORDER_USE
85330258Ssjg.endif
86330258Ssjg.endfor
87330258Ssjg
88330258Ssjg# and this makes it all happen
89330258Ssjg.ldorder: ${_ldorders}
90330258Ssjg
91330258Ssjg# this is how we get the dependencies
92330258Ssjg.if ${.INCLUDEDFROMFILE:M*.${LDORDER_INC}} != ""
93330258Ssjg_ldorder := .ldorder-${.INCLUDEDFROMFILE:S/.${LDORDER_INC}//}
94330258Ssjg${_ldorder}: ${_ldorders}
95330258Ssjg.ldorder-rm: ${.INCLUDEDFROMDIR}/${.INCLUDEDFROMFILE}
96330258Ssjg.endif
97330258Ssjg
98330258Ssjg# set DEBUG_LDORDER to pattern[s] that match the dirs of interest
99330258Ssjg.if ${DEBUG_LDORDER:Uno:@x@${RELDIR:M$x}@} != ""
100330258Ssjg.info ${_ldorder}: ${_ldorders}
101330258Ssjg.endif
102330258Ssjg
103330258Ssjg# now try to find more ...
104330258Ssjg# each *.${LDORDER_INC} should set LDORDER_LIBS to what it needs
105330258Ssjg# it can also add to CFLAGS etc.
106330258Ssjg.for __inc in ${LDORDER_LIBS:S,$,.${LDORDER_INC},}
107330258Ssjg.if !target(__${__inc}__)
108330258Ssjg__${__inc}__:
109330258Ssjg# make sure this is reset
110330258SsjgLDORDER_LIBS =
111330258Ssjg.-include <${__inc}>
112330258Ssjg.endif
113330258Ssjg.endfor
114330258Ssjg
115330258Ssjg.endif				# !empty(LDORDER_LIBS)
116330258Ssjg
117330258Ssjg.ifdef LIB
118330258Ssjg# you can make this depend on files (must match *ldorder*)
119330258Ssjg# to add extra content - like CFLAGS
120330258SsjglibLDORDER_INC = lib${LIB}.${LDORDER_INC}
121330258Ssjg.if !commands(${libLDORDER_INC})
122330258Ssjg${libLDORDER_INC}:
123330258Ssjg	@(cat /dev/null ${.ALLSRC:M*ldorder*}; \
124330258Ssjg	echo 'LDORDER_LIBS= ${_LDORDER_LIBS:T:R:${LDORDER_INC_FILTER:ts:}:tu:C,.*,_{&},}'; \
125330258Ssjg	echo; echo '.include <ldorder.mk>' ) | sed 's,_{,$${,g' > ${.TARGET}
126330258Ssjg.endif
127330258Ssjg.endif
128