# 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}" )