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