1# $Id: ldorder.mk,v 1.28 2025/08/09 22:42:24 sjg Exp $ 2# 3# @(#) Copyright (c) 2015, Simon J. Gerraty 4# 5# SPDX-License-Identifier: BSD-2-Clause 6# 7# Please send copies of changes and bug-fixes to: 8# sjg@crufty.net 9# 10 11# Try to compute optimal link order. 12# When using only shared libs link order does not much matter, 13# but archive libs are a different matter. 14 15# We can construct a graph of .ldorder-lib${LIB*} dependencies 16# and associate each with _LDORDER_USE to output the relevant 17# ld flags. 18# Due to the nature of make, the result will be in the reverse order 19# that we want to feed to ld. 20# So we need to reverse it before use. 21 22.if !target(_LDORDER_USE) 23# does caller want to use ldorder? 24# yes for prog, normally no for lib 25.if ${.ALLTARGETS:Mldorder} != "" 26_ldorder_use: 27.endif 28 29# define this if we need a barrier between local and external libs 30# see below 31LDORDER_EXTERN_BARRIER ?= .ldorder-extern-barrier 32 33.-include <local.ldorder.mk> 34 35# convert /path/to/libfoo.a into _{LIBFOO} 36LDORDER_INC_FILTER += S,+,PLUS,g S,.so$$,,g 37LDORDER_LIBS_FILTER += O:u 38LDORDER_INC ?= ldorder.inc 39# for meta mode 40REFERENCE_FILE ?= : 41 42_LDORDER_USE: .ldorder-rm .USE .NOTMAIN 43 @echo depends: ${.ALLSRC:M.ldorder-lib*} > /dev/null 44 @echo ${LDADD_${.TARGET:T:S,.ldorder-,,}:U${.TARGET:T:S/.ldorder-lib/-l/}} >> .ldorder 45 @${META_COOKIE_TOUCH} 46 47# we need to truncate our working file 48.ldorder-rm: .NOTMAIN 49 @rm -f .ldorder ldorder-* 50 @${.ALLSRC:O:u:@f@${REFERENCE_FILE} < $f;@} 51 @${META_COOKIE_TOUCH} 52 53# make sure this exists 54.ldorder: .NOTMAIN 55 56# and finally we need to reverse the order of content 57ldorder: .ldorder .NOTMAIN 58 @{ test ! -s .ldorder || cat -n .ldorder | sort -rn | \ 59 sed '/ldorder-/d;s,^[[:space:]0-9]*,,'; } > ${.TARGET} 60 61# Initially we hook contents of DPLIBS and DPADD into our graph 62LDORDER_LIBS ?= ${DPLIBS} ${DPADD:M*/lib*} ${__dpadd_libs} 63# we need to remember this 64_LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}} 65 66.if empty(_LDORDER_LIBS) 67# don't use stale ldorder 68LDADD_LDORDER = 69.else 70# this is how you use it 71LDADD_LDORDER ?= `cat ldorder` 72.endif 73 74# for debug below 75_ldorder = ${RELDIR}.${TARGET_SPEC} 76 77# we make have some libs that exist outside of $SB 78# and want to insert a barrier 79.if target(${LDORDER_EXTERN_BARRIER}) 80# eg. in local.ldorder.mk 81# ${LDORDER_EXTERN_BARRIER}: 82# @test -z "${extern_ldorders}" || \ 83# echo -Wl,-Bdynamic >> .ldorder 84# 85# feel free to put more suitable version in local.ldorder.mk if needed 86# we do *not* count host libs in extern_ldorders 87extern_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-} 88sb_ldorders ?= ${.ALLTARGETS:M.ldorder-*:N${LDORDER_EXTERN_BARRIER}:N.ldorder-rm:${extern_ldorders:${M_ListToSkip}}:N.ldorder-} 89 90# finally in Makefile after include of *.mk put 91# .ldorder ${sb_ldorders}: ${LDORDER_EXTERN_BARRIER} 92# ${LDORDER_EXTERN_BARRIER}: ${extern_ldorders} 93.endif 94 95.endif # !target(_LDORDER_USE) 96 97.if !empty(LDORDER_LIBS) && target(_ldorder_use) 98# canonicalize - these are just tokens anyway 99LDORDER_LIBS := ${LDORDER_LIBS:${LDORDER_LIBS_FILTER:ts:}:R:C/\.so.*//} 100_ldorders := ${LDORDER_LIBS:T:Mlib*:S,^,.ldorder-,} 101 102.for t in ${_ldorders} 103.if !target($t) 104$t: _LDORDER_USE 105.endif 106.endfor 107 108# and this makes it all happen 109.ldorder: ${_ldorders} 110 111# this is how we get the dependencies 112.if ${.INCLUDEDFROMFILE:M*.${LDORDER_INC}} != "" 113_ldorder := .ldorder-${.INCLUDEDFROMFILE:S/.${LDORDER_INC}//} 114${_ldorder}: ${_ldorders} 115.ldorder-rm: ${.INCLUDEDFROMDIR}/${.INCLUDEDFROMFILE} 116.endif 117 118# set DEBUG_LDORDER to pattern[s] that match the dirs of interest 119.if ${DEBUG_LDORDER:Uno:@x@${RELDIR:M$x}@} != "" 120.info ${_ldorder}: ${_ldorders} 121.endif 122 123# now try to find more ... 124# each *.${LDORDER_INC} should set LDORDER_LIBS to what it needs 125# it can also add to CFLAGS etc. 126.for __inc in ${LDORDER_LIBS:S,$,.${LDORDER_INC},} 127.if !target(__${__inc}__) 128__${__inc}__: .NOTMAIN 129# make sure this is reset 130LDORDER_LIBS = 131_ldorders = 132.-include <${__inc}> 133.endif 134.endfor 135 136.endif # !empty(LDORDER_LIBS) 137 138.ifdef LIB 139# you can make this depend on files (must match *ldorder*) 140# to add extra content - like CFLAGS 141libLDORDER_INC = lib${LIB}.${LDORDER_INC} 142.if !commands(${libLDORDER_INC}) 143.if target(ldorder-header) 144${libLDORDER_INC}: ldorder-header 145.endif 146${libLDORDER_INC}: 147 @(cat /dev/null ${.ALLSRC:M*ldorder*}; \ 148 echo 'LDORDER_LIBS= ${_LDORDER_LIBS:T:R:${LDORDER_INC_FILTER:ts:}:tu:C,.*,_{&},:N_{}}'; \ 149 echo; echo '.include <ldorder.mk>' ) | sed 's,_{,$${,g' > ${.TARGET} 150.endif 151.endif 152