{"id":9100,"date":"2024-05-06T15:22:26","date_gmt":"2024-05-06T13:22:26","guid":{"rendered":"https:\/\/www.basyskom.de\/?p=9100"},"modified":"2024-07-17T17:56:56","modified_gmt":"2024-07-17T15:56:56","slug":"about-qml-efficiency-compilers-language-server-and-type-annotations","status":"publish","type":"post","link":"https:\/\/www.basyskom.de\/en\/about-qml-efficiency-compilers-language-server-and-type-annotations\/","title":{"rendered":"About QML Efficiency: Compilers, Language Server, and Type Annotations"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"9100\" class=\"elementor elementor-9100\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2835688 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no e-con e-parent\" data-id=\"2835688\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-50dc76c elementor-widget elementor-widget-text-editor\" data-id=\"50dc76c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The QML Language Server provides the information gathered by the QML Linter through the Language Server Protocol (LSP) to an editor of your liking. LSP is an open, JSON-RPC-based protocol that enables an editor to talk to a language server that supplies language-specific features like code completion, refactoring capabilities, and warning markers. Kindly refer to your editor\u2019s documentation on how to configure it to run the <em>qmlls<\/em> binary that is distributed alongside Qt Qml.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c9b6068 elementor-widget elementor-widget-image\" data-id=\"c9b6068\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"800\" height=\"563\" src=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-1024x720.png\" class=\"attachment-large size-large wp-image-9108\" alt=\"KDE\u2019s Kate editor illustrating some of qmlls\u2019s capabilities\" srcset=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-1024x720.png 1024w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-300x211.png 300w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-768x540.png 768w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-1536x1080.png 1536w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-2048x1440.png 2048w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-18x12.png 18w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2024\/05\/qmlls-kate-qt6-560x394.png 560w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/>\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">qmlls in action<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-eac6459 elementor-widget elementor-widget-heading\" data-id=\"eac6459\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Configuring the linter and language server<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-65c4378 elementor-widget elementor-widget-text-editor\" data-id=\"65c4378\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The build system sets up linter targets automatically. In order for the language server to find your imports, however, it also needs to be configured. It\u2019s possible to specify the \u201c-b\u201d (build directory) argument when running qmlls manually but an editor will normally just run a single instance and point it at the file being edited. Using CMake\u2019s <em>configure_file<\/em> feature we can generate the configuration file and place it in our source directory automatically. Create a <em>qmlls.ini.in<\/em> as follows:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c5a4151 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"c5a4151\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>[General]\nbuildDir=${QT_QML_OUTPUT_DIRECTORY} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a8462cf elementor-widget elementor-widget-text-editor\" data-id=\"a8462cf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tand then configure it using CMake:\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-98e79fb elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"98e79fb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>configure_file(qmlls.ini.in ${CMAKE_SOURCE_DIR}\/.qmlls.ini) <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ab7368d elementor-widget elementor-widget-text-editor\" data-id=\"ab7368d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Qt 6.7 can actually do this for you when the project is configured with <em>-DQT_QML_GENERATE_QMLLS_INI=ON<\/em>. Note that the resulting configuration file is specific to the particular build and should not be checked into version control. You might want to add it to your <em>.gitignore<\/em> file.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dce06d7 elementor-widget elementor-widget-text-editor\" data-id=\"dce06d7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>A project can likewise provide a <em>.qmllint.ini<\/em> in its source directory. This file configures which checks the linter performs and which of them should be treated as a fatal error. A default file which can then be tweaked is created by running:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6d3c44d elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"6d3c44d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-bash'>$ qmllint --write-defaults <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4e0a208 elementor-widget elementor-widget-text-editor\" data-id=\"4e0a208\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe key difference is that you add your <em>QT_QML_OUTPUT_DIRECTORY<\/em> to the <em>AdditionalQmlImportPaths<\/em> key.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a6e6292 elementor-widget elementor-widget-heading\" data-id=\"a6e6292\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Function type annotations<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf1ef2f elementor-widget elementor-widget-text-editor\" data-id=\"cf1ef2f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNow that we\u2019ve set up the QML Linter and QML Language Server, let\u2019s have a look at how we can help the QML Compiler generate more efficient code for us:\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a5c5a27 elementor-widget elementor-widget-text-editor\" data-id=\"a5c5a27\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAs you may recall, type information is key to this. It has already been possible since Qt 5.14 to annotate JavaScript functions in QML using a TypeScript-like syntax to improve IDE auto-completion and improve interoperation between C++ and QML. Doing so becomes even more important in Qt 6 where it\u2019s also possible to explicitly specify \u201cvoid\u201d as a return type. In addition to value types, QML type names can also be used, such as \u201cRectangle\u201d.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c3f8400 elementor-widget elementor-widget-text-editor\" data-id=\"c3f8400\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Consider a stop watch and a simple function to format the elapsed time display:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5f1bee5 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"5f1bee5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-javascript'>function formatElapsedTime(time) {\n    \/\/: Elapsed seconds\n    return qsTr(&quot;%L1 s&quot;).arg(time \/ 1000);\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8c29b4b elementor-widget elementor-widget-text-editor\" data-id=\"8c29b4b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tThe QML engine has no idea what type of arguments the function takes and what it returns until it actually executes it. The only thing it could perhaps infer by just looking at it is that it returns a string. Let\u2019s fix that!\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3b3280a elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"3b3280a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-typescript'>function formatElapsedTime(time : int) : string {\n    \/\/: Elapsed seconds\n    return qsTr(&quot;%L1 s&quot;).arg(time \/ 1000);\n} <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-844a9e3 elementor-widget elementor-widget-text-editor\" data-id=\"844a9e3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Despite the type annotations, it\u2019s not possible to overload JavaScript functions: there can only be one \u201cformatElapsedTime\u201d function in our component. Calling the function is also still possible with unexpected types: while a function taking a <em>Rectangle<\/em> will throw a <em>TypeError<\/em> when called with a <em>Button<\/em> (unless <em>Button<\/em> implements <em>Rectangle<\/em>, of course), the <em>formatElapsedTime<\/em> function will happily accept a <em>string<\/em> for \u201ctime\u201d and then try to interpret it as an <em>int<\/em>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e656cf0 elementor-widget elementor-widget-text-editor\" data-id=\"e656cf0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Additionally, an annotated function interfaces better with C++. Rather than having to wrap its arguments in <em>QVariant<\/em>, the actual types can be used on the C++ side as well:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-335305d elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"335305d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>QString text;\nQMetaObject::invokeMethod(timerPage, &quot;formatElapsedTime&quot;, qReturnArg(text), 1200);\nqDebug() &lt;&lt; text; \/\/ &quot;1.2 s&quot; <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f2891de elementor-widget elementor-widget-text-editor\" data-id=\"f2891de\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Simple as that. Also note the new <em>invokeMethod<\/em> syntax introduced in Qt 6.5, no more <em>Q_ARG<\/em>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cb57b51 elementor-widget elementor-widget-heading\" data-id=\"cb57b51\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">QML compiler magic<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-07572ef elementor-widget elementor-widget-text-editor\" data-id=\"07572ef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>If we now look at the magic <em>TimerPage_qml.cpp<\/em> generated by <em>qmlcachegen<\/em> hidden in our build directory, we can suddenly find an actual C++ function at the end of the file:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9a94cb3 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"9a94cb3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-cpp'>\/\/ formatElapsedTime at line 22, column 5\nQString r8_0;\ndouble r6_0 = double((*static_cast&lt;int*&gt;(argumentsPtr[0])));\ndouble r12_0;\ndouble r2_1;\ndouble r11_0;\nQString r2_0;\nQString r10_0;\nr2_0 = QStringLiteral(&quot;%L1 s&quot;);\nr10_0 = std::move(r2_0);\naotContext-&gt;captureTranslation();\nr2_0 = QCoreApplication::translate(aotContext-&gt;translationContext().toUtf8().constData(), std::move(r10_0).toUtf8().constData(), &quot;&quot;, -1);\nr8_0 = std::move(r2_0);\nr12_0 = r6_0;\nr2_1 = double(1000);\nr2_1 = (r12_0 \/ r2_1);\nr11_0 = r2_1;\nr2_0 = std::move(r8_0).arg(r11_0);\nreturn r2_0; <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f38840e elementor-widget elementor-widget-text-editor\" data-id=\"f38840e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>It even transformed the <em>qsTr<\/em> statement into a proper call to <em>QCoreApplication::translate<\/em>. How cool is that?!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf20419 elementor-widget elementor-widget-text-editor\" data-id=\"cf20419\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Of course you cannot be expected to read obscure C++ files that still mostly consist of QML byte code. Nevertheless, it would be useful to know in advance if a QML expression is sub-optimal. Running <em>qmlcachegen<\/em> in verbose mode provides a lot of diagnostics on why it did or didn\u2019t decide to generate C++ code:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-018e992 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"018e992\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>set_target_properties(myhmi PROPERTIES\n    QT_QMLCACHEGEN_ARGUMENTS &quot;&ndash;-verbose&quot;\n) <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-63ca64c elementor-widget elementor-widget-text-editor\" data-id=\"63ca64c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tIn the above example the relevant warning is:\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f0c9c43 elementor-widget elementor-widget-elementor-syntax-highlighter\" data-id=\"f0c9c43\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"elementor-syntax-highlighter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre><code class='language-solid'>Warning: TimerPage.qml:20:5: Functions without type annotations won&#039;t be compiled [compiler]\nfunction formatElapsedTime(time) {\n^^^^^^^^^ <\/code><\/pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https:\/\/www.basyskom.de\/wp-content\/plugins\/syntax-highlighter-for-elementor\/assets\/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-280859d elementor-widget elementor-widget-text-editor\" data-id=\"280859d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Unfortunately, it cannot deal with \u201coptional imports\u201d yet that are used by QtQuick.Controls. After all, they dynamically load a style appropriate for the given platform. This also means that it\u2019s not advisable to generally build the project verbose like this since you will just drown in warnings. Instead, you need to import the relevant style yourself, such as <em>QtQuick.Controls.Windows<\/em> in order to make full use of the QML Compiler. This might be a valid option for an embedded application but not really for a desktop application that tries to actually fit into its environment.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5f34f2c elementor-widget elementor-widget-heading\" data-id=\"5f34f2c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Conclusion<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-084a128 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no e-con e-parent\" data-id=\"084a128\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-79b789f elementor-widget elementor-widget-text-editor\" data-id=\"79b789f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>We have now seen QML compiler magic in action, and I hope you enjoyed this peek under the hood of what makes QML work. With QML modules and type annotations we unlock a wealth of useful tools that make our applications faster to develop, more reliable, and easier to debug. We can probably all agree that making use of modern QML tooling will pay off in the long run.<\/p><div>\u00a0<\/div><div><strong>Further reading:<\/strong><br \/><br \/><\/div><ul><li><a href=\"https:\/\/doc.qt.io\/qt-6\/qtqml-tooling-qmlls.html\" target=\"_blank\" rel=\"noopener\">QML Language Server Reference<\/a><\/li><li><a href=\"https:\/\/doc.qt.io\/qt-6\/qt-add-qml-module.html#caching-compiled-qml-sources\" target=\"_blank\" rel=\"noopener\">Caching compiled QML sources<\/a><\/li><li><a href=\"https:\/\/doc.qt.io\/qt-6\/qtqml-javascript-hostenvironment.html#type-annotations-and-assertions\" target=\"_blank\" rel=\"noopener\">Type annotations and assertions<\/a><\/li><\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>In our last post we had a look at how to set up QML Modules and how we can benefit from the QML Linter. Today we\u2019re going to set up the QML Language Server to get an IDE-like experience in an editor of our choice. We\u2019ll also help the the QML Compiler generate more efficient code.<\/p>","protected":false},"author":23,"featured_media":4011,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1,2,8],"tags":[126,15],"class_list":["post-9100","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-allgemein","category-blog","category-qt","tag-qml","tag-qt"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/9100","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/users\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/comments?post=9100"}],"version-history":[{"count":44,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/9100\/revisions"}],"predecessor-version":[{"id":10735,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/9100\/revisions\/10735"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media\/4011"}],"wp:attachment":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media?parent=9100"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/categories?post=9100"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/tags?post=9100"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}