Solution that wraps qt deploy with cmake

main
pappeste 5 years ago
parent 9fe06453d3
commit 47c3c3a5d0

@ -8,19 +8,3 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
add_custom_command(TARGET LmbrCentral.Editor POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DLY_TIMESTAMP_REFERENCE=$<TARGET_FILE_DIR:LmbrCentral.Editor>/lrelease.exe
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:LmbrCentral.Editor>/qtdeploy.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND "${CMAKE_COMMAND}" -E
env PATH="${QT_PATH}/bin"
${WINDEPLOYQT_EXECUTABLE}
$<$<CONFIG:Debug>:--pdb>
--verbose 0
--no-compiler-runtime
$<TARGET_FILE_DIR:LmbrCentral.Editor>/lrelease.exe
COMMENT "Patching lrelease..."
VERBATIM
)

@ -23,7 +23,6 @@ endif()
ly_add_target(
NAME QtForPython.Editor.Static STATIC
NAMESPACE Gem
find_package(Qt)
FILES_CMAKE
qtforpython_editor_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
@ -41,7 +40,7 @@ ly_add_target(
Gem::EditorPythonBindings.Static
RUNTIME_DEPENDENCIES
3rdParty::pyside2
Qt5::Test
3rdParty::Qt::Test
)
ly_add_target(

@ -87,4 +87,9 @@ endif()
if(LY_TIMESTAMP_REFERENCE)
# Touch the timestamp file
file(TOUCH ${LY_TIMESTAMP_FILE})
endif()
if(LY_LOCK_FILE)
file(LOCK ${LY_LOCK_FILE} RELEASE)
file(REMOVE ${LY_LOCK_FILE})
endif()

@ -13,9 +13,6 @@ set(LY_UNITY_BUILD OFF CACHE BOOL "UNITY builds")
include(CMakeFindDependencyMacro)
include(cmake/LyAutoGen.cmake)
if(PAL_TRAIT_BUILD_HOST_QT_SUPPORTED)
include(cmake/Qt.cmake)
endif()
ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME})
include(${pal_dir}/LYWrappers_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
@ -292,8 +289,6 @@ function(ly_add_target)
foreach(prop IN ITEMS AUTOMOC AUTORCC)
if(${ly_add_target_${prop}})
set_property(TARGET ${ly_add_target_NAME} PROPERTY ${prop} ON)
# Flag this target as depending on Qt
set_property(GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${ly_add_target_NAME} ON)
endif()
endforeach()
if(${ly_add_target_AUTOUIC})
@ -335,10 +330,6 @@ function(ly_add_target)
VERBATIM
)
detect_qt_dependency(${ly_add_target_NAME} QT_DEPENDENCY)
if(QT_DEPENDENCY)
ly_qt_deploy_qtconf(${ly_add_target_NAME})
endif()
endif()
if(ly_add_target_AUTOGEN_RULES)
@ -429,60 +420,6 @@ function(ly_delayed_target_link_libraries)
endfunction()
#! detect_qt_dependency: Determine if a target will link directly to a Qt library
#
# qt deployment introspects a shared library or executable for its direct
# dependencies on Qt libraries. In CMake, this will be true if a target, or any
# of its link libraries which are static libraries, recursively, links to Qt.
function(detect_qt_dependency TARGET_NAME OUTPUT_VARIABLE)
if(TARGET ${TARGET_NAME})
get_target_property(alias ${TARGET_NAME} ALIASED_TARGET)
if(alias)
set(TARGET_NAME ${alias})
endif()
endif()
get_property(cached_is_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${TARGET_NAME})
if(cached_is_qt_dependency)
set(${OUTPUT_VARIABLE} ${cached_is_qt_dependency} PARENT_SCOPE)
return()
endif()
if(${TARGET_NAME} MATCHES "^3rdParty::Qt::.*")
set_property(GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${TARGET_NAME} ON)
set(${OUTPUT_VARIABLE} ON PARENT_SCOPE)
return()
endif()
get_property(delayed_link GLOBAL PROPERTY LY_DELAYED_LINK_${TARGET_NAME})
set(exclude_library_types SHARED_LIBRARY MODULE_LIBRARY)
foreach(library IN LISTS delayed_link)
if(TARGET ${library})
get_target_property(child_target_type ${library} TYPE)
# If the dependency to Qt has to go through a shared/module library,
# it is not a direct dependency
if (child_target_type IN_LIST exclude_library_types)
continue()
endif()
endif()
detect_qt_dependency(${library} child_depends_on_qt)
if(child_depends_on_qt)
set_property(GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${TARGET_NAME} ON)
set(${OUTPUT_VARIABLE} ON PARENT_SCOPE)
return()
endif()
endforeach()
set_property(GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${TARGET_NAME} OFF)
set(${OUTPUT_VARIABLE} OFF PARENT_SCOPE)
endfunction()
#! ly_parse_third_party_dependencies: Validates any 3rdParty library dependencies through the find_package command
#
# \arg:ly_THIRD_PARTY_LIBRARIES name of the target libraries to validate existance of through the find_package command.

