diff options
author | Cristian Adam <cristian.adam@qt.io> | 2020-02-05 19:38:18 +0100 |
---|---|---|
committer | Alessandro Portale <alessandro.portale@qt.io> | 2020-02-06 18:03:33 +0000 |
commit | 8d767a3a2139b710f97e3b14553aa98fdae1362f (patch) | |
tree | d00d83ca8fe20e4f0fc65bfb9c001f7003471060 /cmake | |
parent | decb6866b91cb0023ed71f7a5186520a8ce20d03 (diff) |
CMake Deployment: Remove Dependencies component
- Install will also copy the dependencies.
- Made the dependencies search recursive, not just two steps
- Moved install code to a script, not having to escape quotes and dollars
Change-Id: I6c5fb19e4094e9dcd4b339d5b90be6e7c5055223
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Diffstat (limited to 'cmake')
-rw-r--r-- | cmake/CMakeLists.txt | 101 | ||||
-rw-r--r-- | cmake/InstallDependentSharedObjects.cmake.in | 150 |
2 files changed, 251 insertions, 0 deletions
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000000..2d2d9f2b1b --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,101 @@ +# Deployment of Qt, Clang, C++ Runtime libraries is being done in this script. +# +# It should be included as a subdirectory as last because of CMake's +# cmake_install.cmake script behviour of including subdirectories at the end +# of the script, not respecting the order of install commands from CMakeLists.txt +# +# This way we are sure that all the binaries have been installed before. + +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16) + get_target_property(moc_binary Qt5::moc IMPORTED_LOCATION) + get_filename_component(moc_dir "${moc_binary}" DIRECTORY) + get_filename_component(qt5_base_dir "${moc_dir}/../" ABSOLUTE) + + if (MSVC AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + set(exclusion_mask PATTERN "*d.dll" EXCLUDE) + endif() + + if (WIN32) + set(qt5_plugin_dest_dir ${IDE_BIN_PATH}/plugins) + set(qt5_qml_dest_dir ${IDE_BIN_PATH}/qml) + elseif(APPLE) + set(qt5_plugin_dest_dir ${IDE_PLUGIN_PATH}) + set(qt5_qml_dest_dir ${IDE_DATA_PATH}/../Imports/qtquick2) + else() + set(qt5_plugin_dest_dir ${IDE_LIBRARY_BASE_PATH}/Qt/plugins) + set(qt5_qml_dest_dir ${IDE_LIBRARY_BASE_PATH}/Qt/qml) + endif() + + foreach(plugin + designer iconengines imageformats platforms platformthemes + printsupport qmltooling sqldrivers styles) + if(NOT EXISTS "${qt5_base_dir}/plugins/${plugin}") + continue() + endif() + install( + DIRECTORY "${qt5_base_dir}/plugins/${plugin}" + DESTINATION ${qt5_plugin_dest_dir} + ${exclusion_mask} + ) + list(APPEND qt5_plugin_directories "${qt5_plugin_dest_dir}/${plugin}") + endforeach() + + install( + DIRECTORY "${qt5_base_dir}/qml/" + DESTINATION ${qt5_qml_dest_dir} + PATTERN "qml/*" + ${exclusion_mask} + ) + + install(CODE " + function(create_qt_conf location base_dir) + get_filename_component(install_prefix \"\${CMAKE_INSTALL_PREFIX}\" ABSOLUTE) + file(RELATIVE_PATH qt_conf_binaries + \"\${install_prefix}/\${base_dir}\" + \"\${install_prefix}/${IDE_BIN_PATH}\" + ) + if (NOT qt_conf_binaries) + set(qt_conf_binaries .) + endif() + file(RELATIVE_PATH qt_conf_plugins + \"\${install_prefix}/\${base_dir}\" + \"\${install_prefix}/${qt5_plugin_dest_dir}\" + ) + file(RELATIVE_PATH qt_conf_qml + \"\${install_prefix}/\${base_dir}\" + \"\${install_prefix}/${qt5_qml_dest_dir}\" + ) + + file(WRITE \"\${CMAKE_INSTALL_PREFIX}/\${location}/qt.conf\" + \"[Paths]\n\" + \"Binaries=\${qt_conf_binaries}\n\" + \"Plugins=\${qt_conf_plugins}\n\" + \"Qml2Imports=\${qt_conf_qml}\n\" + ) + endfunction() + + if(APPLE) + create_qt_conf(\"${IDE_DATA_PATH}\" \"${IDE_DATA_PATH}/..\") + create_qt_conf(\"${IDE_LIBEXEC_PATH}\" \"${IDE_DATA_PATH}/..\") + else() + create_qt_conf(\"${IDE_APP_PATH}\" \"${IDE_APP_PATH}\") + create_qt_conf(\"${IDE_LIBEXEC_PATH}\" \"${IDE_LIBEXEC_PATH}\") + endif() + + " + ) + + # Analyze the binaries and install missing dependencies if they are + # found the CMAKE_PREFIX_PATH e.g. Qt, Clang + configure_file(InstallDependentSharedObjects.cmake.in InstallDependentSharedObjects.cmake @ONLY) + install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/InstallDependentSharedObjects.cmake) + + if (MSVC) + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP ON) + include(InstallRequiredsystemLibraries) + + install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} + DESTINATION ${IDE_APP_PATH} + ) + endif() +endif() diff --git a/cmake/InstallDependentSharedObjects.cmake.in b/cmake/InstallDependentSharedObjects.cmake.in new file mode 100644 index 0000000000..2149489080 --- /dev/null +++ b/cmake/InstallDependentSharedObjects.cmake.in @@ -0,0 +1,150 @@ +if (MINGW AND @CMAKE_CXX_COMPILER_ID@ MATCHES "Clang") + set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL objdump) +endif() +if (WIN32) + set(filter_regex PRE_EXCLUDE_REGEXES "api-ms-.*|ext-ms-.*") +elseif (APPLE) + set(filter_regex PRE_EXCLUDE_REGEXES "libiodbc.*|libpq.*") +endif() + +get_filename_component(install_prefix "${CMAKE_INSTALL_PREFIX}" ABSOLUTE) + +# Get the dependencies of Qt's plugins +foreach(plugin @qt5_plugin_directories@) + file(GLOB plugin_files "${install_prefix}/${plugin}/*@CMAKE_SHARED_LIBRARY_SUFFIX@") + list(APPEND qt5_plugin_files "${plugin_files}") +endforeach() + +# Get the qml module dependencies +file(GLOB_RECURSE qml_plugin_files "${install_prefix}/@qt5_qml_dest_dir@/*/*@CMAKE_SHARED_LIBRARY_SUFFIX@") +list(APPEND qt5_plugin_files "${qml_plugin_files}") + +set(installed_EXECUTABLES_NOT_PREFIXED "@__QTC_INSTALLED_EXECUTABLES@") +set(installed_LIBRARIES_NOT_PREFIXED "@__QTC_INSTALLED_LIBRARIES@") +set(installed_MODULES_NOT_PREFIXED "@__QTC_INSTALLED_PLUGINS@") + +foreach(binary_type EXECUTABLES LIBRARIES MODULES) + foreach(element IN LISTS installed_${binary_type}_NOT_PREFIXED) + if (EXISTS "${install_prefix}/${element}") + list(APPEND installed_${binary_type} "${install_prefix}/${element}") + endif() + endforeach() +endforeach() + +# Install first the dependencies, and continue to install the dependencies +# of the installed dependencies e.g. libicu for libQt5Core on Linux. + +list(LENGTH installed_LIBRARIES installed_libraries_size) +unset(qt_plugins_installed) + +while(installed_libraries_size GREATER 0) + foreach(binary_type EXECUTABLES LIBRARIES MODULES) + list(LENGTH installed_${binary_type} list_size) + if (NOT list_size EQUAL 0) + set(${binary_type}_TO_ANALYZE ${binary_type} "${installed_${binary_type}}") + else() + set(${binary_type}_TO_ANALYZE "") + endif() + endforeach() + + file(GET_RUNTIME_DEPENDENCIES + UNRESOLVED_DEPENDENCIES_VAR unresolved_deps + RESOLVED_DEPENDENCIES_VAR resolved_deps + CONFLICTING_DEPENDENCIES_PREFIX conflicts + ${EXECUTABLES_TO_ANALYZE} + ${LIBRARIES_TO_ANALYZE} + ${MODULES_TO_ANALYZE} + DIRECTORIES + "${install_prefix}/@IDE_BIN_PATH@" + "${install_prefix}/@IDE_PLUGIN_PATH@" + "${install_prefix}/@IDE_LIBRARY_PATH@" + "${install_prefix}/@IDE_LIBRARY_BASE_PATH@/Qt/lib" + ${filter_regex} + ) + + # Clear for next step + set(installed_EXECUTABLES "") + set(installed_LIBRARIES "") + set(installed_MODULES "") + + if (NOT qt_plugins_installed) + if (WIN32) + # Needed by QmlDesigner, QmlProfiler, but they are not referenced directly. + list(APPEND unresolved_deps libEGL.dll libGLESv2.dll) + endif() + + set(qt_plugins_installed TRUE) + set(installed_MODULES "${qt5_plugin_files}") + endif() + + list(REMOVE_DUPLICATES unresolved_deps) + list(REMOVE_DUPLICATES resolved_deps) + + file(TO_CMAKE_PATH "@CMAKE_PREFIX_PATH@" prefix_path) + + # Add parent link directory paths. Needed for e.g. MinGW choco libstdc++-6.dll + if (WIN32) + foreach(path "@CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES@") + get_filename_component(parent_path "${path}" DIRECTORY) + list(APPEND prefix_path "${parent_path}") + endforeach() + endif() + + # On Linux the Qt libraries might exist in the system, and they are passed + # as resolved, therefore scan the resolved dependencies too + if (NOT WIN32 AND NOT APPLE) + list(APPEND unresolved_deps "${resolved_deps}") + endif() + + foreach(so IN LISTS unresolved_deps) + + # Skip the installed dependencies + string(FIND "${so}" "${install_prefix}" found_prefix_path) + if (NOT found_prefix_path EQUAL -1) + continue() + endif() + + # On Linux get the name of the resolved Qt dependency, this would come from ldconfig + # with the full path on the system + if (NOT APPLE AND NOT WIN32) + get_filename_component(so "${so}" NAME) + endif() + + if (APPLE) + string(REPLACE "@rpath/" "" so "${so}") + get_filename_component(so_dir "${so}" DIRECTORY) + endif() + + message(STATUS "Dependency: ${so}") + foreach(p IN LISTS prefix_path) + if (WIN32) + set(so_src "${p}/bin/${so}") + set(so_dest "${install_prefix}/@IDE_BIN_PATH@") + elseif(APPLE) + set(so_src "${p}/lib/${so}") + set(so_dest "${install_prefix}/@IDE_LIBRARY_PATH@/${so_dir}") + else() + set(so_src "${p}/lib/${so}") + if (p STREQUAL "@qt5_base_dir@") + set(so_dest "${install_prefix}/@IDE_LIBRARY_BASE_PATH@/Qt/lib") + else() + set(so_dest "${install_prefix}/@IDE_LIBRARY_PATH@") + endif() + endif() + + message(STATUS "Looking at: ${so_src}") + if (EXISTS "${so_src}") + file(INSTALL "${so_src}" DESTINATION "${so_dest}" FOLLOW_SYMLINK_CHAIN) + if (APPLE) + get_filename_component(so "${so}" NAME) + endif() + list(APPEND installed_LIBRARIES "${so_dest}/${so}") + break() + endif() + + endforeach() + endforeach() + + list(LENGTH installed_LIBRARIES installed_libraries_size) + +endwhile() |