QML C++ Plugins with Qt Creator 2.2 on OS X
-
I'm trying to figure out a reproducible way of getting a C++ QML plugin recognized by Qt Creator 2.2. I want to get the plugin deployed within the app bundle of Qt Creator. To compile the plugin I use the latest SDK, on Snow Leopard (OS X on Mac).
Here's what I've done so far:
git clone of most recent QML components for desktop
Use Qt 4.7.3 from SDK 1.1, seems to be binary-compatible with 4.7.3 used to build Qt Creator
Compiled the desktop styleplugin from QML components for desktop
Verified that the libstyleplugin.dylib thus obtained is compatible with Qt Creator -- same build key etc, as seen from
@$ strings MacOS/desktop/components/libstyleplugin.dylib |grep -4 debug
pattern=QT_PLUGIN_VERIFICATION_DATA
version=4.7.3
debug=false
buildkey=macosx macx-cocoa g++-4 full-config@
The only difference between this and binaries from Qt Creator is that the latter are v. 4.7.4, this should be binary compatible.Modified the library paths in the plugin to match those in Qt Creator's app bundle, using a script included at the end of this post. There are no dylib errors when the plugin is loading (there would be otherwise).
The plugin is named @libstyleplugin.dylib@ and goes into @/Applications/Creator.app/MacOS/desktop/components@, also there goes @qmldir@ containing following line:
@plugin styleplugin@
I modified QML components as follows:
@diff --git a/components/qmldir b/components/qmldir
index d2d8068..7d9a7fc 100644
--- a/components/qmldir
+++ b/components/qmldir
xx -19,5 +19,4 xx Dial 1.0 Dial.qml
TableView 1.0 TableView.qml
CheckBox 1.0 CheckBox.qml
RadioButton 1.0 RadioButton.qml
-plugin styleplugin plugin
HeaderSection 1.0 HeaderSection.qml
diff --git a/components/styleitem/qstyleplugin.cpp b/components/styleitem/qstyleplugin.cpp
index 25844dd..3763da9 100644
--- a/components/styleitem/qstyleplugin.cpp
+++ b/components/styleitem/qstyleplugin.cpp
xx -74,6 +74,7 xx public:void StylePlugin::registerTypes(const char *uri)
{- printf("uri: %sn", uri);
qmlRegisterType<QStyleItem>(uri, 1, 0, "QStyleItem");
qmlRegisterType<QRangeModel>(uri, 1, 0, "RangeModel");
qmlRegisterType<QGraphicsDropShadowEffect>(uri, 1, 0, "DropShadow");
diff --git a/components/styleitem/styleitem.pro b/components/styleitem/styleitem.pro
index 04a179a..b8f0c5b 100644
--- a/components/styleitem/styleitem.pro
+++ b/components/styleitem/styleitem.pro
xx -1,5 +1,6 xx
TEMPLATE = lib
-CONFIG += qt plugin
+CONFIG += qt plugin release
QT += declarative
QT += scriptdiff --git a/desktop.qmlproject b/desktop.qmlproject
index 961602a..edb7f5f 100644
--- a/desktop.qmlproject
+++ b/desktop.qmlproject
xx -1,6 +1,7 xx
/* File generated by QtCreator */import QmlProject 1.0
+import desktop.components 1.0Project {
/* Include .qml, .js, and image files from current directory and subdirectories */@
The desktop/components/qmldir has the plugin line removed as the plugin is no longer local, it's deployed within Qt Creator's app bundle.continued...
- printf("uri: %sn", uri);
-
I start Qt Creator as follows, and then open the desktop.qmlproject as above:
@Contents $ export QML_IMPORT_TRACE=1
Contents $ MacOS/Qt Creator
QDeclarativeImportDatabase::addImportPath: "/Applications/Qt Creator.app/Contents/imports"
QDeclarativeImportDatabase::addImportPath: "/Applications/Qt Creator.app/Contents/MacOS"
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject)::addImport: "." -1.-1 File as ""
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject)::addImport: "QmlProject" 1.0 Library as ""
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject)::addImport: "desktop.components" 1.0 Library as ""
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject::importExtension: loaded "/Applications/Qt Creator.app/Contents/MacOS/desktop/components/qmldir"
QDeclarativeImportDatabase::importPlugin: "desktop.components" from "/Applications/Qt Creator.app/Contents/MacOS/desktop/components/libstyleplugin.dylib"
uri: desktop.components
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject)::resolveType: "Project" => "QmlProjectManager::QmlProjectItem"
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject)::resolveType: "QmlFiles" => "QmlProjectManager::QmlFileFilterItem"
QDeclarativeImports(file:///Users/kuba/desktop/desktop.qmlproject)::resolveType: "JavaScriptFiles" => "QmlProjectManager::JsFileFilterItem"@
I added a line to qstyleplugin.cpp to emit the uri in registerTypes(...), this confirms that the types are indeed being registered at the correct uri.Creator seemingly loads the plugin, but it doesn't work: QStyleItem is still being underlined in the code view, and the built-in qmldesigner cannot handle elements that derive from QStyleItem (or other element types in styleplugin).
Note that this has nothing much to do with the QML for desktop framework, I used it just as an example. Same thing happens when I try to use a skeletal plugin that declares a minimal class deriving from QDeclarativeItem.
I have a bunch of other C++ QML plugins that I can use directly from my own application, but Qt Creator doesn't see them at all.
All of this code works when used via qmlviewer, as long as I modify each qml file to @import desktop.components 1.0@ in lieu of importing the now-defunct plugin/, and of course when I deploy to ~/QtSDK/Desktop/Qt/473/gcc/imports/desktop/components/....
What is the exact procedure on OS X needed to deploy QML C++ plugins so that they'd be visible to code etc. within Qt Creator? I don't care much yet if they're available from the qmldesigner's library, this will take a separate plugin. First I need the code checker to pick those up, so that the qmldesigner will stop barfing on unknown types...
Below is the script I use to fix framework references in the compiled plugin that goes into Qt Creator's app bundle. Assuming that pwd is /Applications/Qt Creator.app/Contents, and plugin is in MacOS/desktop/components,
I'd invoke the script below as reset_frameworks ../../Qt Creator.app MacOS/desktop/components/libstyleplugin.dylib
@#! /bin/bashif [ ! "$1" ] || [ ! "$2" ]; then
echo "usage: reset_frameworks Bundle.app path/to/library.dylib"
exit 1
fiapp="$1"
lib="$2"
libpath="$app/Contents/$lib"otool -L "$libpath" |
grep -E 'Qt(Core|Gui|Script|Declarative)' |
while read line; do
set $line
src="$1"
stem=$(echo "$1" | sed -e 's+./++')
echo "$stem..."
dst=(Frameworks/$stem.framework/Versions//$stem)
#install_name_tool -change "$src" "@loader_path/../../../$dst" "$libpath"
install_name_tool -change "$src" "@executable_path/../$dst" "$libpath"
done@ -
Hi,
getting the plugin not to be underlined by the code editor, and getting it inside QuickDesigner, are two different things. I'll concentrate on the former.
For the code editor Qt Creator doesn't have to load the plugin into it's own process. Instead it uses a tool called 'qmldump' which is meant to be compiled for the target Qt version. This one is then launched to dump the content of the C++ plugin to stdout in a QML format (that is, if it can locate the plugin).
What I guess goes wrong for you is that the Qt versions we ship in the Qt SDK have a qmldump that isn't compatible with the one we ship in Qt Creator 2.2. That is, dumping will fail. We'll update them as soon as QtCreator 2.2 becomes part of the SDK. You can check whether this is the culpritby having a look at the 'General Messages' Pane in Qt Creator (Window->Output Panes), or hovering over the underlined import. If it contains lines like
Usage: qmldump [plugin/import/path plugin.uri]
The qmldump is outdated.
More details about qmldump can be found at
http://labs.qt.nokia.com/2010/11/30/new-qml-editor-features/As a workaround you have to compile Qt on your own (because then you have the Qt private headers, which in turn allows Qt Creator to compile qmldump in the Qt4 settings).
I know that this isn't a satisifying answer. We plan to overcome this by two means:
- qmldump will be part of Qt from 4.8 onwards
- We encourage module providers to ship the output of qmldump along their C++ plugin, in a file called 'plugins.qmltypes'.
-
When you create a QML module containing a plugin you should, as part of the packaging step:
- Get qmldump built, either from Qt Creator or Qt 4.8+.
- Run 'qmldump My.Module 7.1 import/path' and save the output to a plugins.qmltypes file next to the module's qmldir file.
As a user, if you see a module without the plugins.qmltypes file it is still possible to make it work correctly with Creator by creating the file yourself. Alternatively, you should be able to put the file in (on linux) ~/.config/Nokia/qtcreator/qml-type-descriptions. I'm not sure about the path.
Starting from Qt 4.8 you'll be able to list your qmltypes files in the qmldir file itself, making the whole thing more explicit.
You need QtCreator 2.2 for this work.
-
I appreciate the helpful answers kk and ck. I will try it out and let you know. My goal is to write a blog page that describes the process from start to finish.
I think that Qt Creator has to load the plugin, and it does: if the plugin is imported in the foo.qmlproject file that's subsequently opened in Qt Creator, creator does load the plugin. This is necessary for the QML files that reference the plugin to work in qmldesigner; it of course doesn't list the plugin itself in the library pane -- I do know there's a separate qmldesigner plugin to be written for that. I will be doing that, too, eventually.
I want our designer to get going with doing UI designs for us using Qt Creator. So far QML seems to be very designer-friendly in the sense of the amount of expressive power it gives one.
-
Please report if it worked for you kuba.
I've got the same issue with the desktop-components, but was too lazy to do anything about it.
So I wrote all QML by hand until now.