@ -12,7 +12,6 @@
ly_set(PAL_EXECUTABLE_APPLICATION_FLAG)
set(PAL_LINKOPTION_MODULE MODULE)
ly_set(PAL_TRAIT_BUILD_HOST_QT_SUPPORTED FALSE)
ly_set(PAL_TRAIT_BUILD_HOST_GUI_TOOLS FALSE)
ly_set(PAL_TRAIT_BUILD_HOST_TOOLS FALSE)
ly_set(PAL_TRAIT_BUILD_SERVER_SUPPORTED FALSE)

@ -389,16 +389,7 @@ function(ly_setup_runtime_dependencies)
# Common functions used by the bellow code
install(CODE
"function(ly_deploy_qt_install target_output)
execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\" --verbose 0 --no-compiler-runtime \"\${target_output}\" ERROR_VARIABLE deploy_error RESULT_VARIABLE deploy_result)
if (NOT \${deploy_result} EQUAL 0)
if(NOT deploy_error MATCHES \"does not seem to be a Qt executable\" )
message(SEND_ERROR \"Deploying qt for \${target_output} returned \${deploy_result}: \${deploy_error}\")
endif()
endif()
endfunction()
function(ly_copy source_file target_directory)
"function(ly_copy source_file target_directory)
file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS})
endfunction()"
)
@ -419,18 +410,6 @@ endfunction()"
file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory})
endif()
# Qt
get_property(has_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${target})
if(has_qt_dependency)
# Qt deploy needs to be done after the binary is copied to the output, so we do a install(CODE) which effectively
# puts it as a postbuild step of the "install" target. Binaries are copied at that point.
if(NOT EXISTS ${WINDEPLOYQT_EXECUTABLE})
message(FATAL_ERROR "Qt deploy executable not found: ${WINDEPLOYQT_EXECUTABLE}")
endif()
set(target_output "${install_output_folder}/${target_runtime_output_subdirectory}/$<TARGET_FILE_NAME:${target}>")
list(APPEND runtime_commands "ly_deploy_qt_install(\"${target_output}\")\n")
endif()
# runtime dependencies that need to be copied to the output
set(target_file_dir "${install_output_folder}/${target_runtime_output_subdirectory}")
ly_get_runtime_dependencies(runtime_dependencies ${target})

