Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-137199

Minimize discrepancies in QML import paths between different QML tools, out-of-the-box

    XMLWordPrintable

Details

    Description

      Background
      Based on many support requests and forum posts, a common cry for help is, "My project obviously runs just fine... so why does Qt Creator say that it can't find my imports?!" Furthermore, those messages displayed by the IDE can differ between different QML tools. It's really not obvious to people why this is.

       

      Case Study
      The attached project contains a variety of "non-recommended" structures that are commonly found in user projects:

      CMakeLists.txt
      ├── App/
      │   ├── CMakeLists.txt          # URI: App
      │   ├── ExemplaryLib/
      │   │   └── CMakeLists.txt      # URI: ExemplaryLib
      │   ├── nested/
      │   │   └── DeepLib/
      │   │       └── CMakeLists.txt  # URI: DeepLib
      │   └── MismatchedUriLib/
      │       └── CMakeLists.txt      # URI: Mismatched.URI.Lib
      └── OutOfTreeLib/
          └── CMakeLists.txt          # URI: OutOfTreeLib
      

       

      Scenario 1: Vanilla project
      The attached project does not specify DEPENDENCIES or QT_QML_GENERATE_QMLLS_INI, so I guess we can expect some issues. Let's see... who can find which import in Main.qml?:

      Import statement Runtime QML engine qmlsc qmllint qmltc qmlls
      import App
      import ExemplaryLib
      import DeepLib
      import Mismatched.URI.Lib
      import OutOfTreeLib

      Observations

      • "App" and "ExemplaryLib" follows the "recommended structure" relative to each other, so qmlsc and qmllint are happy.
      • qmltc failed to appreciate the fact that ExemplaryLib has followed our recommendations.
      • Worse and more confusingly, qmlls can't find ExemplaryLib... but it can find OutOfTreeLib!

       

      Scenario 2: Specifying DEPENDENCIES

      Now, let's say I specify the DEPENDENCIES correctly:

      Import statement Runtime QML engine qmlsc qmllint qmltc qmlls
      import App
      import ExemplaryLib
      import DeepLib
      import Mismatched.URI.Lib
      import OutOfTreeLib

      Observations

      • Yay, qmlsc and qmllint see more modules now. But still not all.
      • qmltc or qmlls enjoyed no benefits whatsoever.

       

      Scenario 3: Setting QT_QML_OUTPUT_DIRECTORY to ${CMAKE_BINARY_DIR}

      Suppose that a different developer inherited the attached project, and he didn't know about DEPENDENCIES. Instead, he read somewhere that setting QT_QML_OUTPUT_DIRECTORY might help so he tried it:

      Import statement Runtime QML engine qmlsc qmllint qmltc qmlls
      import App
      import ExemplaryLib
      import DeepLib
      import Mismatched.URI.Lib
      import OutOfTreeLib

      Observations

      • Magic! Now qmllint and qmlls see everything, just like the runtime engine!
      • And yet, qmlsc is now worse off than when we started.

       

      Notes

      • This study was done with Qt 6.9.0
      • I wanted to test QML Preview too, but couldn't due to QTBUG-137197
      • I am aware of the known limitations of qmltc so I'm not expecting type compilation to succeed. However, I do expect qmltc to see the same import paths as the other tools (i.e. qmltc should not complain, "Failed to import ExemplaryLib. Are your import paths set up properly?")

       

      Overall observations

      • It is very bad for our tools to disagree with each other like this (where one tools says that import paths are fine while a different tool says they're not).
      • It is a lousy developer experience when our tools can't find imports when the app runs perfectly fine.
      • Scenario 1 shows that qmlls already treats the build directory as an import path by default. But the other tools don't.
      • Scenario 3 shows that qmllint also treats the build directory as an import path IF we manually point the output directory to it. But the other tools don't.

       

      Proposals
      By default, we should maximize the chances that our QML tools "see" exactly what the runtime QQmlEngine would "see", even if the project doesn't follow our recommended structure. Here is an easy way to do so:

      1. Set QT_QML_OUTPUT_DIRECTORY to ${CMAKE_BINARY_DIR} by default (a new Policy, perhaps?)
      2. Make the build directory a default import path for all build tools, just like qmlls
      3. In the event that the user decides to set a different output directory: All our QML tools should still always use the same import paths as each other.
        • Import paths are currently stored in *.rsp files and passed to qmllint. Could the *.rsp import paths be refactored out and shared between all tools? This would reduce the risk of future divergence.

       

      Rationale

      Just the first 2 proposals alone will give us this out of the box:

      Import statement Runtime QML engine qmlsc qmllint qmltc qmlls
      import App
      import ExemplaryLib
      import DeepLib
      import Mismatched.URI.Lib
      import OutOfTreeLib

      ...even if the user was unaware of DEPENDENCIES or .qmlls.ini files.

      This means:

      • Less confusion/frustration in the QML community, less calls for help, and more time for everyone to do more useful things.
      • qmlls can work usefully most of the time, even if .qmlls.ini files cannot be used (e.g. when the source code is in a read-only location)
      • We no longer have to impose restrictions/recommendations on users' project structure

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              qtqmlteam Qt Qml Team User
              skoh-qt Sze Howe Koh
              Votes:
              1 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes