125039b37SCy Schubert# Travis Testing 225039b37SCy Schubert 325039b37SCy SchubertUnbound 1.10 and above leverage Travis CI to increase coverage of compilers and platforms. Compilers include Clang and GCC; while platforms include Android, iOS, Linux, and OS X on AMD64, Aarch64, PowerPC and s390x hardware. 425039b37SCy Schubert 525039b37SCy SchubertAndroid is tested on armv7a, aarch64, x86 and x86_64. The Android recipes build and install OpenSSL and Expat, and then builds Unbound. The testing is tailored for Android NDK-r19 and above, and includes NDK-r20 and NDK-r21. Mips and Mips64 are not tested because they are no longer supported under current NDKs. 625039b37SCy Schubert 725039b37SCy SchubertiOS is tested for iPhoneOS, WatchOS, AppleTVOS, iPhoneSimulator, AppleTVSimulator and WatchSimulator. The testing uses Xcode 10 on OS X 10.13. 825039b37SCy Schubert 925039b37SCy SchubertThe Unbound Travis configuration file `.travis.yml` does not use top-level keys like `os:` and `compiler:` so there is no matrix expansion. Instead Unbound specifies the exact job to run under the `jobs:` and `include:` keys. 1025039b37SCy Schubert 1125039b37SCy Schubert## Typical recipe 1225039b37SCy Schubert 1325039b37SCy SchubertA typical recipe tests Clang and GCC on various hardware. The hardware includes AMD64, Aarch64, PowerPC and s390x. PowerPC is a little-endian platform, and s390x is a big-endian platform. There are pairs of recipes that are similar to the following. 1425039b37SCy Schubert 1525039b37SCy Schubert``` 1625039b37SCy Schubert- os: linux 1725039b37SCy Schubert name: GCC on Linux, Aarch64 1825039b37SCy Schubert compiler: gcc 1925039b37SCy Schubert arch: arm64 2025039b37SCy Schubert dist: bionic 2125039b37SCy Schubert- os: linux 2225039b37SCy Schubert name: Clang on Linux, Aarch64 2325039b37SCy Schubert compiler: clang 2425039b37SCy Schubert arch: arm64 2525039b37SCy Schubert dist: bionic 2625039b37SCy Schubert``` 2725039b37SCy Schubert 2825039b37SCy SchubertOS X provides a single recipe to test Clang. GCC is not tested because GCC is an alias for Clang. 2925039b37SCy Schubert 3025039b37SCy Schubert## Sanitizer builds 3125039b37SCy Schubert 3225039b37SCy SchubertTwo sanitizer builds are tested using Clang and GCC, for a total of four builds. The first sanitizer is Undefined Behavior sanitizer (UBsan), and the second is Address sanitizer (Asan). The sanitizers are only run on AMD64 hardware. Note the environment includes `TEST_UBSAN=yes` or `TEST_ASAN=yes` for the sanitizer builds. 3325039b37SCy Schubert 3425039b37SCy SchubertThe recipes are similar to the following. 3525039b37SCy Schubert 3625039b37SCy Schubert``` 3725039b37SCy Schubert- os: linux 3825039b37SCy Schubert name: UBsan, GCC on Linux, Amd64 3925039b37SCy Schubert compiler: gcc 4025039b37SCy Schubert arch: amd64 4125039b37SCy Schubert dist: bionic 4225039b37SCy Schubert env: TEST_UBSAN=yes 4325039b37SCy Schubert- os: linux 4425039b37SCy Schubert name: UBsan, Clang on Linux, Amd64 4525039b37SCy Schubert compiler: clang 4625039b37SCy Schubert arch: amd64 4725039b37SCy Schubert dist: bionic 4825039b37SCy Schubert env: TEST_UBSAN=yes 4925039b37SCy Schubert``` 5025039b37SCy Schubert 5125039b37SCy SchubertWhen the Travis script encounters a sanitizer it uses different `CFLAGS` and configuration string. 5225039b37SCy Schubert 5325039b37SCy Schubert``` 5425039b37SCy Schubertif [ "$TEST_UBSAN" = "yes" ]; then 5525039b37SCy Schubert export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=undefined -fno-sanitize-recover" 5625039b37SCy Schubert ./configure 5725039b37SCy Schubert make -j 2 5825039b37SCy Schubert make test 5925039b37SCy Schubertelif [ "$TEST_ASAN" = "yes" ]; then 6025039b37SCy Schubert export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" 6125039b37SCy Schubert ./configure 6225039b37SCy Schubert make -j 2 6325039b37SCy Schubert make test 6425039b37SCy Schubert... 6525039b37SCy Schubert``` 6625039b37SCy Schubert 6725039b37SCy Schubert## Android builds 6825039b37SCy Schubert 6925039b37SCy SchubertTravis tests Android builds for the armv7a, aarch64, x86 and x86_64 architectures. The builds are trickier than other builds for several reasons. The testing requires installation of the Android NDK and SDK, it requires a cross-compile, and requires OpenSSL and Expat prerequisites. The Android cross-compiles also require care to set the Autotools triplet, the OpenSSL triplet, the toolchain path, the tool variables, and the sysroot. The discussion below detail the steps of the Android recipes. 7025039b37SCy Schubert 7125039b37SCy Schubert### Android job 7225039b37SCy Schubert 7325039b37SCy SchubertThe first step sets environmental variables for the cross-compile using the Travis job. A typical job with variables is shown below. 7425039b37SCy Schubert 7525039b37SCy Schubert``` 7625039b37SCy Schubert- os: linux 7725039b37SCy Schubert name: Android armv7a, Linux, Amd64 7825039b37SCy Schubert compiler: clang 7925039b37SCy Schubert arch: amd64 8025039b37SCy Schubert dist: bionic 8125039b37SCy Schubert env: 8225039b37SCy Schubert - TEST_ANDROID=yes 8325039b37SCy Schubert - AUTOTOOLS_HOST=armv7a-linux-androideabi 8425039b37SCy Schubert - OPENSSL_HOST=android-arm 8525039b37SCy Schubert - ANDROID_CPU=armv7a 8625039b37SCy Schubert - ANDROID_API=23 8725039b37SCy Schubert - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU" 8825039b37SCy Schubert - ANDROID_SDK_ROOT="$HOME/android-sdk" 8925039b37SCy Schubert - ANDROID_NDK_ROOT="$HOME/android-ndk" 9025039b37SCy Schubert``` 9125039b37SCy Schubert 9225039b37SCy Schubert### ANDROID_NDK_ROOT 9325039b37SCy Schubert 9425039b37SCy SchubertThe second step for Android is to set the environmental variables `ANDROID_NDK_ROOT` and `ANDROID_SDK_ROOT`. This is an important step because the NDK and SDK use the variables internally to locate their own tools. Also see [Recommended NDK Directory?](https://groups.google.com/forum/#!topic/android-ndk/qZjhOaynHXc) on the android-ndk mailing list. (Many folks miss this step, or use incorrect variables like `ANDROID_NDK_HOME` or `ANDROID_SDK_HOME`). 9525039b37SCy Schubert 9625039b37SCy SchubertIf you are working from a developer machine you probably already have the necessary tools installed. You should ensure `ANDROID_NDK_ROOT` and `ANDROID_SDK_ROOT` are set properly. 9725039b37SCy Schubert 9825039b37SCy Schubert### Tool installation 9925039b37SCy Schubert 10025039b37SCy SchubertThe second step installs tools needed for OpenSSL, Expat and Unbound. This step is handled in by the script `contrib/android/install_tools.sh`. The tools include curl, tar, zip, unzip and java. 10125039b37SCy Schubert 10225039b37SCy Schubert``` 10325039b37SCy Schubertbefore_script: 10425039b37SCy Schubert - | 10525039b37SCy Schubert if [ "$TEST_ANDROID" = "yes" ]; then 10625039b37SCy Schubert ./contrib/android/install_tools.sh 10725039b37SCy Schubert elif [ "$TEST_IOS" = "yes" ]; then 10825039b37SCy Schubert ./contrib/ios/install_tools.sh 10925039b37SCy Schubert fi 11025039b37SCy Schubert``` 11125039b37SCy Schubert 11225039b37SCy Schubert### NDK installation 11325039b37SCy Schubert 11425039b37SCy SchubertThe third step installs the NDK and SDK. This step is handled in by the script `contrib/android/install_ndk.sh`. The script uses `ANDROID_NDK_ROOT` and `ANDROID_SDK_ROOT` to place the NDK and SDK in the `$HOME` directory. 11525039b37SCy Schubert 11625039b37SCy SchubertIf you are working from a developer machine you probably already have a NDK and SDK installed. 11725039b37SCy Schubert 11825039b37SCy Schubert### Android environment 11925039b37SCy Schubert 12025039b37SCy SchubertThe fourth step sets the Android cross-compile environment using the script `contrib/android/setenv_android.sh`. The script is `sourced` so the variables in the script are available to the calling shell. The script sets variables like `CC`, `CXX`, `AS` and `AR`; sets `CFLAGS` and `CXXFLAGS`; sets a `sysroot` so Android headers and libraries are found; and adds the path to the toolchain to `PATH`. 12125039b37SCy Schubert 12225039b37SCy Schubert`contrib/android/setenv_android.sh` knows which toolchain and architecture to select by inspecting environmental variables set by Travis for the job. In particular, the variables `ANDROID_CPU` and `ANDROID_API` tell `contrib/android/setenv_android.sh` which tools and libraries to select. 12325039b37SCy Schubert 12425039b37SCy SchubertThe `contrib/android/setenv_android.sh` script specifies the tools in a `case` statement like the following. There is a case for each of the architectures armv7a, aarch64, x86 and x86_64. 12525039b37SCy Schubert 12625039b37SCy Schubert``` 12725039b37SCy Schubertarmv8a|aarch64|arm64|arm64-v8a) 12825039b37SCy Schubert CC="aarch64-linux-android$ANDROID_API-clang" 12925039b37SCy Schubert CXX="aarch64-linux-android$ANDROID_API-clang++" 13025039b37SCy Schubert LD="aarch64-linux-android-ld" 13125039b37SCy Schubert AS="aarch64-linux-android-as" 13225039b37SCy Schubert AR="aarch64-linux-android-ar" 13325039b37SCy Schubert RANLIB="aarch64-linux-android-ranlib" 13425039b37SCy Schubert STRIP="aarch64-linux-android-strip" 13525039b37SCy Schubert 13625039b37SCy Schubert CFLAGS="-funwind-tables -fexceptions" 13725039b37SCy Schubert CXXFLAGS="-funwind-tables -fexceptions -frtti" 13825039b37SCy Schubert``` 13925039b37SCy Schubert 14025039b37SCy Schubert### OpenSSL and Expat 14125039b37SCy Schubert 14225039b37SCy SchubertThe fifth step builds OpenSSL and Expat. OpenSSL and Expat are built for Android using the scripts `contrib/android/install_openssl.sh` and `contrib/android/install_expat.sh`. The scripts download, configure and install the latest release version of the libraries. The libraries are configured with `--prefix="$ANDROID_PREFIX"` so the headers are placed in `$ANDROID_PREFIX/include` directory, and the libraries are placed in the `$ANDROID_PREFIX/lib` directory. 14325039b37SCy Schubert 14425039b37SCy Schubert`ANDROID_PREFIX` is the value `$HOME/android$ANDROID_API-$ANDROID_CPU`. The libraries will be installed in `$HOME/android23-armv7a`, `$HOME/android23-aarch64`, etc. For Autotools projects, the appropriate `PKG_CONFIG_PATH` is exported. `PKG_CONFIG_PATH` is the userland equivalent to sysroot, and allows Autotools to find non-system headers and libraries for an architecture. Typical `PKG_CONFIG_PATH` are `$HOME/android23-armv7a/lib/pkgconfig` and `$HOME/android23-aarch64/lib/pkgconfig`. 14525039b37SCy Schubert 14625039b37SCy SchubertOpenSSL also uses a custom configuration file called `15-android.conf`. It is a copy of the OpenSSL's project file and located at `contrib/android/15-android.conf`. The Unbound version is copied to the OpenSSL source files after unpacking the OpenSSL distribution. The Unbound version has legacy NDK support removed and some other fixes, like `ANDROID_NDK_ROOT` awareness. The changes mean Unbound's `15-android.conf` will only work with Unbound, with NDK-r19 and above, and a properly set environment. 14725039b37SCy Schubert 14825039b37SCy SchubertOpenSSL is configured with `no-engine`. If you want to include OpenSSL engines then edit `contrib/android/install_openssl.sh` and remove the config option. 14925039b37SCy Schubert 15025039b37SCy Schubert### Android build 15125039b37SCy Schubert 15225039b37SCy SchubertFinally, once OpenSSL and Expat are built, then the Travis script configures and builds Unbound. The recipe looks as follows. 15325039b37SCy Schubert 15425039b37SCy Schubert``` 15525039b37SCy Schubertelif [ "$TEST_ANDROID" = "yes" ]; then 15625039b37SCy Schubert export AUTOTOOLS_BUILD="$(./config.guess)" 15725039b37SCy Schubert export PKG_CONFIG_PATH="$ANDROID_PREFIX/lib/pkgconfig" 15825039b37SCy Schubert ./contrib/android/install_ndk.sh 15925039b37SCy Schubert source ./contrib/android/setenv_android.sh 16025039b37SCy Schubert ./contrib/android/install_openssl.sh 16125039b37SCy Schubert ./contrib/android/install_expat.sh 16225039b37SCy Schubert ./configure \ 16325039b37SCy Schubert --build="$AUTOTOOLS_BUILD" \ 16425039b37SCy Schubert --host="$AUTOTOOLS_HOST" \ 16525039b37SCy Schubert --prefix="$ANDROID_PREFIX" \ 16625039b37SCy Schubert --with-ssl="$ANDROID_PREFIX" \ 16725039b37SCy Schubert --with-libexpat="$ANDROID_PREFIX" \ 16825039b37SCy Schubert --disable-gost; 16925039b37SCy Schubert make -j 2 17025039b37SCy Schubert make install 17125039b37SCy Schubert``` 17225039b37SCy Schubert 17325039b37SCy SchubertTravis only smoke tests an Android build using a compile, link and install. The self tests are not run. TODO: figure out how to fire up an emulator, push the tests to the device and run them. 17425039b37SCy Schubert 17525039b37SCy Schubert### Android flags 17625039b37SCy Schubert 17725039b37SCy Schubert`contrib/android/setenv_android.sh` uses specific flags for `CFLAGS` and `CXXFLAGS`. They are taken from `ndk-build`, so we consider them the official flag set. It is important to use the same flags across projects to avoid subtle problems due to mixing and matching different flags. 17825039b37SCy Schubert 17925039b37SCy Schubert`CXXFLAGS` includes `-fexceptions` and `-frtti` because exceptions and runtime type info are disabled by default. `CFLAGS` include `-funwind-tables` and `-fexceptions` to ensure C++ exceptions pass through C code, if needed. Also see `docs/CPLUSPLUS-SUPPORT.html` in the NDK docs. 18025039b37SCy Schubert 18125039b37SCy SchubertTo inspect the flags used by `ndk-build` for a platform clone ASOP's [ndk-samples](https://github.com/android/ndk-samples/tree/master/hello-jni) and build the `hello-jni` project. Use the `V=1` flag to see the full compiler output from `ndk-build`. 18225039b37SCy Schubert 18325039b37SCy Schubert## iOS builds 18425039b37SCy Schubert 18525039b37SCy SchubertTravis tests iOS builds for the armv7a, armv7s and aarch64 architectures for iPhoneOS, AppleTVOS and WatchOS. iPhoneOS is tested using both 32-bit builds (iPhones) and 64-bit builds (iPads). Travis also tests compiles against the simulators. The builds are trickier than other builds for several reasons. The testing requires a cross-compile, and requires OpenSSL and Expat prerequisites. The iOS cross-compiles also require care to set the Autotools triplet, the OpenSSL triplet, the toolchain path, the tool variables, and the sysroot. The discussion below detail the steps of the iOS recipes. 18625039b37SCy Schubert 18725039b37SCy Schubert### iOS job 18825039b37SCy Schubert 18925039b37SCy SchubertThe first step sets environmental variables for the cross-compile using the Travis job. A typical job with variables is shown below. 19025039b37SCy Schubert 19125039b37SCy Schubert``` 19225039b37SCy Schubert- os: osx 19325039b37SCy Schubert osx_image: xcode10 19425039b37SCy Schubert name: Apple iPhone on iOS, armv7 19525039b37SCy Schubert compiler: clang 19625039b37SCy Schubert env: 19725039b37SCy Schubert - TEST_IOS=yes 19825039b37SCy Schubert - AUTOTOOLS_HOST=armv7-apple-ios 19925039b37SCy Schubert - OPENSSL_HOST=ios-cross 20025039b37SCy Schubert - IOS_SDK=iPhoneOS 20125039b37SCy Schubert - IOS_CPU=armv7s 20225039b37SCy Schubert - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" 20325039b37SCy Schubert``` 20425039b37SCy Schubert 20525039b37SCy Schubert### Tool installation 20625039b37SCy Schubert 20725039b37SCy SchubertThe second step installs tools needed for OpenSSL, Expat and Unbound. This step is handled in by the script `contrib/ios/install_tools.sh`. The tools include autotools, curl and perl. The installation happens at the `before_script:` stage of Travis. 20825039b37SCy Schubert 20925039b37SCy Schubert``` 21025039b37SCy Schubertbefore_script: 21125039b37SCy Schubert - | 21225039b37SCy Schubert if [ "$TEST_ANDROID" = "yes" ]; then 21325039b37SCy Schubert ./contrib/android/install_tools.sh 21425039b37SCy Schubert elif [ "$TEST_IOS" = "yes" ]; then 21525039b37SCy Schubert ./contrib/ios/install_tools.sh 21625039b37SCy Schubert fi 21725039b37SCy Schubert``` 21825039b37SCy Schubert 21925039b37SCy Schubert### iOS environment 22025039b37SCy Schubert 22125039b37SCy SchubertThe third step sets the iOS cross-compile environment using the script `contrib/ios/setenv_ios.sh`. The script is `sourced` so the variables in the script are available to the calling shell. The script sets variables like `CC`, `CXX`, `AS` and `AR`; sets `CFLAGS` and `CXXFLAGS`; sets a `sysroot` so iOS headers and libraries are found; and adds the path to the toolchain to `PATH`. 22225039b37SCy Schubert 22325039b37SCy Schubert`contrib/ios/setenv_ios.sh` knows which toolchain and architecture to select by inspecting environmental variables set by Travis for the job. In particular, the variables `IOS_SDK` and `IOS_CPU` tell `contrib/ios/setenv_ios.sh` which tools and libraries to select. 22425039b37SCy Schubert 22525039b37SCy SchubertThe `contrib/ios/setenv_ios.sh` script specifies the tools to use during the cross-compile. For Apple SDKs, the tool names are the same as a desktop. There are no special prefixes for the mobile tools. 22625039b37SCy Schubert 22725039b37SCy Schubert``` 22825039b37SCy SchubertCPP=cpp 22925039b37SCy SchubertCC=clang 23025039b37SCy SchubertCXX=clang++ 23125039b37SCy SchubertLD=ld 23225039b37SCy SchubertAS=as 23325039b37SCy SchubertAR=ar 23425039b37SCy SchubertRANLIB=ranlib 23525039b37SCy SchubertSTRIP=strip 23625039b37SCy Schubert``` 23725039b37SCy Schubert 23825039b37SCy SchubertIf you are working from a developer machine you probably already have the necessary tools installed. 23925039b37SCy Schubert 24025039b37SCy Schubert### OpenSSL and Expat 24125039b37SCy Schubert 24225039b37SCy SchubertThe fourth step builds OpenSSL and Expat. OpenSSL and Expat are built for iOS using the scripts `contrib/ios/install_openssl.sh` and `contrib/ios/install_expat.sh`. The scripts download, configure and install the latest release version of the libraries. The libraries are configured with `--prefix="$IOS_PREFIX"` so the headers are placed in `$IOS_PREFIX/include` directory, and the libraries are placed in the `$IOS_PREFIX/lib` directory. 24325039b37SCy Schubert 244*24e36522SCy Schubert`IOS_PREFIX` is the value `$HOME/$IOS_SDK-$IOS_CPU`. The scheme handles both iOS SDKs and cpu architectures so the pair receives a unique installation directory. The libraries will be installed in `$HOME/iPhoneOS-armv7s`, `$HOME/iPhoneOS-arm64`, `$HOME/iPhoneSimulator-i386`, etc. For Autotools projects, the appropriate `PKG_CONFIG_PATH` is exported. 24525039b37SCy Schubert 24625039b37SCy Schubert`PKG_CONFIG_PATH` is an important variable. It is the userland equivalent to sysroot, and allows Autotools to find non-system headers and libraries for an architecture. Typical `PKG_CONFIG_PATH` are `$HOME/iPhoneOS-armv7s/lib/pkgconfig` and `$HOME/iPhoneOS-arm64/lib/pkgconfig`. 24725039b37SCy Schubert 24825039b37SCy SchubertOpenSSL also uses a custom configuration file called `15-ios.conf`. It is a copy of the OpenSSL's project file and located at `contrib/ios/15-ios.conf`. The Unbound version is copied to the OpenSSL source files after unpacking the OpenSSL distribution. The changes mean Unbound's `15-ios.conf` will only work with Unbound and a properly set environment. 24925039b37SCy Schubert 25025039b37SCy SchubertOpenSSL is configured with `no-engine`. Engines require dynamic loading so engines are disabled permanently in `15-ios.conf`. 25125039b37SCy Schubert 25225039b37SCy Schubert### iOS build 25325039b37SCy Schubert 25425039b37SCy SchubertFinally, once OpenSSL and Expat are built, then the Travis script configures and builds Unbound. The full recipe looks as follows. 25525039b37SCy Schubert 25625039b37SCy Schubert``` 25725039b37SCy Schubertelif [ "$TEST_IOS" = "yes" ]; then 25825039b37SCy Schubert export AUTOTOOLS_BUILD="$(./config.guess)" 25925039b37SCy Schubert export PKG_CONFIG_PATH="$IOS_PREFIX/lib/pkgconfig" 26025039b37SCy Schubert source ./contrib/ios/setenv_ios.sh 26125039b37SCy Schubert ./contrib/ios/install_openssl.sh 26225039b37SCy Schubert ./contrib/ios/install_expat.sh 26325039b37SCy Schubert ./configure \ 26425039b37SCy Schubert --build="$AUTOTOOLS_BUILD" \ 26525039b37SCy Schubert --host="$AUTOTOOLS_HOST" \ 26625039b37SCy Schubert --prefix="$IOS_PREFIX" \ 26725039b37SCy Schubert --with-ssl="$IOS_PREFIX" \ 26825039b37SCy Schubert --with-libexpat="$IOS_PREFIX" \ 26925039b37SCy Schubert --disable-gost; 27025039b37SCy Schubert make -j 2 27125039b37SCy Schubert make install 27225039b37SCy Schubert``` 27325039b37SCy Schubert 27425039b37SCy SchubertTravis only smoke tests an iOS build using a compile, link and install. The self tests are not run. TODO: figure out how to fire up an simulator, push the tests to the device and run them. 27525039b37SCy Schubert 27625039b37SCy Schubert### iOS flags 27725039b37SCy Schubert 27825039b37SCy Schubert`contrib/ios/setenv_ios.sh` uses specific flags for `CFLAGS` and `CXXFLAGS`. They are taken from Xcode, so we consider them the official flag set. It is important to use the same flags across projects to avoid subtle problems due to mixing and matching different flags. 279