@ -35,6 +35,8 @@ function(ly_get_runtime_dependencies ly_RUNTIME_DEPENDENCIES ly_TARGET)
return() # Nothing to do
endif()
ly_de_alias_target(${ly_TARGET} ly_TARGET)
# To optimize the search, we are going to cache the dependencies for the targets we already walked through.
# To do so, we will create a variable named LY_RUNTIME_DEPENDENCIES_${ly_TARGET} which will contain a list
# of all the dependencies
@ -96,15 +98,7 @@ function(ly_get_runtime_dependencies ly_RUNTIME_DEPENDENCIES ly_TARGET)
# Add the imported locations
get_target_property(is_imported ${ly_TARGET} IMPORTED)
if(is_imported)
# Skip Qt if this is a 3rdParty
# Qt is deployed using qt_deploy, no need to copy the dependencies
set(skip_imported FALSE)
string(REGEX MATCH "3rdParty::([^:,]*)" target_package ${ly_TARGET})
if(target_package)
if(${CMAKE_MATCH_1} STREQUAL "Qt")
set(skip_imported TRUE)
endif()
endif()
if(target_type MATCHES "(STATIC_LIBRARY)")
# No need to copy these dependencies since the outputs are not used at runtime
set(skip_imported TRUE)
@ -118,12 +112,34 @@ function(ly_get_runtime_dependencies ly_RUNTIME_DEPENDENCIES ly_TARGET)
else()
set(imported_property IMPORTED_LOCATION)
endif()
get_target_property(target_locations ${ly_TARGET} ${imported_property})
set(target_locations)
get_target_property(current_target_locations ${ly_TARGET} ${imported_property})
if(current_target_locations)
string(APPEND target_locations ${current_target_locations})
else()
# Check if the property exists for configurations
foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
string(TOUPPER ${conf} UCONF)
unset(current_target_locations)
get_target_property(current_target_locations ${ly_TARGET} ${imported_property}_${UCONF})
if(current_target_locations)
string(APPEND target_locations $<$<CONFIG:${conf}>:${current_target_locations}>)
else()
# try to use the mapping
get_target_property(mapped_conf ${ly_TARGET} MAP_IMPORTED_CONFIG_${UCONF})
if(mapped_conf)
get_target_property(current_target_locations ${ly_TARGET} ${imported_property}_${mapped_conf})
if(current_target_locations)
string(APPEND target_locations $<$<CONFIG:${conf}>:${current_target_locations}>)
endif()
endif()
endif()
endforeach()
endif()
if(target_locations)
list(APPEND all_runtime_dependencies ${target_locations})
endif()
endif()
endif()
@ -238,6 +254,8 @@ function(ly_copy source_file target_directory)
if(\"\${source_file}\" IS_NEWER_THAN \"\${target_directory}/\${target_filename}\")
file(LOCK \"\${target_directory}/\${target_filename}.lock\" GUARD FUNCTION TIMEOUT 30)
file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS})
file(LOCK \"\${target_directory}/\${target_filename}.lock\" RELEASE)
file(REMOVE \"\${target_directory}/\${target_filename}.lock\")
endif()
endif()
endfunction()

@ -12,7 +12,6 @@
ly_set(PAL_EXECUTABLE_APPLICATION_FLAG)
ly_set(PAL_LINKOPTION_MODULE MODULE)
ly_set(PAL_TRAIT_BUILD_HOST_QT_SUPPORTED TRUE)
ly_set(PAL_TRAIT_BUILD_HOST_GUI_TOOLS FALSE)
ly_set(PAL_TRAIT_BUILD_HOST_TOOLS TRUE)
ly_set(PAL_TRAIT_BUILD_SERVER_SUPPORTED TRUE)

@ -1,73 +0,0 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# Clear the cache for found executable
unset(WINDEPLOYQT_EXECUTABLE CACHE)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_PATH}/bin")
mark_as_advanced(WINDEPLOYQT_EXECUTABLE) # Hiding from GUI
function(ly_qt_deploy)
set(options)
set(oneValueArgs TARGET)
set(multiValueArgs)
cmake_parse_arguments(ly_qt_deploy "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Validate input arguments
if(NOT ly_qt_deploy_TARGET)
message(FATAL_ERROR "You must provide a target to detect qt dependencies")
endif()
# When winqtdeploy is used on a unix platform it copies over the hardcoded platform abstraction plugin
# of qxcb plugin. The qxcb plugin requires an X server to be running on linux and order to load properly
# To avoid the issue of requiring an X server to be running in a headless setup, the qminimal
# platform plugin is also copied over to the target file output directory.
set(plugin_path "${QT_PATH}/plugins")
set(platform_plugins ${plugin_path}/platforms/libqminimal.so)
set(xcbglintegrations_plugins ${plugin_path}/xcbglintegrations/libqxcb-glx-integration.so)
add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DLY_TIMESTAMP_REFERENCE=$<TARGET_FILE:${ly_qt_deploy_TARGET}>
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/qtdeploy.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND "${CMAKE_COMMAND}" -E
env PATH=${CMAKE_BINARY_DIR}:${QT_PATH}/bin:$ENV{PATH}
"${CMAKE_COMMAND}" -P "${LY_ROOT_FOLDER}/cmake/Platform/Linux/windeployqt_wrapper.cmake"
"$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>"
"${WINDEPLOYQT_EXECUTABLE}"
--verbose 2
--no-compiler-runtime
--dir "$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>"
"$<TARGET_FILE:${ly_qt_deploy_TARGET}>"
EXEC_COMMAND ${CMAKE_COMMAND} -E make_directory
"$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/platforms"
EXEC_COMMAND ${CMAKE_COMMAND} -E copy_if_different
${platform_plugins}
"$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/platforms"
EXEC_COMMAND ${CMAKE_COMMAND} -E make_directory
"$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/xcbglintegrations"
EXEC_COMMAND ${CMAKE_COMMAND} -E copy_if_different
${xcbglintegrations_plugins}
"$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/xcbglintegrations"
DEPENDS $<TARGET_FILE:${ly_qt_deploy_TARGET}>
COMMENT "Deploying qt..."
VERBATIM
)
endfunction()
# windeployqt uses qmake -query to introspect a given Qt installation. However,
# qmake is not relocatable, so the paths reported are those from the build
# machine, and not from wherever the user has their 3rdParty libraries. So we
# create a fake qmake executable to report the right paths to windeployqt.
configure_file(${CMAKE_CURRENT_LIST_DIR}/Qt_qmake_${PAL_PLATFORM_NAME_LOWERCASE}.cmake.in ${CMAKE_BINARY_DIR}/qmake)

@ -1,38 +0,0 @@
#!${CMAKE_COMMAND} -P
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
execute_process(COMMAND ${CMAKE_COMMAND} -E echo "QT_SYSROOT:
QT_INSTALL_PREFIX:${QT_PATH}
QT_INSTALL_ARCHDATA:${QT_PATH}
QT_INSTALL_DATA:${QT_PATH}
QT_INSTALL_DOCS:${QT_PATH}/doc
QT_INSTALL_HEADERS:${QT_PATH}/include
QT_INSTALL_LIBS:${QT_PATH}/lib
QT_INSTALL_LIBEXECS:${QT_PATH}/libexec
QT_INSTALL_BINS:${QT_PATH}/bin
QT_INSTALL_TESTS:${QT_PATH}/tests
QT_INSTALL_PLUGINS:${QT_PATH}/plugins
QT_INSTALL_IMPORTS:${QT_PATH}/imports
QT_INSTALL_TRANSLATIONS:${QT_PATH}/translations
QT_INSTALL_CONFIGURATION:${QT_PATH}/etc/xdg
QT_INSTALL_EXAMPLES:${QT_PATH}/examples
QT_INSTALL_DEMOS:${QT_PATH}/examples
QT_HOST_PREFIX:${QT_PATH}
QT_HOST_DATA:${QT_PATH}
QT_HOST_BINS:${QT_PATH}/bin
QT_HOST_LIBS:${QT_PATH}/lib
QMAKE_SPEC:linux-g++
QMAKE_XSPEC:linux-g++
QMAKE_VERSION:3.1
QT_VERSION:${QT_PACKAGE_VERSION}")

@ -19,6 +19,5 @@ set(FILES
LYWrappers_linux.cmake
PAL_linux.cmake
PALDetection_linux.cmake
windeployqt_wrapper.cmake
RPathChange.cmake
)

@ -1,121 +0,0 @@
#!/usr/bin/cmake -P
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# We use windeployqt on Linux to copy the necessary Qt libraries and files to
# the build directory. After these files are copied, we need to adjust their
# rpath to point to Qt from the build tree.
# This script is invoked through the CommandExecution.cmake script. The invoked
# commandline is something like:
# cmake -P CommandExecution.cmake EXEC_COMMAND cmake -E env ... cmake -P windeployqt_wrapper.cmake args
# ^ 1 ^ 2 ^ 3
# cmake #1 invokes cmake #2 which invokes cmake #3. But cmake #1 also sees 2 -P
# arguments, so cmake #1 also invokes windeployqt_wrapper.cmake after
# CommandExecution.cmake finishes. We don't want to run this script 2x, so
# detect this case and exit early
# Find the first -P argument
foreach(argi RANGE 1 ${CMAKE_ARGC})
if("${CMAKE_ARGV${argi}}" STREQUAL "-P")
math(EXPR script_argi "${argi} + 1")
set(script_file "${CMAKE_ARGV${script_argi}}")
break()
endif()
endforeach()
if(NOT script_file STREQUAL "${CMAKE_CURRENT_LIST_FILE}")
return()
endif()
set(runtime_directory ${CMAKE_ARGV3})
foreach(argi RANGE 4 ${CMAKE_ARGC})
list(APPEND command_arguments "${CMAKE_ARGV${argi}}")
endforeach()
execute_process(COMMAND ${command_arguments} RESULT_VARIABLE command_result OUTPUT_VARIABLE command_output ERROR_VARIABLE command_err)
if(command_result)
message(FATAL_ERROR "windeployqt returned a non-zero exit status. stdout: ${command_output} stderr: ${command_err}")
endif()
# Process the output to find the list of files that were updated
# Transform the output to a list
string(REGEX REPLACE ";" "\\\\;" command_output "${command_output}")
string(REGEX REPLACE "\n" ";" command_output "${command_output}")
foreach(line IN LISTS command_output)
# windeployqt has output that looks like this if it updated a file:
# > Checking /path/to/src/file.so, /path/to/dst/file.so
# > Updating file.so
# If the file was not modified, it will look like this:
# > Checking /path/to/src/file.so, /path/to/dst/file.so
# > file.so is up to date
if(line MATCHES "^Checking .*")
set(curfile "${line}")
continue()
endif()
if(line MATCHES "^Updating .*")
# curline has 3 parts, 1) "Checking ", 2) source_file, 3) updated_target_file. We
# just need part 3. But we also want to handle the unfortunate
# possibility of spaces in the filename.
string(REGEX REPLACE "^Checking " "" curfile "${curfile}")
string(REPLACE ", " ";" curfile "${curfile}")
list(LENGTH curfile curfile_parts_count)
if(NOT curfile_parts_count EQUAL 2)
message(SEND_ERROR "Unable to parse output of windeployqt output line ${curfile}")
continue()
endif()
list(GET curfile 1 updated_file)
file(RELATIVE_PATH relative_file "${runtime_directory}" "${updated_file}")
get_filename_component(basename "${relative_file}" NAME)
if(basename MATCHES "^libQt5Core\\.so.*")
# We don't need to patch QtCore
continue()
endif()
# READ_ELF has a CAPTURE_ERROR argument, but that is only set on
# platforms that don't support cmake's elf parser. On linux, no error
# will be set, even when the input is not an ELF formatted file. We
# want to skip any non-executable files, so check for the ELF tag at
# the head of the file.
file(READ "${updated_file}" elf_tag LIMIT 4 HEX)
if(NOT elf_tag STREQUAL 7f454c46) # Binary \0x7f followed by ELF
continue()
endif()
# READ_ELF is an undocumented command that allows us to introspect the
# current rpath set in the file
file(READ_ELF "${updated_file}" RUNPATH plugin_runpath)
get_filename_component(dirname "${relative_file}" DIRECTORY)
if(dirname)
file(RELATIVE_PATH parent_dirs "${updated_file}" "${runtime_directory}")
string(REGEX REPLACE "/../$" "" parent_dirs "${parent_dirs}")
set(new_runpath "\$ORIGIN/${parent_dirs}")
else()
set(new_runpath "\$ORIGIN")
endif()
# RPATH_CHANGE is an undocumented command that allows for replacing an
# existing rpath entry with a new value, as long as the new value's
# strlen is <= the current rpath
file(RPATH_CHANGE FILE "${updated_file}" OLD_RPATH "${plugin_runpath}" NEW_RPATH "${new_runpath}")
unset(curfile)
endif()
endforeach()

@ -12,7 +12,6 @@
ly_set(PAL_EXECUTABLE_APPLICATION_FLAG MACOSX_BUNDLE)
ly_set(PAL_LINKOPTION_MODULE MODULE)
ly_set(PAL_TRAIT_BUILD_HOST_QT_SUPPORTED TRUE)
ly_set(PAL_TRAIT_BUILD_HOST_GUI_TOOLS TRUE)
ly_set(PAL_TRAIT_BUILD_HOST_TOOLS TRUE)
ly_set(PAL_TRAIT_BUILD_SERVER_SUPPORTED FALSE)

@ -1,70 +0,0 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# Clear the cache for found executable
unset(MACDEPLOYQT_EXECUTABLE CACHE)
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${QT_PATH}/bin")
mark_as_advanced(MACDEPLOYQT_EXECUTABLE) # Hiding from GUI
function(ly_qt_deploy)
set(options)
set(oneValueArgs TARGET)
set(multiValueArgs)
cmake_parse_arguments(ly_qt_deploy "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Validate input arguments
if(NOT ly_qt_deploy_TARGET)
message(FATAL_ERROR "You must provide a target to detect qt dependencies")
endif()
#get_target_property(is_bundle ${ly_qt_deploy_TARGET} MACOSX_BUNDLE)
if (is_bundle)
add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DLY_TIMESTAMP_REFERENCE=$<TARGET_FILE:${ly_qt_deploy_TARGET}>
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/qtdeploy.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND "${CMAKE_COMMAND}" -E time
${MACDEPLOYQT_EXECUTABLE}
$<TARGET_BUNDLE_DIR:${ly_qt_deploy_TARGET}>
-always-overwrite
-no-strip
-verbose=0
-fs=APFS
DEPENDS $<TARGET_FILE:${ly_qt_deploy_TARGET}>
COMMENT "Deploying qt to the ${ly_qt_deploy_TARGET} bundle ..."
VERBATIM
)
else()
set(qt_conf_config "[Paths]\nPlugins=@plugin_path@")
set(plugin_path "${QT_PATH}/plugins")
string(CONFIGURE "${qt_conf_config}" qt_conf_output @ONLY)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" "${qt_conf_output}")
# output the qt_conf file using "echo" and file redirection
add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DLY_TIMESTAMP_REFERENCE=$<TARGET_FILE:${ly_qt_deploy_TARGET}>
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/qtdeploy.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_BINARY_DIR}/qt.conf
$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/qt.conf
COMMENT "copying over qt.conf..."
VERBATIM
)
endif()
endfunction()

