mirror of
				https://github.com/thunderbrewhq/thunderbrew
				synced 2025-10-31 16:26:03 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			277 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
| #[=======================================================================[
 | |
| 
 | |
| This CMake script contains functions to build an Android APK.
 | |
| It is (currently) limited to packaging binaries for a single architecture.
 | |
| 
 | |
| #]=======================================================================]
 | |
| 
 | |
| cmake_minimum_required(VERSION 3.7...3.28)
 | |
| 
 | |
| if(NOT PROJECT_NAME MATCHES "^SDL.*")
 | |
|   message(WARNING "This module is internal to SDL and is currently not supported.")
 | |
| endif()
 | |
| 
 | |
| function(_sdl_create_outdir_for_target OUTDIRECTORY TARGET)
 | |
|   set(outdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET}.dir")
 | |
|   # Some CMake versions have a slow `cmake -E make_directory` implementation
 | |
|   if(NOT IS_DIRECTORY "${outdir}")
 | |
|     execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${outdir}")
 | |
|   endif()
 | |
|   set("${OUTDIRECTORY}" "${outdir}" PARENT_SCOPE)
 | |
| endfunction()
 | |
| 
 | |
| function(sdl_create_android_debug_keystore TARGET)
 | |
|   set(output "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_debug.keystore")
 | |
|   add_custom_command(OUTPUT ${output}
 | |
|     COMMAND ${CMAKE_COMMAND} -E rm -f "${output}"
 | |
|     COMMAND SdlAndroid::keytool -genkey -keystore "${output}" -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "C=US, O=Android, CN=Android Debug"
 | |
|   )
 | |
