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=1d2504ddc4894786fdf61d41a9bfa435cd8b1935
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
94else
95  # Canonicalize CHOST to work around bug in original
96  # zlib's configure
97  export CHOST=$(sh $TESTDIR/../tools/config.sub $CHOST)
98fi
99if test "$CHOST" = ""
100then
101  echo "abicheck: SKIP, as we don't know CHOST"
102  exit 0
103fi
104
105ABIFILE="test/abi/zlib$suffix-$ABI_GIT_COMMIT-$CHOST$M32.abi"
106if ! $refresh && $refresh_if && ! test -f "$ABIFILE"
107then
108  refresh=true
109fi
110abidw --version
111
112if $refresh
113then
114  # Check out reference source
115  rm -rf btmp1
116  mkdir -p btmp1/src.d
117  cd btmp1/src.d
118  git init
119  git remote add origin $ABI_GIT_REPO
120  git fetch origin $ABI_GIT_COMMIT
121  git reset --hard FETCH_HEAD
122  cd ..
123  # Build unstripped, uninstalled, very debug shared library
124  CFLAGS="$CFLAGS -ggdb" sh src.d/configure $CONFIGURE_ARGS
125  make -j2
126  cd ..
127  # Find shared library, extract its abi
128  dylib1=$(find btmp1 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print)
129  abidw $dylib1 > "$ABIFILE"
130  # Maintainers may wish to check $ABIFILE into git when a new
131  # target is added, or when a major release happens that is
132  # intended to change the ABI.  Alternately, this script could
133  # just always rebuild the reference source, and dispense with
134  # caching abi files in git (but that would slow builds down).
135fi
136
137if test -f "$ABIFILE"
138then
139  ABIFILE="$ABIFILE"
140else
141  echo "abicheck: SKIP: $ABIFILE not found; rerun with --refresh or --refresh_if"
142  exit 0
143fi
144
145# Build unstripped, uninstalled, very debug shared library
146rm -rf btmp2
147mkdir btmp2
148cd btmp2
149CFLAGS="$CFLAGS -ggdb" ../configure $CONFIGURE_ARGS_NG
150make -j2
151cd ..
152# Find shared library, extract its abi
153dylib2=$(find btmp2 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print)
154abidw $dylib2 > btmp2/zlib${suffix}-built.abi
155
156# Compare it to the reference
157# FIXME: use --no-added-syms for now, but we probably want to be more strict.
158if abidiff --no-added-syms --suppressions test/abi/ignore "$ABIFILE" btmp2/zlib${suffix}-built.abi
159then
160  echo "abicheck: PASS"
161else
162  echo "abicheck: FAIL"
163  exit 1
164fi
165