@ -12,7 +12,6 @@
ly_set(PAL_EXECUTABLE_APPLICATION_FLAG WIN32)
ly_set(PAL_LINKOPTION_MODULE MODULE)
ly_set(PAL_TRAIT_BUILD_HOST_QT_SUPPORTED TRUE)
ly_set(PAL_TRAIT_BUILD_HOST_GUI_TOOLS TRUE)
ly_set(PAL_TRAIT_BUILD_HOST_TOOLS TRUE)
ly_set(PAL_TRAIT_BUILD_TESTS_SUPPORTED TRUE)

@ -1,50 +0,0 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# Clear the cache for found executable
unset(WINDEPLOYQT_EXECUTABLE CACHE)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_PATH}/bin")
mark_as_advanced(WINDEPLOYQT_EXECUTABLE) # Hiding from GUI
function(ly_qt_deploy)
set(options)
set(oneValueArgs TARGET)
set(multiValueArgs)
cmake_parse_arguments(ly_qt_deploy "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Validate input arguments
if(NOT ly_qt_deploy_TARGET)
message(FATAL_ERROR "You must provide a target to detect qt dependencies")
endif()
# CMake has an issue with POST_BUILD commands in msbuild when it is executed from outside VS:
# https://gitlab.kitware.com/cmake/cmake/issues/18530
add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DLY_TIMESTAMP_REFERENCE=$<TARGET_FILE:${ly_qt_deploy_TARGET}>
-DLY_LOCK_FILE=$<TARGET_FILE_DIR:${ly_qt_deploy_TARGET}>/qtdeploy.lock
-P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
EXEC_COMMAND "${CMAKE_COMMAND}" -E
env PATH="${QT_PATH}/bin"
${WINDEPLOYQT_EXECUTABLE}
$<$<CONFIG:Debug>:--pdb>
--verbose 0
--no-compiler-runtime
$<TARGET_FILE:${ly_qt_deploy_TARGET}>
DEPENDS $<TARGET_FILE:${ly_qt_deploy_TARGET}> $<TARGET_FILE:AZ::QtTGAImageFormatPlugin>
COMMENT "Deploying qt..."
VERBATIM
)
endfunction()

