cannam@62: #! /usr/bin/env bash cannam@62: cannam@62: set -euo pipefail cannam@62: cannam@62: doit() { cannam@62: echo "@@@@ $@" cannam@62: "$@" cannam@62: } cannam@62: cannam@62: QUICK= cannam@62: cannam@62: PARALLEL=$(nproc 2>/dev/null || echo 1) cannam@62: cannam@62: while [ $# -gt 0 ]; do cannam@62: case "$1" in cannam@62: -j* ) cannam@62: PARALLEL=${1#-j} cannam@62: ;; cannam@62: test ) cannam@62: ;; # nothing cannam@62: quick ) cannam@62: QUICK=quick cannam@62: ;; cannam@62: caffeinate ) cannam@62: # Re-run preventing sleep. cannam@62: shift cannam@62: exec caffeinate -ims $0 $@ cannam@62: ;; cannam@62: tmpdir ) cannam@62: # Clone to a temp directory. cannam@62: if [ "$#" -lt 2 ]; then cannam@62: echo "usage: $0 tmpdir NAME [COMMAND]" >&2 cannam@62: exit 1 cannam@62: fi cannam@62: DIR=/tmp/$2 cannam@62: shift 2 cannam@62: if [ -e $DIR ]; then cannam@62: if [ "${DIR/*..*}" = "" ]; then cannam@62: echo "NO DO NOT PUT .. IN THERE IT'S GOING TO GO IN /tmp AND I'M GONNA DELETE IT" >&2 cannam@62: exit 1 cannam@62: fi cannam@62: if [ ! -e "$DIR/super-test.sh" ]; then cannam@62: echo "$DIR exists and it doesn't look like one of mine." >&2 cannam@62: exit 1 cannam@62: fi cannam@62: # make distcheck leaves non-writable files when it fails, so we need to chmod to be safe. cannam@62: chmod -R +w $DIR cannam@62: rm -rf $DIR cannam@62: fi cannam@62: git clone . $DIR cannam@62: cd $DIR cannam@62: exec ./super-test.sh "$@" cannam@62: ;; cannam@62: remote ) cannam@62: if [ "$#" -lt 2 ]; then cannam@62: echo "usage: $0 remote HOST [COMMAND]" >&2 cannam@62: exit 1 cannam@62: fi cannam@62: HOST=$2 cannam@62: shift 2 cannam@62: echo "=========================================================================" cannam@62: echo "Pushing code to $HOST..." cannam@62: echo "=========================================================================" cannam@62: BRANCH=$(git rev-parse --abbrev-ref HEAD) cannam@62: ssh $HOST '(chmod -fR +w tmp-test-capnp || true) && rm -rf tmp-test-capnp && mkdir tmp-test-capnp && git init tmp-test-capnp' cannam@62: git push ssh://$HOST/~/tmp-test-capnp "$BRANCH:test" cannam@62: ssh $HOST "cd tmp-test-capnp && git checkout test" cannam@62: exec ssh $HOST "cd tmp-test-capnp && ./super-test.sh $@ && cd .. && rm -rf tmp-test-capnp" cannam@62: ;; cannam@62: compiler ) cannam@62: if [ "$#" -lt 2 ]; then cannam@62: echo "usage: $0 compiler CXX_NAME" >&2 cannam@62: exit 1 cannam@62: fi cannam@62: export CXX="$2" cannam@62: shift cannam@62: ;; cannam@62: clang ) cannam@62: export CXX=clang++ cannam@62: ;; cannam@62: gcc-4.9 ) cannam@62: export CXX=g++-4.9 cannam@62: ;; cannam@62: gcc-4.8 ) cannam@62: export CXX=g++-4.8 cannam@62: ;; cannam@62: gcc-4.7 ) cannam@62: export CXX=g++-4.7 cannam@62: ;; cannam@62: mingw ) cannam@62: if [ "$#" -ne 2 ]; then cannam@62: echo "usage: $0 mingw CROSS_HOST" >&2 cannam@62: exit 1 cannam@62: fi cannam@62: CROSS_HOST=$2 cannam@62: cannam@62: cd c++ cannam@62: test -e configure || doit autoreconf -i cannam@62: test ! -e Makefile || (echo "ERROR: Directory unclean!" >&2 && false) cannam@62: cannam@62: export WINEPATH='Z:\usr\'"$CROSS_HOST"'\lib;Z:\usr\lib\gcc\'"$CROSS_HOST"'\6.3-win32;Z:'"$PWD"'\.libs' cannam@62: cannam@62: doit ./configure --host="$CROSS_HOST" --disable-shared CXXFLAGS='-static-libgcc -static-libstdc++' cannam@62: cannam@62: doit make -j$PARALLEL check cannam@62: doit make distclean cannam@62: rm -f *-mingw.exe cannam@62: exit 0 cannam@62: ;; cannam@62: android ) cannam@62: # To install Android SDK: cannam@62: # - Download command-line tools: https://developer.android.com/studio/index.html#command-tools cannam@62: # - Run $SDK_HOME/tools/bin/sdkmanager platform-tools 'platforms;android-25' 'system-images;android-25;google_apis;armeabi-v7a' emulator 'build-tools;25.0.2' ndk-bundle cannam@62: # - Run $SDK_HOME/tools/bin/avdmanager create avd -n capnp -k 'system-images;android-25;google_apis;armeabi-v7a' -b google_apis/armeabi-v7a cannam@62: # - Run $SDK_HOME/ndk-bundle/build/tools/make_standalone_toolchain.py --arch arm --api 24 --install-dir $TOOLCHAIN_HOME cannam@62: if [ "$#" -ne 4 ]; then cannam@62: echo "usage: $0 android SDK_HOME TOOLCHAIN_HOME CROSS_HOST" >&2 cannam@62: exit 1 cannam@62: fi cannam@62: SDK_HOME=$2 cannam@62: TOOLCHAIN_HOME=$3 cannam@62: CROSS_HOST=$4 cannam@62: cannam@62: cd c++ cannam@62: test -e configure || doit autoreconf -i cannam@62: test ! -e Makefile || (echo "ERROR: Directory unclean!" >&2 && false) cannam@62: doit ./configure --disable-shared cannam@62: doit make -j$PARALLEL capnp capnpc-c++ cannam@62: cannam@62: cp capnp capnp-host cannam@62: cp capnpc-c++ capnpc-c++-host cannam@62: cannam@62: export PATH="$TOOLCHAIN_HOME/bin:$PATH" cannam@62: doit make distclean cannam@62: doit ./configure --host="$CROSS_HOST" --with-external-capnp --disable-shared CXXFLAGS='-pie -fPIE' CAPNP=./capnp-host CAPNPC_CXX=./capnpc-c++-host cannam@62: cannam@62: doit make -j$PARALLEL cannam@62: doit make -j$PARALLEL capnp-test cannam@62: cannam@62: echo "Starting emulator..." cannam@62: trap 'kill $(jobs -p)' EXIT cannam@62: # TODO(someday): Speed up with KVM? Then maybe we won't have to skip fuzz tests? cannam@62: $SDK_HOME/emulator/emulator -avd capnp -no-window & cannam@62: $SDK_HOME/platform-tools/adb 'wait-for-device' cannam@62: echo "Waiting for localhost to be resolvable..." cannam@62: doit $SDK_HOME/platform-tools/adb shell 'while ! ping -c 1 localhost > /dev/null 2>&1; do sleep 1; done' cannam@62: # TODO(cleanup): With 'adb shell' I find I cannot put files anywhere, so I'm using 'su' a cannam@62: # lot here. There is probably a better way. cannam@62: doit $SDK_HOME/platform-tools/adb shell 'su 0 tee /data/capnp-test > /dev/null' < capnp-test cannam@62: doit $SDK_HOME/platform-tools/adb shell 'su 0 chmod a+rx /data/capnp-test' cannam@62: doit $SDK_HOME/platform-tools/adb shell 'cd /data && CAPNP_SKIP_FUZZ_TEST=1 su 0 /data/capnp-test && echo ANDROID_""TESTS_PASSED' | tee android-test.log cannam@62: grep -q ANDROID_TESTS_PASSED android-test.log cannam@62: cannam@62: doit make distclean cannam@62: rm -f capnp-host capnpc-c++-host cannam@62: exit 0 cannam@62: ;; cannam@62: cmake ) cannam@62: cd c++ cannam@62: rm -rf cmake-build cannam@62: mkdir cmake-build cannam@62: cd cmake-build cannam@62: doit cmake -G "Unix Makefiles" .. cannam@62: doit make -j$PARALLEL check cannam@62: exit 0 cannam@62: ;; cannam@62: exotic ) cannam@62: echo "=========================================================================" cannam@62: echo "MinGW 64-bit" cannam@62: echo "=========================================================================" cannam@62: "$0" mingw x86_64-w64-mingw32 cannam@62: echo "=========================================================================" cannam@62: echo "MinGW 32-bit" cannam@62: echo "=========================================================================" cannam@62: "$0" mingw i686-w64-mingw32 cannam@62: echo "=========================================================================" cannam@62: echo "Android" cannam@62: echo "=========================================================================" cannam@62: "$0" android /home/kenton/android-sdk-linux /home/kenton/android-24 arm-linux-androideabi cannam@62: echo "=========================================================================" cannam@62: echo "CMake" cannam@62: echo "=========================================================================" cannam@62: "$0" cmake cannam@62: exit 0 cannam@62: ;; cannam@62: clean ) cannam@62: rm -rf tmp-staging cannam@62: cd c++ cannam@62: if [ -e Makefile ]; then cannam@62: doit make maintainer-clean cannam@62: fi cannam@62: rm -f capnproto-*.tar.gz samples/addressbook samples/addressbook.capnp.c++ \ cannam@62: samples/addressbook.capnp.h cannam@62: exit 0 cannam@62: ;; cannam@62: help ) cannam@62: echo "usage: $0 [COMMAND]" cannam@62: echo "commands:" cannam@62: echo " test Runs tests (the default)." cannam@62: echo " clang Runs tests using Clang compiler." cannam@62: echo " gcc-4.7 Runs tests using gcc-4.7." cannam@62: echo " gcc-4.8 Runs tests using gcc-4.8." cannam@62: echo " gcc-4.9 Runs tests using gcc-4.9." cannam@62: echo " remote HOST Runs tests on HOST via SSH." cannam@62: echo " mingw Cross-compiles to MinGW and runs tests using WINE." cannam@62: echo " android Cross-compiles to Android and runs tests using emulator." cannam@62: echo " clean Delete temporary files that may be left after failure." cannam@62: echo " help Prints this help text." cannam@62: exit 0 cannam@62: ;; cannam@62: * ) cannam@62: echo "unknown command: $1" >&2 cannam@62: echo "try: $0 help" >&2 cannam@62: exit 1 cannam@62: ;; cannam@62: esac cannam@62: shift cannam@62: done cannam@62: cannam@62: # Build optimized builds because they catch more problems, but also enable debugging macros. cannam@62: # Enable lots of warnings and make sure the build breaks if they fire. Disable strict-aliasing cannam@62: # because GCC warns about code that I know is OK. Disable sign-compare because I've fixed more cannam@62: # sign-compare warnings than probably all other warnings combined and I've never seen it flag a cannam@62: # real problem. Disable unused parameters because it's stupidly noisy and never a real problem. cannam@62: # Enable expensive release-gating tests. cannam@62: export CXXFLAGS="-O2 -DDEBUG -Wall -Wextra -Werror -Wno-strict-aliasing -Wno-sign-compare -Wno-unused-parameter -DCAPNP_EXPENSIVE_TESTS=1" cannam@62: cannam@62: STAGING=$PWD/tmp-staging cannam@62: cannam@62: rm -rf "$STAGING" cannam@62: mkdir "$STAGING" cannam@62: mkdir "$STAGING/bin" cannam@62: mkdir "$STAGING/lib" cannam@62: export PATH=$STAGING/bin:$PATH cannam@62: export LD_LIBRARY_PATH=$STAGING/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} cannam@62: export PKG_CONFIG_PATH=$STAGING/lib/pkgconfig cannam@62: cannam@62: if [ "$QUICK" = quick ]; then cannam@62: echo "************************** QUICK TEST ***********************************" cannam@62: fi cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Building c++" cannam@62: echo "=========================================================================" cannam@62: cannam@62: # Apple now aliases gcc to clang, so probe to find out what compiler we're really using. cannam@62: if (${CXX:-g++} -dM -E -x c++ /dev/null 2>&1 | grep -q '__clang__'); then cannam@62: IS_CLANG=yes cannam@62: DISABLE_OPTIMIZATION_IF_GCC= cannam@62: else cannam@62: IS_CLANG=no cannam@62: DISABLE_OPTIMIZATION_IF_GCC=-O0 cannam@62: fi cannam@62: cannam@62: if [ $IS_CLANG = yes ]; then cannam@62: # Don't fail out on this ridiculous "argument unused during compilation" warning. cannam@62: export CXXFLAGS="$CXXFLAGS -Wno-error=unused-command-line-argument" cannam@62: else cannam@62: # GCC emits uninitialized warnings all over and they seem bogus. We use valgrind to test for cannam@62: # uninitialized memory usage later on. GCC 4 also emits strange bogus warnings with cannam@62: # -Wstrict-overflow, so we disable it. cannam@62: CXXFLAGS="$CXXFLAGS -Wno-maybe-uninitialized -Wno-strict-overflow" cannam@62: fi cannam@62: cannam@62: cd c++ cannam@62: doit autoreconf -i cannam@62: doit ./configure --prefix="$STAGING" cannam@62: doit make -j$PARALLEL check cannam@62: cannam@62: if [ $IS_CLANG = no ]; then cannam@62: # Verify that generated code compiles with pedantic warnings. Make sure to treat capnp headers cannam@62: # as system headers so warnings in them are ignored. cannam@62: doit ${CXX:-g++} -isystem src -std=c++11 -fno-permissive -pedantic -Wall -Wextra -Werror \ cannam@62: -c src/capnp/test.capnp.c++ -o /dev/null cannam@62: fi cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing c++ install" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit make install cannam@62: cannam@62: test "x$(which capnp)" = "x$STAGING/bin/capnp" cannam@62: test "x$(which capnpc-c++)" = "x$STAGING/bin/capnpc-c++" cannam@62: cannam@62: cd samples cannam@62: cannam@62: doit capnp compile -oc++ addressbook.capnp -I"$STAGING"/include --no-standard-import cannam@62: doit ${CXX:-g++} -std=c++11 addressbook.c++ addressbook.capnp.c++ -o addressbook \ cannam@62: $CXXFLAGS $(pkg-config --cflags --libs capnp) cannam@62: echo "@@@@ ./addressbook (in various configurations)" cannam@62: ./addressbook write | ./addressbook read cannam@62: ./addressbook dwrite | ./addressbook dread cannam@62: rm addressbook addressbook.capnp.c++ addressbook.capnp.h cannam@62: cannam@62: doit capnp compile -oc++ calculator.capnp -I"$STAGING"/include --no-standard-import cannam@62: doit ${CXX:-g++} -std=c++11 calculator-client.c++ calculator.capnp.c++ -o calculator-client \ cannam@62: $CXXFLAGS $(pkg-config --cflags --libs capnp-rpc) cannam@62: doit ${CXX:-g++} -std=c++11 calculator-server.c++ calculator.capnp.c++ -o calculator-server \ cannam@62: $CXXFLAGS $(pkg-config --cflags --libs capnp-rpc) cannam@62: rm -f /tmp/capnp-calculator-example-$$ cannam@62: ./calculator-server unix:/tmp/capnp-calculator-example-$$ & cannam@62: sleep 0.1 cannam@62: ./calculator-client unix:/tmp/capnp-calculator-example-$$ cannam@62: kill %+ cannam@62: wait %+ || true cannam@62: rm calculator-client calculator-server calculator.capnp.c++ calculator.capnp.h /tmp/capnp-calculator-example-$$ cannam@62: cannam@62: cd .. cannam@62: cannam@62: if [ "$QUICK" = quick ]; then cannam@62: doit make maintainer-clean cannam@62: rm -rf "$STAGING" cannam@62: exit 0 cannam@62: fi cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing --with-external-capnp" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit make distclean cannam@62: doit ./configure --prefix="$STAGING" --disable-shared \ cannam@62: --with-external-capnp CAPNP=$STAGING/bin/capnp cannam@62: doit make -j$PARALLEL check cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing --disable-reflection" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit make distclean cannam@62: doit ./configure --prefix="$STAGING" --disable-shared --disable-reflection \ cannam@62: --with-external-capnp CAPNP=$STAGING/bin/capnp cannam@62: doit make -j$PARALLEL check cannam@62: doit make distclean cannam@62: cannam@62: # Test 32-bit build now while we have $STAGING available for cross-compiling. cannam@62: if [ "x`uname -m`" = "xx86_64" ]; then cannam@62: echo "=========================================================================" cannam@62: echo "Testing 32-bit build" cannam@62: echo "=========================================================================" cannam@62: cannam@62: if [[ "`uname`" =~ CYGWIN ]]; then cannam@62: # It's just not possible to run cygwin32 binaries from within cygwin64. cannam@62: cannam@62: # Build as if we are cross-compiling, using the capnp we installed to $STAGING. cannam@62: doit ./configure --prefix="$STAGING" --disable-shared --host=i686-pc-cygwin \ cannam@62: --with-external-capnp CAPNP=$STAGING/bin/capnp cannam@62: doit make -j$PARALLEL cannam@62: doit make -j$PARALLEL capnp-test.exe cannam@62: cannam@62: # Expect a cygwin32 sshd to be listening at localhost port 2222, and use it cannam@62: # to run the tests. cannam@62: doit scp -P 2222 capnp-test.exe localhost:~/tmp-capnp-test.exe cannam@62: doit ssh -p 2222 localhost './tmp-capnp-test.exe && rm tmp-capnp-test.exe' cannam@62: cannam@62: doit make distclean cannam@62: cannam@62: elif [ "x${CXX:-g++}" != "xg++-4.8" ]; then cannam@62: doit ./configure CXX="${CXX:-g++} -m32" --disable-shared cannam@62: doit make -j$PARALLEL check cannam@62: doit make distclean cannam@62: fi cannam@62: fi cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing c++ uninstall" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit ./configure --prefix="$STAGING" cannam@62: doit make uninstall cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing c++ dist" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit make -j$PARALLEL distcheck cannam@62: doit make distclean cannam@62: rm capnproto-*.tar.gz cannam@62: cannam@62: if [ "x`uname`" = xLinux ]; then cannam@62: echo "=========================================================================" cannam@62: echo "Testing generic Unix (no Linux-specific features)" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -DKJ_USE_FUTEX=0 -DKJ_USE_EPOLL=0" cannam@62: doit make -j$PARALLEL check cannam@62: doit make distclean cannam@62: fi cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing with -fno-rtti and -fno-exceptions" cannam@62: echo "=========================================================================" cannam@62: cannam@62: # GCC miscompiles capnpc-c++ when -fno-exceptions and -O2 are specified together. The cannam@62: # miscompilation happens in one specific inlined call site of Array::dispose(), but this method cannam@62: # is inlined in hundreds of other places without issue, so I have no idea how to narrow down the cannam@62: # bug. Clang works fine. So, for now, we disable optimizations on GCC for -fno-exceptions tests. cannam@62: cannam@62: doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -fno-rtti" cannam@62: doit make -j$PARALLEL check cannam@62: doit make distclean cannam@62: doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -fno-exceptions $DISABLE_OPTIMIZATION_IF_GCC" cannam@62: doit make -j$PARALLEL check cannam@62: doit make distclean cannam@62: doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions $DISABLE_OPTIMIZATION_IF_GCC" cannam@62: doit make -j$PARALLEL check cannam@62: cannam@62: # Valgrind is currently "experimental and mostly broken" on OSX and fails to run the full test cannam@62: # suite, but I have it installed because it did manage to help me track down a bug or two. Anyway, cannam@62: # skip it on OSX for now. cannam@62: if [ "x`uname`" != xDarwin ] && which valgrind > /dev/null; then cannam@62: doit make distclean cannam@62: cannam@62: echo "=========================================================================" cannam@62: echo "Testing with valgrind" cannam@62: echo "=========================================================================" cannam@62: cannam@62: doit ./configure --disable-shared CXXFLAGS="-g" cannam@62: doit make -j$PARALLEL cannam@62: doit make -j$PARALLEL capnp-test cannam@62: # Running the fuzz tests under Valgrind is a great thing to do -- but it takes cannam@62: # some 40 minutes. So, it needs to be done as a separate step of the release cannam@62: # process, perhaps along with the AFL tests. cannam@62: CAPNP_SKIP_FUZZ_TEST=1 doit valgrind --leak-check=full --track-fds=yes --error-exitcode=1 ./capnp-test cannam@62: fi cannam@62: cannam@62: doit make maintainer-clean cannam@62: cannam@62: rm -rf "$STAGING"