1# - Functions to help assemble a standalone Qt5 executable. 2# A collection of CMake utility functions useful for deploying 3# Qt5 executables. 4# 5# The following functions are provided by this module: 6# write_qt5_conf 7# resolve_qt5_paths 8# fixup_qt5_executable 9# install_qt5_plugin_path 10# install_qt5_plugin 11# install_qt5_executable 12# Requires CMake 2.6 or greater because it uses function and 13# PARENT_SCOPE. Also depends on BundleUtilities.cmake. 14# 15# WRITE_QT5_CONF(<qt_conf_dir> <qt_conf_contents>) 16# Writes a qt.conf file with the <qt_conf_contents> into <qt_conf_dir>. 17# 18# RESOLVE_QT5_PATHS(<paths_var> [<executable_path>]) 19# Loop through <paths_var> list and if any don't exist resolve them 20# relative to the <executable_path> (if supplied) or the CMAKE_INSTALL_PREFIX. 21# 22# FIXUP_QT5_EXECUTABLE(<executable> [<qtplugins> <libs> <dirs> <plugins_dir> <request_qt_conf>]) 23# Copies Qt plugins, writes a Qt configuration file (if needed) and fixes up a 24# Qt5 executable using BundleUtilities so it is standalone and can be 25# drag-and-drop copied to another machine as long as all of the system 26# libraries are compatible. 27# 28# <executable> should point to the executable to be fixed-up. 29# 30# <qtplugins> should contain a list of the names or paths of any Qt plugins 31# to be installed. 32# 33# <libs> will be passed to BundleUtilities and should be a list of any already 34# installed plugins, libraries or executables to also be fixed-up. 35# 36# <dirs> will be passed to BundleUtilities and should contain and directories 37# to be searched to find library dependencies. 38# 39# <plugins_dir> allows an custom plugins directory to be used. 40# 41# <request_qt_conf> will force a qt.conf file to be written even if not needed. 42# 43# INSTALL_QT5_PLUGIN_PATH(plugin executable copy installed_plugin_path_var <plugins_dir> <component> <configurations>) 44# Install (or copy) a resolved <plugin> to the default plugins directory 45# (or <plugins_dir>) relative to <executable> and store the result in 46# <installed_plugin_path_var>. 47# 48# If <copy> is set to TRUE then the plugins will be copied rather than 49# installed. This is to allow this module to be used at CMake time rather than 50# install time. 51# 52# If <component> is set then anything installed will use this COMPONENT. 53# 54# INSTALL_QT5_PLUGIN(plugin executable copy installed_plugin_path_var <plugins_dir> <component>) 55# Install (or copy) an unresolved <plugin> to the default plugins directory 56# (or <plugins_dir>) relative to <executable> and store the result in 57# <installed_plugin_path_var>. See documentation of INSTALL_QT5_PLUGIN_PATH. 58# 59# INSTALL_QT5_EXECUTABLE(<executable> [<qtplugins> <libs> <dirs> <plugins_dir> <request_qt_conf> <component>]) 60# Installs Qt plugins, writes a Qt configuration file (if needed) and fixes up 61# a Qt5 executable using BundleUtilities so it is standalone and can be 62# drag-and-drop copied to another machine as long as all of the system 63# libraries are compatible. The executable will be fixed-up at install time. 64# <component> is the COMPONENT used for bundle fixup and plugin installation. 65# See documentation of FIXUP_QT5_BUNDLE. 66 67#============================================================================= 68# Copyright 2011 Mike McQuaid <m...@mikemcquaid.com> 69# Copyright 2013 Mihai Moldovan <io...@ionic.de> 70# CMake - Cross Platform Makefile Generator 71# Copyright 2000-2011 Kitware, Inc., Insight Software Consortium 72# All rights reserved. 73# 74# Redistribution and use in source and binary forms, with or without 75# modification, are permitted provided that the following conditions 76# are met: 77# 78# * Redistributions of source code must retain the above copyright 79# notice, this list of conditions and the following disclaimer. 80# 81# * Redistributions in binary form must reproduce the above copyright 82# notice, this list of conditions and the following disclaimer in the 83# documentation and/or other materials provided with the distribution. 84# 85# * Neither the names of Kitware, Inc., the Insight Software Consortium, 86# nor the names of their contributors may be used to endorse or promote 87# products derived from this software without specific prior written 88# permission. 89# 90# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 91# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 92# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 93# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 94# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 95# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 96# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 97# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 98# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 99# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 100# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 101 102# The functions defined in this file depend on the fixup_bundle function 103# (and others) found in BundleUtilities.cmake 104 105include(BundleUtilities) 106set(DeployQt5_cmake_dir "${CMAKE_CURRENT_LIST_DIR}") 107set(DeployQt5_apple_plugins_dir "PlugIns") 108 109function(write_qt5_conf qt_conf_dir qt_conf_contents) 110 set(qt_conf_path "${qt_conf_dir}/qt.conf") 111 message(STATUS "Writing ${qt_conf_path}") 112 file(WRITE "${qt_conf_path}" "${qt_conf_contents}") 113endfunction() 114 115function(resolve_qt5_paths paths_var) 116 set(executable_path ${ARGV1}) 117 118 set(paths_resolved) 119 foreach(path ${${paths_var}}) 120 if(EXISTS "${path}") 121 list(APPEND paths_resolved "${path}") 122 else() 123 if(${executable_path}) 124 list(APPEND paths_resolved 125"${executable_path}/${path}") 126 else() 127 list(APPEND paths_resolved 128"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${path}") 129 endif() 130 endif() 131 endforeach() 132 set(${paths_var} ${paths_resolved} PARENT_SCOPE) 133endfunction() 134 135function(fixup_qt5_executable executable) 136 set(qtplugins ${ARGV1}) 137 set(libs ${ARGV2}) 138 set(dirs ${ARGV3}) 139 set(plugins_dir ${ARGV4}) 140 set(request_qt_conf ${ARGV5}) 141 142 message(STATUS "fixup_qt5_executable") 143 message(STATUS " executable='${executable}'") 144 message(STATUS " qtplugins='${qtplugins}'") 145 message(STATUS " libs='${libs}'") 146 message(STATUS " dirs='${dirs}'") 147 message(STATUS " plugins_dir='${plugins_dir}'") 148 message(STATUS " request_qt_conf='${request_qt_conf}'") 149 150 if(QT_LIBRARY_DIR) 151 list(APPEND dirs "${QT_LIBRARY_DIR}") 152 endif() 153 if(QT_BINARY_DIR) 154 list(APPEND dirs "${QT_BINARY_DIR}") 155 endif() 156 157 if(APPLE) 158 set(qt_conf_dir "${executable}/Contents/Resources") 159 set(executable_path "${executable}") 160 set(write_qt_conf TRUE) 161 if(NOT plugins_dir) 162 set(plugins_dir "${DeployQt5_apple_plugins_dir}") 163 endif() 164 else() 165 get_filename_component(executable_path "${executable}" PATH) 166 if(NOT executable_path) 167 set(executable_path ".") 168 endif() 169 set(qt_conf_dir "${executable_path}") 170 set(write_qt_conf ${request_qt_conf}) 171 endif() 172 173 foreach(plugin ${qtplugins}) 174 set(installed_plugin_path "") 175 install_qt5_plugin("${plugin}" "${executable}" 1 176installed_plugin_path) 177 list(APPEND libs ${installed_plugin_path}) 178 endforeach() 179 180 foreach(lib ${libs}) 181 if(NOT EXISTS "${lib}") 182 message(FATAL_ERROR "Library does not exist: ${lib}") 183 endif() 184 endforeach() 185 186 resolve_qt5_paths(libs "${executable_path}") 187 188 if(write_qt_conf) 189 set(qt_conf_contents "[Paths]\nPlugins = ${plugins_dir}") 190 write_qt5_conf("${qt_conf_dir}" "${qt_conf_contents}") 191 endif() 192 193 fixup_bundle("${executable}" "${libs}" "${dirs}") 194endfunction() 195 196function(install_qt5_plugin_path plugin executable copy 197installed_plugin_path_var) 198 set(plugins_dir ${ARGV4}) 199 set(component ${ARGV5}) 200 set(configurations ${ARGV6}) 201 if(EXISTS "${plugin}") 202 if(APPLE) 203 if(NOT plugins_dir) 204 set(plugins_dir 205"${DeployQt5_apple_plugins_dir}") 206 endif() 207 set(plugins_path 208"${executable}/Contents/${plugins_dir}") 209 else() 210 get_filename_component(plugins_path "${executable}" 211PATH) 212 if(NOT plugins_path) 213 set(plugins_path ".") 214 endif() 215 if(plugins_dir) 216 set(plugins_path 217"${plugins_path}/${plugins_dir}") 218 endif() 219 endif() 220 221 set(plugin_group "") 222 223 get_filename_component(plugin_path "${plugin}" PATH) 224 get_filename_component(plugin_parent_path "${plugin_path}" PATH) 225 get_filename_component(plugin_parent_dir_name 226"${plugin_parent_path}" NAME) 227 get_filename_component(plugin_name "${plugin}" NAME) 228 string(TOLOWER "${plugin_parent_dir_name}" 229plugin_parent_dir_name) 230 231 if("${plugin_parent_dir_name}" STREQUAL "plugins") 232 get_filename_component(plugin_group "${plugin_path}" 233NAME) 234 set(${plugin_group_var} "${plugin_group}") 235 endif() 236 set(plugins_path "${plugins_path}/${plugin_group}") 237 238 if(${copy}) 239 file(MAKE_DIRECTORY "${plugins_path}") 240 file(COPY "${plugin}" DESTINATION "${plugins_path}") 241 else() 242 if(configurations AND (CMAKE_CONFIGURATION_TYPES OR 243CMAKE_BUILD_TYPE)) 244 set(configurations CONFIGURATIONS 245${configurations}) 246 else() 247 unset(configurations) 248 endif() 249 install(FILES "${plugin}" DESTINATION "${plugins_path}" 250${configurations} ${component}) 251 endif() 252 set(${installed_plugin_path_var} 253"${plugins_path}/${plugin_name}" PARENT_SCOPE) 254 endif() 255endfunction() 256 257function(install_qt5_plugin plugin executable copy installed_plugin_path_var) 258 set(plugins_dir ${ARGV4}) 259 set(component ${ARGV5}) 260 if(EXISTS "${plugin}") 261 install_qt5_plugin_path("${plugin}" "${executable}" "${copy}" 262"${installed_plugin_path_var}" "${plugins_dir}" "${component}") 263 else() 264 #string(TOUPPER "QT_${plugin}_PLUGIN" plugin_var) 265 set(plugin_release) 266 set(plugin_debug) 267 set(plugin_tmp_path) 268 set(plugin_find_path "${Qt5Core_DIR}/../../../plugins/") 269 get_filename_component(plugin_find_path "${plugin_find_path}" 270REALPATH) 271 if(COMMAND cmake_policy) 272 CMAKE_POLICY(SET CMP0009 NEW) 273 #CMAKE_POLICY(SET CMP0011 NEW) # disabling a warning about policy changing in this scope 274 endif(COMMAND cmake_policy) 275 276 if (APPLE) 277 set(plugin_find_release_filename "lib${plugin}.dylib") 278 set(plugin_find_debug_filename "lib${plugin}_debug.dylib") 279 file(GLOB_RECURSE pluginlist "${plugin_find_path}" "${plugin_find_path}/*/lib*.dylib") 280 endif() 281 if(WIN32) 282 set(plugin_find_release_filename "${plugin}.dll") 283 set(plugin_find_debug_filename "${plugin}d.dll") 284 file(GLOB_RECURSE pluginlist "${plugin_find_path}" "${plugin_find_path}/*/*.dll") 285 endif(WIN32) 286 foreach(found_plugin ${pluginlist}) 287 get_filename_component(curname "${found_plugin}" NAME) 288 if("${curname}" STREQUAL "${plugin_find_release_filename}") 289 set(plugin_tmp_release_path "${found_plugin}") 290 endif() 291 if("${curname}" STREQUAL "${plugin_find_debug_filename}") 292 set(plugin_tmp_debug_path "${found_plugin}") 293 endif() 294 endforeach() 295 296 if((NOT DEFINED plugin_tmp_release_path OR NOT EXISTS 297"${plugin_tmp_release_path}") AND (NOT DEFINED plugin_tmp_debug_PATH OR NOT 298EXISTS "${plugin_tmp_debug_path}")) 299 message(WARNING "Qt plugin \"${plugin}\" not recognized 300or found.") 301 endif() 302 303 if(EXISTS "${plugin_tmp_release_path}") 304 set(plugin_release "${plugin_tmp_release_path}") 305 elseif(EXISTS "${plugin_tmp_debug_path}") 306 set(plugin_release "${plugin_tmp_debug_path}") 307 endif() 308 309 if(EXISTS "${plugin_tmp_debug_path}") 310 set(plugin_debug "${plugin_tmp_debug_path}") 311 elseif(EXISTS "${plugin_tmp_release_path}") 312 set(plugin_debug "${plugin_tmp_release_path}") 313 endif() 314 315 if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) 316 install_qt5_plugin_path("${plugin_release}" 317"${executable}" "${copy}" "${installed_plugin_path_var}_release" 318"${plugins_dir}" "${component}" "Release|RelWithDebInfo|MinSizeRel") 319 install_qt5_plugin_path("${plugin_debug}" 320"${executable}" "${copy}" "${installed_plugin_path_var}_debug" "${plugins_dir}" 321"${component}" "Debug") 322 323 if(CMAKE_BUILD_TYPE MATCHES "^Debug$") 324 set(${installed_plugin_path_var} 325${${installed_plugin_path_var}_debug}) 326 else() 327 set(${installed_plugin_path_var} 328${${installed_plugin_path_var}_release}) 329 endif() 330 else() 331 install_qt5_plugin_path("${plugin_release}" 332"${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" 333"${component}") 334 endif() 335 endif() 336 set(${installed_plugin_path_var} ${${installed_plugin_path_var}} 337PARENT_SCOPE) 338endfunction() 339 340function(install_qt5_executable executable) 341 set(qtplugins ${ARGV1}) 342 set(libs ${ARGV2}) 343 set(dirs ${ARGV3}) 344 set(plugins_dir ${ARGV4}) 345 set(request_qt_conf ${ARGV5}) 346 set(component ${ARGV6}) 347 if(QT_LIBRARY_DIR) 348 list(APPEND dirs "${QT_LIBRARY_DIR}") 349 endif() 350 if(QT_BINARY_DIR) 351 list(APPEND dirs "${QT_BINARY_DIR}") 352 endif() 353 if(component) 354 set(component COMPONENT ${component}) 355 else() 356 unset(component) 357 endif() 358 359 get_filename_component(executable_absolute "${executable}" ABSOLUTE) 360 if(EXISTS "${QT_QTCORE_LIBRARY_RELEASE}") 361 gp_file_type("${executable_absolute}" 362"${QT_QTCORE_LIBRARY_RELEASE}" qtcore_type) 363 elseif(EXISTS "${QT_QTCORE_LIBRARY_DEBUG}") 364 gp_file_type("${executable_absolute}" "${QT_QTCORE_LIBRARY_DEBUG}" 365qtcore_type) 366 endif() 367 if(qtcore_type STREQUAL "system") 368 set(qt_plugins_dir "") 369 endif() 370 371 if(QT_IS_STATIC) 372 message(WARNING "Qt built statically: not installing plugins.") 373 else() 374 foreach(plugin ${qtplugins}) 375 set(installed_plugin_paths "") 376 install_qt5_plugin("${plugin}" "${executable}" 0 377installed_plugin_paths "${plugins_dir}" "${component}") 378 list(APPEND libs ${installed_plugin_paths}) 379 endforeach() 380 endif() 381 382 resolve_qt5_paths(libs "") 383 384 install(CODE 385 "include(\"${DeployQt5_cmake_dir}/DeployQt5.cmake\") 386 set(BU_CHMOD_BUNDLE_ITEMS TRUE) 387 FIXUP_QT5_EXECUTABLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${executable}\" 388\"\" \"${libs}\" \"${dirs}\" \"${plugins_dir}\" \"${request_qt_conf}\")" 389 ${component} 390 ) 391endfunction() 392