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