summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaishree Vyas <Jaishree.Vyas@qt.io>2022-03-01 15:15:54 +0100
committerJoerg Bornemann <joerg.bornemann@qt.io>2022-03-23 17:02:25 +0100
commit3efb9b544b029b2ed9c78e3417cb07b8d5bf795f (patch)
tree4cac3af065d41c289a4892d7996820e4865b9a69
parentb4c591bcd5b9e1e3fcc34b282c72bd10c95c17dd (diff)
downloadqtdoc-3efb9b544b029b2ed9c78e3417cb07b8d5bf795f.tar.gz
CMake: Add building QML applications and modules
Based on the existing blog post Fixes: QTBUG-100450 Change-Id: I7dc6507e8cc219b72ab029e8f57d662d849bba96 (cherry picked from commit 95058237f9e77330b8f5b2a2ebea02490f5f23e8) Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
-rw-r--r--doc/src/cmake/cmake-manual.qdoc157
-rw-r--r--doc/src/cmake/snippets/cmake/helloworld_qtqml.cmake25
-rw-r--r--doc/src/cmake/snippets/cmake/helloworld_subdirs_qml.cmake8
3 files changed, 187 insertions, 3 deletions
diff --git a/doc/src/cmake/cmake-manual.qdoc b/doc/src/cmake/cmake-manual.qdoc
index 6c2d391b..70c535bf 100644
--- a/doc/src/cmake/cmake-manual.qdoc
+++ b/doc/src/cmake/cmake-manual.qdoc
@@ -55,6 +55,8 @@
\li \l{Adding translations}
\li \l{Further reading}
\endlist
+ \li \l {Building a QML application}
+ \li \l {Building a reusable QML module}
\li \l{Building projects on the command line}
\list
\li \l{CMake generators}
@@ -309,8 +311,8 @@
├── CMakeLists.txt
└── src
├── app
- │   ├── ...
- │   └── main.cpp
+ │ ├── ...
+ │ └── main.cpp
└── businesslogic
├── CMakeLists.txt
├── businesslogic.cpp
@@ -443,11 +445,160 @@
The official \l{CMake Tutorial} covers common build system tasks.
- The book \l{Professional CMake: A Practical Guide} provides a great
+ The book \l{Professional CMake: A Practical Guide} provides a great
introduction to the most relevant CMake features.
*/
/*!
+ \page cmake-build-qml-application.html
+ \title Building a QML application
+ \previouspage Getting started with CMake
+ \nextpage Building a reusable QML module
+
+ In \l{Building a C++ console application} we showed the
+ CMakeLists.txt file for a simple console application. We will now extend it
+ to create a QML application that uses the \l{Qt Quick} module.
+
+ This is the full project file:
+ \quotefile snippets/cmake/helloworld_qtqml.cmake
+
+ Let's walk through the changes we have made.
+ We specify \l {Building a C++ GUI application}{CMAKE_AUTOMOC},
+ \l{Building a C++ console application}{CMAKE_CXX_STANDARD},
+ and CMAKE_CXX_STANDARD_REQUIRED.
+
+ \quotefromfile snippets/cmake/helloworld_qtqml.cmake
+ \skipto CMAKE_AUTOMOC
+ \printuntil CMAKE_CXX_STANDARD_REQUIRED
+
+ In the \c{find_package} call, we replace \c{Core} with \c{Quick}. This
+ will locate the \c{Qt6Quick} module and provide the \c{Qt6::Quick}
+ targets we later link against.
+
+ \printuntil find_package(
+
+ Note that the application will still link against \c{Qt6::Core}, because
+ \c{Qt6::Quick} depends on it.
+
+ \l {qt_add_executable} creates and finalizes an application target:
+
+ \printuntil )
+
+ \l {qt_add_qml_module} passes the target of the executable, a URI, module
+ version, and a list of QML files to ensure that myapp becomes a
+ QML module. Among other things, this places the QML files into
+ \c { qrc:/${URI} } in the resource file system.
+
+ \printuntil )
+
+ First, \c qt_add_qml_module ensures that \c qmlcachegen runs. Second, it
+ creates a \c myapp_qmllint target, which runs \c qmllint on the files in
+ QML_FILES.
+
+ By adding the referenced resources, they get automatically added to
+ the application under the same root path as the QML files – also in the
+ resource file system. By keeping the path in the resource system
+ consistent with the one in the source and build directory, we ensure that
+ the image is always found, as it is resolved relative to FramedImage.qml.
+ It refers to the image in the resource file system if we load main.qml from
+ there, or to the one in the actual file system if we review it with
+ the \c qml tool.
+
+ In the \c{target_link_libraries} command, we link against \c{Qt6::Quick}
+ instead of \c{Qt6::Core}.
+
+ \printuntil target_link_libraries
+*/
+
+/*!
+ \page cmake-build-reusable-qml-module.html
+ \title Building a reusable QML module
+ \previouspage Building a QML application
+ \nextpage Building projects on the command line
+
+ The example below demonstrates how to create a library which exposes C++ to QML.
+ The directory structure for the example looks like this:
+
+ \badcode
+ ├── CMakeLists.txt
+ └── example
+ └── mylib
+ ├── CMakeLists.txt
+ ├── mytype.cpp
+ ├── mytype.h
+ \endcode
+
+ The toplevel \c CMakeLists.txt file does some basic setup, and then uses
+ \c add_subdirectory to include the one in mylib. The subdirectory structure
+ corresponds to the QML module’s URI, but with the dots replaced by
+ slashes. That’s the same logic the engine uses when it searches for a
+ module in the \l{Import Statements}{import paths}. \c mytype.h declares a
+ class and uses the
+ declarative registration macros to expose it to the engine.
+
+ In the subdirectory’s \c CMakeLists.txt we again call \c qt6_add_qml_module.
+ However, the invocation is slightly different:
+
+ \quotefromfile snippets/cmake/helloworld_subdirs_qml.cmake
+ \printuntil mytype.h
+ \skipto )
+ \printuntil )
+
+ To add C++ types, the SOURCES parameter needs to be specified. The target for
+ mylib is not created. Therefore, if the target passed to \c qt6_add_qml_module
+ does not exist, a library target is automatically created, which is needed in
+ this case.
+
+ When the project is built, in addition to the library, a QML plugin is also
+ built. The plugin's auto-generated class extends from
+ \c {QQmlEngineExtensionPlugin}.
+ The mylib library itself already contains the code to register the types
+ with the engine. However, that is only useful in cases where we can link
+ against the library. To make the module usable in a QML file loaded by the
+ \l{QML tool}, a plugin is needed that can be loaded. The
+ plugin is then responsible for actually linking against the library, and
+ ensuring that the types get registered.
+
+ Note that the automatic plugin generation is only possible if the module
+ does not do anything besides registering the types. If it needs to do
+ something more advanced like registering an image provider in
+ \c initializeEngine, you still need to manually write the plugin.
+ \l{qt6_add_qml_module} has support for this with \c NO_GENERATE_PLUGIN_SOURCE.
+
+ Also, following the directory layout convention helps tooling. That layout
+ is mirrored in the build directory. Which means that you can pass the path to
+ your build directory to the QML tool (via the -I flag), and it will find the
+ plugin.
+
+ Before concluding add a QML file to the module. In the lib subfolder,
+ add a \c Mistake.qml file
+ \code
+ import example.mylib
+
+ MyType{
+ answer: 43
+ }
+ \endcode
+
+ and adjust the \c qt6_add_qml_module call:
+
+ \quotefile snippets/cmake/helloworld_subdirs_qml.cmake
+
+ As mentioned, we made a mistake because \c answer is actually a read-only
+ property. This illustrates \c qmllint integration: CMake
+ creates a \c qmllint target, and once we run it, \c qmllint warns
+ about the issue:
+
+ \badcode
+ $> cmake --build . --target mylib_qmllint
+ ...
+ Warning: Mistake.qml:4:13: Cannot assign to read-only property answer
+ answer: 43
+ ^^
+ \endcode
+*/
+
+/*!
\page cmake-build-on-cmdline.html
\title Building projects on the command line
\previouspage Getting started with CMake
diff --git a/doc/src/cmake/snippets/cmake/helloworld_qtqml.cmake b/doc/src/cmake/snippets/cmake/helloworld_qtqml.cmake
new file mode 100644
index 00000000..5fe1c62e
--- /dev/null
+++ b/doc/src/cmake/snippets/cmake/helloworld_qtqml.cmake
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(hello VERSION 1.0 LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.2 COMPONENTS Quick Gui REQUIRED)
+
+qt_add_executable(myapp
+ main.cpp
+)
+
+qt_add_qml_module(myapp
+ URI hello
+ VERSION 1.0
+ QML_FILES
+ main.qml
+ FramedImage.qml
+ RESOURCES
+ img/world.png
+)
+
+target_link_libraries(myapp PRIVATE Qt6::Gui Qt6::Quick)
diff --git a/doc/src/cmake/snippets/cmake/helloworld_subdirs_qml.cmake b/doc/src/cmake/snippets/cmake/helloworld_subdirs_qml.cmake
new file mode 100644
index 00000000..dde6638d
--- /dev/null
+++ b/doc/src/cmake/snippets/cmake/helloworld_subdirs_qml.cmake
@@ -0,0 +1,8 @@
+qt6_add_qml_module(mylib
+ URI example.mylib
+ VERSION 1.0
+ SOURCES
+ mytype.h mytype.cpp
+ QML_FILES
+ Mistake.qml
+)