bsd.lib.mk: Check expected vs actual symbols at build-time.

If, for LIB=foo, you create a file foo.expsym, bsd.lib.mk will list
the dynamic symbols and their versions with

nm --dynamic --extern-only --defined-only --with-symbol-versions

and compare the names (not addresses or types) to foo.expsym.  If
there are any differences, they will be printed and the build will
fail.

foo.expsym should be sorted with `LANG=C sort -u'.

This way, you can verify changes don't inadvertently add or remove
symbols.  If you do want to add (or, if you're bumping the major,
remove) symbols, you can verify the changes and edit the foo.expsym
file accordingly.  This will also help to enforce rules about symbol
changes on pullups in release branches.

Note that using a version map (-Wl,--version-script=...) doesn't
catch symbol removal -- ld quietly ignores symbols in the version map
that aren't actually defined by any object in the library.  So this
supplements the version map.

Proposed on tech-userlevel:
https://mail-index.NetBSD.org/tech-userlevel/2024/03/16/msg014264.html
pull/35/head
riastradh 2024-03-20 13:50:37 +00:00
parent 864e67f08d
commit 837a54d9ce
1 changed files with 37 additions and 1 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: bsd.lib.mk,v 1.394 2023/06/03 21:24:57 lukem Exp $
# $NetBSD: bsd.lib.mk,v 1.395 2024/03/20 13:50:37 riastradh Exp $
# @(#)bsd.lib.mk 8.3 (Berkeley) 4/22/94
.include <bsd.init.mk>
@ -648,6 +648,42 @@ ${_LIB.so.full}: ${_MAINLIBDEPS}
${HOST_LN} -sf ${_LIB.so.full} ${_LIB.so}.tmp
${MV} ${_LIB.so}.tmp ${_LIB.so}
# If there's a file listing expected symbols, fail if the diff from it
# to the actual symbols is nonempty, and show the diff in that case.
.if exists(${.CURDIR}/${LIB}.${MACHINE_ARCH}.expsym)
LIB_EXPSYM?= ${LIB}.${MACHINE_ARCH}.expsym
.elif exists(${.CURDIR}/${LIB}.expsym)
LIB_EXPSYM?= ${LIB}.expsym
.endif
.if !empty(LIB_EXPSYM)
realall: ${_LIB.so.full}.diffsym
${_LIB.so.full}.diffsym: ${LIB_EXPSYM} ${_LIB.so.full}.actsym
${_MKTARGET_CREATE}
if diff -u ${.ALLSRC} >${.TARGET}.tmp; then \
${MV} ${.TARGET}.tmp ${.TARGET}; \
else \
ret=$$?; \
cat ${.TARGET}.tmp; \
echo ${_LIB.so.full}: error: \
actual symbols differ from expected symbols >&2; \
exit $$ret; \
fi
${_LIB.so.full}.actsym: ${_LIB.so.full}
${_MKTARGET_CREATE}
${NM} --dynamic --extern-only --defined-only --with-symbol-versions \
${_LIB.so.full} \
| cut -d' ' -f3 | LANG=C sort -u >${.TARGET}.tmp
${MV} ${.TARGET}.tmp ${.TARGET}
CLEANFILES+= ${_LIB.so.full}.actsym
CLEANFILES+= ${_LIB.so.full}.actsym.tmp
CLEANFILES+= ${_LIB.so.full}.diffsym
CLEANFILES+= ${_LIB.so.full}.diffsym.tmp
update-symbols: .PHONY
update-symbols: ${_LIB.so.full}.actsym
cp ${_LIB.so.full}.actsym ${.CURDIR}/${LIB}.expsym
.endif
.if !empty(LOBJS) # {
LLIBS?= -lc
${_LIB.ln}: ${LOBJS}