CMake: Add `qt_add_ui` API
This commit introduces a new `qt_add_ui` CMake API to be used instead of AUTOUIC, due to several hard-to-fix bugs it has. * Resolves the issue where Ninja required two passes to correctly build `.ui` files. * Avoids build folder leakage, in contrast to `AUTOUIC` * Prevents unnecessary recompilation of unchanged source files when a `.ui` file is modified with Ninja. * Since `qt_add_ui` does not scan source files, it provides a faster build than `AUTOUIC`. These changes aim to streamline the build process and improve efficiency when working with `.ui` files. This addresses the following issues: https://gitlab.kitware.com/cmake/cmake/-/issues/16776 https://gitlab.kitware.com/cmake/cmake/-/issues/25436 https://gitlab.kitware.com/cmake/cmake/-/issues/25195 Task-number: QTBUG-110369 Fixes: QTBUG-114563 Change-Id: I34cd3df70542becf6e08502f0cbcd1c11eeeadd6 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>bb10
parent
0678a8a00d
commit
545b84b93c
|
|
@ -49,3 +49,293 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
function(qt6_add_ui target)
|
||||
if(NOT TARGET ${target})
|
||||
message(FATAL_ERROR "Target \"${target}\" does not exist.")
|
||||
endif()
|
||||
|
||||
set(options)
|
||||
set(oneValueArgs INCLUDE_PREFIX)
|
||||
set(multiValueArgs SOURCES OPTIONS)
|
||||
|
||||
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
set(sources ${arg_SOURCES})
|
||||
set(ui_options ${arg_OPTIONS})
|
||||
set(raw_include_prefix "${arg_INCLUDE_PREFIX}")
|
||||
|
||||
if("${sources}" STREQUAL "")
|
||||
message(FATAL_ERROR "The \"SOURCES\" parameter is empty.")
|
||||
endif()
|
||||
|
||||
|
||||
# Disable AUTOUIC for the target explicitly to avoid the AUTOUIC
|
||||
# error message when the AUTOUIC is enabled for the target.
|
||||
set_target_properties(${target} PROPERTIES AUTOUIC OFF)
|
||||
|
||||
if(NOT "${raw_include_prefix}" STREQUAL "")
|
||||
# generate dummy `_` folders from the given path
|
||||
# e.g. if the given path is `../a/b/c`, then the generated path will be
|
||||
# `_`. if the given path is ``../a/../b/c`, then the generated path will
|
||||
# be `_/_`
|
||||
function(_qt_internal_generate_dash_path_from_input input_path
|
||||
out_generated_dash_path)
|
||||
string(REGEX MATCHALL "\\.\\." upper_folder_list "${input_path}")
|
||||
|
||||
list(JOIN upper_folder_list "" upper_folder_list)
|
||||
string(REGEX REPLACE "\\.\\." "_/" additional_path
|
||||
"${upper_folder_list}")
|
||||
|
||||
# remove last / character
|
||||
if(NOT "${additional_path}" STREQUAL "")
|
||||
string(LENGTH "${additional_path}" additional_path_length)
|
||||
math(EXPR additional_path_length "${additional_path_length} - 1")
|
||||
string(SUBSTRING "${additional_path}" 0 ${additional_path_length}
|
||||
additional_path)
|
||||
endif()
|
||||
|
||||
set(${out_generated_dash_path} "${additional_path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
# NOTE: If previous folders are less than ../ folder count in
|
||||
# ${raw_include_prefix}, relative path calculation will miscalculate,
|
||||
# so we need to add dummy folders to calculate the relative path
|
||||
# correctly
|
||||
_qt_internal_generate_dash_path_from_input("${raw_include_prefix}"
|
||||
dummy_path_for_relative_calculation)
|
||||
if(NOT "${dummy_path_for_relative_calculation}" STREQUAL "")
|
||||
set(dummy_path_for_relative_calculation
|
||||
"/${dummy_path_for_relative_calculation}")
|
||||
set(raw_include_prefix_to_compare
|
||||
"${dummy_path_for_relative_calculation}/${raw_include_prefix}")
|
||||
else()
|
||||
set(dummy_path_for_relative_calculation "/")
|
||||
set(raw_include_prefix_to_compare "/${raw_include_prefix}")
|
||||
endif()
|
||||
# NOTE: This relative path calculation could be done just by using the
|
||||
# below code
|
||||
# cmake_path(RELATIVE_PATH normalized_include_prefix "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
# but due to the backward compatibility, we need to use
|
||||
# file(RELATIVE_PATH) and ../ folder calculation the with
|
||||
# _qt_internal_generate_dash_path_from_input() function
|
||||
if(WIN32)
|
||||
set(dummy_path_for_relative_calculation
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${dummy_path_for_relative_calculation}")
|
||||
set(raw_include_prefix_to_compare
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${raw_include_prefix_to_compare}")
|
||||
string(REGEX REPLACE "//" "/" dummy_path_for_relative_calculation
|
||||
"${dummy_path_for_relative_calculation}")
|
||||
string(REGEX REPLACE "//" "/" raw_include_prefix_to_compare
|
||||
"${raw_include_prefix_to_compare}")
|
||||
endif()
|
||||
|
||||
file(RELATIVE_PATH normalized_include_prefix
|
||||
"${dummy_path_for_relative_calculation}"
|
||||
"${raw_include_prefix_to_compare}")
|
||||
|
||||
# if normalized_include_prefix ends with `/` remove it
|
||||
string(REGEX REPLACE "/$" "" normalized_include_prefix
|
||||
"${normalized_include_prefix}")
|
||||
|
||||
_qt_internal_generate_dash_path_from_input("${normalized_include_prefix}"
|
||||
additional_path)
|
||||
endif()
|
||||
|
||||
if(ui_options MATCHES "\\$<CONFIG")
|
||||
set(is_ui_options_contains_config true)
|
||||
endif()
|
||||
get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(is_multi AND is_ui_options_contains_config)
|
||||
set(include_folder "$<CONFIG>")
|
||||
endif()
|
||||
|
||||
set(include_folder_to_add "${include_folder}")
|
||||
if(NOT "${additional_path}" STREQUAL "")
|
||||
set(include_folder_to_add "${include_folder_to_add}/${additional_path}")
|
||||
endif()
|
||||
|
||||
set(prefix_info_file_cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/prefix_info.cmake")
|
||||
if(EXISTS ${prefix_info_file_cmake})
|
||||
include(${prefix_info_file_cmake})
|
||||
set(prefix_info_file_cmake_exists true)
|
||||
else()
|
||||
set(prefix_info_file_cmake_exists false)
|
||||
endif()
|
||||
|
||||
foreach(source_file ${sources})
|
||||
get_filename_component(outfile "${source_file}" NAME_WE)
|
||||
get_filename_component(infile "${source_file}" ABSOLUTE)
|
||||
string(SHA1 infile_hash "${target}${infile}")
|
||||
string(SUBSTRING "${infile_hash}" 0 6 short_hash)
|
||||
set(file_ui_folder "${CMAKE_CURRENT_BINARY_DIR}/.qt/${short_hash}")
|
||||
target_include_directories(${target} SYSTEM PRIVATE
|
||||
"${file_ui_folder}/${include_folder_to_add}")
|
||||
|
||||
set(target_include_folder_with_add_path
|
||||
"${file_ui_folder}/${include_folder}")
|
||||
# Add additional path to include folder if it is not empty
|
||||
if(NOT "${additional_path}" STREQUAL "")
|
||||
set(target_include_folder_with_add_path
|
||||
"${target_include_folder_with_add_path}/${additional_path}")
|
||||
endif()
|
||||
|
||||
set(inc_dir_to_create "${target_include_folder_with_add_path}")
|
||||
if(NOT "${raw_include_prefix}" STREQUAL "")
|
||||
set(inc_dir_to_create
|
||||
"${target_include_folder_with_add_path}/${raw_include_prefix}")
|
||||
endif()
|
||||
|
||||
set(output_directory "${target_include_folder_with_add_path}")
|
||||
if(NOT "${normalized_include_prefix}" STREQUAL "")
|
||||
set(output_directory
|
||||
"${output_directory}/${normalized_include_prefix}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${infile}")
|
||||
message(FATAL_ERROR "${infile} does not exist.")
|
||||
endif()
|
||||
set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC ON)
|
||||
|
||||
macro(_qt_internal_set_output_file_properties file)
|
||||
set_source_files_properties(${file} PROPERTIES
|
||||
SKIP_AUTOMOC TRUE
|
||||
SKIP_AUTOUIC TRUE
|
||||
SKIP_LINTING TRUE)
|
||||
endmacro()
|
||||
|
||||
set(outfile "${output_directory}/ui_${outfile}.h")
|
||||
# Before CMake 3.27, there is a bug for using $<CONFIG> in a generated
|
||||
# file with Ninja Multi-Config generator. To avoid this issue, we need
|
||||
# to add the generated file for each configuration.
|
||||
# Explicitly set the output file properties for each configuration
|
||||
# to avoid Policy CMP0071 warnings.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/-/issues/24848
|
||||
# Xcode generator cannot handle $<CONFIG> in the output file name.
|
||||
# it changes $<CONFIG> with NOCONFIG. That's why we need to add the
|
||||
# generated file for each configuration for Xcode generator as well.
|
||||
if(is_multi AND outfile MATCHES "\\$<CONFIG>"
|
||||
AND CMAKE_VERSION VERSION_LESS "3.27"
|
||||
OR CMAKE_GENERATOR MATCHES "Xcode")
|
||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(REPLACE "$<CONFIG>" "${config}" outfile_with_config
|
||||
"${outfile}")
|
||||
_qt_internal_set_output_file_properties(
|
||||
${outfile_with_config})
|
||||
target_sources(${target} PRIVATE ${outfile_with_config})
|
||||
endforeach()
|
||||
else()
|
||||
_qt_internal_set_output_file_properties(${outfile})
|
||||
target_sources(${target} PRIVATE ${outfile})
|
||||
endif()
|
||||
# remove double slashes
|
||||
string(REGEX REPLACE "//" "/" outfile "${outfile}")
|
||||
|
||||
# Note: If INCLUDE_PREFIX is changed without changing the corresponding
|
||||
# include path in the source file and Ninja generator is used, this
|
||||
# casues the double build issue. To avoid this issue, we need to
|
||||
# remove the output file in configure step if the include_prefix is
|
||||
# changed.
|
||||
if(CMAKE_GENERATOR MATCHES "Ninja")
|
||||
if(prefix_info_file_cmake_exists)
|
||||
if(NOT "${${short_hash}_prefix}" STREQUAL
|
||||
"${normalized_include_prefix}")
|
||||
file(REMOVE_RECURSE "${file_ui_folder}")
|
||||
list(APPEND prefix_info_list
|
||||
"set(${short_hash}_prefix \"${normalized_include_prefix}\")")
|
||||
elseif(NOT DEFINED ${short_hash}_prefix)
|
||||
list(APPEND prefix_info_list
|
||||
"set(${short_hash}_prefix \"${normalized_include_prefix}\")")
|
||||
endif()
|
||||
else()
|
||||
set(prefix_info_list "")
|
||||
list(APPEND prefix_info_list
|
||||
"set(${short_hash}_prefix \"${normalized_include_prefix}\")")
|
||||
endif()
|
||||
file(MAKE_DIRECTORY ${file_ui_folder})
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.17")
|
||||
set(remove_command rm -rf)
|
||||
else()
|
||||
set(remove_command "remove_directory")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${outfile}
|
||||
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::uic
|
||||
COMMAND ${CMAKE_COMMAND} -E ${remove_command} "${file_ui_folder}/${include_folder}"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${inc_dir_to_create}
|
||||
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::uic ${ui_options} -o
|
||||
${outfile} ${infile}
|
||||
COMMAND_EXPAND_LISTS
|
||||
MAIN_DEPENDENCY ${infile} VERBATIM)
|
||||
endforeach()
|
||||
|
||||
|
||||
get_target_property(is_guard_on ${target} _qt_ui_property_check_guard)
|
||||
if(NOT is_guard_on)
|
||||
# Ninja fails when a newline is used. That's why message is
|
||||
# divided into parts.
|
||||
set(error_message_1
|
||||
"Error: The target \"${target}\" has \"AUTOUIC\" enabled.")
|
||||
set(error_message_2
|
||||
"Error: Please disable \"AUTOUIC\" for the target \"${target}\".")
|
||||
|
||||
set(ui_property_check_dummy_file
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/ui_property_check_timestamp")
|
||||
|
||||
add_custom_command(OUTPUT ${ui_property_check_dummy_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen"
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${ui_property_check_dummy_file}
|
||||
COMMAND
|
||||
"$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
|
||||
;-E;echo;${error_message_1}>"
|
||||
COMMAND
|
||||
"$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
|
||||
;-E;echo;${error_message_2}>"
|
||||
# Remove the dummy file so that the error message is shown until
|
||||
# the AUTOUIC is disabled. Otherwise, the error message is shown
|
||||
# only once when the AUTOUIC is enabled with Visual Studio generator.
|
||||
COMMAND
|
||||
"$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
|
||||
;-E;remove;${ui_property_check_dummy_file}>"
|
||||
COMMAND
|
||||
"$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
|
||||
;-E;false>"
|
||||
COMMAND_EXPAND_LISTS
|
||||
VERBATIM)
|
||||
|
||||
# When AUTOUIC is enabled, AUTOUIC runs before ${target}_ui_property_check
|
||||
# target. So we need to add ${target}_ui_property_check as a dependency
|
||||
# to ${target} to make sure that AUTOUIC runs after ${target}_ui_property_check
|
||||
if (NOT QT_NO_MIX_UI_AUTOUIC_CHECK)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
_qt_ui_property_check_guard ON)
|
||||
add_custom_target(${target}_ui_property_check
|
||||
ALL DEPENDS ${ui_property_check_dummy_file})
|
||||
_qt_internal_assign_to_internal_targets_folder(
|
||||
${target}_ui_property_check)
|
||||
add_dependencies(${target} ${target}_ui_property_check)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# write prefix info file
|
||||
if(CMAKE_GENERATOR MATCHES "Ninja")
|
||||
list(PREPEND prefix_info_list "include_guard()")
|
||||
string(REPLACE ";" "\n" prefix_info_list "${prefix_info_list}")
|
||||
file(WRITE "${prefix_info_file_cmake}" "${prefix_info_list}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
||||
function(qt_add_ui)
|
||||
if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
||||
qt6_add_ui(${ARGN})
|
||||
else()
|
||||
message(FATAL_ERROR "qt_add_ui() is only available in Qt 6.")
|
||||
endif()
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -6,3 +6,30 @@ set(SOURCES mainwindow.cpp main.cpp)
|
|||
qt_wrap_ui(SOURCES mainwindow.ui)
|
||||
qt_add_executable(myapp ${SOURCES})
|
||||
#! [qt_wrap_ui]
|
||||
|
||||
#! [qt6_add_ui_1]
|
||||
qt_add_executable(myapp mainwindow.cpp main.cpp)
|
||||
qt6_add_ui(myapp SOURCES mainwindow.ui)
|
||||
#! [qt6_add_ui_1]
|
||||
|
||||
#! [qt6_add_ui_2]
|
||||
qt_add_executable(myapp mainwindow.cpp main.cpp)
|
||||
qt6_add_ui(myapp INCLUDE_PREFIX "src/files" SOURCES mainwindow.ui)
|
||||
#! [qt6_add_ui_2]
|
||||
|
||||
#! [qt6_add_ui_3]
|
||||
qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
|
||||
qt6_add_ui(myapp INCLUDE_PREFIX "src/files" SOURCES widget1.ui widget2.ui)
|
||||
#! [qt6_add_ui_3]
|
||||
|
||||
#! [qt6_add_ui_4]
|
||||
qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
|
||||
qt6_add_ui(myapp INCLUDE_PREFIX "src/files"
|
||||
SOURCES "my_ui_files_1/widget1.ui" "my_ui_files_2/widget2.ui")
|
||||
#! [qt6_add_ui_4]
|
||||
|
||||
#! [qt6_add_ui_5]
|
||||
qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
|
||||
qt6_add_ui(myapp INCLUDE_PREFIX "src/files_1" SOURCES "my_ui_files/widget1.ui")
|
||||
qt6_add_ui(myapp INCLUDE_PREFIX "src/files_2" SOURCES "my_ui_files/widget2.ui")
|
||||
#! [qt6_add_ui_5]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
|
||||
//! [qt6_add_ui_1]
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
//! [qt6_add_ui_1]
|
||||
|
||||
//! [qt6_add_ui_2]
|
||||
#include "mainwindow.h"
|
||||
#include "src/files/ui_mainwindow.h"
|
||||
//! [qt6_add_ui_2]
|
||||
|
||||
//! [qt6_add_ui_3_1]
|
||||
#include "src/files/ui_widget1.h"
|
||||
//! [qt6_add_ui_3_1]
|
||||
|
||||
//! [qt6_add_ui_3_2]
|
||||
#include "src/files/ui_widget2.h"
|
||||
//! [qt6_add_ui_3_2]
|
||||
|
||||
//! [qt6_add_ui_5]
|
||||
#include "src/files_1/ui_widget1.h"
|
||||
#include "src/files_2/ui_widget2.h"
|
||||
//! [qt6_add_ui_5]
|
||||
|
|
@ -30,6 +30,10 @@ directory. The paths of the generated header files are added to \c{<VAR>}.
|
|||
\note This is a low-level macro. See the \l{CMake AUTOUIC Documentation} for a
|
||||
more convenient way to process \c{.ui} files with \c{uic}.
|
||||
|
||||
Since 6.8:
|
||||
\note \l{qt6_add_ui}{qt_add_ui} is the recommended way to process \c{.ui}
|
||||
files.
|
||||
|
||||
\section1 Options
|
||||
|
||||
You can set additional \c{OPTIONS} that should be added to the \c{uic} calls.
|
||||
|
|
@ -39,3 +43,132 @@ You can find possible options in the \l{uic}{uic documentation}.
|
|||
|
||||
\snippet cmake-macros/examples.cmake qt_wrap_ui
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page qt-add-ui.html
|
||||
\ingroup cmake-macros-qtwidgets
|
||||
|
||||
\title qt_add_ui
|
||||
\keyword qt6_add_ui
|
||||
|
||||
\summary {Adds .ui files to a target.}
|
||||
|
||||
\include cmake-find-package-widgets.qdocinc
|
||||
|
||||
\section1 Synopsis
|
||||
|
||||
\badcode
|
||||
qt_add_ui(<TARGET>
|
||||
SOURCES file1.ui [file2.ui ...]
|
||||
[INCLUDE_PREFIX <PREFIX>]
|
||||
[OPTIONS ...])
|
||||
\endcode
|
||||
|
||||
\versionlessCMakeCommandsNote qt6_add_ui()
|
||||
|
||||
\cmakecommandsince 6.8
|
||||
|
||||
\section1 Description
|
||||
|
||||
Creates rules for calling the \l{uic}{User Interface Compiler (uic)} on the
|
||||
\c{.ui} files. For each input file, a header file is generated in the build
|
||||
directory. The generated header files are added to sources of the target.
|
||||
|
||||
\section1 Arguments
|
||||
|
||||
\section2 TARGET
|
||||
|
||||
The \c{TARGET} argument specifies the CMake target to which the generated header
|
||||
files will be added.
|
||||
|
||||
\section2 SOURCES
|
||||
|
||||
The \c{SOURCES} argument specifies the list of \c{.ui} files to process.
|
||||
|
||||
\section2 INCLUDE_PREFIX
|
||||
|
||||
\c INCLUDE_PREFIX specifies the include prefix for the generated header files.
|
||||
Use the same include prefix as in the \c{#include} directive in the source
|
||||
files. If \c{ui_<basename>.h} is included without a prefix, then this argument
|
||||
can be omitted.
|
||||
|
||||
\section2 OPTIONS
|
||||
|
||||
You can set additional \c{OPTIONS} that should be added to the \c{uic} calls.
|
||||
You can find possible options in the \l{uic}{uic documentation}.
|
||||
|
||||
\section1 Examples
|
||||
|
||||
\section2 Without INCLUDE_PREFIX
|
||||
|
||||
In the following snippet, the \c{mainwindow.cpp} file includes
|
||||
\c{ui_mainwindow.h} and \c{mainwindow.h}.
|
||||
|
||||
\snippet cmake-macros/examples.cpp qt6_add_ui_1
|
||||
|
||||
\c{CMakeLists.txt} is implemented as follows and it calls
|
||||
\l{qt6_add_ui}{qt_add_ui} to add \c{ui_mainwindow.h} to the \c{myapp} target.
|
||||
|
||||
\snippet cmake-macros/examples.cmake qt6_add_ui_1
|
||||
|
||||
In the above example, \c{ui_mainwindow.h} is included without a prefix. So the
|
||||
\c{INCLUDE_PREFIX} argument is not specified.
|
||||
|
||||
\section2 With INCLUDE_PREFIX
|
||||
|
||||
\snippet cmake-macros/examples.cpp qt6_add_ui_2
|
||||
|
||||
In the above snippet, \c{mainwindow.cpp} includes \c{ui_mainwindow.h} with a
|
||||
prefix.
|
||||
|
||||
\snippet cmake-macros/examples.cmake qt6_add_ui_2
|
||||
|
||||
Since \c{ui_mainwindow.h} is included with a prefix, the \c{INCLUDE_PREFIX}
|
||||
argument is specified as \c{src/files} in the above example.
|
||||
|
||||
\section2 Multiple .ui files
|
||||
|
||||
In the following snippets, both \c{widget1.cpp} and \c{widget2.cpp} include
|
||||
\c{ui_widget1.h} and \c{ui_widget2.h} respectively.
|
||||
|
||||
\c{widget1.cpp}:
|
||||
|
||||
\snippet cmake-macros/examples.cpp qt6_add_ui_3_1
|
||||
|
||||
\c{widget2.cpp}:
|
||||
|
||||
\snippet cmake-macros/examples.cpp qt6_add_ui_3_2
|
||||
|
||||
Both \c{ui_widget1.h} and \c{ui_widget2.h} are included with the same prefix
|
||||
|
||||
\snippet cmake-macros/examples.cmake qt6_add_ui_3
|
||||
|
||||
In this case, the \c{INCLUDE_PREFIX} argument can be specified as \c{src/files}
|
||||
for both files in the above snippet.
|
||||
|
||||
\section1 When to prefer \l{qt6_add_ui}{qt_add_ui} over \c{AUTOUIC}?
|
||||
|
||||
\l{qt6_add_ui}{qt_add_ui} has some advantages over \c{AUTOUIC}:
|
||||
|
||||
\list
|
||||
\li \l{qt6_add_ui}{qt_add_ui} ensures that the \c{.ui} files are generated
|
||||
correctly during the first build, for the \c{Ninja} and \c{Ninja Multi-Config}
|
||||
generators.
|
||||
|
||||
\li \l{qt6_add_ui}{qt_add_ui} guarantees that the generated \c{.h} files are
|
||||
not leaked outside the build directory.
|
||||
|
||||
\li Since \l{qt6_add_ui}{qt_add_ui} does not scan source files, it provides a
|
||||
faster build than \c{AUTOUIC}.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 When to prefer \l{qt6_add_ui}{qt_add_ui} over \c{qt_wrap_ui}?
|
||||
|
||||
\l{qt6_add_ui}{qt_add_ui} has the \c{INCLUDE_PREFIX} argument, which can be used to
|
||||
specify the include prefix for the generated header files.
|
||||
|
||||
\note It is not recommended to use both \l{qt6_add_ui}{qt_add_ui} and
|
||||
\c{AUTOUIC} for the same target.
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -399,8 +399,44 @@ endif()
|
|||
|
||||
_qt_internal_test_expect_pass(test_config_expressions)
|
||||
_qt_internal_test_expect_pass(test_QTP0003)
|
||||
|
||||
if(NOT NO_GUI)
|
||||
_qt_internal_test_expect_pass(test_collecting_plugins)
|
||||
endif()
|
||||
|
||||
_qt_internal_test_expect_pass(test_qt_manual_moc)
|
||||
|
||||
# check if the os is opensuse. If it is, we need to skip tests due to CI problems
|
||||
set(is_opensuse FALSE)
|
||||
if(UNIX)
|
||||
if(EXISTS "/etc/os-release")
|
||||
file(STRINGS "/etc/os-release" os_release_content)
|
||||
foreach(line IN LISTS os_release_content)
|
||||
if(line MATCHES "openSUSE" OR line MATCHES "opensuse")
|
||||
set(is_opensuse TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT QNX AND NOT WASM AND NOT (WIN32 AND QT_BUILD_MINIMAL_STATIC_TESTS)
|
||||
AND NOT is_opensuse)
|
||||
# Since our CI machines are slow, ctest --build-and-test buffers the output
|
||||
# of the configure step of a test, and the fact that we run all the test
|
||||
# logic in the configure step, we need to divide the tests into smaller
|
||||
# chunks to avoid CI stdout timeout errors.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/-/issues/25790
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_common)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_1)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_2)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_3)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_4)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_5)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_6)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_7)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_8)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_9)
|
||||
_qt_internal_test_expect_pass(test_qt_add_ui_10)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
if(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: ui_mainwindow.h is included as
|
||||
# "sub1/sub2/sub3/sub4/../../../../src/ui_files/ui_mainwindow.h".
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
# Expect 2: No build folder leakage and generation of the
|
||||
# sub1/sub2/sub3/sub4 folder in ${hash_folder}/include
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder( "example" "${test_ui_file}" hash_folder)
|
||||
string(CONCAT test_build_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/UicBuildLeak_incPathGen"
|
||||
"${config_path}-build")
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_additional_args "-DMAINWINDOW_UI_PATH=sub1/sub2/"
|
||||
"sub3/sub4/../../../../src/ui_files/")
|
||||
string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
|
||||
"${config_arg}/src/ui_files/ui_mainwindow.h")
|
||||
string(CONCAT test_folder_to_check "${test_build_dir}/.qt/"
|
||||
"${hash_folder}/${config_arg}/sub1/sub2/sub3/sub4")
|
||||
incremental_build_test(
|
||||
TEST_NAME UicBuildLeak_incPathGen
|
||||
SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
CONFIG "${config_arg}"
|
||||
GENERATOR "${generator}"
|
||||
ADDITIONAL_ARGS "${test_additional_args}"
|
||||
FILE_TO_TOUCH "${test_ui_file}"
|
||||
FILE_TO_CHECK "${test_file_to_check}"
|
||||
FOLDER_TO_CHECK "${test_folder_to_check}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
# A CI test fails with the below condition. So, we are running the test
|
||||
# only for the Debug configuration.
|
||||
if ("${generator}" MATCHES "Xcode" AND
|
||||
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
set(configs "Debug")
|
||||
elseif(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: mainwindow.ui file is touched after the first build. The
|
||||
# ui_mainwindow.h should be generated without the ${config_arg} folder.
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"qt_add_ui_simple_no_config${config_path}-build")
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder(
|
||||
"example"
|
||||
"${test_ui_file}"
|
||||
hash_folder)
|
||||
incremental_build_test(
|
||||
TEST_NAME qt6_add_ui_simple_no_config
|
||||
SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
CONFIG "${config_arg}"
|
||||
ADDITIONAL_ARGS "-DUI_NO_CONFIG_OPTIONS=ON"
|
||||
FILE_TO_TOUCH "${test_file_to_touch}"
|
||||
FILE_TO_CHECK
|
||||
"${test_build_dir}/.qt/${hash_folder}/ui_mainwindow.h"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
# A CI test fails with the below condition. So, we are running the test
|
||||
# only for the Debug configuration.
|
||||
if ("${generator}" MATCHES "Xcode" AND
|
||||
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
set(configs "Debug")
|
||||
elseif(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: mainwindow.ui file is touched after the first build.
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
set(test_build_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/qt_add_ui_simple${config_path}-build")
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder(
|
||||
"example"
|
||||
"${test_ui_file}"
|
||||
hash_folder)
|
||||
incremental_build_test(
|
||||
TEST_NAME qt6_add_ui_simple
|
||||
SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
CONFIG "${config_arg}"
|
||||
FILE_TO_TOUCH "${test_file_to_touch}"
|
||||
FILE_TO_CHECK
|
||||
"${test_build_dir}/.qt/${hash_folder}/${config_arg}/ui_mainwindow.h"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
if(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: Check whether api sets warning against AUTOUIC activation.
|
||||
# Expect 1: Printing of the error message and failure of the build.
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_warning_test${config_path}-build")
|
||||
run_cmake_configure(SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
CLEAN_FIRST
|
||||
ADDITIONAL_ARGS "-DCMAKE_AUTOUIC=ON"
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
RESULT_VARIABLE cmake_result)
|
||||
if(NOT cmake_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error: "
|
||||
"${cmake_error}\nFAIL: \"uic_warning_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-"
|
||||
"build failed to configure")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_warning_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-"
|
||||
"build was configured successfully")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_warning_test${config_path}-build")
|
||||
run_cmake_build(
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
VERBOSE ON
|
||||
CONFIG "${config_arg}"
|
||||
OUTPUT_VARIABLE cmake_build_output
|
||||
RESULT_VARIABLE cmake_build_result)
|
||||
if(NOT cmake_build_result EQUAL 0)
|
||||
message(STATUS "PASS: \"uic_warning_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}"
|
||||
"-build failed to build")
|
||||
else()
|
||||
message(FATAL_ERROR "FAIL: \"uic_warning_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-"
|
||||
"build was built successfully")
|
||||
endif()
|
||||
expect_string_contains("${cmake_build_output}" "has \"AUTOUIC\" enabled"
|
||||
SUCCESS_MESSAGE "\"uic_warning_test\" test in \
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-build \
|
||||
has \"has AUTOUIC enabled\""
|
||||
FAILURE_MESSAGE "\"uic_warning_test\" test in \
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uic_warning_test${config_path}-build \
|
||||
does not have \"has AUTOUIC enabled\"")
|
||||
|
||||
|
||||
if("${generator}" MATCHES "Ninja")
|
||||
# Test case: If INCLUDE_PREFIX is changed without changing the
|
||||
# corresponding include path in the source file and Ninja generator
|
||||
# is used, this casues the double build issue.
|
||||
# Note: Only happens in Ninja generator.
|
||||
# Expect 1: Failure of the build in the first build.
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_double_build_test${config_path}-build")
|
||||
run_cmake_configure(SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
CLEAN_FIRST
|
||||
ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3/"
|
||||
"-DDO_NOT_GENERATE_FILE=ON"
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
RESULT_VARIABLE cmake_result)
|
||||
|
||||
if(NOT cmake_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
|
||||
": ${cmake_error}\nFAIL: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build failed to configure")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build was configured successfully")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_double_build_test${config_path}-build")
|
||||
run_cmake_build(
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
VERBOSE ON
|
||||
CONFIG "${config_arg}"
|
||||
OUTPUT_VARIABLE cmake_build_output
|
||||
RESULT_VARIABLE cmake_build_result)
|
||||
|
||||
if(NOT cmake_build_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_build_output: ${cmake_build_output}"
|
||||
"FAIL: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build failed to build in the first build")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build was built successfully in the first "
|
||||
"build")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_double_build_test${config_path}-build")
|
||||
run_cmake_configure(SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
# We change the INCLUDE_PREFIX here.
|
||||
ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub/"
|
||||
"-DDO_NOT_GENERATE_FILE=ON"
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
RESULT_VARIABLE cmake_result)
|
||||
|
||||
if(NOT cmake_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
|
||||
":${cmake_error}\nFAIL: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build failed to configure in the second "
|
||||
"build")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build was configured successfully in the "
|
||||
"second build")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_double_build_test${config_path}-build")
|
||||
run_cmake_build(
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
VERBOSE ON
|
||||
CONFIG "${config_arg}"
|
||||
OUTPUT_VARIABLE cmake_build_output
|
||||
ERROR_VARIABLE cmake_build_error
|
||||
RESULT_VARIABLE cmake_build_result)
|
||||
|
||||
if(NOT cmake_build_result EQUAL 0)
|
||||
message(STATUS "PASS: \"uic_double_build_test\" test in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build failed to build in the first build "
|
||||
"after changing INCLUDE_PREFIX")
|
||||
else()
|
||||
message(FATAL_ERROR "cmake_build_output: ${cmake_build_output}"
|
||||
"\ncmake_build_error: ${cmake_build_error}\n"
|
||||
"FAIL: \"uic_double_build_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test"
|
||||
"${config_path}-build was built successfully in the first "
|
||||
"build after changing INCLUDE_PREFIX")
|
||||
endif()
|
||||
|
||||
set(expected_fail_string "No such file or directory|file not found")
|
||||
expect_string_contains(${cmake_build_output}
|
||||
"${expected_fail_string}"
|
||||
SUCCESS_MESSAGE "\"uic_double_build_test\" test in \
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test${config_path}\
|
||||
-build has \"ui_mainwindow.h: No such file or directory\" in \
|
||||
the first build after changing INCLUDE_PREFIX"
|
||||
FAILURE_MESSAGE "\"uic_double_build_test\" test in \
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uic_double_build_test${config_path}\
|
||||
-build does not have \"ui_mainwindow.h: No such file or \
|
||||
directory\" in the first build after changing INCLUDE_PREFIX")
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
# A CI test fails with the below condition. So, we are running the test
|
||||
# only for the Debug configuration.
|
||||
if ("${generator}" MATCHES "Xcode" AND
|
||||
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
set(configs "Debug")
|
||||
elseif(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: widget1.ui file is touched after the first build.
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
# Expect 2: Only touched files to be built
|
||||
set(test_build_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/UicIncrementalBuild${config_path}-build")
|
||||
string(CONCAT ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/UicIncrementalBuild/src/widget1.ui")
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/UicIncrementalBuild")
|
||||
|
||||
generate_hash_folder(
|
||||
"example"
|
||||
"${ui_file}"
|
||||
hash_folder)
|
||||
string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
|
||||
"${config_arg}/src/ui_widget1.h")
|
||||
incremental_build_test(
|
||||
TEST_NAME UicIncrementalBuild
|
||||
SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
CONFIG "${config_arg}"
|
||||
GENERATOR "${generator}"
|
||||
FILE_TO_TOUCH "${ui_file}"
|
||||
FILE_TO_CHECK
|
||||
"${test_file_to_check}"
|
||||
FOLDER_TO_CHECK
|
||||
"${test_build_dir}/.qt/${hash_folder}/${config_arg}/src"
|
||||
CHECK_UNWANTED_BUILDS
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
if(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
|
||||
if("${generator}" MATCHES "Ninja")
|
||||
# Test case: Add a new ui file to CMakeLists.txt after the first
|
||||
# build.
|
||||
# Expect 1: Expect ${target}_autogen/prefix_info.cmake to be
|
||||
# generated as expected.
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_prefix_info_cmake_test${config_path}-build")
|
||||
run_cmake_configure(SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
CLEAN_FIRST
|
||||
ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3/"
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
RESULT_VARIABLE cmake_result)
|
||||
|
||||
if(NOT cmake_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
|
||||
":${cmake_error}\nFAIL: \"uic_prefix_info_cmake_test\" test"
|
||||
" in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build failed to configure")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build was configured successfully")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder("example" "${test_ui_file}"
|
||||
hash_folder_mainwindow)
|
||||
string(CONCAT expected_prefix_info_cmake_content
|
||||
"include_guard()\nset(${hash_folder_mainwindow}_prefix \""
|
||||
"sub1/sub2/sub3\")")
|
||||
# read the content of the prefix_info.cmake file
|
||||
string(CONCAT "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_prefix_info_cmake_test${config_path}-build")
|
||||
file(READ
|
||||
"${test_build_dir}/example_autogen/prefix_info.cmake"
|
||||
prefix_info_cmake_content)
|
||||
|
||||
if("${prefix_info_cmake_content}" STREQUAL
|
||||
"${expected_prefix_info_cmake_content}")
|
||||
message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build has the expected content in "
|
||||
"prefix_info.cmake")
|
||||
else()
|
||||
message(FATAL_ERROR "FAIL: \"uic_prefix_info_cmake_test\" test "
|
||||
"in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build does not have the expected content in"
|
||||
" prefix_info.cmake")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_prefix_info_cmake_test${config_path}-build")
|
||||
run_cmake_build(
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
VERBOSE ON
|
||||
CONFIG "${config_arg}"
|
||||
OUTPUT_VARIABLE cmake_build_output
|
||||
ERROR_VARIABLE cmake_build_error
|
||||
RESULT_VARIABLE cmake_build_result)
|
||||
|
||||
if(NOT cmake_build_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_build_output: ${cmake_build_output}"
|
||||
"\ncmake_build_error: ${cmake_build_error}\n"
|
||||
"FAIL: \"uic_prefix_info_cmake_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build failed to build in the first build")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build was built successfully in the first "
|
||||
"build")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_prefix_info_cmake_test${config_path}-build")
|
||||
run_cmake_configure(SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
GENERATOR "${generator}"
|
||||
ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3/"
|
||||
"-DNEW_UI_PATH=sub5/sub6/sub7/ " "-DADD_NEW_UI=ON"
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
RESULT_VARIABLE cmake_result)
|
||||
|
||||
if(NOT cmake_result EQUAL 0)
|
||||
message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error"
|
||||
": ${cmake_error}\nFAIL: \"uic_prefix_info_cmake_test\" "
|
||||
"test in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_"
|
||||
"test ${config_path}-build failed to configure in the"
|
||||
"second build")
|
||||
else()
|
||||
message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in"
|
||||
" ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build was configured successfully in the "
|
||||
"second build")
|
||||
endif()
|
||||
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/subdir/mainwindow.ui")
|
||||
generate_hash_folder("example" "${test_ui_file}"
|
||||
hash_folder_subdir_mainwindow)
|
||||
set(expected_prefix_info_cmake_content
|
||||
"include_guard()\nset(${hash_folder_subdir_mainwindow}_prefix \
|
||||
\"sub5/sub6/sub7\")")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"uic_prefix_info_cmake_test${config_path}-build")
|
||||
file(READ
|
||||
"${test_build_dir}/example_autogen/prefix_info.cmake"
|
||||
prefix_info_cmake_content)
|
||||
|
||||
if("${prefix_info_cmake_content}" STREQUAL
|
||||
"${expected_prefix_info_cmake_content}")
|
||||
message(STATUS "PASS: \"uic_prefix_info_cmake_test\" test in "
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build has the expected content in "
|
||||
"prefix_info.cmake")
|
||||
else()
|
||||
message(FATAL_ERROR "FAIL: \"uic_prefix_info_cmake_test\" test "
|
||||
"in ${CMAKE_CURRENT_BINARY_DIR}/uic_prefix_info_cmake_test"
|
||||
"${config_path}-build does not have the expected content "
|
||||
"in prefix_info.cmake")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
# A CI test fails with the below condition. So, we are running the test
|
||||
# only for the Debug configuration.
|
||||
if ("${generator}" MATCHES "Xcode" AND
|
||||
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
set(configs "Debug")
|
||||
elseif(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: ui_mainwindow.h is included as
|
||||
# "../../../../src/ui_files/ui_mainwindow.h".
|
||||
# Test case: mainwindow1.ui file is touched after the first build.
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
# Expect 2: No build folder leakage and generation of the "_/_/_/_/"
|
||||
# folder in ${hash_folder}/include.
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../test_qt_add_ui_"
|
||||
"common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder("example" "${test_ui_file}" hash_folder)
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/UicBuildLeak_"
|
||||
"subFolderGen${config_path}-build")
|
||||
string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
|
||||
"${config_arg}/src/ui_files/ui_mainwindow.h")
|
||||
incremental_build_test(
|
||||
TEST_NAME UicBuildLeak_subFolderGen
|
||||
SOURCE_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../test_qt_add_ui_common/uic_test"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
CONFIG "${config_arg}"
|
||||
GENERATOR "${generator}"
|
||||
ADDITIONAL_ARGS "-DMAINWINDOW_UI_PATH=../../../../src/ui_files/"
|
||||
FILE_TO_TOUCH "${test_file_to_touch}"
|
||||
FILE_TO_CHECK "${test_file_to_check}"
|
||||
FOLDER_TO_CHECK
|
||||
"${test_build_dir}/.qt/${hash_folder}/${config_arg}/_/_/_/_"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
# A CI test fails with the below condition. So, we are running the test
|
||||
# only for the Debug configuration.
|
||||
if ("${generator}" MATCHES "Xcode" AND
|
||||
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
set(configs "Debug")
|
||||
elseif(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case 1: There are two widget1.ui files in different folders.
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
# Expect 2: Only touched files to be built.
|
||||
string(CONCAT ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui")
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/sub1/sub2/sub3/"
|
||||
"sub4")
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"UicIncBuild_sameFileDiffFolder${config_path}-build")
|
||||
string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/UicIncBuild_sameFileDiffFolder/src/widget1.ui")
|
||||
generate_hash_folder(
|
||||
"example"
|
||||
"${ui_file}"
|
||||
hash_folder)
|
||||
incremental_build_test(
|
||||
TEST_NAME UicIncBuild_sameFileDiffFolder
|
||||
SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
CONFIG "${config_arg}"
|
||||
GENERATOR "${generator}"
|
||||
FILE_TO_TOUCH "${test_file_to_touch}"
|
||||
CHECK_UNWANTED_BUILDS
|
||||
)
|
||||
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
# A CI test fails with the below condition. So, we are running the test
|
||||
# only for the Debug configuration.
|
||||
if ("${generator}" MATCHES "Xcode" AND
|
||||
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
set(configs "Debug")
|
||||
elseif(multi_config_out)
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: ui_mainwindow.h is included as
|
||||
# "sub1/sub2/sub3/../../../../../../../../../../../../../ui_mainwindow.h".
|
||||
# Test case: mainwindow1.ui file is touched after the first build.
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
# Expect 2: No build folder leakage and generation of the
|
||||
# "_/_/_/_/_/_/_/_/_/_/sub1/sub2/sub3" folder in ${hash_folder}/include.
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder("example" "${test_ui_file}" hash_folder)
|
||||
string(CONCAT test_build_dir "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
"UicBuildLeak_subFolderGen_complex${config_path}-build")
|
||||
string(CONCAT test_additional_args "-DMAINWINDOW_UI_PATH=sub1/sub2/sub3"
|
||||
"/../../../../../../../../../../../../../")
|
||||
string(CONCAT test_file_to_touch "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
|
||||
"${config_arg}/ui_mainwindow.h")
|
||||
string(CONCAT test_folder_to_check "${test_build_dir}/.qt/${hash_folder}/"
|
||||
"${config_arg}/_/_/_/_/_/_/_/_/_/_/sub1/sub2/sub3")
|
||||
incremental_build_test(
|
||||
TEST_NAME UicBuildLeak_subFolderGen_complex
|
||||
SOURCE_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../test_qt_add_ui_common/uic_test"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
CONFIG "${config_arg}"
|
||||
GENERATOR "${generator}"
|
||||
ADDITIONAL_ARGS "${test_additional_args}"
|
||||
FILE_TO_TOUCH "${test_file_to_touch}"
|
||||
FILE_TO_CHECK "${test_file_to_check}"
|
||||
FOLDER_TO_CHECK "${test_folder_to_check}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
include(../test_qt_add_ui_common/RunCMake.cmake)
|
||||
include(../test_qt_add_ui_common/functions.cmake)
|
||||
|
||||
get_generators(generators)
|
||||
|
||||
foreach(generator IN ITEMS ${generators})
|
||||
message(STATUS "Running tests for generator: ${generator}")
|
||||
is_multi_config(${generator} multi_config_out)
|
||||
if(multi_config_out)
|
||||
# Since our CI machines are slow, ctest --build-and-test buffers the
|
||||
# output of the configure step of a test, and the fact that we run all
|
||||
# the test logic in the configure step, we need to exclude Release
|
||||
# to avoid CI stdout timeout errors.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/-/issues/25790
|
||||
set(configs "Debug" "Release")
|
||||
else()
|
||||
set(configs "single_config")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS ${configs})
|
||||
if("${config}" STREQUAL "single_config")
|
||||
set(config_path "")
|
||||
set(config_arg "")
|
||||
else()
|
||||
set(config_path "_${config}")
|
||||
set(config_arg "${config}")
|
||||
endif()
|
||||
|
||||
# Test case: ui_mainwindow.h is included as
|
||||
# "sub2/sub3/../../../src/ui_files/ui_mainwindow.h".
|
||||
# Expect 1: Successful build without the double build issue.
|
||||
# Expect 2: No build folder leakage and generation of
|
||||
# _/sub2/sub3 in ${hash_folder}/include.
|
||||
# Note: This test case is a mix of previous two test cases.
|
||||
string(CONCAT test_ui_file "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test/mainwindow.ui")
|
||||
generate_hash_folder("example" "${test_ui_file}" hash_folder)
|
||||
set(test_build_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/UicBuildLeak_mix${config_path}-build")
|
||||
string(CONCAT test_additional_args "-DMAINWINDOW_UI_PATH=sub2/sub3/"
|
||||
"../../../src/ui_files/")
|
||||
string(CONCAT test_file_to_check "${test_build_dir}/.qt/${hash_folder}/"
|
||||
"${config_arg}/src/ui_files/ui_mainwindow.h")
|
||||
string(CONCAT test_source_dir "${CMAKE_CURRENT_SOURCE_DIR}/../"
|
||||
"test_qt_add_ui_common/uic_test")
|
||||
incremental_build_test(
|
||||
TEST_NAME UicBuildLeak_mix
|
||||
SOURCE_DIR "${test_source_dir}"
|
||||
BUILD_DIR "${test_build_dir}"
|
||||
CONFIG "${config_arg}"
|
||||
GENERATOR "${generator}"
|
||||
ADDITIONAL_ARGS "${test_additional_args}"
|
||||
FILE_TO_TOUCH "${test_ui_file}"
|
||||
FILE_TO_CHECK "${test_file_to_check}"
|
||||
FOLDER_TO_CHECK
|
||||
"${test_build_dir}/.qt/${hash_folder}/${config_arg}/_/sub2/sub3"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(test)
|
||||
|
||||
add_executable(test main.cpp)
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
function(run_cmake_configure)
|
||||
set(options CLEAN_FIRST)
|
||||
set(oneValueArgs SOURCE_DIR BUILD_DIR RESULT_VARIABLE OUTPUT_VARIABLE
|
||||
ERROR_VARIABLE GENERATOR)
|
||||
set(multiValueArgs ADDITIONAL_ARGS)
|
||||
|
||||
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
if(NOT arg_SOURCE_DIR)
|
||||
message(FATAL_ERROR "SOURCE_DIR not specified")
|
||||
endif()
|
||||
|
||||
if(NOT arg_BUILD_DIR)
|
||||
message(FATAL_ERROR "BUILD_DIR not specified")
|
||||
endif()
|
||||
|
||||
is_multi_config(arg_GENERATOR multi_config_out)
|
||||
if (NOT ${multi_config_out})
|
||||
set(run_arg_config_arg -Darg_TYPE=Debug)
|
||||
endif()
|
||||
|
||||
set(test_project_source_dir ${arg_SOURCE_DIR})
|
||||
set(test_project_build_dir ${arg_BUILD_DIR})
|
||||
|
||||
# Make sure that file paths are 'real' paths
|
||||
get_filename_component(test_project_source_dir "${test_project_source_dir}"
|
||||
REALPATH)
|
||||
get_filename_component(test_project_build_dir "${test_project_build_dir}"
|
||||
REALPATH)
|
||||
|
||||
if(arg_CLEAN_FIRST)
|
||||
file(REMOVE_RECURSE "${test_project_build_dir}")
|
||||
endif()
|
||||
file(MAKE_DIRECTORY "${test_project_build_dir}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${CMAKE_COMMAND}"
|
||||
-S "${test_project_source_dir}"
|
||||
-B "${test_project_build_dir}"
|
||||
-G "${arg_GENERATOR}"
|
||||
"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
|
||||
${run_arg_config_arg}
|
||||
${arg_ADDITIONAL_ARGS}
|
||||
RESULT_VARIABLE cmake_result
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
ECHO_ERROR_VARIABLE
|
||||
)
|
||||
|
||||
# set output variables
|
||||
set(${arg_RESULT_VARIABLE} ${cmake_result} PARENT_SCOPE)
|
||||
set(${arg_OUTPUT_VARIABLE} ${cmake_output} PARENT_SCOPE)
|
||||
set(${arg_ERROR_VARIABLE} ${cmake_error} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(run_cmake_build)
|
||||
set(options VERBOSE)
|
||||
set(oneValueArgs CONFIG BUILD_DIR RESULT_VARIABLE OUTPUT_VARIABLE
|
||||
ERROR_VARIABLE)
|
||||
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
if(NOT arg_BUILD_DIR)
|
||||
message(FATAL_ERROR "BUILD_DIR not specified")
|
||||
endif()
|
||||
|
||||
if (arg_VERBOSE OR arg_VERBOSE STREQUAL "")
|
||||
set(arg_VERBOSE_ARG --verbose)
|
||||
endif()
|
||||
|
||||
if(arg_CONFIG)
|
||||
set(arg_BUILD_CONFIG_ARG --config ${arg_CONFIG})
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND}
|
||||
--build ${arg_BUILD_DIR}
|
||||
${arg_VERBOSE_ARG}
|
||||
${arg_BUILD_CONFIG_ARG}
|
||||
RESULT_VARIABLE cmake_result
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
ECHO_ERROR_VARIABLE)
|
||||
|
||||
set(${arg_RESULT_VARIABLE} ${cmake_result} PARENT_SCOPE)
|
||||
set(${arg_OUTPUT_VARIABLE} ${cmake_output} PARENT_SCOPE)
|
||||
set(${arg_ERROR_VARIABLE} ${cmake_error} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(is_multi_config generator output)
|
||||
if ("${generator}" MATCHES "Visual Studio" OR "${generator}" MATCHES "Xcode"
|
||||
OR "${generator}" MATCHES "Ninja Multi-Config")
|
||||
set(${output} TRUE PARENT_SCOPE)
|
||||
else()
|
||||
set(${output} FALSE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# check if string includes substring
|
||||
function(_internal_string_contains output string substring)
|
||||
if("${string}" MATCHES "${substring}")
|
||||
set(${output} TRUE PARENT_SCOPE)
|
||||
else()
|
||||
set(${output} FALSE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(expect_string_contains string substring)
|
||||
set(oneValueArgs SUCCESS_MESSAGE FAILURE_MESSAGE)
|
||||
cmake_parse_arguments(expect_string_contains "${options}" "${oneValueArgs}"
|
||||
"${multiValueArgs}" ${ARGN})
|
||||
_internal_string_contains(result "${string}" "${substring}")
|
||||
if("${result}" STREQUAL TRUE)
|
||||
if (expect_string_contains_SUCCESS_MESSAGE)
|
||||
message(STATUS "PASS: ${expect_string_contains_SUCCESS_MESSAGE}")
|
||||
else()
|
||||
message(STATUS "PASS: \"${string}\" contains \"${substring}\"")
|
||||
endif()
|
||||
else()
|
||||
if (expect_string_contains_FAILURE_MESSAGE)
|
||||
message(FATAL_ERROR
|
||||
"FAIL: ${expect_string_contains_FAILURE_MESSAGE}")
|
||||
else()
|
||||
message(FATAL_ERROR "FAIL: \"${string}\" contains \"${substring}\"")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(expect_string_not_contains string substring)
|
||||
set(oneValueArgs SUCCESS_MESSAGE FAILURE_MESSAGE)
|
||||
cmake_parse_arguments(expect_string_not_contains
|
||||
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
_internal_string_contains(result ${string} ${substring})
|
||||
if(${result} STREQUAL FALSE)
|
||||
if (expect_string_not_contains_SUCCESS_MESSAGE)
|
||||
message(STATUS "PASS: ${expect_string_not_contains_SUCCESS_MESSAGE}")
|
||||
else()
|
||||
message(STATUS "PASS: \"${string}\" not contains \"${substring}\"")
|
||||
endif()
|
||||
else()
|
||||
if (expect_string_not_contains_FAILURE_MESSAGE)
|
||||
message(FATAL_ERROR
|
||||
"FAIL: ${expect_string_not_contains_FAILURE_MESSAGE}")
|
||||
else()
|
||||
message(FATAL_ERROR "FAIL: \"${string}\" contains \"${substring}\"")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget* parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "../../../../src/ui_files/ui_mainwindow.h"
|
||||
#include "widget1.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(new Widget1);
|
||||
|
||||
QWidget* w = new QWidget(this);
|
||||
w->setLayout(layout);
|
||||
|
||||
setCentralWidget(w);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow(QWidget* parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget1</class>
|
||||
<widget class="QWidget" name="Widget1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>OnTextChanged:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="OnTextChanged">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "widget1.h"
|
||||
|
||||
#include "../../../../src/ui_files/ui_widget1.h"
|
||||
|
||||
Widget1::Widget1(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::Widget1)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
|
||||
SLOT(onTextChanged(const QString&)));
|
||||
}
|
||||
|
||||
Widget1::~Widget1()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Widget1::onTextChanged(const QString& text)
|
||||
{
|
||||
ui->OnTextChanged->setText(text);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef WIDGET1_H
|
||||
#define WIDGET1_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class Widget1;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget1 : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Widget1(QWidget* parent = nullptr);
|
||||
~Widget1();
|
||||
public slots:
|
||||
void onTextChanged(const QString& text);
|
||||
|
||||
private:
|
||||
Ui::Widget1* ui;
|
||||
};
|
||||
|
||||
#endif // WIDGET1_H
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget1</class>
|
||||
<widget class="QWidget" name="Widget1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>OnTextChanged:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="OnTextChanged">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "widget2.h"
|
||||
|
||||
#include "../../../../ui_widget1.h"
|
||||
|
||||
Widget2::Widget2(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::Widget2)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
|
||||
SLOT(onTextChanged(const QString&)));
|
||||
}
|
||||
|
||||
Widget2::~Widget2()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Widget2::onTextChanged(const QString& text)
|
||||
{
|
||||
ui->OnTextChanged->setText(text);
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef WIDGET2_H
|
||||
#define WIDGET2_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class Widget2;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget2 : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Widget2(QWidget* parent = nullptr);
|
||||
~Widget2();
|
||||
public slots:
|
||||
void onTextChanged(const QString& text);
|
||||
|
||||
private:
|
||||
Ui::Widget2* ui;
|
||||
};
|
||||
|
||||
#endif // WIDGET2_H
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(UicIncrementalBuild_sameFileDifferentFolder LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
qt_add_executable(example
|
||||
../../../../src/ui_files/mainwindow.ui
|
||||
../../../../src/ui_files/widget1.ui
|
||||
../../../../widget1.ui
|
||||
../../../../src/mainwindow.h
|
||||
../../../../src/widget1.h
|
||||
../../../../src/widget2.h
|
||||
../../../../src/main.cpp
|
||||
../../../../src/mainwindow.cpp
|
||||
../../../../src/widget1.cpp
|
||||
../../../../src/widget2.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(example PRIVATE Qt6::Widgets
|
||||
Qt6::Core
|
||||
Qt6::Gui)
|
||||
|
||||
qt6_add_ui(example
|
||||
INCLUDE_PREFIX "../../../../src/ui_files"
|
||||
SOURCES "../../../../src/ui_files/mainwindow.ui"
|
||||
"../../../../src/ui_files/widget1.ui"
|
||||
OPTIONS "$<$<CONFIG:Debug>:-a>")
|
||||
|
||||
qt6_add_ui(example
|
||||
INCLUDE_PREFIX "../../../../"
|
||||
SOURCES "../../../../widget1.ui"
|
||||
OPTIONS "$<$<CONFIG:Debug>:-a>")
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget2</class>
|
||||
<widget class="QWidget" name="Widget2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>OnTextChanged:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="OnTextChanged">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(UicIncrementalBuild LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
qt_add_executable(example
|
||||
src/mainwindow.ui
|
||||
src/widget1.ui
|
||||
src/widget2.ui
|
||||
src/mainwindow.h
|
||||
src/widget1.h
|
||||
src/widget2.h
|
||||
src/main.cpp
|
||||
src/mainwindow.cpp
|
||||
src/widget1.cpp
|
||||
src/widget2.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(example PRIVATE Qt6::Widgets
|
||||
Qt6::Core
|
||||
Qt6::Gui)
|
||||
|
||||
qt6_add_ui(example
|
||||
INCLUDE_PREFIX "src"
|
||||
SOURCES "src/mainwindow.ui" "src/widget1.ui" "src/widget2.ui"
|
||||
OPTIONS "$<$<CONFIG:Debug>:-a>")
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "src/ui_mainwindow.h"
|
||||
#include "widget1.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(new Widget1);
|
||||
|
||||
QWidget* w = new QWidget(this);
|
||||
w->setLayout(layout);
|
||||
|
||||
setCentralWidget(w);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow(QWidget* parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "widget1.h"
|
||||
|
||||
#include "src/ui_widget1.h"
|
||||
|
||||
Widget1::Widget1(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::Widget1)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
|
||||
SLOT(onTextChanged(const QString&)));
|
||||
}
|
||||
|
||||
Widget1::~Widget1()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Widget1::onTextChanged(const QString& text)
|
||||
{
|
||||
ui->OnTextChanged->setText(text);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef WIDGET1_H
|
||||
#define WIDGET1_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class Widget1;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget1 : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Widget1(QWidget* parent = nullptr);
|
||||
~Widget1();
|
||||
public slots:
|
||||
void onTextChanged(const QString& text);
|
||||
|
||||
private:
|
||||
Ui::Widget1* ui;
|
||||
};
|
||||
|
||||
#endif // WIDGET1_H
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget1</class>
|
||||
<widget class="QWidget" name="Widget1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>OnTextChanged:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="OnTextChanged">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "widget2.h"
|
||||
|
||||
#include "src/ui_widget2.h"
|
||||
|
||||
Widget2::Widget2(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::Widget2)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->lineEdit, SIGNAL(textChanged(const QString&)), this,
|
||||
SLOT(onTextChanged(const QString&)));
|
||||
}
|
||||
|
||||
Widget2::~Widget2()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Widget2::onTextChanged(const QString& text)
|
||||
{
|
||||
ui->OnTextChanged->setText(text);
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifndef WIDGET2_H
|
||||
#define WIDGET2_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class Widget2;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget2 : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Widget2(QWidget* parent = nullptr);
|
||||
~Widget2();
|
||||
public slots:
|
||||
void onTextChanged(const QString& text);
|
||||
|
||||
private:
|
||||
Ui::Widget2* ui;
|
||||
};
|
||||
|
||||
#endif // WIDGET2_H
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget2</class>
|
||||
<widget class="QWidget" name="Widget2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>OnTextChanged:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="OnTextChanged">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
function(generate_hash_folder target_name infile out_folder)
|
||||
get_filename_component(infile_abs "${infile}" ABSOLUTE)
|
||||
string(SHA1 infile_hash "${target_name}${infile_abs}")
|
||||
string(SUBSTRING "${infile_hash}" 0 6 short_hash)
|
||||
set(${out_folder} "${short_hash}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_latest_vs_generator output)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G
|
||||
ERROR_VARIABLE CMAKE_GENERATORS_ERROR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX MATCHALL "Visual Studio [0-9]+ [0-9]+" vs_generators
|
||||
"${CMAKE_GENERATORS_ERROR}")
|
||||
|
||||
if(NOT vs_generators)
|
||||
message(FATAL_ERROR "No visual studio generators found")
|
||||
endif()
|
||||
|
||||
set(last_version "0")
|
||||
set(last_generator "")
|
||||
foreach(generator IN LISTS vs_generators)
|
||||
string(REGEX MATCH "Visual Studio ([0-9]+) [0-9]+" unused "${generator}")
|
||||
if("${CMAKE_MATCH_1}" VERSION_GREATER "${last_version}")
|
||||
set(last_version "${CMAKE_MATCH_1}")
|
||||
set(last_generator "${CMAKE_MATCH_0}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(${output} "${last_generator}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(check_unwanted_builds_after_first_build cmake_output test_name test_dir
|
||||
generator)
|
||||
set(unwanted_builds_success_message
|
||||
"\"${test_name}\" in \"${test_dir}\" -> No unwanted builds")
|
||||
set(unwanted_builds_failure_message
|
||||
"\"${test_name}\" in \"${test_dir}\" -> Unwanted builds found")
|
||||
if(${generator} MATCHES "Ninja")
|
||||
expect_string_not_contains(${cmake_output}
|
||||
"widget2.cpp.o.d|mainwindow.cpp.o.d"
|
||||
SUCCESS_MESSAGE ${unwanted_builds_success_message}
|
||||
FAILURE_MESSAGE ${unwanted_builds_failure_message})
|
||||
elseif(${generator} MATCHES "Make")
|
||||
string(CONCAT not_expect_string
|
||||
"Building CXX object UicIncrementalBuild/CMakeFiles"
|
||||
"/example.dir/src/widget2.cpp.o|Building CXX object UicIncremental"
|
||||
"Build/CMakeFiles/example.dir/src/mainwindow.cpp.o")
|
||||
expect_string_not_contains(${cmake_output} "${not_expect_string}"
|
||||
SUCCESS_MESSAGE ${unwanted_builds_success_message}
|
||||
FAILURE_MESSAGE ${unwanted_builds_failure_message})
|
||||
elseif(${generator} MATCHES "Visual Studio")
|
||||
expect_string_not_contains(${cmake_output} "widget2.cpp|mainwindow.cpp"
|
||||
SUCCESS_MESSAGE ${unwanted_builds_success_message}
|
||||
FAILURE_MESSAGE ${unwanted_builds_failure_message})
|
||||
elseif(${generator} MATCHES "Xcode")
|
||||
expect_string_not_contains(${cmake_output} "widget2.cpp|mainwindow.cpp"
|
||||
SUCCESS_MESSAGE ${unwanted_builds_success_message}
|
||||
FAILURE_MESSAGE ${unwanted_builds_failure_message})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(check_output_after_second_build cmake_output test_name
|
||||
test_dir generator)
|
||||
set(second_build_success_message
|
||||
"\"${test_name}\" in \"${test_dir}\" -> Generation of UI files were not \
|
||||
triggered in the second build")
|
||||
set(second_build_failure_message
|
||||
"\"${test_name}\" in \"${test_dir}\" -> Generation of UI files were \
|
||||
triggered in the second build")
|
||||
|
||||
if(${generator} MATCHES "Ninja")
|
||||
expect_string_contains(${cmake_output} "ninja: no work to do."
|
||||
SUCCESS_MESSAGE ${second_build_success_message}
|
||||
FAILURE_MESSAGE ${second_build_failure_message})
|
||||
elseif(${generator} MATCHES "Visual Studio" OR ${generator} MATCHES "Xcode")
|
||||
expect_string_not_contains(${cmake_output} "mainwindow"
|
||||
SUCCESS_MESSAGE
|
||||
${second_build_success_message}
|
||||
FAILURE_MESSAGE
|
||||
${second_build_failure_message})
|
||||
elseif(${generator} MATCHES "Makefiles")
|
||||
expect_string_not_contains(${cmake_output} "mainwindow.cpp.o.d -o"
|
||||
SUCCESS_MESSAGE ${second_build_success_message}
|
||||
FAILURE_MESSAGE ${second_build_failure_message})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(incremental_build_test)
|
||||
set(options CHECK_UNWANTED_BUILDS)
|
||||
set(oneValueArgs CONFIG TEST_NAME SOURCE_DIR BUILD_DIR FILE_TO_TOUCH
|
||||
FILE_TO_CHECK FOLDER_TO_CHECK GENERATOR)
|
||||
set(multiValueArgs ADDITIONAL_ARGS)
|
||||
|
||||
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
string(REPLACE ";" " " arg_ADDITIONAL_ARGS "${arg_ADDITIONAL_ARGS}")
|
||||
if ("${arg_SOURCE_DIR}" STREQUAL "")
|
||||
message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" test failed because "
|
||||
"SOURCE_DIR is empty")
|
||||
endif()
|
||||
|
||||
if ("${arg_BUILD_DIR}" STREQUAL "")
|
||||
message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" test failed because "
|
||||
"BUILD_DIR is empty")
|
||||
endif()
|
||||
|
||||
if ("${arg_GENERATOR}" STREQUAL "")
|
||||
message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" test failed because "
|
||||
"GENERATOR is empty")
|
||||
endif()
|
||||
|
||||
run_cmake_configure(SOURCE_DIR "${arg_SOURCE_DIR}"
|
||||
BUILD_DIR "${arg_BUILD_DIR}"
|
||||
GENERATOR "${arg_GENERATOR}"
|
||||
CLEAN_FIRST
|
||||
ADDITIONAL_ARGS ${arg_ADDITIONAL_ARGS}
|
||||
OUTPUT_VARIABLE cmake_output
|
||||
ERROR_VARIABLE cmake_error
|
||||
RESULT_VARIABLE cmake_result)
|
||||
|
||||
if(${cmake_result} EQUAL 0)
|
||||
message(STATUS
|
||||
"PASS: \"${arg_TEST_NAME}\" test in ${arg_BUILD_DIR} was configured "
|
||||
"successfully")
|
||||
else()
|
||||
message(FATAL_ERROR "cmake_output: ${cmake_output}\ncmake_error: "
|
||||
"${cmake_error}\nFAIL: \"${arg_TEST_NAME}\" test in ${arg_BUILD_DIR}"
|
||||
" failed to configure")
|
||||
endif()
|
||||
|
||||
if(NOT "${arg_CONFIG}" STREQUAL "single_config")
|
||||
set(config_arg "${arg_CONFIG}")
|
||||
endif()
|
||||
|
||||
run_cmake_build(BUILD_DIR ${arg_BUILD_DIR}
|
||||
VERBOSE ON
|
||||
CONFIG ${config_arg}
|
||||
OUTPUT_VARIABLE cmake_build_output
|
||||
ERROR_VARIABLE cmake_build_error
|
||||
RESULT_VARIABLE cmake_build_result)
|
||||
|
||||
if(${cmake_build_result} EQUAL 0)
|
||||
message(STATUS
|
||||
"PASS: \"${arg_TEST_NAME}\" test in ${arg_BUILD_DIR} was built "
|
||||
"successfully")
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"cmake_build_output: ${cmake_build_output}\ncmake_build_error: "
|
||||
"${cmake_build_error}\nFAIL: \"${arg_TEST_NAME}\" test in "
|
||||
"${arg_BUILD_DIR} failed to build")
|
||||
endif()
|
||||
|
||||
if(NOT "${arg_FILE_TO_CHECK}" STREQUAL "")
|
||||
if(NOT EXISTS "${arg_FILE_TO_CHECK}")
|
||||
message(FATAL_ERROR "FAIL: \"${arg_TEST_NAME}\" ${arg_FILE_TO_CHECK}"
|
||||
" could not be found")
|
||||
else()
|
||||
message(STATUS "PASS: \"${arg_TEST_NAME}\" \"${arg_FILE_TO_CHECK}\" "
|
||||
"was generated successfully")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT "${arg_FOLDER_TO_CHECK}" STREQUAL "" AND NOT WIN32)
|
||||
if(NOT EXISTS "${arg_FOLDER_TO_CHECK}")
|
||||
message(FATAL_ERROR
|
||||
"FAIL: \"${arg_TEST_NAME}\" Folder \"${arg_FOLDER_TO_CHECK}\" "
|
||||
"does not exist")
|
||||
else()
|
||||
message(STATUS
|
||||
"PASS: \"${arg_TEST_NAME}\" Folder \"${arg_FOLDER_TO_CHECK}\" "
|
||||
"exists")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT "${arg_FILE_TO_TOUCH}" STREQUAL "")
|
||||
file(TOUCH "${arg_FILE_TO_TOUCH}")
|
||||
endif()
|
||||
|
||||
run_cmake_build(BUILD_DIR ${arg_BUILD_DIR}
|
||||
VERBOSE ON
|
||||
CONFIG ${arg_CONFIG}
|
||||
OUTPUT_VARIABLE cmake_build_output)
|
||||
if(${arg_CHECK_UNWANTED_BUILDS})
|
||||
check_unwanted_builds_after_first_build(${cmake_build_output}
|
||||
${arg_TEST_NAME} ${arg_BUILD_DIR} ${arg_GENERATOR})
|
||||
endif()
|
||||
|
||||
run_cmake_build(BUILD_DIR ${arg_BUILD_DIR}
|
||||
VERBOSE ON
|
||||
CONFIG ${arg_CONFIG}
|
||||
OUTPUT_VARIABLE cmake_build_output)
|
||||
check_output_after_second_build(${cmake_build_output}
|
||||
${arg_TEST_NAME} ${arg_BUILD_DIR} ${arg_GENERATOR})
|
||||
endfunction()
|
||||
|
||||
function(get_generators output)
|
||||
if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
|
||||
set(generators "Unix Makefiles" "Ninja" "Ninja Multi-Config")
|
||||
elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Windows")
|
||||
# CI fails with Clang and Visual Studio generators.
|
||||
# That's why discard that combination.
|
||||
if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND
|
||||
NOT MINGW)
|
||||
get_latest_vs_generator(latest_vs)
|
||||
endif()
|
||||
set(generators "Ninja" "Ninja Multi-Config" "${latest_vs}")
|
||||
elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin")
|
||||
# TODO: Add Xcode generator when
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/25790 is fixed.
|
||||
# Otherwise, adding Xcode generator might fail CI due to the timeout
|
||||
# issue.
|
||||
set(generators "Unix Makefiles" "Ninja" "Ninja Multi-Config")
|
||||
else()
|
||||
string(JOIN "" ERROR_MESSAGE
|
||||
"FAIL: host OS not supported for this test."
|
||||
"host : ${CMAKE_HOST_SYSTEM_NAME}")
|
||||
message(FATAL_ERROR "${ERROR_MESSAGE}")
|
||||
endif()
|
||||
set(${output} "${generators}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
int main() { return 0; }
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(UicTest LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
if (NOT DO_NOT_GENERATE_FILE)
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mainwindow.cpp"
|
||||
CONTENT " \
|
||||
#include \"${CMAKE_CURRENT_SOURCE_DIR}/../UicBuildFolderLeakageCommon/mainwindow.h\" \n \
|
||||
#include \"${MAINWINDOW_UI_PATH}ui_mainwindow.h\" \n \
|
||||
MainWindow::MainWindow(QWidget* parent) \n \
|
||||
: QMainWindow(parent) \n \
|
||||
, ui(new Ui::MainWindow) \n \
|
||||
{ \n \
|
||||
ui->setupUi(this); \n \
|
||||
} \n \
|
||||
\n \
|
||||
MainWindow::~MainWindow() \n \
|
||||
{ \n \
|
||||
delete ui; \n \
|
||||
} \n \
|
||||
")
|
||||
endif()
|
||||
|
||||
qt_add_executable(example
|
||||
../UicBuildFolderLeakageCommon/main.cpp
|
||||
../UicBuildFolderLeakageCommon/mainwindow.h
|
||||
mainwindow.ui
|
||||
)
|
||||
|
||||
if (${DO_NOT_GENERATE_FILE})
|
||||
target_sources(example PRIVATE mainwindow.cpp)
|
||||
else()
|
||||
target_sources(example PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/mainwindow.cpp")
|
||||
endif()
|
||||
|
||||
target_link_libraries(example PRIVATE Qt6::Widgets
|
||||
Qt6::Core
|
||||
Qt6::Gui)
|
||||
|
||||
if (NOT UI_NO_CONFIG_OPTIONS)
|
||||
set(uic_options "$<$<CONFIG:Debug>:-a>")
|
||||
endif()
|
||||
qt6_add_ui(example
|
||||
INCLUDE_PREFIX "${MAINWINDOW_UI_PATH}"
|
||||
SOURCES "mainwindow.ui"
|
||||
OPTIONS "${uic_options}")
|
||||
|
||||
if(ADD_NEW_UI)
|
||||
qt6_add_ui(example INCLUDE_PREFIX "${NEW_UI_PATH}"
|
||||
SOURCES "subdir/mainwindow.ui"
|
||||
OPTIONS "${uic_options}")
|
||||
endif()
|
||||
|
||||
# Enable AUTOUIC after qt6_add_ui() has been called
|
||||
if (CMAKE_AUTOUIC)
|
||||
set_property(TARGET example PROPERTY AUTOUIC ON)
|
||||
endif()
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "../UicBuildFolderLeakageCommon/mainwindow.h"
|
||||
#include "sub1/sub2/sub3/ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
Reference in New Issue