#! /bin/sh # Written by Zack Weinberg in 2017. # To the extent possible under law, Zack Weinberg has waived all # copyright and related or neighboring rights to this work. # # See https://creativecommons.org/publicdomain/zero/1.0/ for further # details. # This test is only run if we are building a shared library intended # to be binary backward compatible with GNU libc (libcrypt.so.1). # It locates any installed version of libcrypt.so.1, and verifies that # each public symbol exposed by that library is also exposed by our # libcrypt.so.1 with a matching symbol version. # # Due to limitations in Automake, this program takes parameters from # the environment: # $lib_la - full pathname of libcrypt.la set -e LC_ALL=C; export LC_ALL get_symbols_with_versions () { nm -gD --with-symbol-versions "$1" | grep -v ' U ' | cut -d' ' -f3 | sed -e 's/@@*/ /; /^\([A-Z0-9_.]*\) \1$/d' | sort -u } get_our_symbols_with_versions () { eval $(grep dlname= "$1") get_symbols_with_versions "${1%/*}/.libs/${dlname}" unset dlname } get_their_symbols_with_versions () { ( set -e cd "$1" cat >test.c <<\EOF extern char *crypt(const char *, const char *); int main(int argc, char **argv) { return !!crypt(argv[0], argv[1]); } EOF ${CC-cc} test.c -lcrypt >&2 || exit 77 if ldd ./a.out | grep -qF libcrypt.so.1; then get_symbols_with_versions $(ldd ./a.out | grep -F libcrypt.so.1 | cut -d' ' -f3) else exit 77 fi ) if [ $? -ne 0 ]; then exit $?; fi } if [ ! -f "$lib_la" ]; then echo "Usage: lib_la=/path/to/library.la $0" >&2 exit 1 fi # If 'nm' and/or 'ldd' are not available, this test will not work. command -v nm > /dev/null 2>&1 || { echo "Error: 'nm' is unavailable" >&2 exit 77 } command -v ldd > /dev/null 2>&1 || { echo "Error: 'ldd' is unavailable" >&2 exit 77 } workdir="" trap '[ -z "$workdir" ] || rm -rf "$workdir" || :' 0 workdir="$(mktemp -d)" get_our_symbols_with_versions "$lib_la" > "$workdir/our_symbols" get_their_symbols_with_versions "$workdir" > "$workdir/their_symbols" # It's okay if we define more symbol (versions) than they do, but every # symbol they define should have a matching definition in our library. missing_symbols="$(comm -13 "$workdir/our_symbols" "$workdir/their_symbols")" if [ -n "$missing_symbols" ]; then printf '*** Missing symbols: %s\n' "$missing_symbols" >&2 exit 1 fi exit 0