diff options
Diffstat (limited to 'cmake/QtBuild.cmake')
-rw-r--r-- | cmake/QtBuild.cmake | 1080 |
1 files changed, 1080 insertions, 0 deletions
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake new file mode 100644 index 0000000000..cf16be6126 --- /dev/null +++ b/cmake/QtBuild.cmake @@ -0,0 +1,1080 @@ +include(CMakePackageConfigHelpers) + +# Install locations: +set(INSTALL_BINDIR "bin" CACHE PATH "Executables [PREFIX/bin]") +set(INSTALL_INCLUDEDIR "include" CACHE PATH "Header files [PREFIX/include]") +set(INSTALL_LIBDIR "lib" CACHE PATH "Libraries [PREFIX/lib]") +set(INSTALL_ARCHDATADIR "." CACHE PATH "Arch-dependent data [PREFIX]") +set(INSTALL_PLUGINSDIR "${INSTALL_ARCHDATADIR}/plugins" CACHE PATH + "Plugins [ARCHDATADIR/plugins]") + +set(INSTALL_TARGETS_DEFAULT_ARGS + RUNTIME DESTINATION "${INSTALL_BINDIR}" + LIBRARY DESTINATION "${INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${INSTALL_LIBDIR}" COMPONENT Devel + INCLUDES DESTINATION "${INSTALL_INCLUDEDIR}" +) + +if (WIN32) + set(_default_libexec "${INSTALL_ARCHDATADIR}/bin") +else() + set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec") +endif() + +set(INSTALL_LIBEXECDIR "${_default_libexec}" CACHE PATH + "Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]") +set(INSTALL_IMPORTDIR "${INSTALL_ARCHDATADIR}/imports" CACHE PATH + "QML1 imports [ARCHDATADIR/imports]") +set(INSTALL_QMLDIR "${INSTALL_ARCHDATADIR}/qml" CACHE PATH + "QML2 imports [ARCHDATADIR/qml]") +set(INSTALL_DATADIR "." CACHE PATH "Arch-independent data [PREFIX]") +set(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" CACHE PATH "Documentation [DATADIR/doc]") +set(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations" CACHE PATH + "Translations [DATADIR/translations]") +set(INSTALL_SYSCONFDIR "etc/xdg" CACHE PATH + "Settings used by Qt programs [PREFIX/etc/xdg]") +set(INSTALL_EXAMPLESDIR "examples" CACHE PATH "Examples [PREFIX/examples]") +set(INSTALL_TESTSDIR "tests" CACHE PATH "Tests [PREFIX/tests]") + +# Platform define path, etc. +if(WIN32) + set(QT_DEFAULT_PLATFORM_DEFINITIONS UNICODE _UNICODE WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64) + endif() + if(MSVC) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/win32-msvc) + elseif(CLANG) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/win32-clang) + endif() +elseif(LINUX) + if(GCC) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/linux-g++) + elseif(CLANG) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/linux-clang) + endif() +elseif(APPLE) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/macx-clang) +endif() + +if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS) + set(QT_DEFAULT_PLATFORM_DEFINITIONS "") +endif() + +set(QT_PLATFORM_DEFINITIONS ${QT_DEFAULT_PLATFORM_DEFINITIONS} + CACHE STRING "Qt platform specific pre-processor defines") +set(QT_PLATFORM_DEFINITION_DIR ${QT_DEFAULT_PLATFORM_DEFINITION_DIR} + CACHE PATH "Path to directory that contains qplatformdefs.h") +set(QT_NAMESPACE "" CACHE STRING "Qt Namespace") + +# Reset: +set(KNOWN_QT_MODULES "" CACHE INTERNAL "Known Qt modules" FORCE) + + +# For adjusting variables when running tests, we need to know what +# the correct variable is for separating entries in PATH-alike +# variables. +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(QT_PATH_SEPARATOR "\\;") +else() + set(QT_PATH_SEPARATOR ":") +endif() + + +# Functions and macros: + +# Print all variables defined in the current scope. +macro(qt_debug_print_variables) + cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN}) + message("Known Variables:") + get_cmake_property(__variableNames VARIABLES) + list (SORT __variableNames) + if (__arg_DEDUP) + list(REMOVE_DUPLICATES __variableNames) + endif() + + foreach(__var ${__variableNames}) + set(__ignore OFF) + foreach(__i ${__arg_IGNORE}) + if(__var MATCHES "${__i}") + set(__ignore ON) + break() + endif() + endforeach() + + if (__ignore) + continue() + endif() + + set(__show OFF) + foreach(__i ${__arg_MATCH}) + if(__var MATCHES "${__i}") + set(__show ON) + break() + endif() + endforeach() + + if (__show) + message(" ${__var}=${${__var}}.") + endif() + endforeach() +endmacro() + + +macro(assert) + if (${ARGN}) + else() + message(FATAL_ERROR "ASSERT: ${ARGN}.") + endif() +endmacro() + + +function(qt_ensure_perl) + if(DEFINED HOST_PERL) + return() + endif() + find_program(HOST_PERL "perl" DOC "Perl binary") + if (NOT HOST_PERL) + message(FATAL_ERROR "Perl needs to be available to build Qt.") + endif() +endfunction() + + +# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out +# with a message about ${type} having received unknown arguments. +macro(qt_parse_all_arguments result type flags options multiopts) + cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN}) + if(DEFINED ${result}_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).") + endif() +endmacro() + + +# Determines the directory where the generated class-style header files for +# the specified module are located and stores the result in the given result +# variable. +function(qt_internal_module_include_dir result module) + set(${result} "${PROJECT_BINARY_DIR}/include/${module}" PARENT_SCOPE) +endfunction() + +function(qt_internal_add_link_flags target to_add) + get_target_property(_flags "${target}" LINK_FLAGS) + if ("${_flags}" STREQUAL "_flags-NOTFOUND") + set(_flags "") + endif() + string(APPEND _flags " ${to_add}") + set_target_properties("${target}" PROPERTIES LINK_FLAGS "${_flags}") +endfunction() + +function(qt_internal_add_linker_version_script target) + qt_parse_all_arguments(_arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN}) + + if (TEST_ld_version_script) + if (_arg_INTERNAL) + set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };") + else() + set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n") + foreach(ph ${_arg_PRIVATE_HEADERS}) + string(APPEND contents " @FILE:${ph}@\n") + endforeach() + string(APPEND contents "};\n") + set(current "Qt_${PROJECT_VERSION_MAJOR}") + if (QT_NAMESPACE STREQUAL "") + set(tag_symbol "qt_version_tag") + else() + set(tag_symbol "qt_version_tag_${QT_NAMESPACE}") + endif() + string(APPEND contents "${current} { *; };\n") + + foreach(minor_version RANGE ${PROJECT_VERSION_MINOR}) + set(previous "${current}") + set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}") + if (minor_version EQUAL ${PROJECT_VERSION_MINOR}) + string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n") + else() + string(APPEND contents "${current} {} ${previous};\n") + endif() + endforeach() + + set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in") + set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version") + + file(GENERATE OUTPUT "${infile}" CONTENT "${contents}") + + qt_ensure_perl() + + add_custom_command(TARGET "${target}" PRE_LINK + COMMAND "${HOST_PERL}" "${PROJECT_SOURCE_DIR}/mkspecs/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}" + BYPRODUCTS "${outfile}" DEPENDS "${infile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Generating version linker script" + ) + qt_internal_add_link_flags("${target}" "-Wl,--version-script,${outfile}") + endif() + endif() +endfunction() + +# Generates the necessary rules to run moc on the sources specified after the MOC parameter. +# The resulting moc files are returned in the variable specified by the result parameter. +function(qt_internal_wrap_cpp result) + # get include dirs + qt_get_moc_flags(moc_flags) + qt_parse_all_arguments(_arg "qt_internal_wrap_cpp" "" "TARGET;HEADER_FILE_ONLY" "OPTIONS;DEPENDS;MOC" ${ARGN}) + + set(moc_files ${_arg_MOC}) + set(moc_options ${_arg_OPTIONS}) + set(moc_target ${_arg_TARGET}) + set(moc_depends ${_arg_DEPENDS}) + set(wrapped_files "") + + foreach(it ${moc_files}) + get_filename_component(it ${it} ABSOLUTE) + get_filename_component(moc_file_extension ${it} EXT) + + if(${moc_file_extension} STREQUAL ".h") + set(file_prefix "moc_") + set(file_extension "cpp") + else() + set(file_prefix "") + set(file_extension "moc") + endif() + + qt_make_output_file("${it}" "${file_prefix}" "${file_extension}" outfile) + qt_create_moc_command("${it}" "${outfile}" "${moc_flags}" "${moc_options}" "${moc_target}" "${moc_depends}") + set_source_files_properties(${outfile} PROPERTIES HEADER_FILE_ONLY ${_arg_HEADER_FILE_ONLY}) + list(APPEND wrapped_files "${outfile}") + endforeach() + set("${result}" ${wrapped_files} PARENT_SCOPE) +endfunction() + +function(_qt_module_name name result) + set("${result}" "Qt${name}" PARENT_SCOPE) +endfunction() + + +# This function takes a target as a parameter, followed by a list of sources. +# The sources are scanned for Q_OBJECT/Q_GADGET use as well as the inclusion of +# moc_*.cpp/*.moc. Rules are created to call moc accordingly at build time and +# add the generated sources to the target, if the generated code is not +# directly included otherwise. +function(qt_internal_automoc target) + if ("x${ARGN}" STREQUAL "x") + return() + endif() + + if(NOT DEFINED QT_MOCSCANNER) + get_target_property(mocPath "Qt::moc" LOCATION) + get_filename_component(binDirectory "${mocPath}" DIRECTORY) + set(QT_MOCSCANNER "${binDirectory}/qmocscanner${CMAKE_EXECUTABLE_SUFFIX}") + endif() + + string(REPLACE ";" "\n" sources "${ARGN}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/moc_sources_and_headers.txt" ${sources}) + execute_process(COMMAND "${QT_MOCSCANNER}" + "${CMAKE_CURRENT_BINARY_DIR}/moc_sources_and_headers.txt" + "${CMAKE_CURRENT_BINARY_DIR}/moc_files_included.txt" + "${CMAKE_CURRENT_BINARY_DIR}/moc_files_to_build.txt" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + + file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/moc_files_included.txt" moc_files_included) + file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/moc_files_to_build.txt" moc_files_to_build) + + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/moc_sources_and_headers.txt") + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/moc_files_included.txt") + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/moc_files_to_build.txt") + + qt_internal_wrap_cpp(included_mocs TARGET "${target}" MOC ${moc_files_included} HEADER_FILE_ONLY ON) + qt_internal_wrap_cpp(moc_and_build_sources TARGET "${target}" MOC ${moc_files_to_build} HEADER_FILE_ONLY OFF) + + target_sources("${target}" PRIVATE ${moc_and_build_sources} ${included_mocs}) + + foreach(generated_source ${included_mocs}) + get_filename_component(directory "${generated_source}" DIRECTORY) + target_include_directories("${target}" PRIVATE "${directory}") + endforeach() +endfunction() + + +# This function takes a target as a parameter, followed by a list of sources. +# Any sources with the .ui extension are passed on to uic and the generated output +# is added to the target sources. +function(qt_internal_autouic target) + if ("x${ARGN}" STREQUAL "x") + return() + endif() + + set(_ui_files "") + + foreach(s ${ARGN}) + get_filename_component(ext "${s}" EXT) + if("${ext}" STREQUAL ".ui") + qt_create_uic_command("${s}" _ui_file) + list(APPEND _ui_files "${_ui_file}") + endif() + endforeach() + target_sources("${target}" PRIVATE "${_ui_files}") +endfunction() + + +# This function attempts to (poorly) parse the given resourceFile (.qrc) and +# determine the dependencies, i.e. which files are intended for inclusion into +# the Qt resource. +function(qt_extract_qrc_dependencies resourceFile _out_depends _rc_depends) + get_filename_component(rc_path ${resourceFile} PATH) + + if(EXISTS "${infile}") + # parse file for dependencies + # all files are absolute paths or relative to the location of the qrc file + file(READ "${infile}" RC_FILE_CONTENTS) + string(REGEX MATCHALL "<file[^<]+" RC_FILES "${RC_FILE_CONTENTS}") + set(RC_DEPENDS "") + foreach(RC_FILE ${RC_FILES}) + string(REGEX REPLACE "^<file[^>]*>" "" RC_FILE "${RC_FILE}") + if(NOT IS_ABSOLUTE "${RC_FILE}") + set(RC_FILE "${rc_path}/${RC_FILE}") + endif() + set(RC_DEPENDS ${RC_DEPENDS} "${RC_FILE}") + endforeach() + # Since this cmake function is doing the dependency scanning for these files, + # let's make a configured file and add it as a dependency so cmake is run + # again when dependencies need to be recomputed. + qt_make_output_file("${infile}" "" "qrc.depends" out_depends) + configure_file("${infile}" "${out_depends}" COPYONLY) + else() + # The .qrc file does not exist (yet). Let's add a dependency and hope + # that it will be generated later + set(out_depends) + endif() + + set(${_out_depends} ${out_depends} PARENT_SCOPE) + set(${_rc_depends} ${RC_DEPENDS} PARENT_SCOPE) +endfunction() + + +# This function creates the necessary rule to call rcc on the given +# resource file and stores the name of the to-be generated C++ source +# file (created by rcc) in the outCppFile variable. +function(qt_create_rcc_command resourceFile outCppFile) + get_filename_component(outfilename "${resourceFile}" NAME_WE) + get_filename_component(infile "${resourceFile}" ABSOLUTE) + set(generatedCppFile "${CMAKE_CURRENT_BINARY_DIR}/qrc_${outfilename}.cpp") + + qt_extract_qrc_dependencies("${infile}" _out_depends _rc_depends) + set_source_files_properties("${infile}" PROPERTIES SKIP_AUTORCC ON) + + add_custom_command(OUTPUT "${generatedCppFile}" + COMMAND "Qt::rcc" --name "${outfilename}" --output "${generatedCppFile}" "${infile}" + MAIN_DEPENDENCY "${infile}" + DEPENDS "${_rc_depends}" "${_out_depends}" VERBATIM) + set_source_files_properties("${generatedCppFile}" PROPERTIES SKIP_AUTOMOC ON) + set_source_files_properties("${generatedCppFile}" PROPERTIES SKIP_AUTOUIC ON) + set("${outCppFile}" "${generatedCppFile}" PARENT_SCOPE) +endfunction() + + +# This function takes a target as a parameter, followed by a list of sources. +# Any sources ending with the .qrc extension are treated as Qt resources and rules +# to call rcc are generated. The source files rcc generates are added to the target. +function(qt_internal_autorcc target) + if ("x${ARGN}" STREQUAL "x") + return() + endif() + + set(_qrc_cpp_files "") + + foreach(s ${ARGN}) + get_filename_component(ext "${s}" EXT) + if("${ext}" STREQUAL ".qrc") + qt_create_rcc_command("${s}" _qrc_cpp_file) + list(APPEND _qrc_cpp_files "${_qrc_cpp_file}") + endif() + endforeach() + target_sources("${target}" PRIVATE "${_qrc_cpp_files}") +endfunction() + + +# This function takes a target as a parameter, followed by a list of sources. +# The sources are scanned for .ui and .qrc as well as Q_OBJECT/Q_GADGET use +# and rules to call uic/rcc/moc are created. Any generated sources are added +# as private sources to the specified target. +function(qt_internal_process_automatic_sources target) + qt_internal_automoc("${target}" ${ARGN}) + qt_internal_autouic("${target}" ${ARGN}) + qt_internal_autorcc("${target}" ${ARGN}) +endfunction() + + +set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES") +set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES") + + +# This function can be used to add sources/libraries/etc. to the specified CMake target +# if the provided CONDITION evaluates to true. +function(extend_target target) + if (NOT TARGET "${target}") + message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") + endif() + qt_parse_all_arguments(_arg "extend_target" "" "" + "CONDITION;${__default_public_args};${__default_private_args};COMPILE_FLAGS" ${ARGN}) + if ("x${_arg_CONDITION}" STREQUAL x) + set(_arg_CONDITION ON) + endif() + + qt_evaluate_config_expression(result ${_arg_CONDITION}) + if (${result}) + qt_internal_process_automatic_sources("${target}" ${_arg_SOURCES}) + + foreach(dep ${_arg_LIBRARIES} ${_arg_PUBLIC_LIBRARIES}) + if("${dep}" MATCHES "Qt::(.+)(Private?)") + set(depTarget ${CMAKE_MATCH_1}) + + # Fetch features from dependencies and make them available to the + # caller as well as to the local scope for configure.cmake evaluation. + + if("x${CMAKE_MATCH_2}" STREQUAL "xPrivate") + qt_push_features_into_parent_scope(PRIVATE_FEATURES ${depTarget}) + qt_pull_features_into_current_scope(PRIVATE_FEATURES ${depTarget}) + endif() + qt_push_features_into_parent_scope(PUBLIC_FEATURES ${depTarget}) + qt_pull_features_into_current_scope(PUBLIC_FEATURES ${depTarget}) + if(TARGET "${dep}") + continue() + endif() + find_package(Qt${PROJECT_VERSION_MAJOR}${depTarget} REQUIRED) + endif() + endforeach() + + target_sources("${target}" PRIVATE ${_arg_SOURCES}) + if (_arg_COMPILE_FLAGS) + set_source_files_properties(${_arg_SOURCES} PROPERTIES COMPILE_FLAGS "${_arg_COMPILE_FLAGS}") + endif() + target_include_directories("${target}" PUBLIC ${_arg_PUBLIC_INCLUDE_DIRECTORIES} PRIVATE ${_arg_INCLUDE_DIRECTORIES}) + target_compile_definitions("${target}" PUBLIC ${_arg_PUBLIC_DEFINES} PRIVATE ${_arg_DEFINES}) + target_link_libraries("${target}" PUBLIC ${_arg_PUBLIC_LIBRARIES} PRIVATE ${_arg_LIBRARIES}) + endif() +endfunction() + + +function(qt_internal_library_deprecation_level result) + if(WIN32) + # On Windows, due to the way DLLs work, we need to export all functions, + # including the inlines + set("${result}" "QT_DISABLE_DEPRECATED_BEFORE=0x040800" PARENT_SCOPE) + else() + # On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API + set("${result}" "QT_DISABLE_DEPRECATED_BEFORE=0x050000" PARENT_SCOPE) + endif() +endfunction() + + +function(qt_read_headers_pri module resultVarPrefix) + qt_internal_module_include_dir(include_dir "${module}") + file(STRINGS "${include_dir}/headers.pri" headers_pri_contents) + foreach(line ${headers_pri_contents}) + if("${line}" MATCHES "SYNCQT.HEADER_FILES = (.*)") + set(public_module_headers "${CMAKE_MATCH_1}") + separate_arguments(public_module_headers UNIX_COMMAND "${public_module_headers}") + elseif("${line}" MATCHES "SYNCQT.PRIVATE_HEADER_FILES = (.*)") + set(private_module_headers "${CMAKE_MATCH_1}") + separate_arguments(private_module_headers UNIX_COMMAND "${private_module_headers}") + elseif("${line}" MATCHES "SYNCQT.GENERATED_HEADER_FILES = (.*)") + set(generated_module_headers "${CMAKE_MATCH_1}") + separate_arguments(generated_module_headers UNIX_COMMAND "${generated_module_headers}") + foreach(generated_header ${generated_module_headers}) + list(APPEND public_module_headers "${include_dir}/${generated_header}") + endforeach() + # Ignore INJECTIONS! + elseif("${line}" MATCHES "SYNCQT.([A-Z_]+)_HEADER_FILES = (.+)") + set(prefix "${CMAKE_MATCH_1}") + string(TOLOWER "${prefix}" prefix) + set(entries "${CMAKE_MATCH_2}") + separate_arguments(entries UNIX_COMMAND "${entries}") + set("${resultVarPrefix}_${prefix}" "${entries}" PARENT_SCOPE) + endif() + endforeach() + set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE) + set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE) +endfunction() + + +# This is the main entry function for creating a Qt module, that typically +# consists of a library, public header files, private header files and configurable +# features. +# +# A CMake target with the specified name parameter is created. If the current source +# directory has a configure.cmake file, then that is also processed for feature definition +# and testing. Any features defined as well as any features coming from dependencies to +# this module are imported into the scope of the calling feature. +function(add_qt_module name) + qt_parse_all_arguments(_arg "add_qt_module" "NO_MODULE_HEADERS;STATIC" "CONFIG_MODULE_NAME" + "${__default_private_args};${__default_public_args};FEATURE_DEPENDENCIES" ${ARGN}) + + _qt_module_name("${name}" module) + set(versioned_module_name "Qt${PROJECT_VERSION_MAJOR}${name}") + set(target "${name}") + string(TOUPPER "${name}" name_upper) + string(TOLOWER "${name}" name_lower) + + set(known_modules "${KNOWN_QT_MODULES}" "${target}") + set(KNOWN_QT_MODULES ${known_modules} CACHE INTERNAL "Modules that are built." FORCE) + + ### Define Targets: + if(${_arg_STATIC}) + add_library("${target}" STATIC) + elseif(${QT_BUILD_SHARED_LIBS}) + add_library("${target}" SHARED) + else() + add_library("${target}" STATIC) + endif() + add_library("Qt::${target}" ALIAS "${target}") + + # Add _private target to link against the private headers: + set(target_private "${target}Private") + add_library("${target_private}" INTERFACE) + add_library("Qt::${target_private}" ALIAS ${target_private}) + + if(NOT DEFINED _arg_CONFIG_MODULE_NAME) + set(_arg_CONFIG_MODULE_NAME "${name_lower}") + endif() + + # Import global features + if(NOT "${target}" STREQUAL "Core") + qt_push_features_into_parent_scope(PUBLIC_FEATURES PRIVATE_FEATURES FEATURE_PROPERTY_INFIX "GLOBAL_" Qt::Core) + endif() + + # Fetch features from dependencies and make them available to the + # caller as well as to the local scope for configure.cmake evaluation. + foreach(dep ${_arg_LIBRARIES} ${_arg_PUBLIC_LIBRARIES}) + if("${dep}" MATCHES "(Qt::.+)Private") + set(publicDep ${CMAKE_MATCH_1}) + qt_push_features_into_parent_scope(PRIVATE_FEATURES ${publicDep}) + qt_pull_features_into_current_scope(PRIVATE_FEATURES ${publicDep}) + else() + set(publicDep ${dep}) + endif() + qt_push_features_into_parent_scope(PUBLIC_FEATURES ${publicDep}) + qt_pull_features_into_current_scope(PUBLIC_FEATURES ${publicDep}) + endforeach() + + if(NOT ${_arg_NO_MODULE_HEADERS}) + qt_ensure_perl() + if(NOT DEFINED QT_SYNCQT) + get_target_property(mocPath "Qt::moc" LOCATION) + get_filename_component(binDirectory "${mocPath}" DIRECTORY) + # We could put this into the cache, but on the other hand there's no real need to + # pollute the app's cache with this. For the first qtbase build, the variable is + # set in global scope. + set(QT_SYNCQT "${binDirectory}/syncqt.pl") + endif() + execute_process(COMMAND "${HOST_PERL}" -w "${QT_SYNCQT}" -quiet -module "${module}" -version "${PROJECT_VERSION}" -outdir "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}") + endif() + + if(NOT ${_arg_NO_MODULE_HEADERS}) + set_target_properties("${target}" PROPERTIES MODULE_HAS_HEADERS ON) + else() + set_target_properties("${target}" PROPERTIES MODULE_HAS_HEADERS OFF) + endif() + + set_target_properties("${target}" PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_LIBDIR}") + set_target_properties("${target}" PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}") + set_target_properties("${target}" PROPERTIES OUTPUT_NAME "${versioned_module_name}") + + qt_internal_module_include_dir(include_dir "${module}") + + set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake") + if(EXISTS "${configureFile}") + qt_feature_module_begin( + LIBRARY "${module}" + PUBLIC_FILE "qt${_arg_CONFIG_MODULE_NAME}-config.h" + PRIVATE_FILE "qt${_arg_CONFIG_MODULE_NAME}-config_p.h" + PUBLIC_DEPENDENCIES ${_arg_FEATURE_DEPENDENCIES} + PRIVATE_DEPENDENCIES ${_arg_FEATURE_DEPENDENCIES} + ) + include(${configureFile}) + qt_feature_module_end("${target}") + qt_push_features_into_parent_scope(PUBLIC_FEATURES PRIVATE_FEATURES "${target}") + + set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${_arg_CONFIG_MODULE_NAME}-config.h") + set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${_arg_CONFIG_MODULE_NAME}-config_p.h") + + if("${target}" STREQUAL "Core") + set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/global/qconfig.h") + set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/global/qconfig_p.h") + endif() + endif() + + qt_internal_library_deprecation_level(deprecation_define) + + extend_target("${target}" + SOURCES ${_arg_SOURCES} + PUBLIC_INCLUDE_DIRECTORIES + $<BUILD_INTERFACE:${include_dir}> + $<INSTALL_INTERFACE:include/${module}> + ${_arg_PUBLIC_INCLUDE_DIRECTORIES} + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include> + "${include_dir}/${PROJECT_VERSION}" + "${include_dir}/${PROJECT_VERSION}/${module}" + ${_arg_INCLUDE_DIRECTORIES} + PUBLIC_DEFINES + ${_arg_PUBLIC_DEFINES} + QT_${name_upper}_LIB + DEFINES + ${_arg_DEFINES} + QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS + QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code + QT_USE_QSTRINGBUILDER + QT_DEPRECATED_WARNINGS + QT_BUILDING_QT + QT_BUILD_${name_upper}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore + "${deprecation_define}" + PUBLIC_LIBRARIES + ${_arg_PUBLIC_LIBRARIES} + LIBRARIES + ${_arg_LIBRARIES} + ) + + ### FIXME: Can we replace headers.pri? + qt_internal_module_include_dir(include_dir "${module}") + if(NOT ${_arg_NO_MODULE_HEADERS}) + qt_read_headers_pri("${module}" "module_headers") + set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${module_headers_public}") + set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${module_headers_private}") + set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${include_dir}/${module}Depends") + endif() + + if(DEFINED module_headers_private) + qt_internal_add_linker_version_script("${target}" PRIVATE_HEADERS ${module_headers_private}) + else() + qt_internal_add_linker_version_script("${target}") + endif() + + qt_push_features_into_parent_scope(PUBLIC_FEATURES PRIVATE_FEATURES ${_arg_FEATURE_DEPENDENCIES}) + + install(TARGETS "${target}" "${target_private}" EXPORT "${versioned_module_name}Targets" + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module} + PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private + ) + + set(config_install_dir "${INSTALL_LIBDIR}/cmake/${versioned_module_name}") + install(EXPORT "${versioned_module_name}Targets" NAMESPACE Qt:: DESTINATION ${config_install_dir}) + + configure_package_config_file( + "${Qt${PROJECT_VERSION_MAJOR}_DIR}/QtModuleConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${versioned_module_name}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${versioned_module_name}ConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + set(extra_cmake_files) + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${versioned_module_name}Macros.cmake") + list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${versioned_module_name}Macros.cmake") + endif() + + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${versioned_module_name}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${versioned_module_name}ConfigVersion.cmake" + ${extra_cmake_files} + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins + # that belong to Qt. + if (GCC) + qt_internal_add_link_flags("${target}" "-Wl,--no-undefined") + endif() + + # When a public module depends on private, also make its private depend on the other's private + set(_qt_libs_private "") + foreach(it ${KNOWN_QT_MODULES}) + list(FIND _arg_LIBRARIES "Qt::${it}Private" _pos) + if(_pos GREATER -1) + list(APPEND _qt_libs_private "Qt::${it}Private") + endif() + endforeach() + + target_link_libraries("${target_private}" INTERFACE "${target}" "${_qt_libs_private}") + + qt_internal_module_include_dir(include_dir "${module}") + target_include_directories("${target_private}" INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> + $<BUILD_INTERFACE:${include_dir}/${PROJECT_VERSION}> + $<BUILD_INTERFACE:${include_dir}/${PROJECT_VERSION}/${module}> + $<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}> + $<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}/${module}> + ) +endfunction() + + +# This is the main entry point for defining Qt plugins. +# A CMake target is created with the given name. The TYPE parameter is needed to place the +# plugin into the correct plugins/ sub-directory. +function(add_qt_plugin name) + # This is a copy paste of add_qt_module with minor changes and some commented out stuff. + # FIXME !!! + set(module "${name}") + string(TOUPPER "${name}" name_upper) + + qt_parse_all_arguments(_arg "add_qt_plugin" "" "TYPE" "${__default_private_args};${__default_public_args}" ${ARGN}) + if (NOT DEFINED _arg_TYPE) + message(FATAL_ERROR "add_qt_plugin called without setting a TYPE.") + endif() + + add_library("${module}") + set_target_properties("${module}" PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_PLUGINSDIR}/${_arg_TYPE}") + set_target_properties("${module}" PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}") + + # Import global features + qt_push_features_into_parent_scope(PUBLIC_FEATURES PRIVATE_FEATURES FEATURE_PROPERTY_INFIX "GLOBAL_" Qt::Core) + + # Fetch features from dependencies and make them available to the + # caller as well as to the local scope for configure.cmake evaluation. + foreach(dep ${_arg_LIBRARIES} ${_arg_PUBLIC_LIBRARIES}) + if("${dep}" MATCHES "(Qt::.+)Private") + set(publicDep ${CMAKE_MATCH_1}) + qt_push_features_into_parent_scope(PRIVATE_FEATURES ${publicDep}) + qt_pull_features_into_current_scope(PRIVATE_FEATURES ${publicDep}) + else() + set(publicDep ${dep}) + endif() + qt_push_features_into_parent_scope(PUBLIC_FEATURES ${publicDep}) + qt_pull_features_into_current_scope(PUBLIC_FEATURES ${publicDep}) + endforeach() + + qt_internal_library_deprecation_level(deprecation_define) + + extend_target("${module}" + SOURCES ${_arg_SOURCES} + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + ${_arg_INCLUDE_DIRECTORIES} + PUBLIC_INCLUDE_DIRECTORIES ${_arg_PUBLIC_INCLUDE_DIRECTORIES} + LIBRARIES ${_arg_LIBRARIES} + PUBLIC_LIBRARIES ${_arg_PUBLIC_LIBRARIES} + DEFINES + ${_arg_DEFINES} + QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS + QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code + QT_USE_QSTRINGBUILDER + QT_DEPRECATED_WARNINGS + QT_BUILDING_QT + QT_BUILD_${name_upper}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore + "${deprecation_define}" + PUBLIC_DEFINES + QT_${name_upper}_LIB + ${_arg_PUBLIC_DEFINES} + ) + + install(TARGETS "${module}" EXPORT "${module}Targets" + LIBRARY DESTINATION ${INSTALL_PLUGINSDIR}/${_arg_TYPE} + ARCHIVE DESTINATION ${INSTALL_LIBDIR}/${_arg_TYPE} + ) + install(EXPORT "${module}Targets" NAMESPACE Qt:: DESTINATION ${INSTALL_LIBDIR}/cmake) + + ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins + # that belong to Qt. + if (GCC) + qt_internal_add_link_flags("${module}" "-Wl,--no-undefined") + endif() + + qt_internal_add_linker_version_script(${module}) +endfunction() + + +# This function creates a CMake target for a generic console or GUI binary. +# Please consider to use a more specific version target like the one created +# by add_qt_test or add_qt_tool below. +function(add_qt_executable name) + qt_parse_all_arguments(_arg "add_qt_executable" "GUI" "OUTPUT_DIRECTORY" "EXE_FLAGS;${__default_private_args}" ${ARGN}) + + if ("x${_arg_OUTPUT_DIRECTORY}" STREQUAL "x") + set(_arg_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}") + endif() + + add_executable("${name}" ${_arg_EXE_FLAGS}) + extend_target("${name}" + SOURCES ${_arg_SOURCES} + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + ${_arg_INCLUDE_DIRECTORIES} + DEFINES ${_arg_DEFINES} + LIBRARIES ${_arg_LIBRARIES} + ) + set_target_properties("${name}" PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${_arg_OUTPUT_DIRECTORY}" + WIN32_EXECUTABLE "${_arg_GUI}" + MACOSX_BUNDLE "${_arg_GUI}" + ) +endfunction() + + +# This function creates a CMake test target with the specified name for use with CTest. +function(add_qt_test name) + qt_parse_all_arguments(_arg "add_qt_test" "RUN_SERIAL" "" "${__default_private_args}" ${ARGN}) + set(_path "${CMAKE_CURRENT_BINARY_DIR}") + + add_qt_executable("${name}" + OUTPUT_DIRECTORY "${_path}" + SOURCES "${_arg_SOURCES}" + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + "${_arg_INCLUDE_DIRECTORIES}" + DEFINES "${_arg_DEFINES}" + LIBRARIES "Qt::Core;Qt::Test;${_arg_LIBRARIES}" + ) + + add_test(NAME "${name}" COMMAND "${name}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + + set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${_arg_RUN_SERIAL}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "PATH=${_path}${QT_PATH_SEPARATOR}${CMAKE_CURRENT_BINARY_DIR}${QT_PATH_SEPARATOR}$ENV{PATH}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}") +endfunction() + + +# This function creates an executable for use as helper program with tests. Some +# tests launch separate programs to test certainly input/output behavior. +function(add_qt_test_helper name) + add_qt_executable("${name}" OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ${ARGN}) +endfunction() + + +# This function is used to define a "Qt tool", such as moc, uic or rcc. +# The BOOTSTRAP option allows building it as standalone program, otherwise +# it will be linked against QtCore. +function(add_qt_tool name) + qt_parse_all_arguments(_arg "add_qt_tool" "BOOTSTRAP" "" "${__default_private_args}" ${ARGN}) + + if (_arg_BOOTSTRAP) + set(corelib Qt::Bootstrap) + else() + set(corelib Qt::Core) + endif() + + add_qt_executable("${name}" OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}" + # Do not pass sources here: They may not get processed when BOOTSTRAP is set! + INCLUDE_DIRECTORIES + ${_arg_INCLUDE_DIRECTORIES} + DEFINES ${_arg_DEFINES} + LIBRARIES ${corelib} ${_arg_LIBRARIES} + ) + target_sources("${name}" PRIVATE "${_arg_SOURCES}") + add_executable("Qt::${name}" ALIAS "${name}") + + if (NOT _arg_BOOTSTRAP) + qt_internal_process_automatic_sources("${name}" ${_arg_SOURCES}) + endif() + + install(TARGETS "${name}" EXPORT "Qt${PROJECT_VERSION_MAJOR}ToolsTargets" DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) +endfunction() + + + +function(qt_create_tracepoints name tracePointsFile) + #### TODO + string(TOLOWER "${name}" name) + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qt${name}_tracepoints_p.h" CONTENT + "#include <private/qtrace_p.h>") +endfunction() + + + +function(add_qt_resource target resourceName) + qt_parse_all_arguments(rcc "add_qt_resource" "" "PREFIX;BASE" "FILES" ${ARGN}) + + set(qrcContents "<RCC>") + if (${rcc_PREFIX}) + string(APPEND qrcContents " <qresource>\n") + else() + string(APPEND qrcContents " <qresource prefix=\"${rcc_PREFIX}\">\n") + endif() + + foreach(file ${rcc_FILES}) + get_property(alias SOURCE ${file} PROPERTY alias) + if (NOT alias) + set(alias "${file}") + endif() + ### FIXME: escape file paths to be XML conform + string(APPEND qrcContents " <file alias=\"${alias}\">${CMAKE_CURRENT_SOURCE_DIR}/${file}</file>\n") + endforeach() + + string(APPEND qrcContents " </qresource>\n</RCC>\n") + set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/${resourceName}.qrc") + file(GENERATE OUTPUT "${generatedResourceFile}" CONTENT "${qrcContents}") + + set(generatedSourceCode "${CMAKE_CURRENT_BINARY_DIR}/qrc_${resourceName}.cpp") + add_custom_command(OUTPUT "${generatedSourceCode}" + COMMAND "Qt::rcc" + ARGS --name "${resourceName}" + --output "${generatedSourceCode}" "${generatedResourceFile}" + DEPENDS ${files} + COMMENT "RCC ${resourceName}" + VERBATIM) + target_sources(${target} PRIVATE "${generatedSourceCode}") +endfunction() + +# From Qt5CoreMacros +# Function used to create the names of output files preserving relative dirs +function(qt_make_output_file infile prefix ext result) + string(LENGTH ${CMAKE_CURRENT_BINARY_DIR} _binlength) + string(LENGTH ${infile} _infileLength) + set(_checkinfile ${CMAKE_CURRENT_SOURCE_DIR}) + if(_infileLength GREATER _binlength) + string(SUBSTRING "${infile}" 0 ${_binlength} _checkinfile) + if(_checkinfile STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") + file(RELATIVE_PATH rel ${CMAKE_CURRENT_BINARY_DIR} ${infile}) + else() + file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile}) + endif() + else() + file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile}) + endif() + if(WIN32 AND rel MATCHES "^([a-zA-Z]):(.*)$") # absolute path + set(rel "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") + endif() + set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${rel}") + string(REPLACE ".." "__" _outfile "${_outfile}") + get_filename_component(outpath "${_outfile}" PATH) + get_filename_component(_outfile "${_outfile}" NAME_WE) + file(MAKE_DIRECTORY "${outpath}") + set(full_outfile "${outpath}/${prefix}${_outfile}.${ext}") + set("${result}" "${full_outfile}" PARENT_SCOPE) +endfunction() + +macro(qt_get_moc_flags _moc_flags) + set(${_moc_flags}) + get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES) + + if(CMAKE_INCLUDE_CURRENT_DIR) + list(APPEND _inc_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + foreach(_current ${_inc_DIRS}) + if("${_current}" MATCHES "\\.framework/?$") + string(REGEX REPLACE "/[^/]+\\.framework" "" framework_path "${_current}") + set(${_moc_flags} ${${_moc_flags}} "-F${framework_path}") + else() + set(${_moc_flags} ${${_moc_flags}} "-I${_current}") + endif() + endforeach() + + get_directory_property(_defines COMPILE_DEFINITIONS) + foreach(_current ${_defines}) + set(${_moc_flags} ${${_moc_flags}} "-D${_current}") + endforeach() + + if(WIN32) + set(${_moc_flags} ${${_moc_flags}} -DWIN32) + endif() + if (MSVC) + set(${_moc_flags} ${${_moc_flags}} --compiler-flavor=msvc) + endif() +endmacro() + + +# helper to set up a moc rule +function(qt_create_moc_command infile outfile moc_flags moc_options moc_target moc_depends) + # Pass the parameters in a file. Set the working directory to + # be that containing the parameters file and reference it by + # just the file name. This is necessary because the moc tool on + # MinGW builds does not seem to handle spaces in the path to the + # file given with the @ syntax. + get_filename_component(_moc_outfile_name "${outfile}" NAME) + get_filename_component(_moc_outfile_dir "${outfile}" PATH) + if(_moc_outfile_dir) + set(_moc_working_dir WORKING_DIRECTORY "${_moc_outfile_dir}") + endif() + set (_moc_parameters_file "${outfile}_parameters") + set (_moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}") + string (REPLACE ";" "\n" _moc_parameters "${_moc_parameters}") + + if(moc_target) + set(_moc_parameters_file "${_moc_parameters_file}$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>") + set(targetincludes "$<TARGET_PROPERTY:${moc_target},INCLUDE_DIRECTORIES>") + set(targetdefines "$<TARGET_PROPERTY:${moc_target},COMPILE_DEFINITIONS>") + + set(targetincludes "$<$<BOOL:${targetincludes}>:-I$<JOIN:${targetincludes},\n-I>\n>") + set(targetdefines "$<$<BOOL:${targetdefines}>:-D$<JOIN:${targetdefines},\n-D>\n>") + + file (GENERATE + OUTPUT "${_moc_parameters_file}" + CONTENT "${targetdefines}${targetincludes}${_moc_parameters}\n" + ) + + set(targetincludes) + set(targetdefines) + else() + file(WRITE ${_moc_parameters_file} "${_moc_parameters}\n") + endif() + + set(_moc_extra_parameters_file @${_moc_parameters_file}) + add_custom_command(OUTPUT "${outfile}" + COMMAND "Qt::moc" "${_moc_extra_parameters_file}" + DEPENDS "${infile}" ${moc_depends} + ${_moc_working_dir} + VERBATIM) +endfunction() + + +# helper to set up a uic rule +function(qt_create_uic_command infile _result) + # Pass the parameters in a file. Set the working directory to + # be that containing the parameters file and reference it by + # just the file name. This is necessary because the moc tool on + # MinGW builds does not seem to handle spaces in the path to the + # file given with the @ syntax. + get_filename_component(_uic_basename "${infile}" NAME_WE) + set(outfile "ui_${_uic_basename}.h") + add_custom_command(OUTPUT "${outfile}" + COMMAND "Qt::uic" "${CMAKE_CURRENT_SOURCE_DIR}/${infile}" -o "${CMAKE_CURRENT_BINARY_DIR}/${outfile}" + DEPENDS "${infile}" + COMMENT "Running UIC on ${infile}." + VERBATIM) + set(${_result} "${CMAKE_CURRENT_BINARY_DIR}/${outfile}" PARENT_SCOPE) +endfunction() + + +function(qt_generate_forwarding_headers module) + qt_parse_all_arguments(_arg "qt_generate_forwarding_headers" + "PRIVATE" "SOURCE;DESTINATION" "CLASSES" ${ARGN}) + qt_internal_module_include_dir(include_dir "${module}") + + if (NOT _arg_DESTINATION) + get_filename_component(_arg_DESTINATION "${_arg_SOURCE}" NAME) + endif() + + if (_arg_PRIVATE) + set(main_fwd "${include_dir}/${PROJECT_VERSION}/${module}/private/${_arg_DESTINATION}") + else() + set(main_fwd "${include_dir}/${_arg_DESTINATION}") + endif() + + get_filename_component(main_fwd_dir "${main_fwd}" DIRECTORY) + file(RELATIVE_PATH relpath "${main_fwd_dir}" "${CMAKE_CURRENT_BINARY_DIR}/${_arg_SOURCE}") + set(main_contents "#include \"${relpath}\"") + file(GENERATE OUTPUT "${main_fwd}" CONTENT "${main_contents}") + + foreach(class_fwd ${_arg_CLASSES}) + set(class_fwd_contents "#include \"${fwd_hdr}\"") + message("Generating forwarding header: ${class_fwd} -> ${relpath}.") + file(GENERATE OUTPUT "${include_dir}/${class_fwd}" CONTENT "${class_fwd_contents}") + endforeach() +endfunction() + + +function(add_qt_docs qdocFile) + # TODO +endfunction() |