From 99cefa3420a0d4b5a751731069e6e81ada069ae1 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 15 Sep 2024 22:12:36 +0300 Subject: [PATCH] Simplifications and cleanup to the build script * The script now supports zsh and bash to allow building from macOS and Linux with builtin zsh and bash version 3 or 4. * It now uses curl instead of wget, wget is not builtin on macOS. * Use the default NDk path from the Android SDK. * Allow to set custom build and output folders. * The various build folders for each version are now kept around under the 'build' folder. * At the same time add the build folder to .gitignore. * Create relative symlinks #61. --- .gitignore | 2 + README.md | 13 +-- build_ssl.sh | 321 +++++++++++++++++++++++++++++++-------------------- 3 files changed, 204 insertions(+), 132 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..880ac59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.DS_Store diff --git a/README.md b/README.md index 207cce1..91beb52 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ OpenSSL scripts and binaries for Android (useful for Qt Android apps) In this repo you can find the prebuilt OpenSSL libs for Android, a QMake include project `.pri` file that can be used integrated with Qt projects, and a `.cmake` file for CMake based projects. The following directories are available -* `ssl_3`: used for Qt 6.5.0+. +* `ssl_3`: for Qt 6.5.0+. * `ssl_1_1`: for Qt Qt 5.12.5+, 5.13.1+, 5.14.0+, 5.15.0+, Qt 6.x.x up to 6.4.x ## How to use it @@ -23,7 +23,7 @@ if (ANDROID) FetchContent_Declare( android_openssl DOWNLOAD_EXTRACT_TIMESTAMP true - URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip + URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip # URL_HASH MD5=c97d6ad774fab16be63b0ab40f78d945 #optional ) FetchContent_MakeAvailable(android_openssl) @@ -51,14 +51,11 @@ endif() ## Build Script The build script `build_ssl.sh` can be used to rebuild the OpenSSL libraries. Since specific -versions might depend or work better with specific NDK versions, the OpenSSL<==>NDK version +versions might depend or work better with specific NDK versions, the OpenSSL/NDK version combinations are defined in the script. Before running the script, check that the NDK paths are correct for your environment. ### Build Prerequisites -Both Linux, macOS need `patchelf` command when building for OpenSSL 3+. - -Additionally, for macOS you need: -- `bash` shell version 4+ is required -- `wget` command +The build script was tested against `bash` and `zsh` on Linux and macOS. +The `patchelf` command is required when building for OpenSSL 3. diff --git a/build_ssl.sh b/build_ssl.sh index 096908e..6c78861 100755 --- a/build_ssl.sh +++ b/build_ssl.sh @@ -1,63 +1,114 @@ -#!/bin/bash +#!/bin/bash -x ## Prerequisites -## On both Linux, macOS: 'patchelf' command is needed for OpenSSL 3+ -## On macOS: -## - bash shell version 4+ is required -## - wget command - -BUILD_DIR=$(pwd) - -# Comment out the line for any configuration you don't want to build -declare -a params=( - '' - 'no-asm' -) -declare -A ssl_versions_output_dir=( - ["ssl_1.1"]="1.1*" - ["ssl_3"]="3*" -) -declare -A ssl_versions_ndk=( - ["1.1.1u"]="$HOME/android/ndk/21.4.7075529" - ["3.1.1"]="$HOME/android/ndk/25.2.9519653" -) -declare -A architectures=( - ["x86_64"]="x86_64" - ["x86"]="x86" - ["arm64"]="arm64-v8a" - ["arm"]="armeabi-v7a" -) +## The script supports builds from Linux and macOS. +## The 'patchelf' command is required for OpenSSL 3. +## set BUILD_DIR and OUTPUT_ROOT variables to use custom build and output paths. +## Set NDK_ROOT_PREFIX to use custom Android NDK root path that contains various +## NDK versions. + +set -eo pipefail + +[ -n "$OUTPUT_ROOT" ] || OUTPUT_ROOT="$(pwd)" +[ -n "$BUILD_DIR" ] || BUILD_DIR="$(pwd)/build" + +# Set Android NDK path prefix under the Android SDK +if [ -z "$NDK_ROOT_PREFIX" ]; then + if [[ "$(uname)" == "Darwin" ]]; then + NDK_ROOT_PREFIX="$HOME/Library/Android/sdk/ndk" + else + NDK_ROOT_PREFIX="$HOME/Android/Sdk/ndk" + fi +fi + +ssl_versions=("1.1.1u" "3.1.1") +architectures=("arm64" "arm" "x86_64" "x86") +build_types=('' 'no-asm') + +get_qt_arch() { + # takes OpenSSL arch as argument + case $1 in + arm64) + echo "arm64-v8a" + ;; + arm) + echo "armeabi-v7a" + ;; + *) + echo $1 + ;; + esac +} + +get_ssl_build_dir() { + # takes OpenSSL version as argument + case $1 in + 1.1.*) + echo "ssl_1.1" + ;; + 3.*) + echo "ssl_3" + ;; + *) + echo $1 + ;; + esac +} + +get_ssl_ndk_version() { + # takes OpenSSL version as argument + case $1 in + 1.1.*) + echo "21.4.7075529" + ;; + 3.*) + echo "25.2.9519653" + ;; + *) + echo $1 + ;; + esac +} download_ssl_version() { ssl_version=$1 - echo "Downloading OpenSSL $ssl_version" - if [ ! -f "openssl-$ssl_version.tar.gz" ]; then - wget -q --show-progress "https://www.openssl.org/source/openssl-$ssl_version.tar.gz" + download_dir=$2 + + ssl_filename="openssl-$ssl_version.tar.gz" + echo "Downloading OpenSSL $ssl_filename" + if [ ! -f "$ssl_filename" ]; then + curl -sfL -o "$download_dir/$ssl_filename" "https://www.openssl.org/source/$ssl_filename" \ + || (echo "Downloading sources failed!"; exit 1) fi } extract_package() { - qt_arch=$1 - version=$2 - ssl_version=$3 + ssl_version=$1 + src_path=$2 + output_dir=$3 - echo "Extracting OpenSSL $ssl_version under $(pwd)" - rm -fr "$qt_arch" "$version/$qt_arch" - mkdir -p "$version/$qt_arch" || exit 1 + echo "Extracting OpenSSL $ssl_version under $output_dir" rm -fr "openssl-$ssl_version" - tar xf "openssl-$ssl_version.tar.gz" || exit 1 + tar xf "$src_path/openssl-$ssl_version.tar.gz" || exit 1 } configure_ssl() { - ndk=$1 - param=$2 - ssl_version=$3 - version_out_dir=$4 - arch=$5 + ssl_version=$1 + arch=$2 + ndk=$3 + build_type=$4 + output_dir=$5 log_file=$6 - export ANDROID_NDK_HOME="${ndk}" - export ANDROID_NDK_ROOT="${ndk}" + nkd_path="$NDK_ROOT_PREFIX/$ndk" + + if [ ! -e "$nkd_path" ]; then + echo "NDK path $nkd_path does not exist" + exit 1 + fi + + export ANDROID_NDK_ROOT="$nkd_path" + export ANDROID_NDK_HOME="$nkd_path" declare hosts=("linux-x86_64" "linux-x86" "darwin-x86_64" "darwin-x86") for host in "${hosts[@]}"; do @@ -68,7 +119,7 @@ configure_ssl() { fi done - case $version_out_dir in + case $output_dir in ssl_1.1) ANDROID_API=21 ;; @@ -77,9 +128,10 @@ configure_ssl() { ;; esac - config_params=( "${param}" "shared" "android-${arch}" + config_params=( "${build_type}" "shared" "android-${arch}" "-U__ANDROID_API__" "-D__ANDROID_API__=${ANDROID_API}" ) - echo "Configuring OpenSSL $ssl_version with parameters: ${config_params[@]}" + echo "Configuring OpenSSL $ssl_version with NDK $ndk" + echo "Configure parameters: ${config_params[@]}" ./Configure "${config_params[@]}" 2>&1 1>${log_file} | tee -a ${log_file} || exit 1 make depend @@ -87,99 +139,120 @@ configure_ssl() { build_ssl_1_1() { # Qt up to 6.4 is using OpenSSL 1.1.x but the library is suffixed with _1_1.so - version_out_dir=$1 - qt_arch=$2 - log_file=$3 + output_dir=$1 + log_file=$2 echo "Building..." - make -j$(nproc) SHLIB_VERSION_NUMBER= SHLIB_EXT=_1_1.so build_libs 2>&1 1>>${log_file} | tee -a ${log_file} || exit 1 - llvm-strip --strip-all libcrypto_1_1.so - llvm-strip --strip-all libssl_1_1.so - cp libcrypto_1_1.so libssl_1_1.so "../$version_out_dir/$qt_arch" || exit 1 - cp libcrypto.a libssl.a "../$version_out_dir/$qt_arch" || exit 1 - ln -s "../$version_out_dir/$qt_arch/libcrypto_1_1.so" "../$version_out_dir/$qt_arch/libcrypto.so" - ln -s "../$version_out_dir/$qt_arch/libssl_1_1.so" "../$version_out_dir/$qt_arch/libssl.so" - ln -s "../$version_out_dir/include" "../$version_out_dir/$qt_arch/include" + make -j$(nproc) SHLIB_VERSION_NUMBER= SHLIB_EXT=_1_1.so build_libs 2>&1 1>>${log_file} \ + | tee -a ${log_file} || exit 1 } build_ssl_3() { # Qt 6.5.0+ is using OpenSSL 3.1.x but the library is suffixed with _3.so - version_out_dir=$1 - qt_arch=$2 - log_file=$3 + output_dir=$1 + log_file=$2 echo "Building..." - make -j$(nproc) SHLIB_VERSION_NUMBER= build_libs 2>&1 1>>${log_file} | tee -a ${log_file} || exit 1 - llvm-strip --strip-all libcrypto.so - llvm-strip --strip-all libssl.so - - out_path="../$version_out_dir/$qt_arch" - cp libcrypto.a libssl.a "${out_path}" || exit 1 - cp libcrypto.so "${out_path}/libcrypto_3.so" || exit 1 - cp libssl.so "${out_path}/libssl_3.so" || exit 1 - ln -s "${out_path}/libcrypto_3.so" "${out_path}/libcrypto.so" - ln -s "${out_path}/libssl_3.so" "${out_path}/libssl.so" - ln -s "../$version_out_dir/include" "../$version_out_dir/$qt_arch/include" - - pushd ${out_path} || exit 1 + make -j$(nproc) SHLIB_VERSION_NUMBER= build_libs 2>&1 1>>${log_file} \ + | tee -a ${log_file} || exit 1 + + mv libcrypto.so libcrypto_3.so + mv libssl.so libssl_3.so + + # SHLIB_EXT is no longer supported for OpenSSL, so we need to manually + # use patchelf to modify SONAME and NEEDED sections to set the correct + # suffix for the shared libraries. + # See https://github.com/openssl/openssl/issues/20854 patchelf --set-soname libcrypto_3.so libcrypto_3.so || exit 1 patchelf --set-soname libssl_3.so libssl_3.so || exit 1 patchelf --replace-needed libcrypto.so libcrypto_3.so libssl_3.so || exit 1 - popd } -for param in "${params[@]}"; do - if [ "${param}" ]; then - rm -fr "${param}" - mkdir "${param}" - pushd "${param}" +strip_libs() { + lib_suffix=$1 + + llvm-strip --strip-all libcrypto_$lib_suffix.so + llvm-strip --strip-all libssl_$lib_suffix.so +} + +copy_build_artefacts() { + lib_suffix=$1 + output_dir=$2 + + cp libcrypto_$lib_suffix.so "$output_dir/libcrypto_$lib_suffix.so" || exit 1 + cp libssl_$lib_suffix.so "$output_dir/libssl_$lib_suffix.so" || exit 1 + cp libcrypto.a libssl.a "$output_dir" || exit 1 + + # Create relative non-versioned symlinks + ln -s "libcrypto_$lib_suffix.so" "$output_dir/libcrypto.so" + ln -s "libssl_$lib_suffix.so" "$output_dir/libssl.so" + ln -s "../include" "$output_dir/include" +} + +[[ -e "$BUILD_DIR" ]] && rm -fr "$BUILD_DIR" +mkdir -p "$BUILD_DIR" +pushd "$BUILD_DIR" + +for build_type in "${build_types[@]}"; do + if [[ "${build_type}" ]]; then + mkdir -p $build_type + pushd $build_type fi - for ssl_version in "${!ssl_versions_ndk[@]}"; do - download_ssl_version $ssl_version + for ssl_version in "${ssl_versions[@]}"; do + ndk=$(get_ssl_ndk_version $ssl_version) + version_build_dir=$(get_ssl_build_dir $ssl_version) + mkdir -p $version_build_dir + pushd $version_build_dir - for version_out_dir in "${!ssl_versions_output_dir[@]}"; do - if [[ $ssl_version != ${ssl_versions_output_dir[$version_out_dir]} ]]; then - continue + download_ssl_version $ssl_version $BUILD_DIR + + for arch in "${architectures[@]}"; do + qt_arch=$(get_qt_arch $arch) + + extract_package $ssl_version $BUILD_DIR $version_build_dir + mv "openssl-$ssl_version" "openssl-$ssl_version-$arch" + pushd "openssl-$ssl_version-$arch" || exit 1 + + log_file="build_${arch}_${ssl_version}.log" + configure_ssl ${ssl_version} ${arch} "${ndk}" "${build_type}" \ + ${version_build_dir} ${log_file} + + # Delete existing build artefacts + output_dir="$OUTPUT_ROOT/$build_type/$version_build_dir/$qt_arch" + rm -fr "$output_dir" + mkdir -p "$output_dir" || exit 1 + + # Copy the include dir only once since since it's the same for all abis + if [ ! -d "$output_dir/../include" ]; then + cp -a include "$output_dir/../" || exit 1 + + # Clean include folder + find "$output_dir/../" -name "*.in" -delete + find "$output_dir/../" -name "*.def" -delete fi - echo "Build $ssl_version" - for arch in "${!architectures[@]}"; do - qt_arch="${architectures[$arch]}" - extract_package $qt_arch $version_out_dir $ssl_version - pushd "openssl-$ssl_version" || exit 1 - - log_file="build_${arch}_${ssl_version}.log" - ndk="${ssl_versions_ndk[$ssl_version]}" - configure_ssl "${ndk}" "${param}" ${ssl_version} ${version_out_dir} ${arch} ${log_file} - - if [ "$arch" == "arm64" ] && [ ! -d "../$version_out_dir/include/openssl" ]; then - cp -a include "../$version_out_dir" || exit 1 - fi - - case $version_out_dir in - ssl_1.1) - build_ssl_1_1 ${version_out_dir} ${qt_arch} ${log_file} - ;; - ssl_3) - build_ssl_3 ${version_out_dir} ${qt_arch} ${log_file} - ;; - *) - echo "Unhandled OpenSSL version $version_out_dir" - exit 1 - ;; - esac - - - popd - done + + case $version_build_dir in + ssl_1.1) + build_ssl_1_1 ${output_dir} ${log_file} + suffix="1_1" + ;; + ssl_3) + build_ssl_3 ${output_dir} ${log_file} + suffix="3" + ;; + *) + echo "Unhandled OpenSSL version $version_build_dir" + exit 1 + ;; + esac + + strip_libs "$suffix" + copy_build_artefacts "$suffix" ${output_dir} + + + popd done - rm -fr "openssl-$ssl_version" - rm "openssl-$ssl_version.tar.gz" - done - if [ "${param}" ]; then popd - fi + done + [[ "${build_type}" ]] && popd done - -# Clean include folder -find . -name "*.in" -delete -find . -name "*.def" -delete