diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 3ee54f5d5a4..0852d8ed2fe 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -1293,6 +1293,14 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module} PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private ) + + if (ANDROID) + # Record install library location so it can be accessed by + # qt_android_dependencies without having to specify it again. + set_target_properties(${target} PROPERTIES + QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR}) + endif() + qt_install(EXPORT ${export_name} NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: DESTINATION ${config_install_dir}) diff --git a/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake new file mode 100644 index 00000000000..4677c9dcae4 --- /dev/null +++ b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake @@ -0,0 +1,206 @@ +# +# Android specific functions/macros/properties required for building Qt Modules +# + +define_property(TARGET + PROPERTY + QT_ANDROID_MODULE_INSTALL_DIR + BRIEF_DOCS + "Recorded install location for a Qt Module." + FULL_DOCS + "Recorded install location for a Qt Module. Used by qt_android_dependencies()." +) + + +define_property(TARGET + PROPERTY + QT_ANDROID_JAR_DEPENDENCIES + BRIEF_DOCS + "Qt Module Jar dependencies list." + FULL_DOCS + "Qt Module Jar dependencies list." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + BRIEF_DOCS + "Qt Module Jars that should be bundled with it during packing." + FULL_DOCS + "Qt Module Jars that should be bundled with it during packing." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_LIB_DEPENDENCIES + BRIEF_DOCS + "Qt Module C++ libraries that should be bundled with it during packing." + FULL_DOCS + "Qt Module C++ libraries that should be bundled with it during packing." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS + BRIEF_DOCS + "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property." + FULL_DOCS + "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_BUNDLED_FILES + BRIEF_DOCS + "Qt Module files that need to be bundled during packing." + FULL_DOCS + "Qt Module files that need to be bundled during packing." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_PERMISSIONS + BRIEF_DOCS + "Qt Module android permission list." + FULL_DOCS + "Qt Module android permission list." +) +# Generate Qt Module -android-dependencies.xml required by the +# androiddeploytoolqt to successfully copy all the plugins and other dependent +# items into tha APK +function(qt_android_dependencies target) + + get_target_property(arg_JAR_DEPENDENCIES ${target} QT_ANDROID_JAR_DEPENDENCIES) + get_target_property(arg_BUNDLED_JAR_DEPENDENCIES ${target} QT_ANDROID_BUNDLED_JAR_DEPENDENCIES) + get_target_property(arg_LIB_DEPENDENCIES ${target} QT_ANDROID_LIB_DEPENDENCIES) + get_target_property(arg_LIB_DEPENDENCY_REPLACEMENTS ${target} QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS) + get_target_property(arg_PERMISSIONS ${target} QT_ANDROID_PERMISSIONS) + get_target_property(module_plugins ${target} MODULE_PLUGIN_TYPES) + + if ((NOT module_plugins) + AND (NOT arg_JAR_DEPENDENCIES) + AND (NOT arg_LIB_DEPENDENCY_REPLACEMENTS) + AND (NOT arg_LIB_DEPENDENCIES) + AND (NOT arg_BUNDLED_JAR_DEPENDENCIES) + AND (NOT arg_PERMISSIONS)) + # None of the values were set, so there's nothing to do + return() + endif() + + + get_target_property(target_output_name ${target} OUTPUT_NAME) + if (NOT target_output_name) + set(target_name ${target}) + else() + set(target_name ${target_output_name}) + endif() + + # mimic qmake's section and string splitting from + # mkspecs/feature/qt_android_deps.prf + macro(section string delimiter first second) + string(FIND ${string} ${delimiter} delimiter_location) + if (NOT ${delimiter_location} EQUAL -1) + string(SUBSTRING ${string} 0 ${delimiter_location} ${first}) + math(EXPR delimiter_location "${delimiter_location} + 1") + string(SUBSTRING ${string} ${delimiter_location} -1 ${second}) + else() + set(${first} ${string}) + set(${second} "") + endif() + endmacro() + + get_target_property(target_bin_dir ${target} BINARY_DIR) + set(dependency_file "${target_bin_dir}/${target_name}-android-dependencies.xml") + + file(WRITE ${dependency_file} "\n") + file(APPEND ${dependency_file} "\n") + + # Jar Dependencies + if(arg_JAR_DEPENDENCIES) + foreach(jar_dependency IN LISTS arg_JAR_DEPENDENCIES) + section(${jar_dependency} ":" jar_file init_class) + if (init_class) + set(init_class "initClass=\"${init_class}\"") + endif() + file(TO_NATIVE_PATH ${jar_file} jar_file_native) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + # Bundled Jar Dependencies + if(arg_BUNDLED_JAR_DEPENDENCIES) + foreach(jar_bundle IN LISTS arg_BUNDLED_JAR_DEPENDENCIES) + section(${jar_bundle} ":" bundle_file init_calss) + if (init_class) + set(init_class "initClass=\"${init_class}\"") + endif() + file(TO_NATIVE_PATH ${jar_bundle} jar_bundle_native) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + # Lib Dependencies + if(arg_LIB_DEPENDENCIES) + foreach(lib IN LISTS arg_LIB_DEPENDENCIES) + section(${lib} ":" lib_file lib_extends) + if (lib_extends) + set(lib_extends "extends=\"${lib_extends}\"") + endif() + file(TO_NATIVE_PATH ${lib_file} lib_file_native) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + # Lib Dependencies Replacements + if(arg_LIB_DEPENDENCY_REPLACEMENTS) + foreach(lib IN LISTS arg_LIB_DEPENDENCY_REPLACEMENTS) + section(${lib} ":" lib_file lib_replacement) + if (lib_replacement) + file(TO_NATIVE_PATH ${lib_replacement} lib_replacement_native) + set(lib_replacement "replaces=\"${lib_replacement_native}\"") + endif() + file(TO_NATIVE_PATH ${lib_file} lib_file_native) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + + # Bundled files + if(arg_BUNDLED_FILES) + foreach(file IN LISTS arg_BUNDLED_FILES) + file(TO_NATIVE_PATH ${lib_file} file_native) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + # Module plugins + if(module_plugins) + foreach(plugin IN LISTS module_plugins) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + # Android Permissions + if(arg_PERMISSIONS) + foreach(permission IN LISTS arg_PERMISSIONS) + file(APPEND ${dependency_file} "\n") + endforeach() + endif() + + file(APPEND ${dependency_file} "") + file(APPEND ${dependency_file} "\n") + + get_target_property(target_install_dir ${target} QT_ANDROID_MODULE_INSTALL_DIR) + if (NOT target_install_dir) + message(SEND_ERROR "qt_android_dependencies: Target ${target} is either not a Qt Module or has no recorded install location") + return() + endif() + + # Copy file into install directory, required by the androiddeployqt tool. + qt_install(FILES + ${dependency_file} + DESTINATION + ${target_install_dir} + COMPONENT + Devel) +endfunction() diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index 8a6c2cb7338..590885c44d1 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -142,3 +142,7 @@ macro(qt_examples_build_end) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) endmacro() + +if (ANDROID) + include(QtBuildInternals/QtBuildInternalsAndroid) +endif() diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake index 70768947a06..bc7e0aa862f 100644 --- a/cmake/QtPlatformAndroid.cmake +++ b/cmake/QtPlatformAndroid.cmake @@ -74,7 +74,7 @@ if (NOT QT_ANDROID_SDK_BUILD_TOOLS_VERSION) list(SORT android_build_tools) list(REVERSE android_build_tools) list(GET android_build_tools 0 android_build_tools_latest) - set(qt_QT_ANDROID_SDK_BUILD_TOOLS_VERSION ${android_build_tools_latest}) + set(QT_ANDROID_SDK_BUILD_TOOLS_VERSION ${android_build_tools_latest}) endif() # Ensure we are using the shared version of libc++ diff --git a/cmake/QtPostProcess.cmake b/cmake/QtPostProcess.cmake index 568719d4f0b..53b89f22f10 100644 --- a/cmake/QtPostProcess.cmake +++ b/cmake/QtPostProcess.cmake @@ -276,6 +276,18 @@ function(qt_generate_build_internals_extra_cmake_code) endif() endfunction() +# For every Qt module check if there any android dependencies that require +# processing. +function(qt_modules_process_android_dependencies) + foreach (target ${QT_KNOWN_MODULES}) + qt_android_dependencies(${target}) + endforeach() +endfunction() + qt_internal_create_depends_files() qt_generate_build_internals_extra_cmake_code() qt_internal_create_plugins_files() + +if (ANDROID) + qt_modules_process_android_dependencies() +endif() diff --git a/src/corelib/.prev_CMakeLists.txt b/src/corelib/.prev_CMakeLists.txt index d6726e9336a..f1000e6301a 100644 --- a/src/corelib/.prev_CMakeLists.txt +++ b/src/corelib/.prev_CMakeLists.txt @@ -241,10 +241,19 @@ add_qt_simd_part(Core SIMD mips_dsp +if(ANDROID) + set_property(TARGET Core APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + jar/QtAndroid.jar + ) + set_property(TARGET Core APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES + plugins/platforms/android/libqtforandroid.so + ) + set_property(TARGET Core APPEND PROPERTY QT_ANDROID_PERMISSIONS + android.permission.INTERNET android.permission.WRITE_EXTERNAL_STORAGE + ) +endif() + #### Keys ignored in scope 1:.:.:corelib.pro:: -# ANDROID_BUNDLED_JAR_DEPENDENCIES = "jar/QtAndroid.jar" -# ANDROID_LIB_DEPENDENCIES = "plugins/platforms/android/libqtforandroid.so" -# ANDROID_PERMISSIONS = "android.permission.INTERNET" "android.permission.WRITE_EXTERNAL_STORAGE" # CMAKE_DISABLED_FEATURES = "$$joinQT_DISABLED_FEATURES,"$$escape_expand(\\n) "" # CMAKE_HOST_DATA_DIR = "$$cmakeRelativePath$$[QT_HOST_DATA/src],$$[QT_INSTALL_PREFIX]" # CMAKE_INSTALL_DATA_DIR = "$$cmakeRelativePath$$[QT_HOST_DATA],$$[QT_INSTALL_PREFIX]" diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index da8eb4eea55..4d23f0f8929 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -323,10 +323,19 @@ add_qt_simd_part(Core SIMD mips_dsp +if(ANDROID) + set_property(TARGET Core APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + jar/QtAndroid.jar + ) + set_property(TARGET Core APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES + plugins/platforms/android/libqtforandroid.so + ) + set_property(TARGET Core APPEND PROPERTY QT_ANDROID_PERMISSIONS + android.permission.INTERNET android.permission.WRITE_EXTERNAL_STORAGE + ) +endif() + #### Keys ignored in scope 1:.:.:corelib.pro:: -# ANDROID_BUNDLED_JAR_DEPENDENCIES = "jar/QtAndroid.jar" -# ANDROID_LIB_DEPENDENCIES = "plugins/platforms/android/libqtforandroid.so" -# ANDROID_PERMISSIONS = "android.permission.INTERNET" "android.permission.WRITE_EXTERNAL_STORAGE" # CMAKE_DISABLED_FEATURES = "$$joinQT_DISABLED_FEATURES,"$$escape_expand(\\n) "" # CMAKE_HOST_DATA_DIR = "$$cmakeRelativePath$$[QT_HOST_DATA/src],$$[QT_INSTALL_PREFIX]" # CMAKE_INSTALL_DATA_DIR = "$$cmakeRelativePath$$[QT_HOST_DATA],$$[QT_INSTALL_PREFIX]" diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 738816ee4e9..d82a65e4a6a 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -399,6 +399,11 @@ function(add_qt_gui_executable target) if(ANDROID) qt_android_generate_deployment_settings("${target}") + # On our qmake builds we do don't compile the executables with + # visibility=hidden. Not having this flag set will cause the + # executable to have main() hidden and can then no longer be loaded + # through dlopen() + target_compile_options(${target} PRIVATE -fvisibility=default) endif() endfunction() diff --git a/src/network/.prev_CMakeLists.txt b/src/network/.prev_CMakeLists.txt index b1ba59e7be9..e5756e291d2 100644 --- a/src/network/.prev_CMakeLists.txt +++ b/src/network/.prev_CMakeLists.txt @@ -76,10 +76,19 @@ extend_target(Network CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i386" "/BASE:0x64000000" ) +if(ANDROID AND (QT_FEATURE_bearermanagement)) + set_property(TARGET Network APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + jar/QtAndroidBearer.jar + ) + set_property(TARGET Network APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES + plugins/bearer/libqandroidbearer.so + ) + set_property(TARGET Network APPEND PROPERTY QT_ANDROID_PERMISSIONS + android.permission.ACCESS_NETWORK_STATE + ) +endif() + #### Keys ignored in scope 3:.:.:network.pro:QT_FEATURE_bearermanagement: -# ANDROID_BUNDLED_JAR_DEPENDENCIES = "jar/QtAndroidBearer.jar" -# ANDROID_LIB_DEPENDENCIES = "plugins/bearer/libqandroidbearer.so" -# ANDROID_PERMISSIONS = "android.permission.ACCESS_NETWORK_STATE" # MODULE_PLUGIN_TYPES = "bearer" extend_target(Network CONDITION QT_FEATURE_ftp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 7a6bf8f9e9d..3148c007043 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -76,10 +76,19 @@ extend_target(Network CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i386" "/BASE:0x64000000" ) +if(ANDROID AND (QT_FEATURE_bearermanagement)) + set_property(TARGET Network APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + jar/QtAndroidBearer.jar + ) + set_property(TARGET Network APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES + plugins/bearer/libqandroidbearer.so + ) + set_property(TARGET Network APPEND PROPERTY QT_ANDROID_PERMISSIONS + android.permission.ACCESS_NETWORK_STATE + ) +endif() + #### Keys ignored in scope 3:.:.:network.pro:QT_FEATURE_bearermanagement: -# ANDROID_BUNDLED_JAR_DEPENDENCIES = "jar/QtAndroidBearer.jar" -# ANDROID_LIB_DEPENDENCIES = "plugins/bearer/libqandroidbearer.so" -# ANDROID_PERMISSIONS = "android.permission.ACCESS_NETWORK_STATE" # MODULE_PLUGIN_TYPES = "bearer" extend_target(Network CONDITION QT_FEATURE_ftp diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index 28724b1fc05..96e2bacae9a 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -1536,6 +1536,32 @@ def write_simd_part(cm_fh: typing.IO[str], target: str, scope: Scope, indent: in header = 'add_qt_simd_part({} SIMD {}\n'.format(target, simd), footer = ')\n\n') +def write_android_part(cm_fh: typing.IO[str], target: str, scope:Scope, indent: int = 0): + keys = [ 'ANDROID_BUNDLED_JAR_DEPENDENCIES' + , 'ANDROID_LIB_DEPENDENCIES' + , 'ANDROID_JAR_DEPENDENCIES' + , 'ANDROID_LIB_DEPENDENCY_REPLACEMENTS' + , 'ANDROID_BUNDLED_FILES' + , 'ANDROID_PERMISSIONS' ] + + has_no_values = True + for key in keys: + value = scope.get(key) + if len(value) != 0: + if has_no_values: + if scope.condition: + cm_fh.write('\n{}if(ANDROID AND ({}))\n'.format(spaces(indent), scope.condition)) + else: + cm_fh.write('\n{}if(ANDROID)\n'.format(spaces(indent))) + indent += 1 + has_no_values = False + cm_fh.write('{}set_property(TARGET {} APPEND PROPERTY QT_{}\n'.format(spaces(indent), target, key)) + write_list(cm_fh, value, '', indent + 1) + cm_fh.write('{})\n'.format(spaces(indent))) + indent -= 1 + + if not has_no_values: + cm_fh.write('{}endif()\n'.format(spaces(indent))) def write_main_part(cm_fh: typing.IO[str], name: str, typename: str, cmake_function: str, scope: Scope, *, @@ -1577,6 +1603,8 @@ def write_main_part(cm_fh: typing.IO[str], name: str, typename: str, write_simd_part(cm_fh, name, scope, indent) + write_android_part(cm_fh, name, scopes[0], indent) + ignored_keys_report = write_ignored_keys(scopes[0], spaces(indent)) if ignored_keys_report: cm_fh.write(ignored_keys_report) @@ -1590,12 +1618,12 @@ def write_main_part(cm_fh: typing.IO[str], name: str, typename: str, for c in scopes[1:]: c.reset_visited_keys() + write_android_part(cm_fh, name, c, indent=indent) write_extend_target(cm_fh, name, c, indent=indent) ignored_keys_report = write_ignored_keys(c, spaces(indent)) if ignored_keys_report: cm_fh.write(ignored_keys_report) - def write_module(cm_fh: typing.IO[str], scope: Scope, *, indent: int = 0) -> None: module_name = scope.TARGET