Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
Re: graphics/ffmpeg: update to 8.0.2 (-stable) and 8.1.1 (-current)
To:
Theo Buehler <tb@theobuehler.org>
Cc:
ports@openbsd.org
Date:
Fri, 08 May 2026 01:48:11 +0200

Download raw body.

Thread
On Thu, 07 May 2026 08:02:15 +0200,
Theo Buehler <tb@theobuehler.org> wrote:
> 
> On Wed, May 06, 2026 at 05:29:17PM +0100, Stuart Henderson wrote:
> > On 2026/05/06 18:18, Kirill A. Korinsky wrote:
> > > On Wed, 06 May 2026 18:02:20 +0200,
> > > Stuart Henderson <stu@spacehopper.org> wrote:
> > > > 
> > > > $ diffsyms
> > > 
> > > Now I wonder that it is :)
> > 
> > local script, can't remember who it came from (at least some of it is
> > not mine, I am too lazy to remember about print -u2 and would have used
> > echo >&2 instead ;)
> 
> You shared an adapted-to-ports version of a rather old guenther
> check_sym with me a long time ago (still in ~tb/bin/check_sym).
> 
> This got out of sync with base, missing features like the data object size
> changes and also some fixes I wanted to have, such as cleaning the mess
> it left behind in /tmp, so I extracted your changes into a wrapper script
> of src/lib/check_sym and added the fake check and shared that back with
> you. Then you polished that a bit more by the looks of it.
> 
> If you want to slap an ISC license on it, my contributions seem to be
> from 2022.
> 
> I still hope someone will eventually come up with a bsd.port.mk target
> of this :)
>

Like this?

I've used /usr/src/lib/check_sym as base, get some ideas from
~tb/bin/check_sym with some polish as I thnk right and it ends with this
diff.

Index: /usr/src/share/man/man5/bsd.port.mk.5
===================================================================
RCS file: /home/cvs/src/share/man/man5/bsd.port.mk.5,v
diff -u -p -r1.654 bsd.port.mk.5
--- /usr/src/share/man/man5/bsd.port.mk.5	4 Nov 2025 12:52:28 -0000	1.654
+++ /usr/src/share/man/man5/bsd.port.mk.5	7 May 2026 23:34:55 -0000
@@ -158,6 +158,17 @@ Essentially invoke
 env -i ${MAKE_ENV} ${MAKE_PROGRAM} ${MAKE_FLAGS} \e
 	-f ${MAKE_FILE} ${ALL_TARGET}
 .Ed
+.It Cm check-diffsyms
+Compare dynamic symbols for shared libraries listed in the
+.Ev PLIST
+against the corresponding libraries from the installed package.
+The target requires an installed package for every checked subpackage
+and a completed
+.Cm fake
+stage; unchanged libraries produce no output, while changed libraries
+show added or removed libraries, or added, removed, weakened,
+strengthened, external reference, and PLT differences for matching
+libraries.
 .It Cm check-register
 Introspection target.
 Verify from the ports tree, without building anything, that the current
Index: /usr/ports/infrastructure/mk/bsd.port.mk
===================================================================
RCS file: /home/cvs/ports/infrastructure/mk/bsd.port.mk,v
diff -u -p -r1.1649 bsd.port.mk
--- /usr/ports/infrastructure/mk/bsd.port.mk	1 Apr 2026 15:14:57 -0000	1.1649
+++ /usr/ports/infrastructure/mk/bsd.port.mk	7 May 2026 23:39:53 -0000
@@ -2026,6 +2026,7 @@ CHECK_LIB_DEPENDS_ARGS += -F pthread
 
 _CHECK_LIB_DEPENDS = PORTSDIR=${PORTSDIR} ${_PERLSCRIPT}/check-lib-depends
 _CHECK_LIB_DEPENDS += -d ${_PKG_REPO} -B ${WRKINST} ${CHECK_LIB_DEPENDS_ARGS}
+_PORT_CHECK_SYM = ${_SHSCRIPT}/port-check-sym -B ${WRKINST} -P ${PREFIX}
 
 .for _s in ${MULTI_PACKAGES}
 .  if ${STATIC_PLIST${_s}:L} == "no"
@@ -2536,7 +2537,7 @@ _internal-all _internal-build _internal-
 	_internal-subpackage _internal-subupdate _internal-uninstall \
 	_internal-update _internal-update-or-install _internal-generate-readmes \
 	_internal-update-or-install-all _internal-update-plist \
