From c3a54c47048b7123f51f2a1078e156d259445221 Mon Sep 17 00:00:00 2001 From: mae Date: Thu, 8 Apr 2010 14:54:42 +0200 Subject: Tune plugin import mechanism In shadow build environments, we cannot enforce that shared library objects for plugins are located in the same directory as the qmldir file. This makes it hard for Creator to support mixed projects (qml/c++). In order to gain more flexibility, the patch introduces a pluginPathList to QDeclarativeEngine, which completes the existing importsPathList. The pluginPathList defaults to ["."], which indicates the directory where the qmldir file is located in. The qml viewer tool gains a command line option -P to add to the pluginPathList. For consistency, the -L option ("Library") has been renamed to -I ("Import"). QDeclarativeEngine::importExtension() has been renamed to QDeclarativeEngine::importPlugin(). The documentation has been adjusted accordingly. Done with erikv. Reviewed-by: erikv --- doc/src/declarative/modules.qdoc | 33 ++++--- src/declarative/qml/qdeclarativeengine.cpp | 144 ++++++++++++++++++++++------- src/declarative/qml/qdeclarativeengine.h | 6 +- src/declarative/qml/qdeclarativeengine_p.h | 5 +- tools/qml/main.cpp | 35 ++++++- tools/qml/qmlruntime.cpp | 5 + tools/qml/qmlruntime.h | 1 + 7 files changed, 175 insertions(+), 54 deletions(-) diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc index 68e58fb..0e332d4 100644 --- a/doc/src/declarative/modules.qdoc +++ b/doc/src/declarative/modules.qdoc @@ -86,7 +86,7 @@ The second exception is explained in more detail in the section below on Namespa \section2 The Import Path Installed modules are searched for on the import path. -The \c -L option to the \l {Qt Declarative UI Runtime}{qml} runtime adds paths to the import path. +The \c -I option to the \l {Qt Declarative UI Runtime}{qml} runtime adds paths to the import path. From C++, the path is available via \l QDeclarativeEngine::importPathList() and can be prepended to using \l QDeclarativeEngine::addImportPath(). @@ -114,19 +114,7 @@ Installed files do not need to import the module of which they are a part, as th to the other QML files in the module as relative (local) files, but if the module is imported from a remote location, those files must nevertheless be listed in the \c qmldir file. Types which you do not wish to export to users of your module -may be marked with the \c internal keyword: - -\code -internal -\endcode - -\c plugin [] lines are used to add \l{QDeclarativeExtensionPlugin}{QML C++ plugins} -to the module. is the -name of the library. is an optional argument specifying the full path to the directory -containing the plugin file; if it is omitted then the directory is assumed to be the same as -the directory of the \c qmldir file. Note that is not usually the same as the file name -of the plugin binary, which is platform dependent; e.g. the library MyAppTypes would produce -a libMyAppTypes.so on Linux and MyAppTypes.dll on Windows. +may be marked with the \c internal keyword: \c internal . The same type can be provided by different files in different versions, in which case later earlier versions (eg. 1.2) must precede earlier versions (eg. 1.0), @@ -141,6 +129,23 @@ of installed software, since a versioned import \e only imports types for that v leaving other identifiers available, even if the actual installed version might otherwise provide those identifiers. +\c plugin [] lines are used to add \l{QDeclarativeExtensionPlugin}{QML C++ plugins} +to the module. + + is the name of the library. It is usually not the same as the file name +of the plugin binary, which is platform dependent; e.g. the library MyAppTypes would produce +a libMyAppTypes.so on Linux and MyAppTypes.dll on Windows. +By default the engine searches for the plugin library in the directory containing the \c qmldir +file. The \c -P option to the \l {Qt Declarative UI Runtime}{qml} runtime adds paths to the +plugin search path. +From C++, the path is available via \l QDeclarativeEngine::pluginPathList() and can be prepended to +using \l QDeclarativeEngine::addPluginPath(). + + is an optional argument specifying either an absolute path to the directory containing the +plugin file, or a relative path from the directory containing the \c qmldir file to the directory +containing the plugin file. + + \section2 Namespaces - Named Imports When importing content it by default imports types into the global namespace. diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 1bcadf2..68ce953 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -188,6 +188,8 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e) fileImportPath += builtinPath; #endif + filePluginPath += QLatin1String("."); + } QUrl QDeclarativeScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url) @@ -1497,19 +1499,13 @@ public: foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser.plugins()) { - QDir pluginDir = dir.absoluteFilePath(plugin.path); - - // hack for resources, should probably go away - if (absoluteFilePath.startsWith(QLatin1Char(':'))) - pluginDir = QDir(QCoreApplication::applicationDirPath()); - QString resolvedFilePath = QDeclarativeEnginePrivate::get(engine) - ->resolvePlugin(pluginDir, + ->resolvePlugin(dir, plugin.path, plugin.name); if (!resolvedFilePath.isEmpty()) { - engine->importExtension(resolvedFilePath, uri); + engine->importPlugin(resolvedFilePath, uri); } } } @@ -1804,8 +1800,8 @@ QUrl QDeclarativeEnginePrivate::Imports::baseUrl() const } /*! - Adds \a path as a directory where installed QML components are - defined in a URL-based directory structure. + Adds \a path as a directory where the engine searches for + installed modules in a URL-based directory structure. The newly added \a path will be first in the importPathList(). @@ -1828,7 +1824,7 @@ void QDeclarativeEngine::addImportPath(const QString& path) /*! Returns the list of directories where the engine searches for - installed modules. + installed modules in a URL-based directory structure. For example, if \c /opt/MyApp/lib/imports is in the path, then QML that imports \c com.mycompany.Feature will cause the QDeclarativeEngine to look @@ -1849,7 +1845,7 @@ QStringList QDeclarativeEngine::importPathList() const /*! Sets the list of directories where the engine searches for - installed modules. + installed modules in a URL-based directory structure. By default, the list contains the paths specified in the \c QML_IMPORT_PATH environment variable, then the builtin \c ImportsPath from QLibraryInfo. @@ -1862,15 +1858,73 @@ void QDeclarativeEngine::setImportPathList(const QStringList &paths) d->fileImportPath = paths; } + +/*! + Adds \a path as a directory where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + The newly added \a path will be first in the pluginPathList(). + + \sa setPluginPathList() +*/ +void QDeclarativeEngine::addPluginPath(const QString& path) +{ + if (qmlImportTrace()) + qDebug() << "QDeclarativeEngine::addPluginPath" << path; + Q_D(QDeclarativeEngine); + QUrl url = QUrl(path); + if (url.isRelative() || url.scheme() == QString::fromLocal8Bit("file")) { + QDir dir = QDir(path); + d->filePluginPath.prepend(dir.canonicalPath()); + } else { + d->filePluginPath.prepend(path); + } +} + + +/*! + Returns the list of directories where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + \sa addPluginPath() setPluginPathList() +*/ +QStringList QDeclarativeEngine::pluginPathList() const +{ + Q_D(const QDeclarativeEngine); + return d->filePluginPath; +} + +/*! + Sets the list of directories where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + \sa pluginPathList() addPluginPath() + */ +void QDeclarativeEngine::setPluginPathList(const QStringList &paths) +{ + Q_D(QDeclarativeEngine); + d->filePluginPath = paths; +} + + /*! - Imports the extension named \a fileName from the \a uri provided. - Returns true if the extension was successfully imported. + Imports the plugin named \a filePath with the \a uri provided. + Returns true if the plugin was successfully imported; otherwise returns false. */ -bool QDeclarativeEngine::importExtension(const QString &fileName, const QString &uri) +bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri) { if (qmlImportTrace()) - qDebug() << "QDeclarativeEngine::importExtension" << uri << "from" << fileName; - QFileInfo fileInfo(fileName); + qDebug() << "QDeclarativeEngine::importPlugin" << uri << "from" << filePath; + QFileInfo fileInfo(filePath); const QString absoluteFilePath = fileInfo.absoluteFilePath(); QDeclarativeEnginePrivate *d = QDeclarativeEnginePrivate::get(this); @@ -1943,27 +1997,53 @@ QString QDeclarativeEngine::offlineStoragePath() const /*! \internal - Returns the result of the merge of \a baseName with \a dir, \a suffixes, and \a prefix. + Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix. The \a prefix must contain the dot. + + \a qmldirPath is the location of the qmldir file. */ -QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString &baseName, +QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, const QString &baseName, const QStringList &suffixes, const QString &prefix) { - foreach (const QString &suffix, suffixes) { - QString pluginFileName = prefix; + QStringList searchPaths = filePluginPath; + bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath); + if (!qmldirPluginPathIsRelative) + searchPaths.prepend(qmldirPluginPath); + + foreach (const QString &pluginPath, searchPaths) { + + QString resolvedPath; - pluginFileName += baseName; - pluginFileName += suffix; + if (pluginPath == QLatin1String(".")) { + if (qmldirPluginPathIsRelative) + resolvedPath = qmldirPath.absoluteFilePath(qmldirPluginPath); + else + resolvedPath = qmldirPath.absolutePath(); + } else { + resolvedPath = pluginPath; + } + + // hack for resources, should probably go away + if (resolvedPath.startsWith(QLatin1Char(':'))) + resolvedPath = QCoreApplication::applicationDirPath(); - QFileInfo fileInfo(dir, pluginFileName); + QDir dir(resolvedPath); + foreach (const QString &suffix, suffixes) { + QString pluginFileName = prefix; - if (fileInfo.exists()) - return fileInfo.absoluteFilePath(); + pluginFileName += baseName; + pluginFileName += suffix; + + QFileInfo fileInfo(dir, pluginFileName); + + if (fileInfo.exists()) + return fileInfo.absoluteFilePath(); + } } if (qmlImportTrace()) - qDebug() << "QDeclarativeEngine::resolvePlugin: Could not resolve plugin" << baseName << "in" << dir.absolutePath(); + qDebug() << "QDeclarativeEngine::resolvePlugin: Could not resolve plugin" << baseName << "in" << qmldirPath.absolutePath(); return QString(); } @@ -1984,17 +2064,17 @@ QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString Version number on unix are ignored. */ -QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString &baseName) +QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, const QString &baseName) { #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - return resolvePlugin(dir, baseName, + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, QStringList() # ifdef QT_DEBUG << QLatin1String("d.dll") // try a qmake-style debug build first # endif << QLatin1String(".dll")); #elif defined(Q_OS_SYMBIAN) - return resolvePlugin(dir, baseName, + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, QStringList() << QLatin1String(".dll") << QLatin1String(".qtplugin")); @@ -2002,7 +2082,7 @@ QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString # if defined(Q_OS_DARWIN) - return resolvePlugin(dir, baseName, + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, QStringList() # ifdef QT_DEBUG << QLatin1String("_debug.dylib") // try a qmake-style debug build first @@ -2036,7 +2116,7 @@ QString QDeclarativeEnginePrivate::resolvePlugin(const QDir &dir, const QString // Examples of valid library names: // libfoo.so - return resolvePlugin(dir, baseName, validSuffixList, QLatin1String("lib")); + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib")); # endif #endif diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h index b861c1b..fcaddcf 100644 --- a/src/declarative/qml/qdeclarativeengine.h +++ b/src/declarative/qml/qdeclarativeengine.h @@ -81,7 +81,11 @@ public: void setImportPathList(const QStringList &paths); void addImportPath(const QString& dir); - bool importExtension(const QString &fileName, const QString &uri); + QStringList pluginPathList() const; + void setPluginPathList(const QStringList &paths); + void addPluginPath(const QString& dir); + + bool importPlugin(const QString &filePath, const QString &uri); void setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *); QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory() const; diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index 3f22d61..6bcd0d1 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -231,6 +231,7 @@ public: QDeclarativeCompositeTypeManager typeManager; QStringList fileImportPath; + QStringList filePluginPath; QString offlineStoragePath; mutable quint32 uniqueId; @@ -274,10 +275,10 @@ public: QSet initializedPlugins; - QString resolvePlugin(const QDir &dir, const QString &baseName, + QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, const QString &baseName, const QStringList &suffixes, const QString &prefix = QString()); - QString resolvePlugin(const QDir &dir, const QString &baseName); + QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, const QString &baseName); bool addToImport(Imports*, const QDeclarativeDirComponents &qmldircomponentsnetwork, diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 5099e49..01b3912 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -101,8 +101,9 @@ void usage() qWarning(" -dragthreshold .................... set mouse drag threshold size"); qWarning(" -netcache ......................... set disk cache to size bytes"); qWarning(" -translation ........... set the language to run in"); - qWarning(" -L ........................... prepend to the library search path,"); + qWarning(" -I ........................... prepend to the module import search path,"); qWarning(" display path if is empty"); + qWarning(" -P ........................... prepend to the plugin search path"); qWarning(" -opengl .................................. use a QGLWidget for the viewport"); qWarning(" -script ........................... set the script to use"); qWarning(" -scriptopts |help ............... set the script options to use"); @@ -167,7 +168,8 @@ int main(int argc, char ** argv) QString dither = "none"; QString recordfile; QStringList recordargs; - QStringList libraries; + QStringList imports; + QStringList plugins; QString skin; QString script; QString scriptopts; @@ -239,14 +241,19 @@ int main(int argc, char ** argv) useGL = true; } else if (arg == "-qmlbrowser") { useNativeFileBrowser = false; - } else if (arg == "-L") { + } else if (arg == "-I" || arg == "-L") { + if (arg == "-L") + fprintf(stderr, "-L option provided for compatibility only, use -I instead"); if (lastArg) { QDeclarativeEngine tmpEngine; QString paths = tmpEngine.importPathList().join(QLatin1String(":")); fprintf(stderr, "Current search path: %s\n", paths.toLocal8Bit().constData()); return 0; } - libraries << QString(argv[++i]); + imports << QString(argv[++i]); + } else if (arg == "-P") { + if (lastArg) usage(); + plugins << QString(argv[++i]); } else if (arg == "-script") { if (lastArg) usage(); script = QString(argv[++i]); @@ -320,9 +327,12 @@ int main(int argc, char ** argv) viewer.addLibraryPath(QCoreApplication::applicationDirPath()); - foreach (QString lib, libraries) + foreach (QString lib, imports) viewer.addLibraryPath(lib); + foreach (QString plugin, plugins) + viewer.addPluginPath(plugin); + viewer.setNetworkCacheSize(cache); viewer.setRecordFile(recordfile); if (resizeview) @@ -349,6 +359,21 @@ int main(int argc, char ** argv) viewer.setUseNativeFileBrowser(useNativeFileBrowser); if (fullScreen && maximized) qWarning() << "Both -fullscreen and -maximized specified. Using -fullscreen."; + + if (fileName.isEmpty()) { + QFile qmlapp(QLatin1String("qmlapp")); + if (qmlapp.exists() && qmlapp.open(QFile::ReadOnly)) { + QString content = QString::fromUtf8(qmlapp.readAll()); + qmlapp.close(); + + int newline = content.indexOf(QLatin1Char('\n')); + if (newline >= 0) + fileName = content.left(newline); + else + fileName = content; + } + } + if (!fileName.isEmpty()) { viewer.open(fileName); fullScreen ? viewer.showFullScreen() : maximized ? viewer.showMaximized() : viewer.show(); diff --git a/tools/qml/qmlruntime.cpp b/tools/qml/qmlruntime.cpp index 1ab528e..c4ebd80 100644 --- a/tools/qml/qmlruntime.cpp +++ b/tools/qml/qmlruntime.cpp @@ -870,6 +870,11 @@ void QDeclarativeViewer::addLibraryPath(const QString& lib) canvas->engine()->addImportPath(lib); } +void QDeclarativeViewer::addPluginPath(const QString& plugin) +{ + canvas->engine()->addPluginPath(plugin); +} + void QDeclarativeViewer::reload() { openQml(currentFileOrUrl); diff --git a/tools/qml/qmlruntime.h b/tools/qml/qmlruntime.h index 01777bd..6f1e425 100644 --- a/tools/qml/qmlruntime.h +++ b/tools/qml/qmlruntime.h @@ -96,6 +96,7 @@ public: void setDeviceKeys(bool); void setNetworkCacheSize(int size); void addLibraryPath(const QString& lib); + void addPluginPath(const QString& plugin); void setUseGL(bool use); void setUseNativeFileBrowser(bool); -- cgit v0.12