[Development] QML and Qt Quick versioning of our modules

Shawn Rutledge Shawn.Rutledge at qt.io
Fri Dec 8 09:53:49 CET 2017

> On 7 Dec 2017, at 16:42, Robin Burchell <robin.burchell at crimson.no> wrote:
> On Thu, Dec 7, 2017, at 02:53 PM, Frederik Gladhorn wrote:
>> 2) Make the minor version import optional and we pick the lastest. This
>> should 
>> be optional to prevent the name clashes described above and shifts the
>> risk to 
>> the user.
>> In practice I'd expect this to be pretty safe.
>> import QtQuick.Controls 2 would then give the latest version available.
> I'm inclined to prefer we don't do this, but I don't feel too strongly
> about it, either - at least not as long as revisioning is as weak as it
> is.

Well I suppose making it optional is one thing, but encouraging users to omit the minor version routinely is something else.  Not sure we can guarantee that nothing ever breaks if they do that.

>> 3) Make even the major version optional and we'd pick up the latest
>> version.
>> import QtQuick.Controls would give version 2.11 with Qt 5.11.
> As well as preventing a QtQuickControls 1 -> QtQuickControls 2
> transition again, this would also impact a hypothetical Qt 5 -> Qt 6
> transition: QtQuick 6 (let's say) may well have behaviour changes in
> some form over QtQuick 2. If we don't require versioning at all, then
> suddenly, code that may not be able to work with that will be forced to
> use it. Making the minor version optional doesn't seem to have many
> caveats, but the major version is a bit more limiting and scary, given
> we don't have a linker to help ensure we're using the right
> dependencies…

Yeah, we should maybe reserve the right to release Qt Quick 3 some time before Qt 6, just in case Qt 6 takes way too long.  Although, with the new config system, beginning to work on Qt Quick 6 (if we call it that) ought to already be possible… you’d just need to opt-in at configure time to try it out.

Changing behavior based on import version ought to be possible, but the uri as given to a plugin’s registerTypes(const char *uri) and initializeEngine(QQmlEngine *engine, const char *uri) functions do not include the version number, so I guess we’ll have to change it.  (e.g. registerTypesV2(const char *uri, int majorVersion, int minorVersion))  But we always have objections about bincompat when changing or adding virtual functions to public APIs.

>> Luckily we now have qmlRegisterModule(QT_VERSION_MAJOR, QT_VERSION_MINOR)
>> to help registering the current versions already.
> Yep, this is good :)
> Another potentially interesting idea that came to me while thinking
> about this just now: what about implicit imports (versioned), added in
> the qmldir file? Such that an: "import QtQuick 2.10" in the qmldir
> applied to everything in an import that don't specify an implicit
> version themselves. That would reduce clutter for anything which
> actually has a qmldir (which tend to be most larger more complex
> things), maybe that's good enough? Then, an application template could
> use that out of the box, too. I don't know offhand how hard this would
> be, but I don't think it would be too difficult.

I don’t like the qmldir files much.  It seems to me that most of the information in them should be discoverable, but maybe it’s just saving a little time not to need to discover everything.  And the files on a web server are not as discoverable, if you are using QML that way.

I think that all libraries (not just ours) should be better at providing metadata about themselves.  (e.g. dll files on Windows have metadata like version number, author, copyright etc... you can see it on the Properties dialog if you right-click a dll.  But Linux shared objects don’t.  Why have Linux people let this situation continue for so many years?)  We could at least have some standard functions which can be called to retrieve information from any QML-compatible plugin.  So if you can find the plugin, you can call one or more of those to get the kinds of data that you would’ve gotten from the qmldir file.  (What exactly they return, or whether it should be one function instead of several, is just a detail that needs figuring out.)  Then if you import foo 2.1 the engine could expect libfoo.so.2 to exist in the appropriate directory, and look for that right away instead of looking for qmldir first.  If we still care about matching the minor version, the metadata function(s) can tell us whether the version is 2.0 or 2.1 or higher.  Important metadata like that should be encoded in the _file_, or in resources, not in the _file name_.

I’m not that fond of the idea of replacing qmldir with JSON: yes it’s standard, and tree-structured, but it’s only slightly better than XML.  It still requires too much punctuation for my taste, making it harder to write than a qmldir file, without some rule-enforcing editor.  Eventually the world may get around to taking the next step: a file format that is optimized for machine reading, given that you generally need a specialized editor and/or viewer to work with XML or JSON anyway.  Something where an int is an int, word-aligned so you can mmap it and trivially read it, but which stores general tree-structured key-value data like JSON does.  (I wrote something like this years ago, but wasn’t worried about mmap and word-alignment at that time.)  Lately there are a lot of such formats to choose from for wire protocols, but not so many that are word-aligned I suppose?

But returning machine-readable metadata from a library function, or reading it from a resource block inside the library without having to call a function, is even better, IMO.

A step beyond that would be to say that an importable plugin should always be a single library file, not a whole directory full of stuff.  QML can be embedded as resources inside.  The benefit is that installation is easier, and the plugin would be portable between systems that have the same architecture.  The downside is that embedded QML is harder to access… but I think we could write a resource editor tool which allows modifying QML inside a library.  It would be necessary to satisfy the open-source license requirements if the QML is to be always embedded.  Proprietary vendors would want to encrypt or obfuscate any embedded resources then, but I guess some of them probably already do that.

More information about the Development mailing list