-	lib-depends-check port-lib-depends-check update-patches:
+	lib-depends-check port-lib-depends-check check-diffsyms update-patches:
 .  if !defined(IGNORE_SILENT)
 	@${ECHO_MSG} "===>  ${FULLPKGNAME${SUBPACKAGE}}${_MASTER} ${IGNORE${SUBPACKAGE}} ${_EXTRA_IGNORE}."
 .  endif
@@ -2560,6 +2561,22 @@ port-lib-depends-check: ${WRKINST}/.save
 			${_CHECK_LIB_DEPENDS} -i -s ${WRKINST}/.saved_libs; \
 	done
 
+check-diffsyms: ${_FAKE_COOKIE}
+.for _S in ${BUILD_PACKAGES}
+	@b=$$(cd ${.CURDIR} && SUBPACKAGE=${_S} ${MAKE} print-plist|sed -ne '/^@pkgpath /s,,-e ,p'); \
+	a=$$(${PKG_INFO} -e ${FULLPKGPATH${_S}} $$b 2>/dev/null |sort -u); \
+	case $$a in \
+		'') echo 1>&2 "Fatal: no installed package for ${FULLPKGPATH${_S}}"; exit 1;; \
+		*) d=$$(${_PBUILD} mktemp -d ${WRKDIR}/check-diffsyms.XXXXXXXXXX || exit 1); \
+		   trap "${_PBUILD} rm -rf $$d" 0 1 2 3 15; \
+		   ${PKG_INFO} -qf $$a | sed -n '/^@lib /{ s///; p; }' | \
+			${_PBUILD} tee $$d/oldlibs >/dev/null || exit 1; \
+		   cd ${.CURDIR} && SUBPACKAGE=${_S} ${MAKE} print-plist-libs | \
+			${_PBUILD} ${_PORT_CHECK_SYM} -T $$d -o $$d/oldlibs; \
+		   r=$$?; ${_PBUILD} rm -rf $$d; trap - 0 1 2 3 15; exit $$r;; \
+	esac
+.endfor
+
 # Most standard port targets create a cookie to avoid being re-run.
 #
 # fetch is an exception, as it uses the files it fetches as `cookies',
