1#!/bin/sh
2
3usage() {
4  cat <<"_EOF_"
5Usage: sh test/pkgcheck.sh [--zlib-compat]
6
7Verifies that the various build systems produce identical results on a Unixlike system.
8If --zlib-compat, tests with zlib compatible builds.
9
10To build the 32 bit version for the current 64 bit arch:
11
12$ sudo apt install ninja-build diffoscope gcc-multilib
13$ export CMAKE_ARGS="-DCMAKE_C_FLAGS=-m32" CFLAGS=-m32 LDFLAGS=-m32
14$ sh test/pkgcheck.sh
15
16To cross-build, install the appropriate qemu and gcc packages,
17and set the environment variables used by configure or cmake.
18On Ubuntu, for example (values taken from .github/workflows/pkgconf.yml):
19
20arm HF:
21$ sudo apt install ninja-build diffoscope qemu gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
22$ export CHOST=arm-linux-gnueabihf
23$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=${CHOST}"
24
25aarch64:
26$ sudo apt install ninja-build diffoscope qemu gcc-aarch64-linux-gnu libc6-dev-arm64-cross
27$ export CHOST=aarch64-linux-gnu
28$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64.cmake -DCMAKE_C_COMPILER_TARGET=${CHOST}"
29
30ppc (32 bit big endian):
31$ sudo apt install ninja-build diffoscope qemu gcc-powerpc-linux-gnu libc6-dev-powerpc-cross
32$ export CHOST=powerpc-linux-gnu
33$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc.cmake"
34
35ppc64le:
36$ sudo apt install ninja-build diffoscope qemu gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross
37$ export CHOST=powerpc64le-linux-gnu
38$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc64le.cmake"
39
40then:
41$ export CC=${CHOST}-gcc
42$ sh test/pkgcheck.sh [--zlib-compat]
43
44Note: on Mac, you may also need to do 'sudo xcode-select -r' to get cmake to match configure/make's behavior (i.e. omit -isysroot).
45_EOF_
46}
47
48set -ex
49
50# Caller can also set CMAKE_ARGS or CONFIGURE_ARGS if desired
51CMAKE_ARGS=${CMAKE_ARGS}
52CONFIGURE_ARGS=${CONFIGURE_ARGS}
53
54case "$1" in
55--zlib-compat)
56  suffix=""
57  CMAKE_ARGS="$CMAKE_ARGS -DZLIB_COMPAT=ON"
58  CONFIGURE_ARGS="$CONFIGURE_ARGS --zlib-compat"
59  ;;
60"")
61  suffix="-ng"
62  ;;
63*)
64  echo "Unknown arg '$1'"
65  usage
66  exit 1
67  ;;
68esac
69
70if ! test -f "configure"
71then
72  echo "Please run from top of source tree"
73  exit 1
74fi
75
76# Tell GNU's ld etc. to use Jan 1 1970 when embedding timestamps
77# Probably only needed on older systems (ubuntu 14.04, BSD?)
78export SOURCE_DATE_EPOCH=0
79case $(uname) in
80Darwin)
81  # Tell Apple's ar etc. to use zero timestamps
82  export ZERO_AR_DATE=1
83  # What CPU are we running on, exactly?
84  sysctl -n machdep.cpu.brand_string
85  sysctl -n machdep.cpu.features
86  sysctl -n machdep.cpu.leaf7_features
87  sysctl -n machdep.cpu.extfeatures
88  ;;
89esac
90
91# Use same compiler for make and cmake builds
92if test "$CC"x = ""x
93then
94  if clang --version
95  then
96    export CC=clang
97  elif gcc --version
98  then
99    export CC=gcc
100  fi
101fi
102
103# New build system
104# Happens to delete top-level zconf.h
105# (which itself is a bug, https://github.com/madler/zlib/issues/162 )
106# which triggers another bug later in configure,
107# https://github.com/madler/zlib/issues/499
108rm -rf btmp2 pkgtmp2
109mkdir btmp2 pkgtmp2
110export DESTDIR=$(pwd)/pkgtmp2
111cd btmp2
112  cmake -G Ninja ${CMAKE_ARGS} ..
113  ninja -v
114  ninja install
115cd ..
116
117# Original build system
118rm -rf btmp1 pkgtmp1
119mkdir btmp1 pkgtmp1
120export DESTDIR=$(pwd)/pkgtmp1
121cd btmp1
122  case $(uname) in
123  Darwin)
124    export LDFLAGS="-Wl,-headerpad_max_install_names"
125    ;;
126  esac
127  ../configure $CONFIGURE_ARGS
128  make
129  make install
130cd ..
131
132repack_ar() {
133  if ! cmp --silent pkgtmp1/usr/local/lib/libz$suffix.a pkgtmp2/usr/local/lib/libz$suffix.a
134  then
135    echo "libz$suffix.a does not match.  Probably filenames differ (.o vs .c.o).  Unpacking and renaming..."
136    # Note: %% is posix shell syntax meaning "Remove Largest Suffix Pattern", see
137    # https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
138    cd pkgtmp1; ar x usr/local/lib/libz$suffix.a; rm usr/local/lib/libz$suffix.a; cd ..
139    cd pkgtmp2; ar x usr/local/lib/libz$suffix.a; rm usr/local/lib/libz$suffix.a; for a in *.c.o; do mv $a ${a%%.c.o}.o; done; cd ..
140    # Also, remove __.SYMDEF SORTED if present, as it has those funky .c.o names embedded in it.
141    rm -f pkgtmp[12]/__.SYMDEF\ SORTED
142  fi
143}
144
145case $(uname) in
146Darwin)
147  # Remove the build uuid.
148  dylib1=$(find pkgtmp1 -type f -name '*.dylib*')
149  dylib2=$(find pkgtmp2 -type f -name '*.dylib*')
150  strip -x -no_uuid "$dylib1"
151  strip -x -no_uuid "$dylib2"
152  ;;
153esac
154
155# The ar on newer systems defaults to -D (i.e. deterministic),
156# but FreeBSD 12.1, Debian 8, and Ubuntu 14.04 seem to not do that.
157# I had trouble passing -D safely to the ar inside CMakeLists.txt,
158# so punt and unpack the archive if needed before comparing.
159# Also, cmake uses different .o suffix anyway...
160repack_ar
161
162if diff -Nur pkgtmp1 pkgtmp2
163then
164  echo pkgcheck-cmake-bits-identical PASS
165else
166  echo pkgcheck-cmake-bits-identical FAIL
167  dylib1=$(find pkgtmp1 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print)
168  dylib2=$(find pkgtmp2 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print)
169  diffoscope $dylib1 $dylib2 | cat
170  exit 1
171fi
172
173rm -rf btmp1 btmp2 pkgtmp1 pkgtmp2
174
175# any failure would have caused an early exit already
176echo "pkgcheck: PASS"
177