Skip to content

Commit

Permalink
CMake: Provide script to configure and build one or more tests
Browse files Browse the repository at this point in the history
Before this patch there were a few ways to build tests
- Configure all tests as part of the repo build
- Configure all tests as part of the repo build, but don't build
  tests by default (-DQT_NO_MAKE_TESTS=ON)
- Configure all tests as a standalone project in a separate build
  dir using -QT_BUILD_STANDALONE_TESTS=ON

All of the above incur some time overhead due to the necessity
of configuring all tests.
Sometimes you just want to build ONE test (or a few).

To facilitate that use case, a new shell script called
bin/qt-cmake-standalone-test(.bat) can now be used to configure
and build one or more tests.

The script takes one single argument pointing to the desired test
project path and configures a generic template project that sets up
all the necessary Qt CMake private API, afterwards calling
add_subdirectory on the passed in project.

Example
$ path/to/qt/bin/qt-cmake-standalone-test ./tests/auto/gui/image/qicon

or

$ path/to/qt/bin/qt-cmake-standalone-test ./tests/auto/gui/image

After that, simply run 'ninja && ctest' to build and run the test(s).

This is the CMake equivalent of calling qmake on a test .pro file
(or on a tests SUBDIRS .pro file)

There are 3 details worth mentioning.

Due to the add_subdirectory call, the built artifacts will not
be in the top-level build dir, but rather in a nested build_dir.

The script currently can't handle more than one argument
(the path to the project), so you can't pass additional
-DFoo=bar arguments.

If a test uses a 3rd party library (like Threads::Threads)
which was not a public dependency for any of the Qt modules,
configuration will fail saying that the target was not found.
Perhaps we should consider recording these packages when
generating the StandaloneConfig.cmake files.

Change-Id: Icde6ecb839341d34f341d9a19402c91196ed5aa0
Reviewed-by: Leander Beernaert <[email protected]>
Reviewed-by: Alexandru Croitor <[email protected]>
  • Loading branch information
alcroito committed Mar 23, 2020
1 parent b888cc6 commit 1f442c6
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 26 deletions.
1 change: 1 addition & 0 deletions bin/qt-cmake-standalone-test.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@__qt_cmake_private_path@ @__qt_cmake_standalone_test_path@ -DQT_STANDALONE_TEST_PATH=@__qt_cmake_standalone_passed_args@
76 changes: 53 additions & 23 deletions cmake/QtBaseGlobalTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,37 @@ qt_install(FILES
COMPONENT Devel
)

# Configure and install the QtBuildInternals package.
set(__build_internals_path_suffix "${INSTALL_CMAKE_NAMESPACE}BuildInternals")
qt_path_join(__build_internals_build_dir ${QT_CONFIG_BUILD_DIR} ${__build_internals_path_suffix})
qt_path_join(__build_internals_install_dir ${QT_CONFIG_INSTALL_DIR}
${__build_internals_path_suffix})
set(__build_internals_standalone_test_template_dir "QtStandaloneTestTemplateProject")

configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake"
"${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfig.cmake"
@ONLY
)

qt_install(FILES
"${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfig.cmake"
"${__build_internals_build_dir}/QtBuildInternalsExtra.cmake"
DESTINATION "${__build_internals_install_dir}"
COMPONENT Devel
)
qt_copy_or_install(
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake"
DESTINATION "${__build_internals_install_dir}")
qt_copy_or_install(
DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/${__build_internals_standalone_test_template_dir}"
DESTINATION "${__build_internals_install_dir}")

set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/${__build_internals_standalone_test_template_dir}/CMakeLists.txt")

# Generate toolchain file for convenience
if(QT_HOST_PATH)
get_filename_component(init_qt_host_path "${QT_HOST_PATH}" ABSOLUTE)
Expand Down Expand Up @@ -159,6 +190,28 @@ qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" DES
endif()
unset(__qt_cmake_extra)

# Provide a private convenience wrapper to configure and build one or more standalone tests.
# Calling CMake directly on a Qt test project won't work because the project does not call
# find_package(Qt...) to get all dependencies like examples do.
# Instead a template CMakeLists.txt project is used which sets up all the necessary private bits
# and then calls add_subdirectory on the provided project path.
set(__qt_cmake_standalone_test_bin_name "qt-cmake-standalone-test")
set(__qt_cmake_private_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qt-cmake-private")
set(__qt_cmake_standalone_test_path
"${__build_internals_install_dir}/${__build_internals_standalone_test_template_dir}")
if(UNIX)
string(PREPEND __qt_cmake_private_path "exec ")
set(__qt_cmake_standalone_passed_args "\"$@\" -DPWD=\"$PWD\"")
else()
string(APPEND __qt_cmake_standalone_test_bin_name ".bat")
string(APPEND __qt_cmake_private_path ".bat")
set(__qt_cmake_standalone_passed_args "%* -DPWD=\"%CD%\"")
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-standalone-test.in"
"${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_standalone_test_bin_name}")
qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/${__qt_cmake_standalone_test_bin_name}"
DESTINATION "${INSTALL_BINDIR}")

