1#!/bin/sh
2set -ex
3TESTDIR="$(cd $(dirname "$0"); pwd)"
4
5usage() {
6    cat <<_EOF_
7Usage: $0 [--zlib-compat][--refresh][--refresh-if]
8
9Build shared library with -ggdb, then compare its ABI to the stable
10ABI, and abort if differences found.
11
12Options:
13--zlib-compat  - check the ABI of the zlib-compatible flavor of zlib-ng.
14--refresh      - build the reference library and extract its ABI rather than using a stored ABI file.
15--refresh-if   - refresh only if ABI file not present.
16
17Obeys CHOST, CONFIGURE_ARGS, CFLAGS, and LDFLAGS.
18
19Requires libabigail (on Ubuntu, install package abigail-tools).
20_EOF_
21}
22
23# Print the multiarch tuple for the current (non-cross) machine,
24# or the empty string if unavailable.
25detect_chost() {
26    dpkg-architecture -qDEB_HOST_MULTIARCH ||
27     $CC -print-multiarch ||
28     $CC -print-search-dirs | sed 's/:/\n/g' | grep -E '^/lib/[^/]+$' | sed 's%.*/%%' ||
29     true
30}
31
32if ! test -f "configure"
33then
34  echo "Please run from top of source tree"
35  exit 1
36fi
37
38suffix="-ng"
39CONFIGURE_ARGS_NG="$CONFIGURE_ARGS"
40refresh=false
41refresh_if=false
42for arg
43do
44  case "$arg" in
45  --zlib-compat)
46    suffix=""
47    CONFIGURE_ARGS_NG="$CONFIGURE_ARGS_NG --zlib-compat"
48    ;;
49  --refresh)
50    refresh=true
51    ;;
52  --refresh-if)
53    refresh_if=true
54    ;;
55  --help)
56    usage
57    exit 0
58    ;;
59  *)
60    echo "Unknown arg '$arg'"
61    usage
62    exit 1
63    ;;
64  esac
65done
66
67# Choose reference repo and commit
68if test "$suffix" = ""
69then
70  # Reference is zlib 1.2.11
71  ABI_GIT_REPO=https://github.com/madler/zlib.git
72  ABI_GIT_COMMIT=v1.2.11
73else
74  # Reference should be the tag for zlib-ng 2.0
75  # but until that bright, shining day, use some
76  # random recent SHA.  Annoyingly, can't shorten it.
77  ABI_GIT_REPO=https://github.com/zlib-ng/zlib-ng.git
78  ABI_GIT_COMMIT=56ce27343bf295ae9457f8e3d38ec96d2f949a1c
79fi
80# FIXME: even when using a tag, check the hash.
81
82# Test compat build for ABI compatibility with zlib
83if test "$CHOST" = ""
84then
85  # Note: don't export CHOST here, as we don't want configure seeing it
86  # when it's just the name for the build machine.
87  # Leave it as a plain shell variable, not an environment variable.
88  CHOST=$(detect_chost)
89  # Support -m32 for non-cross builds.
90  case "$CFLAGS" in
91  *-m32*) M32="-m32";;
92  *) M32="";;
93  esac
94fi
95
96# Canonicalize CHOST to work around bug in original zlib's configure
97# (Don't export it if it wasn't already exported, else may cause
98# default compiler detection failure and shared library link error
99# when building both zlib and zlib-ng.
100# See https://github.com/zlib-ng/zlib-ng/issues/1219)
101CHOST=$(sh $TESTDIR/../tools/config.sub $CHOST)
102
103if test "$CHOST" = ""
104then
105  echo "abicheck: SKIP, as we don't know CHOST"
106  exit 0
107fi
108
109ABIFILE="test/abi/zlib$suffix-$ABI_GIT_COMMIT-$CHOST$M32.abi"
110if ! $refresh && $refresh_if && ! test -f "$ABIFILE"
111then
112  refresh=true
113fi
114abidw --version
115
116if $refresh
117then
118  # Check out reference source
119  rm -rf btmp1
120  mkdir -p btmp1/src.d
121  cd btmp1/src.d
122  git init
123  git remote add origin $ABI_GIT_REPO
124  git fetch origin $ABI_GIT_COMMIT
125  git reset --hard FETCH_HEAD
126  cd ..
127  # Build unstripped, uninstalled, very debug shared library
128  CFLAGS="$CFLAGS -ggdb" src.d/configure $CONFIGURE_ARGS
129  make -j2
130  cd ..
131  # Find shared library, extract its abi
132  dylib1=$(find btmp1 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print)
133  abidw $dylib1 > "$ABIFILE"
134  # Maintainers may wish to check $ABIFILE into git when a new
135  # target is added, or when a major release happens that is
136  # intended to change the ABI.  Alternately, this script could
137  # just always rebuild the reference source, and dispense with
138  # caching abi files in git (but that would slow builds down).
139fi
140
141if ! test -f "$ABIFILE"
142then
143  echo "abicheck: SKIP: $ABIFILE not found; rerun with --refresh or --refresh-if"
144  exit 1
145fi
146
147# Build unstripped, uninstalled, very debug shared library
148rm -rf btmp2
149mkdir btmp2
150cd btmp2
151CFLAGS="$CFLAGS -ggdb" ../configure $CONFIGURE_ARGS_NG
152make -j2
153cd ..
154# Find shared library, extract its abi
155dylib2=$(find btmp2 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print)
156abidw $dylib2 > btmp2/zlib${suffix}-built.abi
157
158# Compare it to the reference
159# FIXME: use --no-added-syms for now, but we probably want to be more strict.
160if abidiff --no-added-syms --suppressions test/abi/ignore "$ABIFILE" btmp2/zlib${suffix}-built.abi
161then
162  echo "abicheck: PASS"
163else
164  echo "abicheck: FAIL"
165  exit 1
166fi
167