summaryrefslogtreecommitdiffstats
path: root/cmake/QtExecutableHelpers.cmake
diff options
context:
space:
mode:
authorAlexey Edelev <alexey.edelev@qt.io>2022-08-03 17:46:15 +0200
committerAlexey Edelev <alexey.edelev@qt.io>2022-09-13 00:50:47 +0200
commitac74b60c9c1101288eb2c558420ba69f675a2ee2 (patch)
tree5feb216236b05bc18ceacf9a4274753530d8cc71 /cmake/QtExecutableHelpers.cmake
parentf0a40991fa5a77bb6e09976a3c041f93cbf44347 (diff)
Add function to add and compile executables at configure time
qt_internal_add_configure_time_executable compiles the executable at configure time and exposes it to the CMake source tree. This is useful when need to run a small C++ program at configure time. Task-number: QTBUG-87480 Change-Id: I031efe797c8afa0721d75b46d4f36f67276bf46e Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'cmake/QtExecutableHelpers.cmake')
-rw-r--r--cmake/QtExecutableHelpers.cmake163
1 files changed, 163 insertions, 0 deletions
diff --git a/cmake/QtExecutableHelpers.cmake b/cmake/QtExecutableHelpers.cmake
index 78e0c671af..61f4c005d1 100644
--- a/cmake/QtExecutableHelpers.cmake
+++ b/cmake/QtExecutableHelpers.cmake
@@ -295,3 +295,166 @@ Q_IMPORT_PLUGIN($<JOIN:${class_names},)\nQ_IMPORT_PLUGIN(>)
endforeach()
endfunction()
+
+# This function compiles the target at configure time the very first time and creates the custom
+# ${target}_build that re-runs compilation at build time if necessary. The resulting executable is
+# imported under the provided target name. This function should only be used to compile tiny
+# executables with system dependencies only.
+# One-value Arguments:
+# CMAKELISTS_TEMPLATE
+# The CMakeLists.txt templated that is used to configure the project
+# for an executable. By default the predefined template from the Qt installation is used.
+# INSTALL_DIRECTORY
+# installation directory of the executable. Ignored if NO_INSTALL is set.
+# OUTPUT_NAME
+# the output name of an executable
+# CONFIG
+# the name of configuration that tool needs to be build with.
+# Multi-value Arguments:
+# PACKAGES
+# list of system packages are required to successfully build the project.
+# INCLUDES
+# list of include directories are required to successfully build the project.
+# DEFINES
+# list of definitions are required to successfully build the project.
+# COMPILE_OPTIONS
+# list of compiler options are required to successfully build the project.
+# LINK_OPTIONS
+# list of linker options are required to successfully build the project.
+# SOURCES
+# list of project sources.
+# CMAKE_FLAGS
+# specify flags of the form -DVAR:TYPE=VALUE to be passed to the cmake command-line used to
+# drive the test build.
+# Options:
+# WIN32
+# reflects the corresponding add_executable argument.
+# MACOSX_BUNDLE
+# reflects the corresponding add_executable argument.
+# NO_INSTALL
+# avoids installing the tool.
+function(qt_internal_add_configure_time_executable target)
+ set(one_value_args
+ CMAKELISTS_TEMPLATE
+ INSTALL_DIRECTORY
+ OUTPUT_NAME
+ CONFIG
+ )
+ set(multi_value_args
+ PACKAGES
+ INCLUDES
+ DEFINES
+ COMPILE_OPTIONS
+ LINK_OPTIONS
+ SOURCES
+ CMAKE_FLAGS
+ )
+ set(option_args WIN32 MACOSX_BUNDLE NO_INSTALL)
+ cmake_parse_arguments(arg "${option_args}" "${one_value_args}" "${multi_value_args}" ${ARGN})
+
+ set(target_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/configure_time_bins")
+ if(arg_CONFIG)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${arg_CONFIG}")
+ endif()
+
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config AND CMAKE_TRY_COMPILE_CONFIGURATION)
+ set(configuration_path "${CMAKE_TRY_COMPILE_CONFIGURATION}/")
+ set(config_build_arg "--config" "${CMAKE_TRY_COMPILE_CONFIGURATION}")
+ endif()
+
+ set(configure_time_target "${target}")
+ if(arg_OUTPUT_NAME)
+ set(configure_time_target "${arg_OUTPUT_NAME}")
+ endif()
+ set(target_binary "${configure_time_target}${CMAKE_EXECUTABLE_SUFFIX}")
+ set(target_binary_path
+ "${target_binary_dir}/${configuration_path}${target_binary}")
+ get_filename_component(target_binary_path "${target_binary_path}" ABSOLUTE)
+
+ if(NOT DEFINED arg_SOURCES)
+ message(FATAL_ERROR "No SOURCES given to target: ${target}")
+ endif()
+ set(sources "${arg_SOURCES}")
+
+ # Timestamp file is required because CMake ignores 'add_custom_command' if we use only the
+ # binary file as the OUTPUT.
+ set(timestamp_file "${target_binary_path}_timestamp")
+ add_custom_command(OUTPUT "${target_binary_path}" "${timestamp_file}"
+ COMMAND
+ ${CMAKE_COMMAND} --build "${target_binary_dir}" ${config_build_arg}
+ COMMAND
+ ${CMAKE_COMMAND} -E touch "${timestamp_file}"
+ DEPENDS
+ ${sources}
+ COMMENT
+ "Compiling ${target}"
+ VERBATIM
+ )
+
+ add_custom_target(${target}_build ALL
+ DEPENDS
+ "${target_binary_path}"
+ "${timestamp_file}"
+ )
+
+ if(NOT EXISTS "${target_binary_path}")
+ foreach(arg IN LISTS multi_value_args)
+ string(TOLOWER "${arg}" template_arg_name)
+ set(${template_arg_name} "")
+ if(DEFINED arg_${arg})
+ set(${template_arg_name} "${arg_${arg}}")
+ endif()
+ endforeach()
+
+ foreach(arg IN LISTS option_args)
+ string(TOLOWER "${arg}" template_arg_name)
+ set(${template_arg_name} "")
+ if(arg_${arg})
+ set(${template_arg_name} "${arg}")
+ endif()
+ endforeach()
+
+ file(MAKE_DIRECTORY "${target_binary_dir}")
+ set(template "${QT_CMAKE_DIR}/QtConfigureTimeExecutableCMakeLists.txt.in")
+ if(DEFINED arg_CMAKELISTS_TEMPLATE)
+ set(template "${arg_CMAKELISTS_TEMPLATE}")
+ endif()
+
+ set(cmake_flags_arg)
+ if(arg_CMAKE_FLAGS)
+ set(cmake_flags_arg CMAKE_FLAGS ${arg_CMAKE_FLAGS})
+ endif()
+ configure_file("${template}" "${target_binary_dir}/CMakeLists.txt" @ONLY)
+ try_compile(result
+ "${target_binary_dir}"
+ "${target_binary_dir}"
+ ${target}
+ ${cmake_flags_arg}
+ OUTPUT_VARIABLE try_compile_output
+ )
+
+ if(NOT result)
+ message(FATAL_ERROR "Unable to build ${target}: ${try_compile_output}")
+ endif()
+ endif()
+
+ add_executable(${target} IMPORTED GLOBAL)
+ add_executable(${QT_CMAKE_EXPORT_NAMESPACE}::${target} ALIAS ${target})
+ set_target_properties(${target} PROPERTIES
+ _qt_internal_configure_time_target TRUE
+ IMPORTED_LOCATION "${target_binary_path}")
+
+ if(NOT arg_NO_INSTALL)
+ set(install_dir "${INSTALL_BINDIR}")
+ if(arg_INSTALL_DIRECTORY)
+ set(install_dir "${arg_INSTALL_DIRECTORY}")
+ endif()
+ set_target_properties(${target} PROPERTIES
+ _qt_internal_configure_time_target_install_location
+ "${install_dir}/${target_binary}"
+ )
+ qt_path_join(target_install_dir ${QT_INSTALL_DIR} ${install_dir})
+ qt_copy_or_install(PROGRAMS "${target_binary_path}" DESTINATION "${target_install_dir}")
+ endif()
+endfunction()