blob: 7cd66c284acc60dcbb1c56786ef7174609bad060 [file]
cmake_minimum_required(VERSION 4.0)
project(CPackAPKGenerator
LANGUAGES CXX
VERSION "1.2.3"
)
# An Android application is a shared library loaded by the Java runtime.
add_library(app SHARED main.cpp)
if(CMAKE_ANDROID_ARCH_ABI)
set(app_destination lib/${CMAKE_ANDROID_ARCH_ABI})
else()
set(app_destination lib)
endif()
# On a host build, where the toolchain file is not in play, a shared library
# may well be a `RUNTIME` artifact instead.
install(TARGETS app
LIBRARY DESTINATION ${app_destination}
RUNTIME DESTINATION ${app_destination}
)
if(APK_TEST_DEFAULT_DIRECTORIES)
# Neither the manifest nor the project sets the target API level, which
# then defaults to the compile API level.
file(READ AndroidManifest.xml manifest)
string(REPLACE " android:targetSdkVersion=\"34\"" "" manifest "${manifest}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml" "${manifest}")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml"
DESTINATION .)
else()
install(FILES AndroidManifest.xml DESTINATION .)
endif()
install(DIRECTORY res assets DESTINATION .)
# An Android archive with a manifest, resources, assets and native libraries
# for several ABIs, but no code.
set(aar_contents "${CMAKE_CURRENT_BINARY_DIR}/aar-contents")
file(COPY aar/ DESTINATION "${aar_contents}")
foreach(abi IN ITEMS arm64-v8a armeabi-v7a x86 x86_64)
file(WRITE "${aar_contents}/jni/${abi}/libaar.so" "not a real library\n")
endforeach()
# Native libraries are stripped, unless they are to keep their debug
# symbols. In a host build, which has no ELF library to strip, a stand-in
# for llvm-strip is given ELF look-alikes. A stand-in for llvm-readelf
# finds one of them linked to the shared C++ runtime, which is packaged from
# a stand-in NDK for its ABI.
if(NOT CMAKE_ANDROID_ARCH_ABI)
string(ASCII 127 elf_magic)
file(WRITE "${aar_contents}/jni/x86_64/libstripped.so"
"${elf_magic}ELF debug\nneeded libc++_shared.so\n")
file(WRITE "${aar_contents}/jni/x86_64/libkept.so" "${elf_magic}ELF debug\n")
set(CPACK_APK_STRIP_EXECUTABLE
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_SOURCE_DIR}/strip.cmake")
set(CPACK_READELF_EXECUTABLE
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_SOURCE_DIR}/readelf.cmake")
set(CPACK_APK_KEEP_DEBUG_SYMBOLS "libke?t*.so")
set(CPACK_APK_NDK_ROOT "${CMAKE_CURRENT_BINARY_DIR}/ndk")
set(ndk_libraries
"${CPACK_APK_NDK_ROOT}/toolchains/llvm/prebuilt/host/sysroot/usr/lib")
foreach(triple IN ITEMS aarch64-linux-android x86_64-linux-android)
file(WRITE "${ndk_libraries}/${triple}/libc++_shared.so"
"${elf_magic}ELF libc++\n")
endforeach()
endif()
# Like those built reproducibly, the archives share their time stamps.
set(aar_mtime "2020-01-01 00:00:00Z")
set(aar "${CMAKE_CURRENT_BINARY_DIR}/testlib.aar")
add_custom_command(OUTPUT "${aar}"
COMMAND ${CMAKE_COMMAND} -E tar cf "${aar}" --format=zip
"--mtime=${aar_mtime}" AndroidManifest.xml res assets jni
WORKING_DIRECTORY "${aar_contents}"
VERBATIM
)
# A second archive, with an asset replacing that of the first, and
# components the first one or the application declares as well.
set(aar2_contents "${CMAKE_CURRENT_BINARY_DIR}/aar2-contents")
file(COPY aar2/ DESTINATION "${aar2_contents}")
file(WRITE "${aar2_contents}/assets/lib.txt" "testlib2 asset
")
set(aar2 "${CMAKE_CURRENT_BINARY_DIR}/testlib2.aar")
add_custom_command(OUTPUT "${aar2}"
COMMAND ${CMAKE_COMMAND} -E tar cf "${aar2}" --format=zip
"--mtime=${aar_mtime}" AndroidManifest.xml assets
WORKING_DIRECTORY "${aar2_contents}"
VERBATIM
)
add_custom_target(aar ALL DEPENDS "${aar}" "${aar2}")
install(FILES "${aar}" "${aar2}" DESTINATION .)
# Create APK package
set(CPACK_GENERATOR APK)
set(CPACK_PACKAGE_NAME APKGeneratorTest)
set(CPACK_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION})
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(CPACK_PACKAGE_VENDOR "ACME Inc")
set(CPACK_PACKAGE_DESCRIPTION "An APK package for testing CMake's CPack APK generator")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A test APK package")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://www.example.com")
# APK generator variables
# Like those of Gradle projects, the manifest does not name the package.
set(CPACK_APK_PACKAGE com.example.app)
set(CPACK_APK_JAVA_SOURCE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/java")
set(CPACK_APK_MANIFEST_PLACEHOLDERS "flavor=test-flavor")
set(CPACK_APK_VERSION_CODE 42)
if(NOT APK_TEST_DEFAULT_DIRECTORIES)
set(CPACK_APK_TARGET_SDK_VERSION 35)
endif()
# A relative path is relative to the directory cpack runs in, not to the one
# the build tools run in.
if(NOT APK_TEST_DEFAULT_DIRECTORIES)
file(COPY res-overlay DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
set(CPACK_APK_RESOURCE_DIRECTORIES
"${CMAKE_CURRENT_SOURCE_DIR}/res"
res-overlay
)
endif()
if(APK_TEST_MAVEN)
include(maven.cmake)
endif()
include(CPack)