diff options
Diffstat (limited to 'cmake/QtInitProject.cmake')
-rw-r--r-- | cmake/QtInitProject.cmake | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/cmake/QtInitProject.cmake b/cmake/QtInitProject.cmake new file mode 100644 index 0000000000..a42f59f5c8 --- /dev/null +++ b/cmake/QtInitProject.cmake @@ -0,0 +1,214 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause +cmake_minimum_required(VERSION 3.16) + +if(NOT PROJECT_DIR) + set(PROJECT_DIR "${CMAKE_SOURCE_DIR}") +endif() + +get_filename_component(project_name "${PROJECT_DIR}" NAME) + +get_filename_component(project_abs_dir "${PROJECT_DIR}" ABSOLUTE) +if(NOT IS_DIRECTORY "${project_abs_dir}") + message(FATAL_ERROR "Unable to scan ${project_abs_dir}. The directory doesn't exist.") +endif() + +set(known_extensions "") +set(types "") + +# The function allows extending the capabilities of this script and establishes simple relation +# chains between the file types. +# Option Arguments: +# EXPERIMENTAL +# Marks that the support of the following files is experimental and the required Qt modules +# are in Technical preview state. +# DEPRECATED +# Marks that the support of the following files will be discontinued soon and the required +# Qt modules are deprecated. +# One-value Arguments: +# TEMPLATE +# The CMake code template. Use the '@files@' string for the files substitution. +# Multi-value Arguments: +# EXTENSIONS +# List of the file extensions treated as this source 'type'. +# MODULES +# List of Qt modules required for these file types. +# DEPENDS +# The prerequisite source 'type' needed by this source 'type' +macro(handle_type type) + cmake_parse_arguments(arg + "EXPERIMENTAL;DEPRECATED" + "TEMPLATE" + "EXTENSIONS;MODULES;DEPENDS" + ${ARGN} + ) + + if(NOT arg_EXTENSIONS) + message(FATAL_ERROR "Unexpected call handle_type of with no EXTENSIONS specified." + " This is the Qt issue, please report a bug at https://bugreports.qt.io.") + endif() + set(unique_extensions_subset "${known_extensions}") + list(REMOVE_ITEM unique_extensions_subset ${arg_EXTENSIONS}) + if(NOT "${known_extensions}" STREQUAL "${unique_extensions_subset}") + message(FATAL_ERROR "${type} contains duplicated extensions, this is not supported." + " This is the Qt issue, please report a bug at https://bugreports.qt.io.") + endif() + set(${type}_file_extensions "${arg_EXTENSIONS}") + + if(NOT arg_TEMPLATE) + message(FATAL_ERROR "Unexpected call handle_type of with no TEMPLATE specified." + " This is the Qt issue, please report a bug at https://bugreports.qt.io.") + endif() + set(${type}_template "${arg_TEMPLATE}") + + if(arg_MODULES) + set(${type}_required_modules "${arg_MODULES}") + endif() + + list(APPEND types ${type}) + + if(arg_EXPERIMENTAL) + set(${type}_is_experimental TRUE) + else() + set(${type}_is_experimental FALSE) + endif() + + if(arg_DEPRECATED) + set(${type}_is_deprecated TRUE) + else() + set(${type}_is_deprecated FALSE) + endif() + + if(arg_DEPENDS) + set(${type}_dependencies ${arg_DEPENDS}) + endif() +endmacro() + +handle_type(cpp EXTENSIONS .c .cc .cpp .cxx .h .hh .hxx .hpp MODULES Core TEMPLATE +"\n\nqt_add_executable(${project_name} + @files@ +)" +) + +handle_type(qml EXTENSIONS .qml .js .mjs MODULES Gui Qml Quick TEMPLATE +"\n\nqt_add_qml_module(${project_name} + URI ${project_name} + OUTPUT_DIRECTORY qml + VERSION 1.0 + RESOURCE_PREFIX /qt/qml + QML_FILES + @files@ +)" +) + +handle_type(ui EXTENSIONS .ui MODULES Gui Widgets DEPENDS cpp TEMPLATE +"\n\ntarget_sources(${project_name} + PRIVATE + @files@ +)" +) + +handle_type(qrc EXTENSIONS .qrc DEPENDS cpp TEMPLATE +"\n\nqt_add_resources(${project_name}_resources @files@) +target_sources(${project_name} + PRIVATE + \\\${${project_name}_resources} +)" +) + +handle_type(protobuf EXPERIMENTAL EXTENSIONS .proto MODULES Protobuf Grpc TEMPLATE +"\n\nqt_add_protobuf(${project_name} + GENERATE_PACKAGE_SUBFOLDERS + PROTO_FILES + @files@ +)" +) + +set(extra_packages "") +file(GLOB_RECURSE files RELATIVE "${project_abs_dir}" "${project_abs_dir}/*") +foreach(f IN LISTS files) + get_filename_component(file_extension "${f}" LAST_EXT) + string(TOLOWER "${file_extension}" file_extension) + + foreach(type IN LISTS types) + if(file_extension IN_LIST ${type}_file_extensions) + list(APPEND ${type}_sources "${f}") + list(APPEND packages ${${type}_required_modules}) + if(${type}_is_experimental) + message("We found files with the following extensions in your directory:" + " ${${type}_file_extensions}\n" + "Note that the modules ${${type}_required_modules} are" + " in the technical preview state.") + endif() + if(${type}_is_deprecated) + message("We found files with the following extensions in your directory:" + " ${${type}_file_extensions}\n" + "Note that the modules ${${type}_required_modules} are deprecated.") + endif() + break() + endif() + endforeach() +endforeach() + +if(packages) + list(REMOVE_DUPLICATES packages) + list(JOIN packages " " packages_string) + list(JOIN packages "\n Qt::" deps_string) + set(deps_string "Qt::${deps_string}") +endif() + +set(content +"cmake_minimum_required(VERSION 3.16) +project(${project_name} LANGUAGES CXX) + +find_package(Qt6 REQUIRED COMPONENTS ${packages_string}) +qt_standard_project_setup()" +) + +set(has_useful_sources FALSE) +foreach(type IN LISTS types) + if(${type}_sources) + set(skip FALSE) + foreach(dep IN LISTS ${type}_dependencies) + if(NOT ${dep}_sources) + set(skip TRUE) + message("Sources of type ${${type}_file_extensions} cannot live in the project" + " without ${${dep}_file_extensions} files. Skipping.") + break() + endif() + endforeach() + if(skip) + continue() + endif() + + set(has_useful_sources TRUE) + string(REGEX MATCH "( +)@files@" unused "${${type}_template}") + list(JOIN ${type}_sources "\n${CMAKE_MATCH_1}" ${type}_sources) + string(REPLACE "@files@" "${${type}_sources}" ${type}_content + "${${type}_template}") + string(APPEND content "${${type}_content}") + endif() +endforeach() + +string(APPEND content "\n\ntarget_link_libraries(${project_name} + PRIVATE + ${deps_string} +)\n" +) + +if(EXISTS "${project_abs_dir}/CMakeLists.txt") + message(FATAL_ERROR "Project is already initialized in current directory." + " Please remove CMakeLists.txt if you want to regenerate the project.") +endif() + +if(NOT has_useful_sources) + message(FATAL_ERROR "Could not find any files to generate the project.") +endif() +file(WRITE "${project_abs_dir}/CMakeLists.txt" "${content}") + +message("The project file is successfully generated. To build the project run:" + "\nmkdir build" + "\ncd build" + "\nqt-cmake ${project_abs_dir}" + "\ncmake --build ${project_abs_dir}" +) |