|   add_custom_target(${TARGET} DEPENDS "${output}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY OUTPUT "${output}")
 | |
| endfunction()
 | |
| 
 | |
| function(sdl_android_compile_resources TARGET)
 | |
|   cmake_parse_arguments(arg "" "RESFOLDER" "RESOURCES" ${ARGN})
 | |
| 
 | |
|   if(NOT arg_RESFOLDER AND NOT arg_RESOURCES)
 | |
|     message(FATAL_ERROR "Missing RESFOLDER or RESOURCES argument (need one or both)")
 | |
|   endif()
 | |
|   _sdl_create_outdir_for_target(outdir "${TARGET}")
 | |
|   set(out_files "")
 | |
| 
 | |
|   set(res_files "")
 | |
|   if(arg_RESFOLDER)
 | |
|     get_filename_component(arg_RESFOLDER "${arg_RESFOLDER}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
 | |
|     file(GLOB_RECURSE res_folder_files "${arg_RESFOLDER}/*")
 | |
|     list(APPEND res_files ${res_folder_files})
 | |
| 
 | |
|     foreach(res_file IN LISTS res_files)
 | |
|       file(RELATIVE_PATH rel_res_file "${arg_RESFOLDER}" "${res_file}")
 | |
|       string(REPLACE "/" "_" rel_comp_path "${rel_res_file}")
 | |
|       if(res_file MATCHES ".*res/values.*\\.xml$")
 | |
|         string(REGEX REPLACE "\\.xml" ".arsc" rel_comp_path "${rel_comp_path}")
 | |
|       endif()
 | |
|       set(comp_path "${outdir}/${rel_comp_path}.flat")
 | |
|       add_custom_command(
 | |
|         OUTPUT "${comp_path}"
 | |
|         COMMAND SdlAndroid::aapt2 compile -o "${outdir}" "${res_file}"
 | |
|         DEPENDS ${res_file}
 | |
|       )
 | |
|       list(APPEND out_files "${comp_path}")
 | |
|     endforeach()
 | |
|   endif()
 | |
| 
 | |
|   if(arg_RESOURCES)
 | |
|     list(APPEND res_files ${arg_RESOURCES})
 | |
|     foreach(res_file IN LISTS arg_RESOURCES)
 | |
|       string(REGEX REPLACE ".*/res/" "" rel_res_file ${res_file})
 | |
|       string(REPLACE "/" "_" rel_comp_path "${rel_res_file}")
 | |
|       if(res_file MATCHES ".*res/values.*\\.xml$")
 | |
|         string(REGEX REPLACE "\\.xml" ".arsc" rel_comp_path "${rel_comp_path}")
 | |
|       endif()
 | |
|       set(comp_path "${outdir}/${rel_comp_path}.flat")
 | |
|       add_custom_command(
 | |
|         OUTPUT "${comp_path}"
 | |
|         COMMAND SdlAndroid::aapt2 compile -o "${outdir}" "${res_file}"
 | |
|         DEPENDS ${res_file}
 | |
|       )
 | |
|       list(APPEND out_files "${comp_path}")
 | |
|     endforeach()
 | |
|   endif()
 | |
| 
 | |
|   add_custom_target(${TARGET} DEPENDS ${out_files})
 | |
|   set_property(TARGET "${TARGET}" PROPERTY OUTPUTS "${out_files}")
 | |
|   set_property(TARGET "${TARGET}" PROPERTY SOURCES "${res_files}")
 | |
| endfunction()
 | |
| 
 | |
| function(sdl_android_link_resources TARGET)
 | |
|   cmake_parse_arguments(arg "NO_DEBUG" "MIN_SDK_VERSION;TARGET_SDK_VERSION;ANDROID_JAR;OUTPUT_APK;MANIFEST;PACKAGE" "RES_TARGETS" ${ARGN})
 | |
| 
 | |
|   if(arg_MANIFEST)
 | |
|     get_filename_component(arg_MANIFEST "${arg_MANIFEST}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
 | |
|   else()
 | |
|     message(FATAL_ERROR "sdl_add_android_link_resources_target requires a Android MANIFEST path (${arg_MANIFEST})")
 | |
|   endif()
 | |
|   if(NOT arg_PACKAGE)
 | |
|     file(READ "${arg_MANIFEST}" manifest_contents)
 | |
|     string(REGEX MATCH "package=\"([a-zA-Z0-9_.]+)\"" package_match "${manifest_contents}")
 | |
|     if(NOT package_match)
 | |
|       message(FATAL_ERROR "Could not extract package from Android manifest (${arg_MANIFEST})")
 | |
|     endif()
 | |
|     set(arg_PACKAGE "${CMAKE_MATCH_1}")
 | |
|   endif()
 | |
| 
 | |
|   set(depends "")
 | |
| 
 | |
|   _sdl_create_outdir_for_target(outdir "${TARGET}")
 | |
|   string(REPLACE "." "/" java_r_path "${arg_PACKAGE}")
 | |
|   get_filename_component(java_r_path "${java_r_path}" ABSOLUTE BASE_DIR "${outdir}")
 | |
|   set(java_r_path "${java_r_path}/R.java")
 | |
| 
 | |
|   set(command SdlAndroid::aapt2 link)
 | |
|   if(NOT arg_NO_DEBUG)
 | |
|     list(APPEND command --debug-mode)
 | |
|   endif()
 | |
|   if(arg_MIN_SDK_VERSION)
 | |
|     list(APPEND command --min-sdk-version ${arg_MIN_SDK_VERSION})
 | |
|   endif()
 | |
|   if(arg_TARGET_SDK_VERSION)
 | |
|     list(APPEND command --target-sdk-version ${arg_TARGET_SDK_VERSION})
 | |
|   endif()
 | |
|   if(arg_ANDROID_JAR)
 | |
|     list(APPEND command -I "${arg_ANDROID_JAR}")
 | |
|   else()
 | |
|     list(APPEND command -I "${SDL_ANDROID_PLATFORM_ANDROID_JAR}")
 | |
|   endif()
 | |
|   if(NOT arg_OUTPUT_APK)
 | |
|     set(arg_OUTPUT_APK "${TARGET}.apk")
 | |
|   endif()
 | |
|   get_filename_component(arg_OUTPUT_APK "${arg_OUTPUT_APK}" ABSOLUTE BASE_DIR "${outdir}")
 | |
|   list(APPEND command -o "${arg_OUTPUT_APK}")
 | |
|   list(APPEND command --java "${outdir}")
 | |
|   list(APPEND command --manifest "${arg_MANIFEST}")
 | |
|   foreach(res_target IN LISTS arg_RES_TARGETS)
 | |
|     list(APPEND command $<TARGET_PROPERTY:${res_target},OUTPUTS>)
 | |
|     list(APPEND depends $<TARGET_PROPERTY:${res_target},OUTPUTS>)
 | |
|   endforeach()
 | |
|   add_custom_command(
 | |
|     OUTPUT "${arg_OUTPUT_APK}" "${java_r_path}"
 | |
|     COMMAND ${command}
 | |
|     DEPENDS ${depends} ${arg_MANIFEST}
 | |
|     COMMAND_EXPAND_LISTS
 | |
|     VERBATIM
 | |
|   )
 | |
|   add_custom_target(${TARGET} DEPENDS "${arg_OUTPUT_APK}" "${java_r_path}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY OUTPUT "${arg_OUTPUT_APK}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY JAVA_R "${java_r_path}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY OUTPUTS "${${arg_OUTPUT_APK}};${java_r_path}")
 | |
| endfunction()
 | |
| 
 | |
| function(sdl_add_to_apk_unaligned TARGET)
 | |
|   cmake_parse_arguments(arg "" "APK_IN;NAME;OUTDIR" "ASSETS;NATIVE_LIBS;DEX" ${ARGN})
 | |
| 
 | |
|   if(NOT arg_APK_IN)
 | |
|     message(FATAL_ERROR "Missing APK_IN argument")
 | |
|   endif()
 | |
| 
 | |
|   if(NOT TARGET ${arg_APK_IN})
 | |
|     message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
 | |
|   endif()
 | |
| 
 | |
|   _sdl_create_outdir_for_target(workdir ${TARGET})
 | |
| 
 | |
|   if(NOT arg_OUTDIR)
 | |
|     set(arg_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}")
 | |
|   endif()
 | |
| 
 | |
|   if(NOT arg_NAME)
 | |
|     string(REGEX REPLACE "[:-]+" "." arg_NAME "${TARGET}")
 | |
|     if(NOT arg_NAME MATCHES "\\.apk")
 | |
|       set(arg_NAME "${arg_NAME}.apk")
 | |
|     endif()
 | |
|   endif()
 | |
|   get_filename_component(apk_file "${arg_NAME}" ABSOLUTE BASE_DIR "${arg_OUTDIR}")
 | |
| 
 | |
|   set(apk_libdir "lib/${ANDROID_ABI}")
 | |
| 
 | |
|   set(depends "")
 | |
| 
 | |
|   set(commands
 | |
|     COMMAND "${CMAKE_COMMAND}" -E remove_directory -rf "${apk_libdir}" "assets"
 | |
|     COMMAND "${CMAKE_COMMAND}" -E make_directory "${apk_libdir}" "assets"
 | |
|     COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_PROPERTY:${arg_APK_IN},OUTPUT>" "${apk_file}"
 | |
|   )
 | |
| 
 | |
|   set(dex_i "1")
 | |
|   foreach(dex IN LISTS arg_DEX)
 | |
|     set(suffix "${dex_i}")
 | |
|     if(suffix STREQUAL "1")
 | |
|       set(suffix "")
 | |
|     endif()
 | |
|     list(APPEND commands
 | |
|       COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_PROPERTY:${dex},OUTPUT>" "classes${suffix}.dex"
 | |
|       COMMAND SdlAndroid::zip -u -q -j "${apk_file}" "classes${suffix}.dex"
 | |
|     )
 | |
|     math(EXPR dex_i "${dex_i}+1")
 | |
|     list(APPEND depends "$<TARGET_PROPERTY:${dex},OUTPUT>")
 | |
|   endforeach()
 | |
| 
 | |
|   foreach(native_lib IN LISTS arg_NATIVE_LIBS)
 | |
|     list(APPEND commands
 | |
|       COMMAND "${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${native_lib}> "${apk_libdir}/$<TARGET_FILE_NAME:${native_lib}>"
 | |
|       COMMAND SdlAndroid::zip -u -q "${apk_file}" "${apk_libdir}/$<TARGET_FILE_NAME:${native_lib}>"
 | |
|     )
 | |
|   endforeach()
 | |
|   if(arg_ASSETS)
 | |
|     list(APPEND commands
 | |
|       COMMAND "${CMAKE_COMMAND}" -E copy ${arg_ASSETS} "assets"
 | |
|       COMMAND SdlAndroid::zip -u -r -q "${apk_file}" "assets"
 | |
|     )
 | |
|   endif()
 | |
| 
 | |
|   add_custom_command(OUTPUT "${apk_file}"
 | |
|     ${commands}
 | |
|     DEPENDS ${arg_NATIVE_LIBS} ${depends} "$<TARGET_PROPERTY:${arg_APK_IN},OUTPUT>"
 | |
|     WORKING_DIRECTORY "${workdir}"
 | |
|   )
 | |
|   add_custom_target(${TARGET} DEPENDS "${apk_file}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
 | |
| endfunction()
 | |
| 
 | |
| function(sdl_apk_align TARGET APK_IN)
 | |
|   cmake_parse_arguments(arg "" "NAME;OUTDIR" "" ${ARGN})
 | |
| 
 | |
|   if(NOT TARGET ${arg_APK_IN})
 | |
|     message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
 | |
|   endif()
 | |
| 
 | |
|   if(NOT arg_OUTDIR)
 | |
|     set(arg_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}")
 | |
|   endif()
 | |
| 
 | |
|   if(NOT arg_NAME)
 | |
|     string(REGEX REPLACE "[:-]+" "." arg_NAME "${TARGET}")
 | |
|     if(NOT arg_NAME MATCHES "\\.apk")
 | |
|       set(arg_NAME "${arg_NAME}.apk")
 | |
|     endif()
 | |
|   endif()
 | |
|   get_filename_component(apk_file "${arg_NAME}" ABSOLUTE BASE_DIR "${arg_OUTDIR}")
 | |
| 
 | |
|   add_custom_command(OUTPUT "${apk_file}"
 | |
|     COMMAND SdlAndroid::zipalign -f 4 "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" "${apk_file}"
 | |
|     DEPENDS "$<TARGET_PROPERTY:${APK_IN},OUTPUT>"
 | |
|   )
 | |
|   add_custom_target(${TARGET} DEPENDS "${apk_file}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
 | |
| endfunction()
 | |
| 
 | |
| function(sdl_apk_sign TARGET APK_IN)
 | |
|   cmake_parse_arguments(arg "" "OUTPUT;KEYSTORE" "" ${ARGN})
 | |
| 
 | |
|   if(NOT TARGET ${arg_APK_IN})
 | |
|     message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
 | |
|   endif()
 | |
| 
 | |
|   if(NOT TARGET ${arg_KEYSTORE})
 | |
|     message(FATAL_ERROR "APK_KEYSTORE (${APK_KEYSTORE}) must be a target providing a keystore")
 | |
|   endif()
 | |
| 
 | |
|   if(NOT arg_OUTPUT)
 | |
|     string(REGEX REPLACE "[:-]+" "." arg_OUTPUT "${TARGET}")
 | |
|     if(NOT arg_OUTPUT MATCHES "\\.apk")
 | |
|       set(arg_OUTPUT "${arg_OUTPUT}.apk")
 | |
|     endif()
 | |
|   endif()
 | |
|   get_filename_component(apk_file "${arg_OUTPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
 | |
| 
 | |
|   add_custom_command(OUTPUT "${apk_file}"
 | |
|     COMMAND SdlAndroid::apksigner sign
 | |
|       --ks "$<TARGET_PROPERTY:${arg_KEYSTORE},OUTPUT>"
 | |
|       --ks-pass pass:android --in "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" --out "${apk_file}"
 | |
|     DEPENDS "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" "$<TARGET_PROPERTY:${arg_KEYSTORE},OUTPUT>"
 | |
|     BYPRODUCTS "${apk_file}.idsig"
 | |
|   )
 | |
|   add_custom_target(${TARGET} DEPENDS "${apk_file}")
 | |
|   set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
 | |
| endfunction()
 | 