## Library to hold global features:
## These features are stored and accessed via Qt::GlobalConfig, but the
## files always lived in Qt::Core, so we keep it that way
Expand Down Expand Up @@ -274,29 +327,6 @@ if(MACOS)
)
endif()

# Configure and install the QtBuildInternals package.
set(__build_internals_path_suffix "${INSTALL_CMAKE_NAMESPACE}BuildInternals")
qt_path_join(__build_internals_build_dir ${QT_CONFIG_BUILD_DIR} ${__build_internals_path_suffix})
qt_path_join(__build_internals_install_dir ${QT_CONFIG_INSTALL_DIR}
${__build_internals_path_suffix})
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake"
"${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfig.cmake"
@ONLY
)

qt_install(FILES
"${__build_internals_build_dir}/${INSTALL_CMAKE_NAMESPACE}BuildInternalsConfig.cmake"
"${__build_internals_build_dir}/QtBuildInternalsExtra.cmake"
DESTINATION "${__build_internals_install_dir}"
COMPONENT Devel
)
qt_copy_or_install(
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake"
DESTINATION "${__build_internals_install_dir}")


# Generate the new resource API
set(QT_CORE_RESOURCE_GENERATED_FILE_NAME "${INSTALL_CMAKE_NAMESPACE}CoreResource.cmake" CACHE INTERNAL "")
set(QT_CORE_RESOURCE_GENERATED_FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${QT_CORE_RESOURCE_GENERATED_FILE_NAME}" CACHE INTERNAL "")
Expand Down
14 changes: 11 additions & 3 deletions cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ endif()
# build.
include(QtPlatformSupport)

macro(qt_build_repo_begin)
macro(qt_build_internals_set_up_private_api)
# Qt specific setup common for all modules:
include(QtSetup)
include(FeatureSummary)
Expand All @@ -63,6 +63,10 @@ macro(qt_build_repo_begin)

# Decide whether tools will be built.
qt_check_if_tools_will_be_built()
endmacro()

macro(qt_build_repo_begin)
qt_build_internals_set_up_private_api()

# Add global docs targets that will work both for per-repo builds, and super builds.
if(NOT TARGET docs)
Expand Down Expand Up @@ -184,12 +188,16 @@ macro(qt_set_up_standalone_tests_build)
# Standalone tests are not handled via the main repo project and qt_build_tests.
endmacro()

function(qt_get_standalone_tests_confg_files_path out_var)
set(path "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}BuildInternals/StandaloneTests")
set("${out_var}" "${path}" PARENT_SCOPE)
endfunction()

macro(qt_build_tests)
if(QT_BUILD_STANDALONE_TESTS)
# Find location of TestsConfig.cmake. These contain the modules that need to be
# find_package'd when testing.
set(_qt_build_tests_install_prefix
"${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}BuildInternals/StandaloneTests")
qt_get_standalone_tests_confg_files_path(_qt_build_tests_install_prefix)
if(QT_WILL_INSTALL)
qt_path_join(_qt_build_tests_install_prefix
${CMAKE_INSTALL_PREFIX} ${_qt_build_tests_install_prefix})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.16)
project(qt_single_test VERSION 6.0.0 LANGUAGES C CXX ASM)

find_package(Qt6 REQUIRED COMPONENTS BuildInternals)

# Includes QtSetup and friends for private CMake API.
qt_build_internals_set_up_private_api()

# Find all StandaloneTestsConfig.cmake files, and include them
# This will find all Qt packages that are required for standalone tests.
# It will find more packages that needed for a certain test, but will ensure any test can
# be built.
qt_get_standalone_tests_confg_files_path(standalone_tests_config_path)
file(GLOB config_files "${standalone_tests_config_path}/*")
foreach(file ${config_files})
include("${file}")
endforeach()

# Get the absolute path of the passed-in project dir, relative to the current working directory
# of the calling script, rather than relative to this source directory.
# The calling script sets PWD. If not set, just use the passed-in value as-is.
if(DEFINED PWD)
get_filename_component(absolute_project_path "${QT_STANDALONE_TEST_PATH}" ABSOLUTE
BASE_DIR "${PWD}")
else()
set(absolute_project_path "${QT_STANDALONE_TEST_PATH}")
endif()

# Add the test project path as a subdirectory project.
add_subdirectory("${absolute_project_path}" "build_dir")

0 comments on commit 1f442c6

Please sign in to comment.