@@ -3857,7 +3874,7 @@ _all_phony = ${_recursive_depends_target
 	delete-package distpatch do-build do-configure do-distpatch \
 	do-gen do-extract do-install do-test fetch-all \
 	install-all lib-depends lib-depends-list \
-	peek-ftp port-lib-depends-check post-build post-configure \
+	peek-ftp port-lib-depends-check check-diffsyms post-build post-configure \
 	post-distpatch post-extract post-install \
 	post-patch post-test pre-build pre-configure pre-extract pre-fake \
 	pre-install pre-patch pre-test prepare \
Index: /usr/ports/infrastructure/bin/port-check-sym
===================================================================
RCS file: /usr/ports/infrastructure/bin/port-check-sym
diff -N /usr/ports/infrastructure/bin/port-check-sym
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ /usr/ports/infrastructure/bin/port-check-sym	7 May 2026 23:46:34 -0000
@@ -0,0 +1,393 @@
+#!/bin/ksh
+# $OpenBSD$
+#
+# Copyright (c) 2026 Kirill A. Korinsky <kirill@korins.ky>
+# Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
+# Copyright (c) 2016,2019,2022 Philip Guenther <guenther@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# port-check-sym derives from /usr/src/lib/check_sym, but is
+# specialised for ports: it compares installed package libraries with
+# their WRKINST replacements, accepts PLIST library streams, and stays
+# silent when no ABI differences are found.
+
+pick_highest()
+{
+	old=
+	omaj=-1
+	omin=0
+	for i
+	do
+		[[ -f $i ]] || continue
+		maj=${i%.*}; maj=${maj##*.}
+		min=${i##*.}
+		if [[ $maj -gt $omaj || ( $maj -eq $omaj && $min -gt $omin ) ]]
+		then
+			old=$i
+			omaj=$maj
+			omin=$min
+		fi
+	done
+	[[ $old != "" ]]
+}
+
+fail() { echo "$*" >&2; exit 1; }
+
+usage()
+{
+	usage="usage: port-check-sym [-hv] -B wrkinst [-P prefix] [-T tmpdir] [-o oldlibs] [lib ...]"
+	[[ $# -eq 0 ]] || fail "port-check-sym: $*
+$usage"
+	echo "$usage"
+	exit 0
+}
+
+
+#
+#  Output helpers
+#
+output_if_not_empty()
+{
+	leader=$1
+	shift
+	if "$@" | grep -q .
+	then
+		echo "$leader"
+		"$@" | sed 's:^:	:'
+		echo
+	fi
+}
+
+
+#
+#  Dynamic library routines
+#
+
+dynamic_collect()
+{
+	readelf -sW $old | filt_symtab > $odir/Ds1
+	readelf -sW $new | filt_symtab > $odir/Ds2
+
+	readelf -rW $old > $odir/r1
+	readelf -rW $new > $odir/r2
+
+	case $(readelf -h $new | grep '^ *Machine:') in
+	*MIPS*)	cpu=mips64
+		gotsym1=$(readelf -d $old | awk '$2 ~ /MIPS_GOTSYM/{print $3}')
+		gotsym2=$(readelf -d $new | awk '$2 ~ /MIPS_GOTSYM/{print $3}')
+		;;
+	*HPPA*)	cpu=hppa;;
+	*)	cpu=dontcare;;
+	esac
+}
+
+jump_slots()
+{ 
+	case $cpu in
+	hppa)	awk '/IPLT/ && $5 != ""{print $5}' r$1
+		;;
+	mips64)	# the $((gotsym$1)) converts hex to decimal
+		awk -v g=$((gotsym$1)) \
+			'/^Symbol table ..symtab/{exit}
+			$6 == "PROTECTED" { next }
+			$1+0 >= g && $4 == "FUNC" {print $8}' Ds$1
+		;;
+	*)	awk '/JU*MP_SL/ && $5 != ""{print $5}' r$1
+		;;
+	esac | sort -o j$1
+}
+
+dynamic_sym()
+{
+	awk -v s=$1 '/^Symbol table ..symtab/{exit}
+		! /^ *[1-9]/   {next}
+		$5 == "LOCAL"  {next}
+		$7 == "UND"    {print $8     | ("sort -o DU" s); next }
+		$5 == "GLOBAL" {print $8     | ("sort -o DS" s) }
+		$5 == "WEAK"   {print $8     | ("sort -o DW" s) }
+		{print $8 | ("sort -o D" s)
+		 print $4, $5, $6, $8}' Ds$1 | sort -o d$1
+}
+
+dynamic_analysis()
+{
+	jump_slots $1
+	dynamic_sym $1
+	comm -23 j$1 DU$1 >J$1
+	return 0
+}
+
+dynamic_output()
+{
+	if ! cmp -s d[12]
+	then
+		printf "Dynamic export changes:\n"
+		output_if_not_empty "added:" comm -13 D[12]
+		output_if_not_empty "removed:" comm -23 D[12]
+		output_if_not_empty "weakened:" comm -12 DS1 DW2
+		output_if_not_empty "strengthened:" comm -12 DW1 DS2
+	fi
+	if ! cmp -s DU[12]
+	then
+		printf "External reference changes:\n"
+		output_if_not_empty "added:" comm -13 DU[12]
+		output_if_not_empty "removed:" comm -23 DU[12]
+	fi
+
+	if $verbose; then
+		printf "\nReloc counts:\nbefore:\n" 
+		grep ^R r1
+		printf "\nafter:\n"
+		grep ^R r2
+	fi
+
+	output_if_not_empty "PLT added:" comm -13 J[12]
+	output_if_not_empty "PLT removed:" comm -23 J[12]
+}
+
+dynamic_changed()
+{
+	! cmp -s d[12] || ! cmp -s DU[12] || ! cmp -s J[12]
+}
+
+make_odir()
+{
+	if [[ -n $tmpdir ]]
+	then
+		mktemp -d "$tmpdir/port-check-sym.XXXXXXXXXX"
+	else
+		mktemp -dt port-check-sym.XXXXXXXXXX
+	fi
+}
+
+compare_libs()
+(
+	unset odir
+	trap 'ret=$?; rm -rf "$odir"; exit $ret' 0 1 2 15 ERR
+	odir=$(make_odir)
+
+	set -C
+	for i in $odir/$file_list
+	do
+		rm -f $i
+		3>$i
+		files="$files $i"
+	done
+	set +C
+
+
+	#
+	#  Collect data
+	#
+	dynamic_collect
+
+	# Now that we're done accessing $old and $new (which could be
+	# relative paths), chdir into our work directory, whatever it is
+	cd $odir
+
+	#
+	#  Do The Job
+	#
+	for i in 1 2
+	do
+		dynamic_analysis $i
+	done
+
+	if dynamic_changed || $verbose
+	then
+		echo "$old --> $new"
+		dynamic_output
+	fi
+)
+
+port_check_lib()
+{
+	case $1 in
+	"")	return 0;;
+	esac
+
+	case ${1##*/} in
+	lib*.so.*)	;;
+	*)		return 0;;
+	esac
+
+	case $1 in
+	/*)	oldpath=$1
+		new=$wrkinst$1
+		;;
+	*)	oldpath=$prefix/$1
+		new=$wrkinst$prefix/$1
+		;;
+	esac
+
+	lib=${oldpath##*/}
+	lib=${lib%%.so.*}
+	if [[ -f $oldpath ]]
+	then
+		old=$oldpath
+	else
+		if ! pick_highest ${oldpath%/*}/$lib.so.*
+		then
+			echo "$oldpath doesn't exist" >&2
+			return 1
+		fi
+	fi
+	[[ -f $new ]] || {
+		echo "$new doesn't exist" >&2
+		return 1
+	}
+
+	compare_libs
+}
+
+port_check_lib_pair()
+{
+	case $1 in
+	/*)	old=$1;;
+	*)	old=$prefix/$1;;
+	esac
+	case $2 in
+	/*)	new=$wrkinst$2;;
+	*)	new=$wrkinst$prefix/$2;;
+	esac
+
+	[[ -f $old ]] || {
+		echo "$old doesn't exist" >&2
+		return 1
+	}
+	[[ -f $new ]] || {
+		echo "$new doesn't exist" >&2
+		return 1
+	}
+
+	compare_libs
+}
+
+port_lib_map()
+{
+	awk -v prefix="$prefix" '/(^|\/)lib[^\/]*\.so\./ {
+		k = $0
+		if (prefix != "" && index(k, prefix "/") == 1)
+			k = substr(k, length(prefix) + 2)
+		sub(/\.so\..*$/, "", k)
+		print k, $0
+	}'
+}
+
+port_check_libs()
+(
+	unset odir
+	trap 'ret=$?; rm -rf "$odir"; exit $ret' 0 1 2 15 ERR
+	odir=$(make_odir)
+
+	if [[ $# -eq 0 ]]
+	then
+		cat > $odir/newlibs
+	else
+		for _lib
+		do
+			echo "$_lib"
+		done > $odir/newlibs
+	fi
+
+	port_lib_map < $old_libs | sort -u > $odir/oldmap
+	port_lib_map < $odir/newlibs | sort -u > $odir/newmap
+
+	join -v 2 $odir/oldmap $odir/newmap |
+	    sed 's/^[^ ]* //' > $odir/added
+	join -v 1 $odir/oldmap $odir/newmap |
+	    sed 's/^[^ ]* //' > $odir/removed
+	if [[ -s $odir/added || -s $odir/removed ]]
+	then
+		printf "Library changes:\n"
+		output_if_not_empty "added:" cat $odir/added
+		output_if_not_empty "removed:" cat $odir/removed
+	fi
+
+	join $odir/oldmap $odir/newmap > $odir/common
+	failed=0
+	while read _key _old _new
+	do
+		if ! port_check_lib_pair "$_old" "$_new"
+		then
+			failed=1
+		fi
+	done < $odir/common
+
+	exit $failed
+)
+
+
+unset odir
+file_list={D{,S,s,W,U},J,d,j,r}{1,2}
+
+prefix=${PREFIX:-/usr/local}
+wrkinst=${WRKINST:-}
+verbose=false
+failed=0
+old_libs=
+tmpdir=
+
+while getopts :B:ho:P:T:v opt "$@"
+do
+	case $opt in
+	B)	wrkinst=$OPTARG;;
+	h)	usage;;
+	o)	old_libs=$OPTARG;;
+	P)	prefix=$OPTARG;;
+	T)	tmpdir=$OPTARG;;
+	v)	verbose=true;;
+	\?)	usage "unknown option -- $OPTARG";;
+	esac
+done
+shift $((OPTIND - 1))
+
+[[ -n $wrkinst ]] || fail "WRKINST not set"
+[[ -z $tmpdir || -d $tmpdir ]] || fail "$tmpdir doesn't exist"
+prefix=${prefix%/}
+wrkinst=${wrkinst%/}
+
+# Filter the output of readelf -s to be easier to parse by removing a
+# field that only appears on some symbols: [<other>: 88]
+# Not really arch-specific, but I've only seen it on alpha
+filt_symtab() { sed 's/\[<other>: [0-9a-f]*\]//'; }
+
+if [[ -n $old_libs ]]
+then
+	[[ -f $old_libs ]] || fail "$old_libs doesn't exist"
+	port_check_libs "$@"
+	exit $?
+fi
+
+if [[ $# -eq 0 ]]
+then
+	while IFS= read _lib
+	do
+		if ! port_check_lib "$_lib"
+		then
+			failed=1
+		fi
+	done
+else
+	for _lib
+	do
+		if ! port_check_lib "$_lib"
+		then
+			failed=1
+		fi
+	done
+fi
+
+exit $failed


-- 
wbr, Kirill