From eae679718ed3a17597fd82c26ae56b55c4597e04 Mon Sep 17 00:00:00 2001 From: Joe McIlvain Date: Sun, 2 Nov 2014 17:33:23 -0800 Subject: [PATCH] Problem: No builtin way to build for qt-android Solution: Add qt-android build system and add to travis-ci --- .gitignore | 1 + .travis.yml | 15 +- builds/qt-android/android_build_helper.sh | 307 ++++++++++++++++++++++ builds/qt-android/build.sh | 56 ++++ builds/qt-android/ci_build.sh | 14 + ci_build.sh | 15 ++ 6 files changed, 398 insertions(+), 10 deletions(-) create mode 100644 builds/qt-android/android_build_helper.sh create mode 100755 builds/qt-android/build.sh create mode 100755 builds/qt-android/ci_build.sh create mode 100755 ci_build.sh diff --git a/.gitignore b/.gitignore index b2150e6a..ef73164a 100644 --- a/.gitignore +++ b/.gitignore @@ -124,6 +124,7 @@ builds/msvc/**/*.user builds/msvc/**/*Debug builds/msvc/**/*Release builds/redhat/zeromq.spec +builds/qt-android/prefix/ packaging/nuget/*.nupkg foreign/openpgm/* !foreign/openpgm/*.tar.bz2 diff --git a/.travis.yml b/.travis.yml index f103646d..9a553456 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,9 @@ language: c -# Build required projects first -before_script: +env: + - BUILD_TYPE=default + - BUILD_TYPE=qt-android -# libsodium -- git clone git://github.com/jedisct1/libsodium.git -- ( cd libsodium; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) - -# Build and check this project -script: -- ./autogen.sh && ./configure --with-libsodium=yes && make && make check -- sudo make install +# Build and check this project according to the BUILD_TYPE +script: ./ci_build.sh diff --git a/builds/qt-android/android_build_helper.sh b/builds/qt-android/android_build_helper.sh new file mode 100644 index 00000000..af57e59a --- /dev/null +++ b/builds/qt-android/android_build_helper.sh @@ -0,0 +1,307 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2014, Joe Eli McIlvain +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +### +# +# https://github.com/jemc/android_build_helper +# android_build_helper.sh +# +# The following is a helper script for setting up android builds for +# "native" libraries maintained with an autotools build system. +# It merely helps to create the proper cross-compile environment. +# It makes no attempt to wrap the library or make it accessible to Java code; +# the intention is to make the bare library available to other "native" code. +# +# To get the latest version of this script, please download from: +# https://github.com/jemc/android_build_helper +# +# You are free to modify this script, but if you add improvements, +# please consider submitting a pull request to the aforementioned upstream +# repository for the benefit of other users. +# + +# Get directory of current script (if not already set) +# This directory is also the basis for the build directories the get created. +if [ -z "$ANDROID_BUILD_DIR" ]; then + ANDROID_BUILD_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +fi + +# Set up a variable to hold the global failure reasons, separated by newlines +# (Empty string indicates no failure) +ANDROID_BUILD_FAIL=() + +function android_build_check_fail { + if [ ! ${#ANDROID_BUILD_FAIL[@]} -eq 0 ]; then + echo "qt-android build failed for the following reasons:" + for reason in "${ANDROID_BUILD_FAIL[@]}"; do + local formatted_reason=" ${reason}" + echo "${formatted_reason}" + done + exit 1 + fi +} + +function android_build_env { + ## + # Check that necessary environment variables are set + + if [ -z "$ANDROID_NDK_ROOT" ]; then + ANDROID_BUILD_FAIL+=("Please set the ANDROID_NDK_ROOT environment variable") + ANDROID_BUILD_FAIL+=(" (eg. \"/home/user/android/android-ndk-r9d\")") + fi + + if [ -z "$TOOLCHAIN_PATH" ]; then + ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_PATH environment variable") + ANDROID_BUILD_FAIL+=(" (eg. \"/home/user/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin\")") + fi + + if [ -z "$TOOLCHAIN_NAME" ]; then + ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_NAME environment variable") + ANDROID_BUILD_FAIL+=(" (eg. \"arm-linux-androideabi-4.8\")") + fi + + if [ -z "$TOOLCHAIN_HOST" ]; then + ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_HOST environment variable") + ANDROID_BUILD_FAIL+=(" (eg. \"arm-linux-androideabi\")") + fi + + if [ -z "$TOOLCHAIN_ARCH" ]; then + ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_ARCH environment variable") + ANDROID_BUILD_FAIL+=(" (eg. \"arm\")") + fi + + android_build_check_fail + + ## + # Check that directories given by environment variables exist + + if [ ! -d "$ANDROID_NDK_ROOT" ]; then + ANDROID_BUILD_FAIL+=("The ANDROID_NDK_ROOT directory does not exist") + ANDROID_BUILD_FAIL+=(" ${ANDROID_NDK_ROOT}") + fi + + if [ ! -d "$TOOLCHAIN_PATH" ]; then + ANDROID_BUILD_FAIL+=("The TOOLCHAIN_PATH directory does not exist") + ANDROID_BUILD_FAIL+=(" ${TOOLCHAIN_PATH}") + fi + + ## + # Set up some local variables and check them + + ANDROID_BUILD_SYSROOT="${ANDROID_NDK_ROOT}/platforms/android-9/arch-${TOOLCHAIN_ARCH}" + + if [ ! -d "$ANDROID_BUILD_SYSROOT" ]; then + ANDROID_BUILD_FAIL+=("The ANDROID_BUILD_SYSROOT directory does not exist") + ANDROID_BUILD_FAIL+=(" ${ANDROID_BUILD_SYSROOT}") + fi + + ANDROID_BUILD_PREFIX="${ANDROID_BUILD_DIR}/prefix/${TOOLCHAIN_NAME}" + + mkdir -p "$ANDROID_BUILD_PREFIX" || { + ANDROID_BUILD_FAIL+=("Failed to make ANDROID_BUILD_PREFIX directory") + ANDROID_BUILD_FAIL+=(" ${ANDROID_BUILD_PREFIX}") + } + + android_build_check_fail +} + +function _android_build_opts_process_binaries { + local CPP="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-cpp" + local CC="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-gcc" + local CXX="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-g++" + local LD="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ld" + local AS="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-as" + local AR="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ar" + local RANLIB="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ranlib" + + if [ ! -x "${CPP}" ]; then + ANDROID_BUILD_FAIL+=("The CPP binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${CPP}") + fi + + if [ ! -x "${CC}" ]; then + ANDROID_BUILD_FAIL+=("The CC binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${CC}") + fi + + if [ ! -x "${CXX}" ]; then + ANDROID_BUILD_FAIL+=("The CXX binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${CXX}") + fi + + if [ ! -x "${LD}" ]; then + ANDROID_BUILD_FAIL+=("The LD binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${LD}") + fi + + if [ ! -x "${AS}" ]; then + ANDROID_BUILD_FAIL+=("The AS binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${AS}") + fi + + if [ ! -x "${AR}" ]; then + ANDROID_BUILD_FAIL+=("The AR binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${AR}") + fi + + if [ ! -x "${RANLIB}" ]; then + ANDROID_BUILD_FAIL+=("The RANLIB binary does not exist or is not executable") + ANDROID_BUILD_FAIL+=(" ${RANLIB}") + fi + + ANDROID_BUILD_OPTS+=("CPP=${CPP}") + ANDROID_BUILD_OPTS+=("CC=${CC}") + ANDROID_BUILD_OPTS+=("CXX=${CXX}") + ANDROID_BUILD_OPTS+=("LD=${LD}") + ANDROID_BUILD_OPTS+=("AS=${AS}") + ANDROID_BUILD_OPTS+=("AR=${AR}") + ANDROID_BUILD_OPTS+=("RANLIB=${RANLIB}") + + android_build_check_fail +} + +function _android_build_opts_process_cxx_stl { + case "${ANDROID_BUILD_CXXSTL}" in + stlport_static) + LIBS+=" -lstlport_static" + CPPFLAGS+=" -I${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/stlport" + case "${TOOLCHAIN_ARCH}" in + arm) + LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/armeabi" + ;; + x86) + LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/x86" + ;; + mips) + LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/mips" + ;; + *) + ANDROID_BUILD_FAIL+=("Unknown combination for ANDROID_BUILD_CXXSTL and TOOLCHAIN_ARCH") + ANDROID_BUILD_FAIL+=(" ${ANDROID_BUILD_CXXSTL}") + ANDROID_BUILD_FAIL+=(" ${TOOLCHAIN_ARCH}") + ;; + esac + ;; + gnustl_shared_48) + LIBS+=" -lgnustl_shared" + CPPFLAGS+=" -I${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/include" + case "${TOOLCHAIN_ARCH}" in + arm) + LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi" + CPPFLAGS+=" -I${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/include" + ;; + x86) + LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86" + CPPFLAGS+=" -I${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86/include" + ;; + mips) + LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/mips" + CPPFLAGS+=" -I${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/mips/include" + ;; + *) + ANDROID_BUILD_FAIL+=("Unknown combination for ANDROID_BUILD_CXXSTL and TOOLCHAIN_ARCH") + ANDROID_BUILD_FAIL+=(" ${ANDROID_BUILD_CXXSTL}") + ANDROID_BUILD_FAIL+=(" ${TOOLCHAIN_ARCH}") + ;; + esac + ;; + '');; + *) + ANDROID_BUILD_FAIL+=("Unknown value for ANDROID_BUILD_CXXSTL") + ANDROID_BUILD_FAIL+=(" ${ANDROID_BUILD_CXXSTL}") + ;; + esac +} + +# Set the ANDROID_BUILD_OPTS variable to a bash array of configure options +function android_build_opts { + ANDROID_BUILD_OPTS=() + + local CFLAGS="--sysroot=${ANDROID_BUILD_SYSROOT} -I${ANDROID_BUILD_PREFIX}/include" + local CPPFLAGS="--sysroot=${ANDROID_BUILD_SYSROOT} -I${ANDROID_BUILD_PREFIX}/include" + local CXXFLAGS="--sysroot=${ANDROID_BUILD_SYSROOT} -I${ANDROID_BUILD_PREFIX}/include" + local LDFLAGS="" + local LIBS="-lc -lgcc -ldl" + + _android_build_opts_process_binaries + _android_build_opts_process_cxx_stl + + ANDROID_BUILD_OPTS+=("CFLAGS=${CFLAGS} ${ANDROID_BUILD_EXTRA_CFLAGS}") + ANDROID_BUILD_OPTS+=("CPPFLAGS=${CPPFLAGS} ${ANDROID_BUILD_EXTRA_CPPFLAGS}") + ANDROID_BUILD_OPTS+=("CXXFLAGS=${CXXFLAGS} ${ANDROID_BUILD_EXTRA_CXXFLAGS}") + ANDROID_BUILD_OPTS+=("LDFLAGS=${LDFLAGS} ${ANDROID_BUILD_EXTRA_LDFLAGS}") + ANDROID_BUILD_OPTS+=("LIBS=${LIBS} ${ANDROID_BUILD_EXTRA_LIBS}") + + ANDROID_BUILD_OPTS+=("PKG_CONFIG_PATH=${ANDROID_BUILD_PREFIX}/lib/pkgconfig") + ANDROID_BUILD_OPTS+=("--host=${TOOLCHAIN_HOST}") + ANDROID_BUILD_OPTS+=("--prefix=${ANDROID_BUILD_PREFIX}") + + android_build_check_fail +} + +# Parse readelf output to verify the correct linking of libraries. +# The first argument should be the soname of the newly built library. +# The rest of the arguments should be the sonames of dependencies. +# All sonames should be unversioned for android (no trailing numbers). +function android_build_verify_so { + local soname="$1" + shift # Get rid of first argument - the rest represent dependencies + + local sofile="${ANDROID_BUILD_PREFIX}/lib/${soname}" + if [ ! -f "${sofile}" ]; then + ANDROID_BUILD_FAIL+=("Found no library named ${soname}") + ANDROID_BUILD_FAIL+=(" ${sofile}") + fi + android_build_check_fail + + local elfoutput=$(readelf -d ${sofile}) + + local soname_regexp='soname: \[([[:alnum:]\.]+)\]' + if [[ $elfoutput =~ $soname_regexp ]]; then + local parsed_soname="${BASH_REMATCH[1]}" + if [ "${parsed_soname}" != "${soname}" ]; then + ANDROID_BUILD_FAIL+=("Actual soname of library ${soname} is incorrect (or versioned):") + ANDROID_BUILD_FAIL+=(" ${parsed_soname}") + fi + else + ANDROID_BUILD_FAIL+=("Failed to meaningfully parse readelf output for library ${soname}:") + ANDROID_BUILD_FAIL+=(" ${elfoutput}") + fi + + for dep_soname do + if [[ $elfoutput != *"library: [${dep_soname}]"* ]]; then + ANDROID_BUILD_FAIL+=("Library ${soname} was expected to be linked to library with soname:") + ANDROID_BUILD_FAIL+=(" ${dep_soname}") + fi + done + + android_build_check_fail +} diff --git a/builds/qt-android/build.sh b/builds/qt-android/build.sh new file mode 100755 index 00000000..2b4d3c9f --- /dev/null +++ b/builds/qt-android/build.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Get directory of current script +ANDROID_BUILD_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Get access to android_build functions and variables +source ${ANDROID_BUILD_DIR}/android_build_helper.sh + +# Choose a C++ standard library implementation from the ndk +ANDROID_BUILD_CXXSTL="gnustl_shared_48" + +# Set up android build environment and set ANDROID_BUILD_OPTS array +android_build_env +android_build_opts + +# Clear a temporary build directory +cache="/tmp/android_build/${TOOLCHAIN_NAME}" +rm -rf "${cache}" +mkdir -p "${cache}" + + +echo +echo "Building qt-android libsodium from latest release tarball..." +echo + +wget "https://download.libsodium.org/libsodium/releases/LATEST.tar.gz" \ + -O "${cache}/libsodium.tar.gz" + +(cd "${cache}" && mkdir libsodium \ + && tar -C libsodium -xvf libsodium.tar.gz --strip=1 \ + && cd "libsodium" && ./autogen.sh \ + && ./configure "${ANDROID_BUILD_OPTS[@]}" --disable-soname-versions \ + && make \ + && make install) || exit 1 + +echo +echo "Building qt-android libzmq from local source..." +echo + +cp -r ../.. "${cache}/libzmq" + +(cd "${cache}/libzmq" && ./autogen.sh \ + && ./configure "${ANDROID_BUILD_OPTS[@]}" --with-libsodium=yes \ + && make \ + && make install) || exit 1 + +echo +echo "Verifying qt-android libsodium.so and libzmq.so libraries..." +echo + +android_build_verify_so "libsodium.so" +android_build_verify_so "libzmq.so" "libsodium.so" + +echo +echo "Completed qt-android build!" +echo diff --git a/builds/qt-android/ci_build.sh b/builds/qt-android/ci_build.sh new file mode 100755 index 00000000..09724fbd --- /dev/null +++ b/builds/qt-android/ci_build.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +(cd '/tmp' \ + && wget http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2 \ + && tar -xvf android-ndk-r9-linux-x86_64.tar.bz2 \ + && mv android-ndk-r9 android-ndk) + +export ANDROID_NDK_ROOT="/tmp/android-ndk" +export TOOLCHAIN_PATH="/tmp/android-ndk/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin" +export TOOLCHAIN_NAME="arm-linux-androideabi-4.8" +export TOOLCHAIN_HOST="arm-linux-androideabi" +export TOOLCHAIN_ARCH="arm" + +source ./build.sh diff --git a/ci_build.sh b/ci_build.sh new file mode 100755 index 00000000..e26f3091 --- /dev/null +++ b/ci_build.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +if [ $BUILD_TYPE == "default" ]; then + # Build required projects first + + # libsodium + git clone git://github.com/jedisct1/libsodium.git + ( cd libsodium; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) + + # Build and check this project + ./autogen.sh && ./configure --with-libsodium=yes && make && make check + sudo make install +else + cd ./builds/${BUILD_TYPE} && ./ci_build.sh +fi