@ -1,199 +0,0 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
include_guard()
ly_download_associated_package(Qt)
find_package(Qt REQUIRED MODULE)
# UIC executable
unset(QT_UIC_EXECUTABLE CACHE)
find_program(QT_UIC_EXECUTABLE uic HINTS "${QT_PATH}/bin")
mark_as_advanced(QT_UIC_EXECUTABLE) # Hiding from GUI
# RCC executable
unset(AUTORCC_EXECUTABLE CACHE)
find_program(AUTORCC_EXECUTABLE rcc HINTS "${QT_PATH}/bin")
mark_as_advanced(AUTORCC_EXECUTABLE) # Hiding from GUI
set(Qt5Core_RCC_EXECUTABLE "${AUTORCC_EXECUTABLE}" CACHE FILEPATH "Qt's resource compiler, used by qt5_add_resources" FORCE)
mark_as_advanced(Qt5Core_RCC_EXECUTABLE) # Hiding from GUI
# LRELEASE executable
unset(QT_LRELEASE_EXECUTABLE CACHE)
find_program(QT_LRELEASE_EXECUTABLE lrelease HINTS "${QT_PATH}/bin")
mark_as_advanced(QT_LRELEASE_EXECUTABLE) # Hiding from GUI
if(NOT QT_LRELEASE_EXECUTABLE)
message(FATAL_ERROR "Qt's lrelease executbale not found")
endif()
set(Qt5_LRELEASE_EXECUTABLE "${QT_LRELEASE_EXECUTABLE}" CACHE FILEPATH "Qt's lrelease executable, used by qt5_add_translation" FORCE)
mark_as_advanced(Qt5_LRELEASE_EXECUTABLE) # Hiding from GUI
#! ly_qt_uic_target: handles qt's ui files by injecting uic generation
#
# AUTOUIC has issues to detect changes in UIC files and trigger regeneration:
# https://gitlab.kitware.com/cmake/cmake/-/issues/18741
# So instead, we are going to manually wrap the files. We dont use qt5_wrap_ui because
# it outputs to ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h and we want to follow the
# same folder structure that AUTOUIC uses
#
function(ly_qt_uic_target TARGET)
get_target_property(all_ui_sources ${TARGET} SOURCES)
list(FILTER all_ui_sources INCLUDE REGEX "^.*\\.ui$")
if(NOT all_ui_sources)
message(FATAL_ERROR "Target ${TARGET} contains AUTOUIC but doesnt have any .ui file")
endif()
if(AUTOGEN_BUILD_DIR)
set(gen_dir ${AUTOGEN_BUILD_DIR})
else()
set(gen_dir ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_autogen/include)
endif()
foreach(ui_source ${all_ui_sources})
get_filename_component(filename ${ui_source} NAME_WE)
get_filename_component(dir ${ui_source} DIRECTORY)
if(IS_ABSOLUTE ${dir})
file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir})
endif()
set(outfolder ${gen_dir}/${dir})
set(outfile ${outfolder}/ui_${filename}.h)
get_filename_component(infile ${ui_source} ABSOLUTE)
file(MAKE_DIRECTORY ${outfolder})
add_custom_command(OUTPUT ${outfile}
COMMAND ${QT_UIC_EXECUTABLE} -o ${outfile} ${infile}
MAIN_DEPENDENCY ${infile} VERBATIM
COMMENT "UIC ${infile}"
)
set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC TRUE)
set_source_files_properties(${outfile} PROPERTIES
SKIP_AUTOMOC TRUE
SKIP_AUTOUIC TRUE
GENERATED TRUE
)
list(APPEND all_ui_wrapped_sources ${outfile})
endforeach()
# Add files to the target
target_sources(${TARGET} PRIVATE ${all_ui_wrapped_sources})
source_group("Generated Files" FILES ${all_ui_wrapped_sources})
# Add include directories relative to the generated folder
# query for the property first to avoid the "NOTFOUND" in a list
get_property(has_includes TARGET ${TARGET} PROPERTY INCLUDE_DIRECTORIES SET)
if(has_includes)
get_property(all_include_directories TARGET ${TARGET} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${all_include_directories})
if(IS_ABSOLUTE ${dir})
file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir})
endif()
list(APPEND new_includes ${gen_dir}/${dir})
endforeach()
endif()
list(APPEND new_includes ${gen_dir})
target_include_directories(${TARGET} PRIVATE ${new_includes})
endfunction()
#! ly_add_translations: adds translations (ts) to a target.
#
# This wrapper will generate a qrc file with those translations and add the files under "prefix" and add them to
# the indicated targets. These files will be added under the "Generated Files" filter
#
# \arg:TARGETS name of the targets that the translations will be added to
# \arg:PREFIX prefix where the translation will be located within the qrc file
# \arg:FILES translation files to add
#
function(ly_add_translations)
set(options)
set(oneValueArgs PREFIX)
set(multiValueArgs TARGETS FILES)
cmake_parse_arguments(ly_add_translations "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Validate input arguments
if(NOT ly_add_translations_TARGETS)
message(FATAL_ERROR "You must provide at least one target")
endif()
if(NOT ly_add_translations_FILES)
message(FATAL_ERROR "You must provide at least a translation file")
endif()
qt5_add_translation(TRANSLATED_FILES ${ly_add_translations_FILES})
set(qrc_file_contents
"<RCC>
<qresource prefix=\"/${ly_add_translations_PREFIX}\">
")
foreach(file ${TRANSLATED_FILES})
get_filename_component(filename ${file} NAME)
string(APPEND qrc_file_contents " <file>${filename}</file>
")
endforeach()
string(APPEND qrc_file_contents " </qresource>
</RCC>
")
set(qrc_file_path ${CMAKE_CURRENT_BINARY_DIR}/i18n_${ly_add_translations_PREFIX}.qrc)
file(WRITE
${qrc_file_path}
${qrc_file_contents}
)
set_source_files_properties(
${TRANSLATED_FILES}
${qrc_file_path}
PROPERTIES
GENERATED TRUE
SKIP_AUTORCC TRUE
)
qt5_add_resources(RESOURCE_FILE ${qrc_file_path})
foreach(target ${ly_add_translations_TARGETS})
target_sources(${target} PRIVATE "${TRANSLATED_FILES};${qrc_file_path};${RESOURCE_FILE}")
endforeach()
endfunction()
#! ly_qt_deploy_qtconf: deploys the qt.conf file for TARGET
#
# Instead of running a qt deploy on regular builds, we are using the qt.conf method:
# https://doc.qt.io/qt-5/qt-conf.html
# With such method we can use Qt from the 3rdParty package folder without requiring to
# copy the dlls/plugins to the output.
#
# A full deploy will be done on cmake install
#
# \arg:TARGET target that defines where to deploy to. This also adds a custom POST_BUILD
# command to TARGET to copy the file.
#
function(ly_qt_deploy_qtconf TARGET)
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-E copy_if_different
${CMAKE_BINARY_DIR}/qt.conf
$<TARGET_FILE_DIR:${TARGET}>/qt.conf
COMMENT "Copying over qt.conf..."
VERBATIM
)
endfunction()
# Generate the file once so we copy it per target
file(WRITE "${CMAKE_BINARY_DIR}/qt.conf" "[Paths]\nPlugins=${QT_PATH}/plugins")
include(${LY_ROOT_FOLDER}/cmake/Platform/${PAL_PLATFORM_NAME}/QtDeploy_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
Loading…
Cancel
Save