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