summaryrefslogtreecommitdiffstats
path: root/cmake/QtInitProject.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtInitProject.cmake')
-rw-r--r--cmake/QtInitProject.cmake214
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}"
+)