1#!/usr/bin/env bash
2################################################################################
3#  THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY  #
4#  Read the zproject/README.md for information about making permanent changes. #
5################################################################################
6#
7# Courtesy of Joe Eli McIlvain; original code at:
8# https://github.com/jemc/android_build_helper
9#   android_build_helper.sh
10#
11# The following is a helper script for setting up android builds for
12# "native" libraries maintained with an autotools build system.
13# It merely helps to create the proper cross-compile environment.
14# It makes no attempt to wrap the library or make it accessible to Java code;
15# the intention is to make the bare library available to other "native" code.
16#
17# To get the latest version of this script, please download from:
18#   https://github.com/jemc/android_build_helper
19#
20# You are free to modify and redistribute this script, but if you add
21# improvements, please consider submitting a pull request or patch to the
22# aforementioned upstream repository for the benefit of other users.
23#
24# This script is provided with no express or implied warranties.
25#
26
27# Get directory of current script (if not already set)
28# This directory is also the basis for the build directories the get created.
29if [ -z "$ANDROID_BUILD_DIR" ]; then
30    ANDROID_BUILD_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
31fi
32
33# Set up a variable to hold the global failure reasons, separated by newlines
34# (Empty string indicates no failure)
35ANDROID_BUILD_FAIL=()
36
37function android_build_check_fail {
38    if [ ! ${#ANDROID_BUILD_FAIL[@]} -eq 0 ]; then
39        echo "Android (${TOOLCHAIN_ARCH}) build failed for the following reasons:"
40        for reason in "${ANDROID_BUILD_FAIL[@]}"; do
41            local formatted_reason="  ${reason}"
42            echo "${formatted_reason}"
43        done
44        exit 1
45    fi
46}
47
48function android_build_set_env {
49    BUILD_ARCH=$1
50
51    export TOOLCHAIN_PATH="${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/${HOST_PLATFORM}/bin"
52
53    # Set variables for each architecture
54    if [ $BUILD_ARCH == "arm" ]; then
55        export TOOLCHAIN_HOST="arm-linux-androideabi"
56        export TOOLCHAIN_COMP="armv7a-linux-androideabi${MIN_SDK_VERSION}"
57        export TOOLCHAIN_ABI="armeabi-v7a"
58        export TOOLCHAIN_ARCH="arm"
59    elif [ $BUILD_ARCH == "x86" ]; then
60        export TOOLCHAIN_HOST="i686-linux-android"
61        export TOOLCHAIN_COMP="i686-linux-android${MIN_SDK_VERSION}"
62        export TOOLCHAIN_ABI="x86"
63        export TOOLCHAIN_ARCH="x86"
64    elif [ $BUILD_ARCH == "arm64" ]; then
65        export TOOLCHAIN_HOST="aarch64-linux-android"
66        export TOOLCHAIN_COMP="aarch64-linux-android${MIN_SDK_VERSION}"
67        export TOOLCHAIN_ABI="arm64-v8a"
68        export TOOLCHAIN_ARCH="arm64"
69    elif [ $BUILD_ARCH == "x86_64" ]; then
70        export TOOLCHAIN_HOST="x86_64-linux-android"
71        export TOOLCHAIN_COMP="x86_64-linux-android${MIN_SDK_VERSION}"
72        export TOOLCHAIN_ABI="x86_64"
73        export TOOLCHAIN_ARCH="x86_64"
74    fi
75
76    export ANDROID_BUILD_SYSROOT="${ANDROID_NDK_ROOT}/platforms/android-${MIN_SDK_VERSION}/arch-${TOOLCHAIN_ARCH}"
77    export ANDROID_BUILD_PREFIX="${ANDROID_BUILD_DIR}/prefix/${TOOLCHAIN_ARCH}"
78}
79
80function android_build_env {
81    ##
82    # Check that necessary environment variables are set
83
84    if [ -z "$ANDROID_NDK_ROOT" ]; then
85        ANDROID_BUILD_FAIL+=("Please set the ANDROID_NDK_ROOT environment variable")
86        ANDROID_BUILD_FAIL+=("  (eg. \"/home/user/android/android-ndk-r21\")")
87    fi
88
89    if [ -z "$TOOLCHAIN_PATH" ]; then
90        ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_PATH environment variable")
91        ANDROID_BUILD_FAIL+=("  (eg. \"/home/user/android/android-ndk-r21/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin\")")
92    fi
93
94    if [ -z "$TOOLCHAIN_HOST" ]; then
95        ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_HOST environment variable")
96        ANDROID_BUILD_FAIL+=("  (eg. \"arm-linux-androideabi\")")
97    fi
98
99    if [ -z "$TOOLCHAIN_COMP" ]; then
100        ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_COMP environment variable")
101        ANDROID_BUILD_FAIL+=("  (eg. \"armv7a-linux-androideabi\")")
102    fi
103
104    if [ -z "$TOOLCHAIN_ABI" ]; then
105        ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_ABI environment variable")
106        ANDROID_BUILD_FAIL+=("  (eg. \"armeabi-v7a\")")
107    fi
108
109    if [ -z "$TOOLCHAIN_ARCH" ]; then
110        ANDROID_BUILD_FAIL+=("Please set the TOOLCHAIN_ARCH environment variable")
111        ANDROID_BUILD_FAIL+=("  (eg. \"arm\")")
112    fi
113
114    android_build_check_fail
115
116    ##
117    # Check that directories given by environment variables exist
118
119    if [ ! -d "$ANDROID_NDK_ROOT" ]; then
120        ANDROID_BUILD_FAIL+=("The ANDROID_NDK_ROOT directory does not exist")
121        ANDROID_BUILD_FAIL+=("  ${ANDROID_NDK_ROOT}")
122    fi
123
124    if [ ! -d "$TOOLCHAIN_PATH" ]; then
125        ANDROID_BUILD_FAIL+=("The TOOLCHAIN_PATH directory does not exist")
126        ANDROID_BUILD_FAIL+=("  ${TOOLCHAIN_PATH}")
127    fi
128
129    ##
130    # Set up some local variables and check them
131
132    if [ ! -d "$ANDROID_BUILD_SYSROOT" ]; then
133        ANDROID_BUILD_FAIL+=("The ANDROID_BUILD_SYSROOT directory does not exist")
134        ANDROID_BUILD_FAIL+=("  ${ANDROID_BUILD_SYSROOT}")
135    fi
136
137    mkdir -p "$ANDROID_BUILD_PREFIX" || {
138        ANDROID_BUILD_FAIL+=("Failed to make ANDROID_BUILD_PREFIX directory")
139        ANDROID_BUILD_FAIL+=("  ${ANDROID_BUILD_PREFIX}")
140    }
141
142    android_build_check_fail
143}
144
145function _android_build_opts_process_binaries {
146    local TOOLCHAIN="${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/${HOST_PLATFORM}"
147    local CC="${TOOLCHAIN_PATH}/${TOOLCHAIN_COMP}-clang"
148    local CXX="${TOOLCHAIN_PATH}/${TOOLCHAIN_COMP}-clang++"
149    local LD="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ld"
150    local AS="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-as"
151    local AR="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ar"
152    local RANLIB="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ranlib"
153    local STRIP="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-strip"
154
155    if [ ! -x "${CC}" ]; then
156        ANDROID_BUILD_FAIL+=("The CC binary does not exist or is not executable")
157        ANDROID_BUILD_FAIL+=("  ${CC}")
158    fi
159
160    if [ ! -x "${CXX}" ]; then
161        ANDROID_BUILD_FAIL+=("The CXX binary does not exist or is not executable")
162        ANDROID_BUILD_FAIL+=("  ${CXX}")
163    fi
164
165    if [ ! -x "${LD}" ]; then
166        ANDROID_BUILD_FAIL+=("The LD binary does not exist or is not executable")
167        ANDROID_BUILD_FAIL+=("  ${LD}")
168    fi
169
170    if [ ! -x "${AS}" ]; then
171        ANDROID_BUILD_FAIL+=("The AS binary does not exist or is not executable")
172        ANDROID_BUILD_FAIL+=("  ${AS}")
173    fi
174
175    if [ ! -x "${AR}" ]; then
176        ANDROID_BUILD_FAIL+=("The AR binary does not exist or is not executable")
177        ANDROID_BUILD_FAIL+=("  ${AR}")
178    fi
179
180    if [ ! -x "${RANLIB}" ]; then
181        ANDROID_BUILD_FAIL+=("The RANLIB binary does not exist or is not executable")
182        ANDROID_BUILD_FAIL+=("  ${RANLIB}")
183    fi
184
185    if [ ! -x "${STRIP}" ]; then
186        ANDROID_BUILD_FAIL+=("The STRIP binary does not exist or is not executable")
187        ANDROID_BUILD_FAIL+=("  ${STRIP}")
188    fi
189
190    ANDROID_BUILD_OPTS+=("TOOLCHAIN=${TOOLCHAIN}")
191    ANDROID_BUILD_OPTS+=("CC=${CC}")
192    ANDROID_BUILD_OPTS+=("CXX=${CXX}")
193    ANDROID_BUILD_OPTS+=("LD=${LD}")
194    ANDROID_BUILD_OPTS+=("AS=${AS}")
195    ANDROID_BUILD_OPTS+=("AR=${AR}")
196    ANDROID_BUILD_OPTS+=("RANLIB=${RANLIB}")
197    ANDROID_BUILD_OPTS+=("STRIP=${STRIP}")
198
199    android_build_check_fail
200}
201
202# Set the ANDROID_BUILD_OPTS variable to a bash array of configure options
203function android_build_opts {
204    ANDROID_BUILD_OPTS=()
205
206    _android_build_opts_process_binaries
207
208    local LIBS="-lc -lgcc -ldl -lm -llog -lc++_shared"
209    local LDFLAGS="-L${ANDROID_BUILD_PREFIX}/lib"
210    LDFLAGS+=" -L${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/${TOOLCHAIN_ABI}"
211    CFLAGS+=" -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE"
212    CPPFLAGS+=" -I${ANDROID_BUILD_PREFIX}/include"
213
214    ANDROID_BUILD_OPTS+=("CFLAGS=${CFLAGS} ${ANDROID_BUILD_EXTRA_CFLAGS}")
215    ANDROID_BUILD_OPTS+=("CPPFLAGS=${CPPFLAGS} ${ANDROID_BUILD_EXTRA_CPPFLAGS}")
216    ANDROID_BUILD_OPTS+=("CXXFLAGS=${CXXFLAGS} ${ANDROID_BUILD_EXTRA_CXXFLAGS}")
217    ANDROID_BUILD_OPTS+=("LDFLAGS=${LDFLAGS} ${ANDROID_BUILD_EXTRA_LDFLAGS}")
218    ANDROID_BUILD_OPTS+=("LIBS=${LIBS} ${ANDROID_BUILD_EXTRA_LIBS}")
219
220    ANDROID_BUILD_OPTS+=("PKG_CONFIG_LIBDIR=${ANDROID_NDK_ROOT}/prebuilt/${HOST_PLATFORM}/lib/pkgconfig")
221    ANDROID_BUILD_OPTS+=("PKG_CONFIG_PATH=${ANDROID_BUILD_PREFIX}/lib/pkgconfig")
222    ANDROID_BUILD_OPTS+=("PKG_CONFIG_SYSROOT_DIR=${ANDROID_BUILD_SYSROOT}")
223    ANDROID_BUILD_OPTS+=("PKG_CONFIG_DIR=")
224    ANDROID_BUILD_OPTS+=("--with-sysroot=${ANDROID_BUILD_SYSROOT}")
225    ANDROID_BUILD_OPTS+=("--host=${TOOLCHAIN_HOST}")
226    ANDROID_BUILD_OPTS+=("--prefix=${ANDROID_BUILD_PREFIX}")
227
228    android_build_check_fail
229}
230
231# Parse readelf output to verify the correct linking of libraries.
232#   The first argument should be the soname of the newly built library.
233#   The rest of the arguments should be the sonames of dependencies.
234#   All sonames should be unversioned for android (no trailing numbers).
235function android_build_verify_so {
236    local soname="$1"
237    shift # Get rid of first argument - the rest represent dependencies
238
239    local sofile="${ANDROID_BUILD_PREFIX}/lib/${soname}"
240    if [ ! -f "${sofile}" ]; then
241        ANDROID_BUILD_FAIL+=("Found no library named ${soname}")
242        ANDROID_BUILD_FAIL+=("  ${sofile}")
243    fi
244    android_build_check_fail
245
246    local READELF="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-readelf"
247    if command -v ${READELF} >/dev/null 2>&1 ; then
248        local readelf_bin="${READELF}"
249    elif command -v readelf >/dev/null 2>&1 ; then
250        local readelf_bin="readelf"
251    elif command -v greadelf >/dev/null 2>&1 ; then
252        local readelf_bin="greadelf"
253    else
254        ANDROID_BUILD_FAIL+=("Could not find any of readelf, greadelf, or ${READELF}")
255    fi
256    android_build_check_fail
257
258    local elfoutput=$(LC_ALL=C $readelf_bin -d ${sofile})
259
260    local soname_regexp='soname: \[([[:alnum:]\.]+)\]'
261    if [[ $elfoutput =~ $soname_regexp ]]; then
262        local parsed_soname="${BASH_REMATCH[1]}"
263        if [ "${parsed_soname}" != "${soname}" ]; then
264            ANDROID_BUILD_FAIL+=("Actual soname of library ${soname} is incorrect (or versioned):")
265            ANDROID_BUILD_FAIL+=("  ${parsed_soname}")
266        fi
267    else
268        ANDROID_BUILD_FAIL+=("Failed to meaningfully parse readelf output for library ${soname}:")
269        ANDROID_BUILD_FAIL+=("  ${elfoutput}")
270    fi
271
272    for dep_soname do
273        if [[ $elfoutput != *"library: [${dep_soname}]"* ]]; then
274            ANDROID_BUILD_FAIL+=("Library ${soname} was expected to be linked to library with soname:")
275            ANDROID_BUILD_FAIL+=("  ${dep_soname}")
276        fi
277    done
278
279    android_build_check_fail
280}
281
282################################################################################
283#  THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY  #
284#  Read the zproject/README.md for information about making permanent changes. #
285################################################################################
286