From 1d0de0b4503f67b18fbc502daf7dc8e96d62c5da Mon Sep 17 00:00:00 2001 From: Alex Studer Date: Wed, 3 Jul 2024 15:17:16 -0400 Subject: [PATCH] Android: Integrate vcpkg with Gradle build This ensures that vcpkg downloads and builds all dependencies for Android. We add it as a CMAKE_TOOLCHAIN_FILE that then chainloads the Android NDK's toolchain file, as per the vcpkg documentation. --- CMakeLists.txt | 7 ++ Ladybird/Android/BuildLagomTools.sh | 27 ++++++-- Ladybird/Android/build.gradle.kts | 5 +- Ladybird/Android/vcpkg_android.cmake | 96 ++++++++++++++++++++++++++++ vcpkg.json | 4 ++ 5 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 Ladybird/Android/vcpkg_android.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 25cac077b23..4b67f0136db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,12 @@ cmake_minimum_required(VERSION 3.25) +if (VCPKG_TARGET_ANDROID) + # If we are building for Android, we must load vcpkg_android.cmake before the project() declaration. + # This ensures that the CMAKE_TOOLCHAIN_FILE is set correctly. + # (we cannot set CMAKE_TOOLCHAIN_FILE from Gradle, unfortunately, so this is the only place we can do it.) + include("Ladybird/Android/vcpkg_android.cmake") +endif() + project(ladybird VERSION 0.1.0 LANGUAGES C CXX diff --git a/Ladybird/Android/BuildLagomTools.sh b/Ladybird/Android/BuildLagomTools.sh index fecff837d08..5fda0959b6c 100755 --- a/Ladybird/Android/BuildLagomTools.sh +++ b/Ladybird/Android/BuildLagomTools.sh @@ -4,24 +4,39 @@ set -eo pipefail DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -SERENITY_ROOT="$(realpath "${DIR}"/../..)" +LADYBIRD_SOURCE_DIR="$(realpath "${DIR}"/../..)" # shellcheck source=/dev/null -. "${SERENITY_ROOT}/Meta/shell_include.sh" +. "${LADYBIRD_SOURCE_DIR}/Meta/shell_include.sh" # shellcheck source=/dev/null -. "${SERENITY_ROOT}/Meta/find_compiler.sh" +. "${LADYBIRD_SOURCE_DIR}/Meta/find_compiler.sh" pick_host_compiler -BUILD_DIR=${BUILD_DIR:-"${SERENITY_ROOT}/Build"} +BUILD_DIR=${BUILD_DIR:-"${LADYBIRD_SOURCE_DIR}/Build"} CACHE_DIR=${CACHE_DIR:-"${BUILD_DIR}/caches"} -cmake -S "$SERENITY_ROOT/Meta/Lagom" -B "$BUILD_DIR/lagom-tools" \ +# HACK: This export of XDG_CACHE_HOME is required to make vcpkg happy. +# This is because vcpkg tries to find a cache directory by: +# 1) checking $XDG_CACHE_HOME +# 2) appending "/.cache" to $HOME +# The problem is, in the Android build environment, neither of those environment variables are set. +# This causes vcpkg to fail; so, we set a dummy $XDG_CACHE_HOME, ensuring that vcpkg is happy. +# (Note that vcpkg appends "/vcpkg" to the cache directory we give it.) +# (And this also works on macOS, despite the fact that $XDG_CACHE_HOME is a Linux-ism.) +export XDG_CACHE_HOME="$CACHE_DIR" + +cmake -S "${LADYBIRD_SOURCE_DIR}/Meta/Lagom" -B "$BUILD_DIR/lagom-tools" \ -GNinja -Dpackage=LagomTools \ -DCMAKE_INSTALL_PREFIX="$BUILD_DIR/lagom-tools-install" \ -DCMAKE_C_COMPILER="$CC" \ -DCMAKE_CXX_COMPILER="$CXX" \ - -DSERENITY_CACHE_DIR="$CACHE_DIR" + -DSERENITY_CACHE_DIR="$CACHE_DIR" \ + -DCMAKE_TOOLCHAIN_FILE="$LADYBIRD_SOURCE_DIR/Toolchain/Tarballs/vcpkg/scripts/buildsystems/vcpkg.cmake" \ + -DVCPKG_INSTALL_OPTIONS="--no-print-usage" \ + -DVCPKG_OVERLAY_TRIPLETS="$LADYBIRD_SOURCE_DIR/Meta/CMake/vcpkg/release-triplets" \ + -DVCPKG_ROOT="$LADYBIRD_SOURCE_DIR/Toolchain/Tarballs/vcpkg" \ + -DVCPKG_MANIFEST_DIR="$LADYBIRD_SOURCE_DIR" ninja -C "$BUILD_DIR/lagom-tools" install diff --git a/Ladybird/Android/build.gradle.kts b/Ladybird/Android/build.gradle.kts index 128b431af1b..4f5ecc91c06 100644 --- a/Ladybird/Android/build.gradle.kts +++ b/Ladybird/Android/build.gradle.kts @@ -7,6 +7,7 @@ plugins { var buildDir = layout.buildDirectory.get() var cacheDir = System.getenv("SERENITY_CACHE_DIR") ?: "$buildDir/caches" +var sourceDir = layout.projectDirectory.dir("../../").toString() task("buildLagomTools") { commandLine = listOf("./BuildLagomTools.sh") @@ -36,7 +37,9 @@ android { cppFlags += "-std=c++23" arguments += listOf( "-DLagomTools_DIR=$buildDir/lagom-tools-install/share/LagomTools", - "-DSERENITY_CACHE_DIR=$cacheDir" + "-DSERENITY_CACHE_DIR=$cacheDir", + "-DVCPKG_ROOT=$sourceDir/Toolchain/Tarballs/vcpkg", + "-DVCPKG_TARGET_ANDROID=ON" ) } } diff --git a/Ladybird/Android/vcpkg_android.cmake b/Ladybird/Android/vcpkg_android.cmake new file mode 100644 index 00000000000..93a20ce26ea --- /dev/null +++ b/Ladybird/Android/vcpkg_android.cmake @@ -0,0 +1,96 @@ +# This file is based on the vcpkg Android example from here https://github.com/microsoft/vcpkg-docs/blob/06b496c3f24dbe651fb593a26bee50537eeaf4e5/vcpkg/examples/vcpkg_android_example_cmake_script/cmake/vcpkg_android.cmake +# It was modified to use CMake variables instead of environment variables, because it's not possible to set environment variables in the Android Gradle plugin. +# +# vcpkg_android.cmake +# +# Helper script when using vcpkg with cmake. It should be triggered via the variable VCPKG_TARGET_ANDROID +# +# For example: +# if (VCPKG_TARGET_ANDROID) +# include("cmake/vcpkg_android.cmake") +# endif() +# +# This script will: +# 1 & 2. check the presence of needed env variables: ANDROID_NDK and VCPKG_ROOT +# 3. set VCPKG_TARGET_TRIPLET according to ANDROID_ABI +# 4. Combine vcpkg and Android toolchains by setting CMAKE_TOOLCHAIN_FILE +# and VCPKG_CHAINLOAD_TOOLCHAIN_FILE + +# Note: VCPKG_TARGET_ANDROID is not an official vcpkg variable. +# it is introduced for the need of this script + +if (VCPKG_TARGET_ANDROID) + + # + # 1. Check the presence of variable ANDROID_NDK + # + if (NOT DEFINED ANDROID_NDK) + message(FATAL_ERROR "Please set CMake variable ANDROID_NDK") + endif() + + # + # 2. Check the presence of environment variable VCPKG_ROOT + # + if (NOT DEFINED VCPKG_ROOT) + message(FATAL_ERROR "Please set a CMake variable VCPKG_ROOT") + endif() + + # + # 3. Set VCPKG_TARGET_TRIPLET according to ANDROID_ABI + # + # There are four different Android ABI, each of which maps to + # a vcpkg triplet. The following table outlines the mapping from vcpkg architectures to android architectures + # + # |VCPKG_TARGET_TRIPLET | ANDROID_ABI | + # |---------------------------|----------------------| + # |arm64-android | arm64-v8a | + # |arm-android | armeabi-v7a | + # |x64-android | x86_64 | + # |x86-android | x86 | + # + # The variable must be stored in the cache in order to successfully the two toolchains. + # + if (ANDROID_ABI MATCHES "arm64-v8a") + set(VCPKG_TARGET_TRIPLET "arm64-android" CACHE STRING "" FORCE) + elseif(ANDROID_ABI MATCHES "armeabi-v7a") + set(VCPKG_TARGET_TRIPLET "arm-android" CACHE STRING "" FORCE) + elseif(ANDROID_ABI MATCHES "x86_64") + set(VCPKG_TARGET_TRIPLET "x64-android" CACHE STRING "" FORCE) + elseif(ANDROID_ABI MATCHES "x86") + set(VCPKG_TARGET_TRIPLET "x86-android" CACHE STRING "" FORCE) + else() + message(FATAL_ERROR " + Please specify ANDROID_ABI + For example + cmake ... -DANDROID_ABI=armeabi-v7a + + Possible ABIs are: arm64-v8a, armeabi-v7a, x64-android, x86-android + ") + endif() + message("vcpkg_android.cmake: VCPKG_TARGET_TRIPLET was set to ${VCPKG_TARGET_TRIPLET}") + + # + # 4. Combine vcpkg and Android toolchains + # + + # vcpkg and android both provide dedicated toolchains: + # + # vcpkg_toolchain_file=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake + # android_toolchain_file=$ANDROID_NDK/build/cmake/android.toolchain.cmake + # + # When using vcpkg, the vcpkg toolchain shall be specified first. + # However, vcpkg provides a way to preload and additional toolchain, + # with the VCPKG_CHAINLOAD_TOOLCHAIN_FILE option. + set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE ${ANDROID_NDK}/build/cmake/android.toolchain.cmake) + set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake) + message("vcpkg_android.cmake: CMAKE_TOOLCHAIN_FILE was set to ${CMAKE_TOOLCHAIN_FILE}") + message("vcpkg_android.cmake: VCPKG_CHAINLOAD_TOOLCHAIN_FILE was set to ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}") + + # vcpkg depends on the environment variables ANDROID_NDK_HOME and VCPKG_ROOT being set. + # However, we cannot set those through the Android Gradle plugin (we can only set CMake variables). + # Therefore, we forward our CMake variables to environment variables. + # FIXME: would be nice if vcpkg's android toolchain did not require this... + set(ENV{ANDROID_NDK_HOME} ${ANDROID_NDK}) + set(ENV{VCPKG_ROOT} ${VCPKG_ROOT}) + +endif(VCPKG_TARGET_ANDROID) diff --git a/vcpkg.json b/vcpkg.json index 1253f5f22b3..4815584f489 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -27,6 +27,10 @@ "vulkan" ] }, + { + "name": "skia", + "platform": "android" + }, "sqlite3", "woff2" ],