Add simple project generation based on existing source files
Introduce the qt-cmake-create script. The script generates the simple CMakeLists.txt based on the source files located in the current or specified directory. The initial version can generate a CMake code for the following file types: - .c .cc .cpp .cxx .h .hh .hxx .hpp - generates the qt_add_executable call with prerequisites. - .qml .js .mjs - generates the qt_add_qml_module call with prerequisites. - .ui - adds the found ui files to the existing executable. Requires C++ files be present in the directory too. - .qrc - generates the qt_add_resources call and adds the resources to the existing executable. Requires C++ files be present in the directory too. - .proto - generates qt_add_protobuf call with prerequisites. The QtInitProject.cmake script contains the 'handle_type' function that allows extending the script capabilities and establish simple relation chains between the file types. Note: The initial implementation doesn't deal with sub-directories, so all files from sub-directories will be added to and handled in the top-level CMakeLists.txt file. This can be extended by user request. Task-number: QTBUG-104388 Change-Id: I5abd9e07da109e867ff95986572ed2bf02ef9d3d Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
parent
52150469a8
commit
214c3a033a
18
bin/qt-cmake-create.bat.in
Normal file
18
bin/qt-cmake-create.bat.in
Normal file
@ -0,0 +1,18 @@
|
||||
@echo off
|
||||
:: The directory of this script is the expanded absolute path of the "$qt_prefix/bin" directory.
|
||||
set script_dir_path=%~dp0
|
||||
|
||||
:: Try to use original cmake, otherwise to make it relocatable, use any cmake found in PATH.
|
||||
set cmake_path=@CMAKE_COMMAND@
|
||||
if not exist "%cmake_path%" set cmake_path=cmake
|
||||
|
||||
if NOT "%~2" == "" goto :showhelp
|
||||
if NOT "%~1" == "" (set PROJECT_DIR=%~1) else (set PROJECT_DIR=%cd%)
|
||||
|
||||
"%cmake_path%" -DPROJECT_DIR="%PROJECT_DIR%" -P "%script_dir_path%\@__GlobalConfig_relative_path_from_bin_dir_to_cmake_config_dir@\QtInitProject.cmake"
|
||||
exit /b %errorlevel%
|
||||
|
||||
:showhelp
|
||||
echo Usage
|
||||
echo. qt-cmake-create <path/to/project>
|
||||
exit /b 1
|
29
bin/qt-cmake-create.in
Executable file
29
bin/qt-cmake-create.in
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
HELP_MESSAGE="Usage
|
||||
qt-cmake-create <path/to/project>"
|
||||
|
||||
# The directory of this script is the expanded absolute path of the "$qt_prefix/bin" directory.
|
||||
script_dir_path=`dirname $0`
|
||||
script_dir_path=`(cd "$script_dir_path"; /bin/pwd)`
|
||||
|
||||
# Try to use original cmake, otherwise to make it relocatable, use any cmake found in PATH.
|
||||
original_cmake_path="@CMAKE_COMMAND@"
|
||||
cmake_path=$original_cmake_path
|
||||
if ! test -f "$cmake_path"; then
|
||||
cmake_path="cmake"
|
||||
fi
|
||||
|
||||
if [ "$#" -gt 1 ]; then
|
||||
echo "Invalid number of arguments"
|
||||
echo "$HELP_MESSAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
PROJECT_DIR=$1
|
||||
else
|
||||
PROJECT_DIR=$PWD
|
||||
fi
|
||||
exec "$cmake_path" -DPROJECT_DIR="$PROJECT_DIR" -P \
|
||||
"$script_dir_path/@__GlobalConfig_relative_path_from_bin_dir_to_cmake_config_dir@/QtInitProject.cmake"
|
@ -330,6 +330,7 @@ set(__public_cmake_helpers
|
||||
cmake/QtCopyFileIfDifferent.cmake
|
||||
cmake/QtFeature.cmake
|
||||
cmake/QtFeatureCommon.cmake
|
||||
cmake/QtInitProject.cmake
|
||||
cmake/QtPublicAppleHelpers.cmake
|
||||
cmake/QtPublicCMakeHelpers.cmake
|
||||
cmake/QtPublicCMakeVersionHelpers.cmake
|
||||
|
214
cmake/QtInitProject.cmake
Normal file
214
cmake/QtInitProject.cmake
Normal file
@ -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
|
||||
AUTO_RESOURCE_PREFIX
|
||||
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}"
|
||||
)
|
@ -39,6 +39,20 @@ function(qt_internal_create_wrapper_scripts)
|
||||
DESTINATION "${INSTALL_BINDIR}")
|
||||
endif()
|
||||
|
||||
if(generate_unix)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-create.in"
|
||||
"${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create" @ONLY
|
||||
NEWLINE_STYLE LF)
|
||||
qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create"
|
||||
DESTINATION "${INSTALL_BINDIR}")
|
||||
endif()
|
||||
if(generate_non_unix)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-create.bat.in"
|
||||
"${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create.bat" @ONLY
|
||||
NEWLINE_STYLE CRLF)
|
||||
qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create.bat"
|
||||
DESTINATION "${INSTALL_BINDIR}")
|
||||
endif()
|
||||
# Provide a private convenience wrapper with options which should not be propagated via the
|
||||
# public qt-cmake wrapper e.g. CMAKE_GENERATOR.
|
||||
# These options can not be set in a toolchain file, but only on the command line.
|
||||
|
@ -313,3 +313,16 @@ $ cd some/empty/directory
|
||||
$ ~/Qt/6.0.0/bin/qt-cmake-standalone-test ~/source/of/qtbase/test/auto/corelib/io/qprocess
|
||||
$ cmake --build .
|
||||
```
|
||||
|
||||
## qt-cmake-create
|
||||
|
||||
Generates a simple CMakeLists.txt based on source files in specified project directory.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
$ cd some/source/directory/
|
||||
$ qt-cmake-create
|
||||
$ qt-cmake -S . -B /build/directory
|
||||
$ cmake --build /build/directory
|
||||
```
|
||||
|
@ -11,6 +11,7 @@ if(NOT ANDROID AND NOT IOS)
|
||||
endif()
|
||||
add_subdirectory(moc)
|
||||
add_subdirectory(rcc)
|
||||
add_subdirectory(qt_cmake_create)
|
||||
endif()
|
||||
# QTBUG-88538 # special case
|
||||
if(TARGET Qt::Widgets AND NOT ANDROID AND NOT IOS)
|
||||
|
14
tests/auto/tools/qt_cmake_create/CMakeLists.txt
Normal file
14
tests/auto/tools/qt_cmake_create/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Collect test data
|
||||
file(GLOB_RECURSE test_data_glob
|
||||
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
testdata/*)
|
||||
list(APPEND test_data ${test_data_glob})
|
||||
|
||||
qt_internal_add_test(tst_qt_cmake_create
|
||||
SOURCES
|
||||
tst_qt_cmake_create.cpp
|
||||
TESTDATA ${test_data}
|
||||
)
|
14
tests/auto/tools/qt_cmake_create/testdata/cpp_project/CMakeLists.txt.expected
vendored
Normal file
14
tests/auto/tools/qt_cmake_create/testdata/cpp_project/CMakeLists.txt.expected
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(cpp_project LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(cpp_project
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(cpp_project
|
||||
PRIVATE
|
||||
Qt::Core
|
||||
)
|
7
tests/auto/tools/qt_cmake_create/testdata/cpp_project/main.cpp
vendored
Normal file
7
tests/auto/tools/qt_cmake_create/testdata/cpp_project/main.cpp
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char *[])
|
||||
{
|
||||
std::cout << "Now I have CMakeLists.txt. Thanks!" << std::endl;
|
||||
return 0;
|
||||
}
|
17
tests/auto/tools/qt_cmake_create/testdata/proto_project/CMakeLists.txt.expected
vendored
Normal file
17
tests/auto/tools/qt_cmake_create/testdata/proto_project/CMakeLists.txt.expected
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(proto_project LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Protobuf Grpc)
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_protobuf(proto_project
|
||||
GENERATE_PACKAGE_SUBFOLDERS
|
||||
PROTO_FILES
|
||||
test.proto
|
||||
)
|
||||
|
||||
target_link_libraries(proto_project
|
||||
PRIVATE
|
||||
Qt::Protobuf
|
||||
Qt::Grpc
|
||||
)
|
5
tests/auto/tools/qt_cmake_create/testdata/proto_project/test.proto
vendored
Normal file
5
tests/auto/tools/qt_cmake_create/testdata/proto_project/test.proto
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package test;
|
||||
message Noop {
|
||||
}
|
27
tests/auto/tools/qt_cmake_create/testdata/qml_project/CMakeLists.txt.expected
vendored
Normal file
27
tests/auto/tools/qt_cmake_create/testdata/qml_project/CMakeLists.txt.expected
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(qml_project LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Gui Qml Quick Core)
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(qml_project
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(qml_project
|
||||
URI qml_project
|
||||
OUTPUT_DIRECTORY qml
|
||||
VERSION 1.0
|
||||
AUTO_RESOURCE_PREFIX
|
||||
QML_FILES
|
||||
TestComponent.qml
|
||||
main.qml
|
||||
)
|
||||
|
||||
target_link_libraries(qml_project
|
||||
PRIVATE
|
||||
Qt::Gui
|
||||
Qt::Qml
|
||||
Qt::Quick
|
||||
Qt::Core
|
||||
)
|
4
tests/auto/tools/qt_cmake_create/testdata/qml_project/TestComponent.qml
vendored
Normal file
4
tests/auto/tools/qt_cmake_create/testdata/qml_project/TestComponent.qml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
}
|
18
tests/auto/tools/qt_cmake_create/testdata/qml_project/main.cpp
vendored
Normal file
18
tests/auto/tools/qt_cmake_create/testdata/qml_project/main.cpp
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
const QUrl url(QStringLiteral("qrc:/qt/qml/qml_project/main.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
16
tests/auto/tools/qt_cmake_create/testdata/qml_project/main.qml
vendored
Normal file
16
tests/auto/tools/qt_cmake_create/testdata/qml_project/main.qml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
|
||||
Window {
|
||||
width: 640
|
||||
height: 480
|
||||
visible: true
|
||||
title: "Hello World"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 16
|
||||
text: "Now I have CMakeLists.txt. Thanks!"
|
||||
}
|
||||
TestComponent {
|
||||
}
|
||||
}
|
20
tests/auto/tools/qt_cmake_create/testdata/qrc_project/CMakeLists.txt.expected
vendored
Normal file
20
tests/auto/tools/qt_cmake_create/testdata/qrc_project/CMakeLists.txt.expected
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(qrc_project LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(qrc_project
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_resources(qrc_project_resources test.qrc)
|
||||
target_sources(qrc_project
|
||||
PRIVATE
|
||||
${qrc_project_resources}
|
||||
)
|
||||
|
||||
target_link_libraries(qrc_project
|
||||
PRIVATE
|
||||
Qt::Core
|
||||
)
|
13
tests/auto/tools/qt_cmake_create/testdata/qrc_project/main.cpp
vendored
Normal file
13
tests/auto/tools/qt_cmake_create/testdata/qrc_project/main.cpp
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
QFile file(":/test.txt");
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
return 1;
|
||||
|
||||
QString data = QString::fromUtf8(file.readAll());
|
||||
qDebug() << data;
|
||||
return 0;
|
||||
}
|
5
tests/auto/tools/qt_cmake_create/testdata/qrc_project/test.qrc
vendored
Normal file
5
tests/auto/tools/qt_cmake_create/testdata/qrc_project/test.qrc
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>test.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
1
tests/auto/tools/qt_cmake_create/testdata/qrc_project/test.txt
vendored
Normal file
1
tests/auto/tools/qt_cmake_create/testdata/qrc_project/test.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
Now I have CMakeLists.txt. Thanks!
|
32
tests/auto/tools/qt_cmake_create/testdata/ui_only_project/widget.ui
vendored
Normal file
32
tests/auto/tools/qt_cmake_create/testdata/ui_only_project/widget.ui
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget</class>
|
||||
<widget class="QWidget" name="Widget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Widget</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>6</y>
|
||||
<width>781</width>
|
||||
<height>581</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Now I have CMakeLists.txt. Thanks!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
23
tests/auto/tools/qt_cmake_create/testdata/ui_project/CMakeLists.txt.expected
vendored
Normal file
23
tests/auto/tools/qt_cmake_create/testdata/ui_project/CMakeLists.txt.expected
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(ui_project LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(ui_project
|
||||
main.cpp
|
||||
widget.cpp
|
||||
widget.h
|
||||
)
|
||||
|
||||
target_sources(ui_project
|
||||
PRIVATE
|
||||
widget.ui
|
||||
)
|
||||
|
||||
target_link_libraries(ui_project
|
||||
PRIVATE
|
||||
Qt::Core
|
||||
Qt::Gui
|
||||
Qt::Widgets
|
||||
)
|
11
tests/auto/tools/qt_cmake_create/testdata/ui_project/main.cpp
vendored
Normal file
11
tests/auto/tools/qt_cmake_create/testdata/ui_project/main.cpp
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#include "widget.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
Widget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
15
tests/auto/tools/qt_cmake_create/testdata/ui_project/widget.cpp
vendored
Normal file
15
tests/auto/tools/qt_cmake_create/testdata/ui_project/widget.cpp
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#include "widget.h"
|
||||
#include "ui_widget.h"
|
||||
|
||||
Widget::Widget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::Widget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
21
tests/auto/tools/qt_cmake_create/testdata/ui_project/widget.h
vendored
Normal file
21
tests/auto/tools/qt_cmake_create/testdata/ui_project/widget.h
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef WIDGET_H
|
||||
#define WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class Widget; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Widget(QWidget *parent = nullptr);
|
||||
~Widget();
|
||||
|
||||
private:
|
||||
Ui::Widget *ui;
|
||||
};
|
||||
#endif // WIDGET_H
|
32
tests/auto/tools/qt_cmake_create/testdata/ui_project/widget.ui
vendored
Normal file
32
tests/auto/tools/qt_cmake_create/testdata/ui_project/widget.ui
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget</class>
|
||||
<widget class="QWidget" name="Widget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Widget</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>6</y>
|
||||
<width>781</width>
|
||||
<height>581</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Now I have CMakeLists.txt. Thanks!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
157
tests/auto/tools/qt_cmake_create/tst_qt_cmake_create.cpp
Normal file
157
tests/auto/tools/qt_cmake_create/tst_qt_cmake_create.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QtTest>
|
||||
|
||||
#include <QLibraryInfo>
|
||||
#include <QLatin1StringView>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include <array>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
class tst_qt_cmake_create : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_qt_cmake_create();
|
||||
|
||||
private slots:
|
||||
void init();
|
||||
void initTestCase();
|
||||
void generatingCMakeLists_data();
|
||||
void generatingCMakeLists();
|
||||
|
||||
private:
|
||||
QString m_testWorkDir;
|
||||
QString m_shell;
|
||||
QString m_cmd;
|
||||
};
|
||||
|
||||
tst_qt_cmake_create::tst_qt_cmake_create() : m_testWorkDir(qApp->applicationDirPath()) { }
|
||||
|
||||
void tst_qt_cmake_create::initTestCase()
|
||||
{
|
||||
QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
m_shell = QString("cmd.exe");
|
||||
m_cmd = QString("%1/qt-cmake-create.bat").arg(binpath);
|
||||
#else
|
||||
m_shell = QString("/bin/sh");
|
||||
m_cmd = QString("%1/qt-cmake-create").arg(binpath);
|
||||
QVERIFY(QFile::exists(m_shell));
|
||||
#endif
|
||||
|
||||
QVERIFY(QFile::exists(m_cmd));
|
||||
}
|
||||
|
||||
void tst_qt_cmake_create::init()
|
||||
{
|
||||
QFETCH(QString, projectDirPath);
|
||||
QDir workDir(m_testWorkDir);
|
||||
QString fullProjectPath = m_testWorkDir + '/' + projectDirPath;
|
||||
if (workDir.exists(fullProjectPath)) {
|
||||
QDir projectDir(projectDirPath);
|
||||
projectDir.removeRecursively();
|
||||
}
|
||||
workDir.mkdir(projectDirPath);
|
||||
auto testDataPath = QFINDTESTDATA("testdata"_L1 + '/' + projectDirPath);
|
||||
QVERIFY(QFile::exists(testDataPath));
|
||||
|
||||
for (const auto &fileInfo : QDir(testDataPath).entryInfoList(QDir::Files)) {
|
||||
QVERIFY(QFile::copy(fileInfo.absoluteFilePath(),
|
||||
fullProjectPath + '/' + fileInfo.fileName()));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qt_cmake_create::generatingCMakeLists_data()
|
||||
{
|
||||
QTest::addColumn<QString>("projectDirPath");
|
||||
QTest::addColumn<bool>("expectPass");
|
||||
QTest::addColumn<QString>("workDir");
|
||||
|
||||
const std::array<QLatin1StringView, 5> expectPass = {
|
||||
"cpp"_L1, "proto"_L1, "qml"_L1, "qrc"_L1, "ui"_L1,
|
||||
};
|
||||
|
||||
const std::array<QString, 5> workDirs = {
|
||||
m_testWorkDir, ""_L1, m_testWorkDir, ""_L1, m_testWorkDir,
|
||||
};
|
||||
|
||||
static_assert(expectPass.size() == workDirs.size());
|
||||
|
||||
const QLatin1StringView expectFail[] = {
|
||||
"ui_only"_L1,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < expectPass.size(); ++i) {
|
||||
const auto type = expectPass.at(i);
|
||||
QTest::addRow("tst_qt_cmake_create_%s", type.data())
|
||||
<< QString("%1_project").arg(type) << true << workDirs.at(i);
|
||||
}
|
||||
|
||||
for (const auto type : expectFail) {
|
||||
QTest::addRow("tst_qt_cmake_create_%s", type.data())
|
||||
<< QString("%1_project").arg(type) << false << QString();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qt_cmake_create::generatingCMakeLists()
|
||||
{
|
||||
QFETCH(QString, projectDirPath);
|
||||
QFETCH(bool, expectPass);
|
||||
QFETCH(QString, workDir);
|
||||
|
||||
QString fullProjectPath = m_testWorkDir + '/' + projectDirPath;
|
||||
QProcess command;
|
||||
QStringList arguments = {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
"/C"_L1,
|
||||
#endif
|
||||
m_cmd
|
||||
};
|
||||
|
||||
QString workingDirectory = fullProjectPath;
|
||||
if (!workDir.isEmpty()) {
|
||||
workingDirectory = workDir;
|
||||
arguments.append(fullProjectPath);
|
||||
}
|
||||
command.setProgram(m_shell);
|
||||
command.setArguments(arguments);
|
||||
command.setWorkingDirectory(workingDirectory);
|
||||
|
||||
command.start();
|
||||
QVERIFY(command.waitForFinished());
|
||||
QCOMPARE(command.exitCode() == 0, expectPass);
|
||||
|
||||
QFile actualFile = QFile(fullProjectPath + '/' + "CMakeLists.txt"_L1);
|
||||
|
||||
// Skip the rest if we expect that qt-cmake-create should exit with error
|
||||
if (!expectPass) {
|
||||
QVERIFY(!actualFile.exists());
|
||||
return;
|
||||
}
|
||||
|
||||
QFile expectedFile = QFile(fullProjectPath + '/' + "CMakeLists.txt.expected"_L1);
|
||||
QVERIFY(actualFile.open(QFile::ReadOnly));
|
||||
QVERIFY(expectedFile.open(QFile::ReadOnly));
|
||||
|
||||
auto actualData = actualFile.readAll();
|
||||
actualData.replace(QByteArrayView("\r\n"), QByteArrayView("\n"));
|
||||
auto expectedData = expectedFile.readAll();
|
||||
expectedData.replace(QByteArrayView("\r\n"), QByteArrayView("\n"));
|
||||
|
||||
static auto hash = [](const QByteArray &data) {
|
||||
return QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
|
||||
};
|
||||
QCOMPARE_EQ(hash(actualData), hash(expectedData));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qt_cmake_create)
|
||||
#include "tst_qt_cmake_create.moc"
|
Loading…
Reference in New Issue
Block a user