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