mirror of https://github.com/KLayout/klayout.git
Provide a more elaborate interface for native plugins
With this interface, plugins will be able to specify their version, register autorun functions and more.
This commit is contained in:
parent
0978fb527f
commit
19777e5629
|
|
@ -59,7 +59,8 @@ HEADERS = \
|
|||
laySaltController.h \
|
||||
laySignalHandler.h \
|
||||
layLibraryController.h \
|
||||
layFontController.h
|
||||
layFontController.h \
|
||||
layNativePlugin.h
|
||||
|
||||
FORMS = \
|
||||
ClipDialog.ui \
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "layConfig.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layMacroEditorDialog.h"
|
||||
#include "layNativePlugin.h"
|
||||
#include "layVersion.h"
|
||||
#include "layMacro.h"
|
||||
#include "laySignalHandler.h"
|
||||
|
|
@ -164,23 +165,47 @@ static void ui_exception_handler_def (QWidget *parent)
|
|||
|
||||
static Application *ms_instance = 0;
|
||||
|
||||
static void load_plugin (const std::string &pp)
|
||||
static PluginDescriptor load_plugin (const std::string &pp)
|
||||
{
|
||||
PluginDescriptor desc;
|
||||
desc.path = pp;
|
||||
|
||||
klp_init_func_t init_func = 0;
|
||||
static const char *init_func_name = "klp_init";
|
||||
|
||||
// NOTE: since we are using a different suffix ("*.klp"), we can't use QLibrary.
|
||||
#ifdef _WIN32
|
||||
// there is no "dlopen" on mingw, so we need to emulate it.
|
||||
HINSTANCE handle = LoadLibraryW ((const wchar_t *) tl::to_qstring (pp).constData ());
|
||||
if (! handle) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to load plugin: %s with error message: %s ")), pp, GetLastError ());
|
||||
}
|
||||
init_func = reinterpret_cast<init_func_t> (GetProcAddress (handle, init_func_name));
|
||||
#else
|
||||
void *handle;
|
||||
handle = dlopen (tl::string_to_system (pp).c_str (), RTLD_LAZY);
|
||||
if (! handle) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to load plugin: %s")), pp);
|
||||
}
|
||||
init_func = reinterpret_cast<klp_init_func_t> (dlsym (handle, init_func_name));
|
||||
#endif
|
||||
|
||||
// If present, call the initialization function to fetch some details from the plugin
|
||||
if (init_func) {
|
||||
const char *version = 0;
|
||||
const char *description = 0;
|
||||
(*init_func) (&desc.autorun, &desc.autorun_early, &version, &description);
|
||||
if (version) {
|
||||
desc.version = version;
|
||||
}
|
||||
if (description) {
|
||||
desc.description = description;
|
||||
}
|
||||
}
|
||||
|
||||
tl::log << "Loaded plugin '" << pp << "'";
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
Application::Application (int &argc, char **argv, bool non_ui_mode)
|
||||
|
|
@ -301,6 +326,9 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
// - in one of the Salt packages
|
||||
// - in one of the Salt packages, in a folder named after the architecture
|
||||
|
||||
std::string version = lay::Version::version ();
|
||||
std::vector<std::string> vv = tl::split (version, ".");
|
||||
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
|
||||
std::set<std::string> modules;
|
||||
|
|
@ -310,12 +338,27 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
klp_paths.push_back (QDir (klp_paths.back ()).filePath (tl::to_qstring (tl::arch_string ())));
|
||||
|
||||
lay::Salt salt;
|
||||
// TODO: this is code duplicated from the SaltController. But this one
|
||||
// is initialized much later.
|
||||
salt.add_location (tl::to_string (QDir (tl::to_qstring (*p)).filePath (QString::fromUtf8 ("salt"))));
|
||||
|
||||
// Build the search path for the *.klp files. The search priority is for example:
|
||||
// salt/mypackage/x86_64-linux-gcc-0.25.1
|
||||
// salt/mypackage/x86_64-linux-gcc-0.25
|
||||
// salt/mypackage/x86_64-linux-gcc-0
|
||||
// salt/mypackage/x86_64-linux-gcc
|
||||
// salt/mypackage
|
||||
|
||||
for (lay::Salt::flat_iterator g = salt.begin_flat (); g != salt.end_flat (); ++g) {
|
||||
QDir dir = QDir (tl::to_qstring ((*g)->path ()));
|
||||
klp_paths.push_back (dir.filePath (tl::to_qstring (tl::arch_string () + "-" + lay::Version::version())));
|
||||
if (vv.size () >= 2) {
|
||||
klp_paths.push_back (dir.filePath (tl::to_qstring (tl::arch_string () + "-" + vv[0] + "." + vv[1])));
|
||||
}
|
||||
if (vv.size () >= 1) {
|
||||
klp_paths.push_back (dir.filePath (tl::to_qstring (tl::arch_string () + "-" + vv[0])));
|
||||
}
|
||||
klp_paths.push_back (dir.filePath (tl::to_qstring (tl::arch_string () + "-" + tl::to_string (lay::Version::version ()))));
|
||||
klp_paths.push_back (dir.filePath (tl::to_qstring (tl::arch_string ())));
|
||||
klp_paths.push_back (tl::to_qstring ((*g)->path ()));
|
||||
klp_paths.push_back (QDir (klp_paths.back ()).filePath (tl::to_qstring (tl::arch_string ())));
|
||||
}
|
||||
|
||||
for (std::vector<QString>::const_iterator p = klp_paths.begin (); p != klp_paths.end (); ++p) {
|
||||
|
|
@ -330,9 +373,10 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
QFileInfo klp_file (*p, *im);
|
||||
if (klp_file.exists () && klp_file.isReadable ()) {
|
||||
std::string m = tl::to_string (klp_file.absoluteFilePath ());
|
||||
if (modules.find (m) == modules.end ()) {
|
||||
load_plugin (m);
|
||||
modules.insert (m);
|
||||
std::string mn = tl::to_string (klp_file.fileName ());
|
||||
if (modules.find (mn) == modules.end ()) {
|
||||
m_native_plugins.push_back (load_plugin (m));
|
||||
modules.insert (mn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,7 +516,7 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
|
||||
} else if (a == "-p" && (i + 1) < argc) {
|
||||
|
||||
load_plugin (args [++i]);
|
||||
m_native_plugins.push_back (load_plugin (args [++i]));
|
||||
|
||||
} else if (a == "-s") {
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,24 @@ class ProgressReporter;
|
|||
class ProgressBar;
|
||||
class MacroCollection;
|
||||
|
||||
/**
|
||||
* @brief A tiny struct describing a native plugin
|
||||
*/
|
||||
struct PluginDescriptor
|
||||
{
|
||||
typedef void (*runner_func_t) ();
|
||||
|
||||
runner_func_t autorun;
|
||||
runner_func_t autorun_early;
|
||||
std::string version;
|
||||
std::string path;
|
||||
std::string description;
|
||||
|
||||
PluginDescriptor ()
|
||||
: autorun (0), autorun_early (0)
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The basic application object
|
||||
*
|
||||
|
|
@ -293,6 +311,14 @@ public:
|
|||
return m_klayout_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the native plugin descriptors
|
||||
*/
|
||||
const std::vector<PluginDescriptor> &native_plugins () const
|
||||
{
|
||||
return m_native_plugins;
|
||||
}
|
||||
|
||||
private:
|
||||
void shutdown ();
|
||||
void finish ();
|
||||
|
|
@ -343,6 +369,7 @@ private:
|
|||
lay::ProgressBar *mp_pb;
|
||||
lay::PluginRoot *mp_plugin_root;
|
||||
gtf::Recorder *mp_recorder;
|
||||
std::vector<PluginDescriptor> m_native_plugins;
|
||||
};
|
||||
|
||||
} // namespace lay
|
||||
|
|
|
|||
|
|
@ -5428,7 +5428,27 @@ HelpAboutDialog::HelpAboutDialog (QWidget *parent)
|
|||
}
|
||||
s += "</ul>";
|
||||
}
|
||||
|
||||
|
||||
if (! lay::Application::instance ()->native_plugins ().empty ()) {
|
||||
s += "<p>";
|
||||
s += "<h4>";
|
||||
s += escape_xml (tl::to_string (QObject::tr ("Native extensions:")));
|
||||
s += "</h4><ul>";
|
||||
for (std::vector<lay::PluginDescriptor>::const_iterator pd = lay::Application::instance ()->native_plugins ().begin (); pd != lay::Application::instance ()->native_plugins ().end (); ++pd) {
|
||||
s += "<li>";
|
||||
if (! pd->description.empty ()) {
|
||||
s += escape_xml (pd->description);
|
||||
} else {
|
||||
s += escape_xml (pd->path);
|
||||
}
|
||||
if (! pd->version.empty ()) {
|
||||
s += " (" + escape_xml (pd->version) + ")";
|
||||
}
|
||||
s += "</li>";
|
||||
}
|
||||
s += "</ul>";
|
||||
}
|
||||
|
||||
s += "</body></html>";
|
||||
|
||||
std::string t = tl::to_string (QObject::tr ("About ")) + lay::Version::name ();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2017 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layNativePlugin
|
||||
#define HDR_layNativePlugin
|
||||
|
||||
/**
|
||||
* @brief A struct to hold the data of the plugin
|
||||
*
|
||||
* Use it like this:
|
||||
*
|
||||
* @code
|
||||
* static NativePlugin plugin_desc = {
|
||||
* 0, // (void (*)()) pointer to autorun function or 0 if not present
|
||||
* 0, // (void (*)()) pointer to early autorun function or 0 if not present
|
||||
* "1.0", // (const char *) version information - should be given at least
|
||||
* 0 // (const char *) description or 0/empty if no description is given
|
||||
* };
|
||||
* DECLARE_NATIVE_PLUGIN (plugin_desc);
|
||||
* @endcode
|
||||
*/
|
||||
struct NativePlugin {
|
||||
void (*autorun) ();
|
||||
void (*autorun_early) ();
|
||||
const char *version;
|
||||
const char *description;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A typedef for the initialization function a plugin is supposed to expose.
|
||||
*/
|
||||
typedef void (*klp_init_func_t) (void (**autorun) (), void (**autorun_early) (), const char **version, const char **description);
|
||||
|
||||
# if defined _WIN32 || defined __CYGWIN__
|
||||
# define _INIT_PUBLIC __declspec(dllexport)
|
||||
# else
|
||||
# if __GNUC__ >= 4
|
||||
# define _INIT_PUBLIC __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define _INIT_PUBLIC
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
#define DECLARE_NATIVE_PLUGIN(desc) \
|
||||
extern "C" { \
|
||||
_INIT_PUBLIC void klp_init (void (**autorun) (), void (**autorun_early) (), const char **version, const char **description) { \
|
||||
*autorun = desc.autorun; \
|
||||
*autorun_early = desc.autorun_early; \
|
||||
*version = desc.version; \
|
||||
*description = desc.description; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ SaltGrain::valid_name (const std::string &n)
|
|||
tl::Extractor ex (n);
|
||||
|
||||
std::string s;
|
||||
if (! ex.try_read_word (s, "_")) {
|
||||
if (! ex.try_read_word (s, "_.")) {
|
||||
return false;
|
||||
}
|
||||
res += s;
|
||||
|
|
@ -260,7 +260,7 @@ SaltGrain::valid_name (const std::string &n)
|
|||
if (! ex.test ("/")) {
|
||||
return false;
|
||||
}
|
||||
if (! ex.try_read_word (s, "_")) {
|
||||
if (! ex.try_read_word (s, "_.")) {
|
||||
return false;
|
||||
}
|
||||
res += "/";
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public:
|
|||
if (name.empty ()) {
|
||||
name_alert->error () << tr ("Name must not be empty");
|
||||
} else if (! SaltGrain::valid_name (name)) {
|
||||
name_alert->error () << tr ("Name is not valid (must be composed of letters, digits or underscores.\nGroups and names need to be separated with slashes.");
|
||||
name_alert->error () << tr ("Name is not valid (must be composed of letters, digits, dots or underscores.\nGroups and names need to be separated with slashes.");
|
||||
} else {
|
||||
|
||||
// check, if this name does not exist yet
|
||||
|
|
|
|||
Loading…
Reference in New Issue