##// END OF EJS Templates
Some minor improvements on plugin loading:...
jeandet -
r609:7c40e9303976
parent child
Show More
@@ -1,79 +1,80
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the QLop Software
2 -- This file is a part of the QLop Software
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "MainWindow.h"
22 #include "MainWindow.h"
23 #include <QProcessEnvironment>
23 #include <QProcessEnvironment>
24 #include <QThread>
24 #include <QThread>
25 #include <SqpApplication.h>
25 #include <SqpApplication.h>
26 #include <qglobal.h>
26 #include <qglobal.h>
27
27
28 #include <Plugin/PluginManager.h>
28 #include <Plugin/PluginManager.h>
29 #include <QDir>
29 #include <QDir>
30
30
31 #include <QLoggingCategory>
31 #include <QLoggingCategory>
32
32
33 Q_LOGGING_CATEGORY(LOG_Main, "Main")
33 Q_LOGGING_CATEGORY(LOG_Main, "Main")
34
34
35 namespace {
35 namespace {
36
36
37 /// Name of the directory containing the plugins
38
39 #if _WIN32 || _WIN64
40 const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins");
37 const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins");
41 #endif
38
42
39
43 } // namespace
40 } // namespace
44
41
45 int main(int argc, char *argv[])
42 int main(int argc, char *argv[])
46 {
43 {
47 SqpApplication a{argc, argv};
44 SqpApplication a{argc, argv};
48 SqpApplication::setOrganizationName("LPP");
45 SqpApplication::setOrganizationName("LPP");
49 SqpApplication::setOrganizationDomain("lpp.fr");
46 SqpApplication::setOrganizationDomain("lpp.fr");
50 SqpApplication::setApplicationName("SciQLop");
47 SqpApplication::setApplicationName("SciQLop");
51 MainWindow w;
48 MainWindow w;
52 w.show();
49 w.show();
53
50
54 // Loads plugins
51 // Loads plugins
55 auto pluginDir = QDir{sqpApp->applicationDirPath()};
52 auto pluginDir = QDir{a.applicationDirPath()};
53 auto pluginLookupPath = {
54 a.applicationDirPath(),
55 a.applicationDirPath() + "/" + PLUGIN_DIRECTORY_NAME,
56 a.applicationDirPath() + "/../lib64/SciQlop",
57 a.applicationDirPath() + "/../lib64/sciqlop",
58 a.applicationDirPath() + "/../lib/SciQlop",
59 a.applicationDirPath() + "/../lib/sciqlop",
60 a.applicationDirPath() + "/../plugins",
61 };
62
56 #if _WIN32 || _WIN64
63 #if _WIN32 || _WIN64
57 pluginDir.mkdir(PLUGIN_DIRECTORY_NAME);
64 pluginDir.mkdir(PLUGIN_DIRECTORY_NAME);
58 pluginDir.cd(PLUGIN_DIRECTORY_NAME);
65 pluginDir.cd(PLUGIN_DIRECTORY_NAME);
59 #endif
66 #endif
60
67
68 PluginManager pluginManager{};
61
69
62 #if __unix || __APPLE
70 for (auto &&path : pluginLookupPath) {
63 #if __x86_64__ || __ppc64__
71 QDir directory{path};
64 if (!pluginDir.cd("../lib64/SciQlop")) {
72 if (directory.exists()) {
65 pluginDir.cd("../lib64/sciqlop");
73 qCDebug(LOG_Main())
74 << QObject::tr("Plugin directory: %1").arg(directory.absolutePath());
75 pluginManager.loadPlugins(directory);
76 }
66 }
77 }
67 #else
68 if (!pluginDir.cd("../lib/SciQlop")) {
69 pluginDir.cd("../lib/sciqlop");
70 }
71 #endif
72 #endif
73 qCDebug(LOG_Main()) << QObject::tr("Plugin directory: %1").arg(pluginDir.absolutePath());
74
75 PluginManager pluginManager{};
76 pluginManager.loadPlugins(pluginDir);
77
78
78 return a.exec();
79 return a.exec();
79 }
80 }
@@ -1,118 +1,124
1 #include <Plugin/PluginManager.h>
1 #include <Plugin/PluginManager.h>
2
2
3 #include <Plugin/IPlugin.h>
3 #include <Plugin/IPlugin.h>
4
4
5 #include <QDir>
5 #include <QDir>
6 #include <QLibrary>
6 #include <QLibrary>
7 #include <QPluginLoader>
7 #include <QPluginLoader>
8
8
9 Q_LOGGING_CATEGORY(LOG_PluginManager, "PluginManager")
9 Q_LOGGING_CATEGORY(LOG_PluginManager, "PluginManager")
10
10
11 namespace {
11 namespace {
12
12
13 /// Key for retrieving metadata of the plugin
13 /// Key for retrieving metadata of the plugin
14 const auto PLUGIN_METADATA_KEY = QStringLiteral("MetaData");
14 const auto PLUGIN_METADATA_KEY = QStringLiteral("MetaData");
15
15
16 /// Key for retrieving the name of the plugin in its metadata
16 /// Key for retrieving the name of the plugin in its metadata
17 const auto PLUGIN_NAME_KEY = QStringLiteral("name");
17 const auto PLUGIN_NAME_KEY = QStringLiteral("name");
18
18
19 /// Helper to state the plugin loading operation
19 /// Helper to state the plugin loading operation
20 struct LoadPluginState {
20 struct LoadPluginState {
21 explicit LoadPluginState(const QString &pluginPath)
21 explicit LoadPluginState(const QString &pluginPath)
22 : m_PluginPath{pluginPath}, m_Valid{true}, m_ErrorMessage{}
22 : m_PluginPath{pluginPath}, m_Valid{true}, m_ErrorMessage{}
23 {
23 {
24 }
24 }
25
25
26 void log() const
26 void log() const
27 {
27 {
28 if (m_Valid) {
28 if (m_Valid) {
29 qCDebug(LOG_PluginManager())
29 qCDebug(LOG_PluginManager())
30 << QObject::tr("File '%1' has been loaded as a plugin").arg(m_PluginPath);
30 << QObject::tr("File '%1' has been loaded as a plugin").arg(m_PluginPath);
31 }
31 }
32 else {
32 else {
33 qCWarning(LOG_PluginManager())
33 qCWarning(LOG_PluginManager())
34 << QObject::tr("File '%1' can't be loaded as a plugin: %2")
34 << QObject::tr("File '%1' can't be loaded as a plugin: %2")
35 .arg(m_PluginPath)
35 .arg(m_PluginPath)
36 .arg(m_ErrorMessage);
36 .arg(m_ErrorMessage);
37 }
37 }
38 }
38 }
39
39
40 void setError(const QString &errorMessage)
40 void setError(const QString &errorMessage)
41 {
41 {
42 m_Valid = false;
42 m_Valid = false;
43 m_ErrorMessage = errorMessage;
43 m_ErrorMessage = errorMessage;
44 }
44 }
45
45
46 QString m_PluginPath;
46 QString m_PluginPath;
47 bool m_Valid;
47 bool m_Valid;
48 QString m_ErrorMessage;
48 QString m_ErrorMessage;
49 };
49 };
50
50
51 } // namespace
51 } // namespace
52
52
53 struct PluginManager::PluginManagerPrivate {
53 struct PluginManager::PluginManagerPrivate {
54 /**
54 /**
55 * Loads a single plugin into SciQlop. The method has no effect if the plugin is malformed (e.g.
55 * Loads a single plugin into SciQlop. The method has no effect if the plugin is malformed (e.g.
56 * wrong library type, missing metadata, etc.)
56 * wrong library type, missing metadata, etc.)
57 * @param pluginPath the path to the plugin library.
57 * @param pluginPath the path to the plugin library.
58 */
58 */
59 void loadPlugin(const QString &pluginPath)
59 void loadPlugin(const QString &pluginPath)
60 {
60 {
61 qCDebug(LOG_PluginManager())
61 qCDebug(LOG_PluginManager())
62 << QObject::tr("Attempting to load file '%1' as a plugin").arg(pluginPath);
62 << QObject::tr("Attempting to load file '%1' as a plugin").arg(pluginPath);
63
63
64 LoadPluginState loadState{pluginPath};
64 LoadPluginState loadState{pluginPath};
65
65
66 if (QLibrary::isLibrary(pluginPath)) {
66 if (QLibrary::isLibrary(pluginPath)) {
67 QPluginLoader pluginLoader{pluginPath};
67 QPluginLoader pluginLoader{pluginPath};
68
68
69 // Retrieving the plugin name to check if it can be loaded (i.e. no plugin with the same
69 // Retrieving the plugin name to check if it can be loaded (i.e. no plugin with the same
70 // name has been registered yet)
70 // name has been registered yet)
71 auto metadata = pluginLoader.metaData().value(PLUGIN_METADATA_KEY).toObject();
71 auto metadata = pluginLoader.metaData().value(PLUGIN_METADATA_KEY).toObject();
72 auto pluginName = metadata.value(PLUGIN_NAME_KEY).toString();
72 auto pluginName = metadata.value(PLUGIN_NAME_KEY).toString();
73
73
74 if (pluginName.isEmpty()) {
74 if (pluginName.isEmpty()) {
75 loadState.setError(QObject::tr("empty file name"));
75 loadState.setError(QObject::tr("empty file name"));
76 }
76 }
77 else if (m_RegisteredPlugins.contains(pluginName)) {
77 else if (m_RegisteredPlugins.contains(pluginName)) {
78 loadState.setError(QObject::tr("name '%1' already registered").arg(pluginName));
78 loadState.setError(QObject::tr("name '%1' already registered").arg(pluginName));
79 }
79 }
80 else {
80 else {
81 if (auto pluginInstance = qobject_cast<IPlugin *>(pluginLoader.instance())) {
81 if (auto pluginInstance = qobject_cast<IPlugin *>(pluginLoader.instance())) {
82 pluginInstance->initialize();
82 pluginInstance->initialize();
83 m_RegisteredPlugins.insert(pluginName, pluginPath);
83 m_RegisteredPlugins.insert(pluginName, pluginPath);
84 }
84 }
85 else {
85 else {
86 loadState.setError(QObject::tr("the file is not a Sciqlop plugin"));
86 loadState.setError(QObject::tr("the file is not a Sciqlop plugin"));
87 }
87 }
88 }
88 }
89 }
89 }
90 else {
90 else {
91 loadState.setError(QObject::tr("the file is not a library"));
91 loadState.setError(QObject::tr("the file is not a library"));
92 }
92 }
93
93
94 // Log loading result
94 // Log loading result
95 loadState.log();
95 loadState.log();
96 }
96 }
97
97
98 /// Registered plugins (key: plugin name, value: plugin path)
98 /// Registered plugins (key: plugin name, value: plugin path)
99 QHash<QString, QString> m_RegisteredPlugins;
99 QHash<QString, QString> m_RegisteredPlugins;
100 };
100 };
101
101
102 PluginManager::PluginManager() : impl{spimpl::make_unique_impl<PluginManagerPrivate>()}
102 PluginManager::PluginManager() : impl{spimpl::make_unique_impl<PluginManagerPrivate>()}
103 {
103 {
104 }
104 }
105
105
106 void PluginManager::loadPlugins(const QDir &pluginDir)
106 void PluginManager::loadPlugins(const QDir &pluginDir)
107 {
107 {
108 // Load plugins
108 // Load plugins
109 auto pluginInfoList = pluginDir.entryInfoList(QDir::Files, QDir::Name);
109 auto pluginInfoList
110 for (auto pluginInfo : qAsConst(pluginInfoList)) {
110 = pluginDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
111 impl->loadPlugin(pluginInfo.absoluteFilePath());
111 for (auto entryInfo : qAsConst(pluginInfoList)) {
112 if (entryInfo.isDir())
113 this->loadPlugins(QDir{entryInfo.absoluteFilePath()});
114 else {
115 if (QLibrary::isLibrary(entryInfo.absoluteFilePath()))
116 impl->loadPlugin(entryInfo.absoluteFilePath());
117 }
112 }
118 }
113 }
119 }
114
120
115 int PluginManager::nbPluginsLoaded() const noexcept
121 int PluginManager::nbPluginsLoaded() const noexcept
116 {
122 {
117 return impl->m_RegisteredPlugins.size();
123 return impl->m_RegisteredPlugins.size();
118 }
124 }
@@ -1,70 +1,73
1
1
2 amdaplugin_moc_headers = [
2 amdaplugin_moc_headers = [
3 'include/AmdaPlugin.h'
3 'include/AmdaPlugin.h'
4 ]
4 ]
5
5
6 amdaplugin_sources = [
6 amdaplugin_sources = [
7 'src/AmdaDefs.cpp',
7 'src/AmdaDefs.cpp',
8 'src/AmdaParser.cpp',
8 'src/AmdaParser.cpp',
9 'src/AmdaPlugin.cpp',
9 'src/AmdaPlugin.cpp',
10 'src/AmdaProvider.cpp',
10 'src/AmdaProvider.cpp',
11 'src/AmdaResultParser.cpp'
11 'src/AmdaResultParser.cpp'
12 ]
12 ]
13
13
14 amdaplugin_ui_files = []
14 amdaplugin_ui_files = []
15 amdaplugin_resources_files = [
15 amdaplugin_resources_files = [
16 'resources/amdaresources.qrc'
16 'resources/amdaresources.qrc'
17 ]
17 ]
18
18
19 amdaplugin_inc = include_directories(['include', '../../plugin/include'])
19 amdaplugin_inc = include_directories(['include', '../../plugin/include'])
20
20
21 moc_gen = generator(moc,
21 moc_gen = generator(moc,
22 output : 'moc_@BASENAME@.cpp',
22 output : 'moc_@BASENAME@.cpp',
23 arguments : ['@INPUT@',
23 arguments : ['@INPUT@',
24 '-DPLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/amda/resources/amda.json"',
24 '-DPLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/amda/resources/amda.json"',
25 '-I', meson.current_source_dir()+'/include',
25 '-I', meson.current_source_dir()+'/include',
26 '-I', meson.current_source_dir()+'/../../plugin/include',
26 '-I', meson.current_source_dir()+'/../../plugin/include',
27 '-o', '@OUTPUT@'])
27 '-o', '@OUTPUT@'])
28
28
29 rcc_gen = generator(rcc,
29 rcc_gen = generator(rcc,
30 output : 'qrc_@BASENAME@.cpp',
30 output : 'qrc_@BASENAME@.cpp',
31 arguments : ['--name=@BASENAME@"',
31 arguments : ['--name=@BASENAME@"',
32 '--output',
32 '--output',
33 '@OUTPUT@',
33 '@OUTPUT@',
34 '@INPUT@'])
34 '@INPUT@'])
35
35
36 amdaplugin_moc_plugin_files = moc_gen.process(amdaplugin_moc_headers)
36 amdaplugin_moc_plugin_files = moc_gen.process(amdaplugin_moc_headers)
37
37
38 amdaplugin_rcc_plugin_files = rcc_gen.process(amdaplugin_resources_files)
38 amdaplugin_rcc_plugin_files = rcc_gen.process(amdaplugin_resources_files)
39
39
40 #amdaplugin_rcc_plugin_files = qt5.preprocess(
41 # qresources : amdaplugin_resources_files)
42
40 amdaplugin_moc_files = qt5.preprocess(
43 amdaplugin_moc_files = qt5.preprocess(
41 ui_files : amdaplugin_ui_files)
44 ui_files : amdaplugin_ui_files)
42
45
43 sciqlop_amdaplugin = library('amdaplugin',
46 sciqlop_amdaplugin = library('amdaplugin',
44 amdaplugin_sources,
47 amdaplugin_sources,
45 amdaplugin_moc_files,
48 amdaplugin_moc_files,
46 amdaplugin_rcc_plugin_files,
49 amdaplugin_rcc_plugin_files,
47 amdaplugin_moc_plugin_files,
50 amdaplugin_moc_plugin_files,
48 cpp_args : '-DAMDA_LIB',
51 cpp_args : ['-DAMDA_LIB','-DQT_PLUGIN'],
49 link_with : [sciqlop_core, sciqlop_gui],
52 link_with : [sciqlop_core, sciqlop_gui],
50 include_directories : [amdaplugin_inc, core_inc, gui_inc],
53 include_directories : [amdaplugin_inc, core_inc, gui_inc],
51 dependencies : [qt5core, qt5gui, qt5widgets, qt5network],
54 dependencies : [qt5core, qt5gui, qt5widgets, qt5network],
52 install : true
55 install : true
53 )
56 )
54
57
55
58
56 tests = [
59 tests = [
57 [['tests/TestAmdaParser.cpp'],'test_amda_parser','AMDA parser test'],
60 [['tests/TestAmdaParser.cpp'],'test_amda_parser','AMDA parser test'],
58 [['tests/TestAmdaResultParser.cpp'],'test_amda_result_parser','AMDA result parser test'],
61 [['tests/TestAmdaResultParser.cpp'],'test_amda_result_parser','AMDA result parser test'],
59 [['tests/TestAmdaAcquisition.cpp'],'test_amda_acquisition','AMDA Acquisition test']
62 [['tests/TestAmdaAcquisition.cpp'],'test_amda_acquisition','AMDA Acquisition test']
60 ]
63 ]
61
64
62 foreach unit_test : tests
65 foreach unit_test : tests
63 test_moc_files = qt5.preprocess(moc_sources : unit_test[0])
66 test_moc_files = qt5.preprocess(moc_sources : unit_test[0])
64 test_exe = executable(unit_test[1],unit_test[0] , test_moc_files,
67 test_exe = executable(unit_test[1],unit_test[0] , test_moc_files,
65 link_with : [sciqlop_core, sciqlop_amdaplugin, sciqlop_gui],
68 link_with : [sciqlop_core, sciqlop_amdaplugin, sciqlop_gui],
66 include_directories : [core_inc, amdaplugin_inc, gui_inc],
69 include_directories : [core_inc, amdaplugin_inc, gui_inc],
67 cpp_args : ['-DAMDA_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/tests-resources"'],
70 cpp_args : ['-DAMDA_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/tests-resources"'],
68 dependencies : [qt5core, qt5widgets, qt5network,qt5test])
71 dependencies : [qt5core, qt5widgets, qt5network,qt5test])
69 test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])], timeout: 3 * 60)
72 test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])], timeout: 3 * 60)
70 endforeach
73 endforeach
General Comments 0
You need to be logged in to leave comments. Login now