WIP: started refactoring the plugin structure. Goal: standalone db module with it's own plugins like LEF/DEF, Gerber, MEBES including GSI bindings.

This commit is contained in:
Matthias Koefferlein 2018-06-13 00:33:43 +02:00
parent acacdc3997
commit 409392d561
54 changed files with 1000 additions and 846 deletions

View File

@ -35,6 +35,12 @@ INCLUDEPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb
PLUGINPATH += \
$$PWD/../../../plugins/streamers/gds2/db_plugin \
INCLUDEPATH += $$PLUGINPATH
DEPENDPATH += $$PLUGINPATH
INCLUDEPATH += $$RBA_INC
DEPENDPATH += $$RBA_INC

View File

@ -24,8 +24,8 @@
#define HDR_bdReaderOptions
#include "bdCommon.h"
#include "dbGDS2Reader.h"
#include "dbCommonReader.h"
#include "dbGDS2Reader.h"
#include "dbOASISReader.h"
#include "dbDXFReader.h"
#include "dbCIFReader.h"

View File

@ -20,3 +20,9 @@ INCLUDEPATH += $$BD_INC $$DB_INC $$TL_INC $$GSI_INC
DEPENDPATH += $$BD_INC $$DB_INC $$TL_INC $$GSI_INC
LIBS += -L$$DESTDIR_UT -lklayout_bd -lklayout_db -lklayout_tl -lklayout_gsi
PLUGINPATH += \
$$PWD/../../plugins/streamers/gds2/db_plugin \
INCLUDEPATH += $$PLUGINPATH
DEPENDPATH += $$PLUGINPATH

View File

@ -35,11 +35,6 @@ SOURCES = \
dbFillTool.cc \
dbForceLinkStreams.cc \
dbFuzzyCellMapping.cc \
dbGDS2.cc \
dbGDS2ReaderBase.cc \
dbGDS2Reader.cc \
dbGDS2WriterBase.cc \
dbGDS2Writer.cc \
dbGlyphs.cc \
dbHershey.cc \
dbInstances.cc \
@ -94,10 +89,6 @@ SOURCES = \
dbVector.cc \
dbWriter.cc \
dbWriterTools.cc \
contrib/dbGDS2Converter.cc \
contrib/dbGDS2Text.cc \
contrib/dbGDS2TextReader.cc \
contrib/dbGDS2TextWriter.cc \
gsiDeclDbBox.cc \
gsiDeclDbCell.cc \
gsiDeclDbCellMapping.cc \
@ -132,7 +123,9 @@ SOURCES = \
dbVariableWidthPath.cc \
dbNamedLayerReader.cc \
dbEdgesToContours.cc \
dbForceLink.cc
dbForceLink.cc \
dbPlugin.cc \
dbInit.cc
HEADERS = \
dbArray.h \
@ -163,11 +156,6 @@ HEADERS = \
dbEdgesToContours.h \
dbFillTool.h \
dbFuzzyCellMapping.h \
dbGDS2.h \
dbGDS2ReaderBase.h \
dbGDS2Reader.h \
dbGDS2WriterBase.h \
dbGDS2Writer.h \
dbHash.h \
dbHersheyFont.h \
dbHershey.h \
@ -226,16 +214,14 @@ HEADERS = \
dbVector.h \
dbWriter.h \
dbWriterTools.h \
contrib/dbGDS2Converter.h \
contrib/dbGDS2Text.h \
contrib/dbGDS2TextReader.h \
contrib/dbGDS2TextWriter.h \
dbCommonReader.h \
dbGlyphs.h \
dbCommon.h \
dbVariableWidthPath.h \
dbNamedLayerReader.h \
dbForceLink.h
dbForceLink.h \
dbPlugin.h \
dbInit.h
RESOURCES = \
dbResources.qrc

View File

@ -25,17 +25,13 @@
// of the objects by using the macros provided when we build tools from common.a.
#include "dbOASIS.h"
#include "dbGDS2.h"
#include "dbCIF.h"
#include "dbDXF.h"
#include "contrib/dbGDS2Text.h"
namespace db
{
FORCE_LINK_OASIS
FORCE_LINK_GDS2
FORCE_LINK_GDS2_TXT
FORCE_LINK_CIF
FORCE_LINK_DXF

191
src/db/db/dbInit.cc Normal file
View File

@ -0,0 +1,191 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "dbInit.h"
#include "dbPlugin.h"
#include "tlException.h"
#include "tlLog.h"
#include "tlString.h"
#ifdef _WIN32
# include <windows.h>
#else
# include <dlfcn.h>
#endif
#include <set>
#include <QFileInfo>
#include <QStringList>
#include <QDir>
namespace db
{
static std::list<db::PluginDescriptor> s_plugins;
const std::list<db::PluginDescriptor> &plugins ()
{
return s_plugins;
}
static PluginDescriptor load_plugin (const std::string &pp)
{
PluginDescriptor desc;
desc.path = pp;
dbp_init_func_t init_func = 0;
static const char *init_func_name = "dbp_init";
#if defined(_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 ());
return;
}
init_func = reinterpret_cast<dbp_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<dbp_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) (&version, &description);
if (version) {
desc.version = version;
}
if (description) {
desc.description = description;
}
}
tl::log << tl::sprintf (tl::to_string (QObject::tr ("Loaded plugin: %s")), pp);
return desc;
}
/**
* @brief Gets the path to the current module
*/
static std::string
get_module_path ()
{
#if defined(_WIN32)
HMODULE h_module = NULL;
if (GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR) &init, &h_module)) {
wchar_t buffer[MAX_PATH];
int len;
if ((len = GetModuleFileName(h_module, buffer, MAX_PATH)) > 0) {
QFileInfo fi (QString::fromUtf16 ((const ushort *) buffer, len));
return tl::to_string (fi.absolutePath ());
}
}
// no way to get module file path
return std::string ();
#else
Dl_info info = { };
if (dladdr ((void *) &init, &info)) {
QFileInfo fi (QString::fromLocal8Bit (info.dli_fname));
return tl::to_string (fi.absolutePath ());
} else {
return std::string ();
}
#endif
}
void init (const std::vector<std::string> &_paths)
{
std::vector<std::string> paths = _paths;
if (paths.empty ()) {
std::string module_path = get_module_path ();
if (! module_path.empty ()) {
paths.push_back (module_path);
}
}
if (paths.empty ()) {
// nothing to do
return;
}
std::set<std::string> modules;
for (std::vector<std::string>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
// look next to the db library, but in "db_plugins" directory
const char *db_plugin_dir = "db_plugins";
std::string pp = tl::to_string (QDir (tl::to_qstring (*p)).filePath (QString::fromUtf8 (db_plugin_dir)));
QStringList name_filters;
#if defined(_WIN32)
name_filters << QString::fromUtf8 ("*.dll");
#else
name_filters << QString::fromUtf8 ("*.so");
#endif
QStringList inst_modules = QDir (tl::to_qstring (pp)).entryList (name_filters);
inst_modules.sort ();
for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
QFileInfo dbp_file (tl::to_qstring (pp), *im);
if (dbp_file.exists () && dbp_file.isReadable ()) {
std::string mn = tl::to_string (dbp_file.fileName ());
if (modules.find (mn) == modules.end ()) {
std::string m = tl::to_string (dbp_file.absoluteFilePath ());
try {
s_plugins.push_back (load_plugin (m));
modules.insert (mn);
} catch (tl::Exception (&ex)) {
tl::error << ex.msg ();
}
}
}
}
}
}
}

View File

@ -21,11 +21,44 @@
*/
#ifndef HDR_dbGDS2Text
#define HDR_dbGDS2Text
#ifndef HDR_dbInit
#define HDR_dbInit
// place this macro to force linking of GDS2Text plugin
#define FORCE_LINK_GDS2_TXT void force_link_GDS2Text_f () { extern int force_link_GDS2Text; force_link_GDS2Text = 0; }
#include "dbCommon.h"
#include <string>
#include <list>
#include <vector>
namespace db
{
/**
* @brief A tiny structure describing a db plugin
*/
struct PluginDescriptor
{
std::string version;
std::string path;
std::string description;
PluginDescriptor ()
{ }
};
/**
* @brief The main initialization function for the "db" module
* This function needs to be called initially by all code using the db
* module. It will load the plugins and perform initialization of all
* of them.
*/
DB_PUBLIC void init (const std::vector<std::string> &paths = std::vector<std::string> ());
/**
* @brief Gets a list of all plugins registered
*/
DB_PUBLIC const std::list<db::PluginDescriptor> &plugins ();
}
#endif

0
src/db/db/dbPlugin.cc Normal file
View File

70
src/db/db/dbPlugin.h Normal file
View File

@ -0,0 +1,70 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_dbPlugin
#define HDR_dbPlugin
/**
* @brief A struct to hold the data of the plugin
*
* Use it like this:
*
* @code
* static DbPlugin plugin_desc = {
* "1.0", // (const char *) version information - should be given at least
* 0 // (const char *) description or 0/empty if no description is given
* };
* DECLARE_DB_PLUGIN (plugin_desc);
* @endcode
*/
struct DbPlugin
{
const char *version;
const char *description;
};
/**
* @brief A typedef for the initialization function a plugin is supposed to expose.
*/
typedef void (*dbp_init_func_t) (const char **version, const char **description);
# if defined _WIN32 || defined __CYGWIN__
# define DBP_PUBLIC __declspec(dllexport)
# else
# if __GNUC__ >= 4 || defined(__clang__)
# define DBP_PUBLIC __attribute__ ((visibility ("default")))
# else
# define DBP_PUBLIC
# endif
# endif
#define DECLARE_DB_PLUGIN(desc) \
extern "C" { \
DBP_PUBLIC void dbp_init (const char **version, const char **description) { \
*version = desc.version; \
*description = desc.description; \
} \
}
#endif

View File

@ -24,8 +24,6 @@
#include "dbStreamLayers.h"
#include "dbReader.h"
#include "dbWriter.h"
#include "dbGDS2Writer.h"
#include "dbOASISWriter.h"
#include "dbCommonReader.h"
#include "dbCell.h"
#include "dbCellInst.h"
@ -54,27 +52,20 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
}
std::string tmp_file;
db::SaveLayoutOptions options;
if (norm == WriteGDS2) {
tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x.gds", hash));
tl::OutputStream stream (tmp_file.c_str ());
db::GDS2Writer writer;
db::SaveLayoutOptions options;
writer.write (const_cast<db::Layout &> (layout), stream, options);
options.set_format ("GDS2");
} else {
tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x.oas", hash));
tl::OutputStream stream (tmp_file.c_str ());
db::OASISWriter writer;
db::SaveLayoutOptions options;
writer.write (const_cast<db::Layout &> (layout), stream, options);
options.set_format ("OASIS");
}
tl::OutputStream stream (tmp_file.c_str ());
db::Writer writer (options);
writer.write (const_cast<db::Layout &> (layout), stream);
const db::Layout *subject = 0;
db::Layout layout2;

View File

@ -25,7 +25,6 @@
#include "dbLayoutDiff.h"
#include "dbWriter.h"
#include "dbCIFWriter.h"
#include "dbGDS2Writer.h"
#include "tlUnitTest.h"
#include <QDir>
@ -81,9 +80,10 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char *
{
tl::OutputStream stream (tmp_gds_file);
db::GDS2Writer writer;
db::SaveLayoutOptions options;
writer.write (layout, stream, options);
options.set_format ("GDS2");
db::Writer writer (options);
writer.write (layout, stream);
}
{

View File

@ -29,9 +29,9 @@
#include "dbReader.h"
#include "dbCommonReader.h"
#include "dbLayoutDiff.h"
#include "dbGDS2Writer.h"
#include "dbGDS2Writer.h"
#include "dbTestSupport.h"
#include "dbSaveLayoutOptions.h"
#include "dbWriter.h"
#include "tlStream.h"
#include "tlTimer.h"
@ -616,9 +616,11 @@ void write (const std::vector<db::Polygon> &q1, const std::vector<db::Polygon> &
cell->shapes (lb).insert (*p);
}
db::GDS2Writer writer;
db::SaveLayoutOptions options;
options.set_format ("GDS2");
db::Writer writer (options);
tl::OutputStream stream (fn);
writer.write (out, stream, db::SaveLayoutOptions ());
writer.write (out, stream);
printf ("%s written.\n", fn.c_str ());
}

View File

@ -22,9 +22,7 @@
#include "dbOASISWriter.h"
#include "dbGDS2Writer.h"
#include "dbOASISReader.h"
#include "dbGDS2Reader.h"
#include "dbLayoutDiff.h"
#include "dbWriter.h"
#include "dbTextWriter.h"
@ -266,8 +264,10 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
{
tl::OutputStream stream (tmp1_file);
db::GDS2Writer writer;
writer.write (layout, stream, options);
db::SaveLayoutOptions gds2_options;
gds2_options.set_format ("GDS2");
db::Writer writer (gds2_options);
writer.write (layout, stream);
}
{

View File

@ -26,8 +26,6 @@ SOURCES = \
dbEdgeProcessor.cc \
dbEdges.cc \
dbEdgesToContours.cc \
dbGDS2Reader.cc \
dbGDS2Writer.cc \
dbLayer.cc \
dbLayerMapping.cc \
dbLayout.cc \

View File

@ -23,8 +23,6 @@
#include "dbLayoutDiff.h"
#include "dbWriter.h"
#include "dbOASISWriter.h"
#include "dbGDS2Writer.h"
#include "extDEFImporter.h"
#include "extLEFImporter.h"
@ -107,9 +105,10 @@ static void run_test (tl::TestBase *_this, const char *lef_dir, const char *file
{
tl::OutputStream stream (tmp_file);
db::OASISWriter writer;
db::SaveLayoutOptions options;
writer.write (layout, stream, options);
options.set_format ("OASIS");
db::Writer writer (options);
writer.write (layout, stream);
}
{

View File

@ -235,6 +235,7 @@ klayout_main_cont (int &argc, char **argv)
try {
// initialize the Python interpreter
pya::PythonInterpreter::initialize ();
// this registers the gsi definitions
@ -259,7 +260,10 @@ klayout_main_cont (int &argc, char **argv)
lay::enable_signal_handler_gui (true);
}
// configures the application with the command line arguments
app->parse_cmd (argc, argv);
// initialize the application
app->init_app ();
/* TODO: this kills valgrind

View File

@ -59,7 +59,8 @@ HEADERS = \
laySystemPaths.h \
layMacroEditorSetupPage.h \
layPasswordDialog.h \
layForceLink.h
layForceLink.h \
layInit.h
FORMS = \
ClipDialog.ui \
@ -165,7 +166,8 @@ SOURCES = \
laySystemPaths.cc \
layMacroEditorSetupPage.cc \
layPasswordDialog.cc \
layForceLink.cc
layForceLink.cc \
layInit.cc
RESOURCES = layBuildInMacros.qrc \
layHelpResources.qrc \

View File

@ -39,6 +39,7 @@
#include "laySaltController.h"
#include "laySystemPaths.h"
#include "layPasswordDialog.h"
#include "layInit.h"
#include "lymMacro.h"
#include "gtf.h"
#include "gsiDecl.h"
@ -49,6 +50,7 @@
#include "dbStatic.h"
#include "dbLibrary.h"
#include "dbLibraryManager.h"
#include "dbInit.h"
#include "tlExceptions.h"
#include "tlException.h"
#include "tlAssert.h"
@ -174,49 +176,6 @@ static void ui_exception_handler_def (QWidget *parent)
static ApplicationBase *ms_instance = 0;
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<klp_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;
}
// --------------------------------------------------------------------------------
// ApplicationBase implementation
@ -449,7 +408,7 @@ ApplicationBase::parse_cmd (int &argc, char **argv)
} else if (a == "-p" && (i + 1) < argc) {
m_native_plugins.push_back (load_plugin (args [++i]));
lay::load_plugin (args [++i]);
} else if (a == "-s") {
@ -560,14 +519,16 @@ ApplicationBase::parse_cmd (int &argc, char **argv)
void
ApplicationBase::init_app ()
{
// Try to locate the native plugins:
// Native plugins are DLL's or SO's disguised as "*.klp" files.
// Try to locate the plugins:
// The are installed either
// - directly in one of the KLAYOUT_PATH directories
// - in a folder named by the architecture (i.e. "i686-win32-mingw" or "x86_64-linux-gcc") below
// one of these folders
// - in one of the Salt packages
// - in one of the Salt packages, in a folder named after the architecture
// Below this, the following folders are looked up:
// - db_plugins for db module plugins
// - lay_plugins for lay module plugins
std::string version = lay::Version::version ();
std::vector<std::string> vv = tl::split (version, ".");
@ -579,18 +540,17 @@ ApplicationBase::init_app ()
}
std::string short_arch_string = tl::join (as, "-");
std::vector<std::string> klp_paths;
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
std::set<std::string> modules;
std::vector<QString> klp_paths;
klp_paths.push_back (tl::to_qstring (*p));
klp_paths.push_back (QDir (klp_paths.back ()).filePath (tl::to_qstring (tl::arch_string ())));
klp_paths.push_back (*p);
klp_paths.push_back (tl::to_string (QDir (tl::to_qstring (klp_paths.back ())).filePath (tl::to_qstring (tl::arch_string ()))));
lay::Salt salt;
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:
// Build the search path for the plugin locations. 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
@ -600,47 +560,25 @@ ApplicationBase::init_app ()
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 (arch_string + "-" + lay::Version::version())));
klp_paths.push_back (tl::to_string (dir.filePath (tl::to_qstring (arch_string + "-" + lay::Version::version()))));
if (vv.size () >= 2) {
klp_paths.push_back (dir.filePath (tl::to_qstring (arch_string + "-" + vv[0] + "." + vv[1])));
klp_paths.push_back (tl::to_string (dir.filePath (tl::to_qstring (arch_string + "-" + vv[0] + "." + vv[1]))));
}
if (vv.size () >= 1) {
klp_paths.push_back (dir.filePath (tl::to_qstring (arch_string + "-" + vv[0])));
klp_paths.push_back (tl::to_string (dir.filePath (tl::to_qstring (arch_string + "-" + vv[0]))));
}
klp_paths.push_back (dir.filePath (tl::to_qstring (arch_string + "-" + tl::to_string (lay::Version::version ()))));
klp_paths.push_back (dir.filePath (tl::to_qstring (arch_string)));
klp_paths.push_back (dir.filePath (tl::to_qstring (short_arch_string)));
klp_paths.push_back (tl::to_qstring ((*g)->path ()));
}
QStringList name_filters;
name_filters << QString::fromUtf8 ("*.klp");
for (std::vector<QString>::const_iterator p = klp_paths.begin (); p != klp_paths.end (); ++p) {
QStringList inst_modules = QDir (*p).entryList (name_filters);
inst_modules.sort ();
for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
QFileInfo klp_file (*p, *im);
if (klp_file.exists () && klp_file.isReadable ()) {
std::string m = tl::to_string (klp_file.absoluteFilePath ());
std::string mn = tl::to_string (klp_file.fileName ());
if (modules.find (mn) == modules.end ()) {
try {
m_native_plugins.push_back (load_plugin (m));
modules.insert (mn);
} catch (tl::Exception &ex) {
tl::error << tl::to_string (QObject::tr ("Unable to load plugin %1: %2").arg (tl::to_qstring (m)).arg (tl::to_qstring (ex.msg ())));
}
}
}
}
klp_paths.push_back (tl::to_string (dir.filePath (tl::to_qstring (arch_string + "-" + tl::to_string (lay::Version::version ())))));
klp_paths.push_back (tl::to_string (dir.filePath (tl::to_qstring (arch_string))));
klp_paths.push_back (tl::to_string (dir.filePath (tl::to_qstring (short_arch_string))));
klp_paths.push_back ((*g)->path ());
}
}
// initialize the modules (load their plugins from the paths)
db::init (klp_paths);
lay::init (klp_paths);
// initialize the GSI class system (Variant binding, Expression support)
// We have to do this now since plugins may register GSI classes and before the
// ruby interpreter, because it depends on a proper class system.
@ -800,7 +738,7 @@ ApplicationBase::init_app ()
tl::Eval::set_global_var ("klayout_path", kp);
// call "autorun_early" on all plugins that wish so
for (std::vector <lay::PluginDescriptor>::const_iterator p = m_native_plugins.begin (); p != m_native_plugins.end (); ++p) {
for (std::list<lay::PluginDescriptor>::const_iterator p = lay::plugins ().begin (); p != lay::plugins ().end (); ++p) {
if (p->autorun_early) {
(*p->autorun_early) ();
}
@ -1212,7 +1150,7 @@ void
ApplicationBase::autorun ()
{
// call "autorun" on all plugins that wish so
for (std::vector <lay::PluginDescriptor>::const_iterator p = m_native_plugins.begin (); p != m_native_plugins.end (); ++p) {
for (std::list <lay::PluginDescriptor>::const_iterator p = lay::plugins ().begin (); p != lay::plugins ().end (); ++p) {
if (p->autorun) {
(*p->autorun) ();
}

View File

@ -61,24 +61,6 @@ class PluginRoot;
class ProgressReporter;
class ProgressBar;
/**
* @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 application base class
*
@ -316,14 +298,6 @@ public:
return m_klayout_path;
}
/**
* @brief Gets the native plugin descriptors
*/
const std::vector<PluginDescriptor> &native_plugins () const
{
return m_native_plugins;
}
/**
* @brief Parses the given command line arguments and configures the application object accordingly.
*/
@ -395,7 +369,6 @@ private:
// in order to maintain a valid MainWindow reference for ruby scripts and Ruby's GC all the time.
gsi::Interpreter *mp_ruby_interpreter;
gsi::Interpreter *mp_python_interpreter;
std::vector<PluginDescriptor> m_native_plugins;
};
/**

192
src/lay/lay/layInit.cc Normal file
View File

@ -0,0 +1,192 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "layInit.h"
#include "layPlugin.h"
#include "tlException.h"
#include "tlLog.h"
#include "tlString.h"
#ifdef _WIN32
# include <windows.h>
#else
# include <dlfcn.h>
#endif
#include <QFileInfo>
#include <QStringList>
#include <QDir>
namespace lay
{
static std::list<lay::PluginDescriptor> s_plugins;
const std::list<lay::PluginDescriptor> &plugins ()
{
return s_plugins;
}
static PluginDescriptor do_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<klp_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;
}
void load_plugin (const std::string &pp)
{
s_plugins.push_back (do_load_plugin (pp));
}
/**
* @brief Gets the path to the current module
*/
static std::string
get_module_path ()
{
#if defined(_WIN32)
HMODULE h_module = NULL;
if (GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR) &init, &h_module)) {
wchar_t buffer[MAX_PATH];
int len;
if ((len = GetModuleFileName(h_module, buffer, MAX_PATH)) > 0) {
QFileInfo fi (QString::fromUtf16 ((const ushort *) buffer, len));
return tl::to_string (fi.absolutePath ());
}
}
// no way to get module file path
return std::string ();
#else
Dl_info info = { };
if (dladdr ((void *) &init, &info)) {
QFileInfo fi (QString::fromLocal8Bit (info.dli_fname));
return tl::to_string (fi.absolutePath ());
} else {
return std::string ();
}
#endif
}
void init (const std::vector<std::string> &_paths)
{
std::vector<std::string> paths = _paths;
if (paths.empty ()) {
std::string module_path = get_module_path ();
if (! module_path.empty ()) {
paths.push_back (module_path);
}
}
if (paths.empty ()) {
// nothing to do
return;
}
std::set<std::string> modules;
for (std::vector<std::string>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
// look next to the db library, but in "lay_plugins" directory
const char *db_plugin_dir = "lay_plugins";
std::string pp = tl::to_string (QDir (tl::to_qstring (*p)).filePath (QString::fromUtf8 (db_plugin_dir)));
QStringList name_filters;
#if defined(_WIN32)
name_filters << QString::fromUtf8 ("*.dll");
#else
name_filters << QString::fromUtf8 ("*.so");
#endif
QStringList inst_modules = QDir (tl::to_qstring (pp)).entryList (name_filters);
inst_modules.sort ();
for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
QFileInfo layp_file (tl::to_qstring (pp), *im);
if (layp_file.exists () && layp_file.isReadable ()) {
std::string mn = tl::to_string (layp_file.fileName ());
if (modules.find (mn) == modules.end ()) {
std::string m = tl::to_string (layp_file.absoluteFilePath ());
try {
s_plugins.push_back (do_load_plugin (m));
modules.insert (mn);
} catch (tl::Exception (&ex)) {
tl::error << ex.msg ();
}
}
}
}
}
}
}

75
src/lay/lay/layInit.h Normal file
View File

@ -0,0 +1,75 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layInit
#define HDR_layInit
#include "layCommon.h"
#include "layNativePlugin.h"
#include <string>
#include <vector>
#include <list>
namespace lay
{
/**
* @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 main initialization function for the "db" module
* This function needs to be called initially by all code using the db
* module. It will load the plugins and perform initialization of all
* of them.
*/
LAY_PUBLIC void init (const std::vector<std::string> &paths = std::vector<std::string> ());
/**
* @brief Explicitly load a specific plugin
*/
LAY_PUBLIC void load_plugin (const std::string &pp);
/**
* @brief Gets a list of all plugins registered
*/
LAY_PUBLIC const std::list<lay::PluginDescriptor> &plugins ();
}
#endif

View File

@ -58,6 +58,7 @@
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbStatic.h"
#include "dbInit.h"
#include "edtConfig.h"
#include "laySession.h"
#include "layApplication.h"
@ -91,6 +92,7 @@
#include "layLayoutPropertiesForm.h"
#include "layLayoutStatisticsForm.h"
#include "layMacroController.h"
#include "layInit.h"
#include "antObject.h"
#include "antService.h"
#include "ui_HelpAboutDialog.h"
@ -5658,12 +5660,14 @@ HelpAboutDialog::HelpAboutDialog (QWidget *parent)
s += "</ul>";
}
if (! lay::ApplicationBase::instance ()->native_plugins ().empty ()) {
if (! lay::plugins ().empty () || ! db::plugins ().empty ()) {
s += "<p>";
s += "<h4>";
s += escape_xml (tl::to_string (QObject::tr ("Binary extensions:")));
s += "</h4><ul>";
for (std::vector<lay::PluginDescriptor>::const_iterator pd = lay::ApplicationBase::instance ()->native_plugins ().begin (); pd != lay::ApplicationBase::instance ()->native_plugins ().end (); ++pd) {
for (std::list<lay::PluginDescriptor>::const_iterator pd = lay::plugins ().begin (); pd != lay::plugins ().end (); ++pd) {
s += "<li>";
if (! pd->description.empty ()) {
s += escape_xml (pd->description);
@ -5675,7 +5679,22 @@ HelpAboutDialog::HelpAboutDialog (QWidget *parent)
}
s += "</li>";
}
for (std::list<db::PluginDescriptor>::const_iterator pd = db::plugins ().begin (); pd != db::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>";

View File

@ -1,195 +0,0 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "dbGDS2.h"
#include "dbGDS2Reader.h"
#include "dbLoadLayoutOptions.h"
#include "layGDS2ReaderPlugin.h"
#include "ui_GDS2ReaderOptionPage.h"
#include "gsiDecl.h"
#include <QFrame>
namespace lay
{
// ---------------------------------------------------------------
// GDS2ReaderOptionPage definition and implementation
GDS2ReaderOptionPage::GDS2ReaderOptionPage (QWidget *parent)
: StreamReaderOptionsPage (parent)
{
mp_ui = new Ui::GDS2ReaderOptionPage ();
mp_ui->setupUi (this);
}
GDS2ReaderOptionPage::~GDS2ReaderOptionPage ()
{
delete mp_ui;
mp_ui = 0;
}
void
GDS2ReaderOptionPage::setup (const db::FormatSpecificReaderOptions *o, const lay::Technology * /*tech*/)
{
static const db::GDS2ReaderOptions default_options;
const db::GDS2ReaderOptions *options = dynamic_cast<const db::GDS2ReaderOptions *> (o);
if (!options) {
options = &default_options;
}
mp_ui->big_records_cbx->setChecked (! options->allow_big_records);
mp_ui->big_poly_cbx->setChecked (! options->allow_multi_xy_records);
mp_ui->box_mode_cb->setCurrentIndex (options->box_mode);
}
void
GDS2ReaderOptionPage::commit (db::FormatSpecificReaderOptions *o, const lay::Technology * /*tech*/)
{
db::GDS2ReaderOptions *options = dynamic_cast<db::GDS2ReaderOptions *> (o);
if (options) {
options->allow_big_records = ! mp_ui->big_records_cbx->isChecked ();
options->allow_multi_xy_records = ! mp_ui->big_poly_cbx->isChecked ();
options->box_mode = mp_ui->box_mode_cb->currentIndex ();
}
}
// ---------------------------------------------------------------
// GDS2ReaderPluginDeclaration definition and implementation
class GDS2ReaderPluginDeclaration
: public StreamReaderPluginDeclaration
{
public:
GDS2ReaderPluginDeclaration ()
: StreamReaderPluginDeclaration (db::GDS2ReaderOptions ().format_name ())
{
// .. nothing yet ..
}
StreamReaderOptionsPage *format_specific_options_page (QWidget *parent) const
{
return new GDS2ReaderOptionPage (parent);
}
db::FormatSpecificReaderOptions *create_specific_options () const
{
return new db::GDS2ReaderOptions ();
}
virtual tl::XMLElementBase *xml_element () const
{
return new lay::ReaderOptionsXMLElement<db::GDS2ReaderOptions> ("gds2",
tl::make_member (&db::GDS2ReaderOptions::box_mode, "box-mode") +
tl::make_member (&db::GDS2ReaderOptions::allow_big_records, "allow-big-records") +
tl::make_member (&db::GDS2ReaderOptions::allow_multi_xy_records, "allow-multi-xy-records")
);
}
};
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl (new lay::GDS2ReaderPluginDeclaration (), 10000, "GDS2Reader");
// ---------------------------------------------------------------
// gsi Implementation of specific methods
static void set_gds2_box_mode (db::LoadLayoutOptions *options, unsigned int n)
{
options->get_options<db::GDS2ReaderOptions> ().box_mode = n;
}
static unsigned int get_gds2_box_mode (const db::LoadLayoutOptions *options)
{
return options->get_options<db::GDS2ReaderOptions> ().box_mode;
}
static void set_gds2_allow_multi_xy_records (db::LoadLayoutOptions *options, bool n)
{
options->get_options<db::GDS2ReaderOptions> ().allow_multi_xy_records = n;
}
static bool get_gds2_allow_multi_xy_records (const db::LoadLayoutOptions *options)
{
return options->get_options<db::GDS2ReaderOptions> ().allow_multi_xy_records;
}
static void set_gds2_allow_big_records (db::LoadLayoutOptions *options, bool n)
{
options->get_options<db::GDS2ReaderOptions> ().allow_big_records = n;
}
static bool get_gds2_allow_big_records (const db::LoadLayoutOptions *options)
{
return options->get_options<db::GDS2ReaderOptions> ().allow_big_records;
}
// extend lay::LoadLayoutOptions with the GDS2 options
static
gsi::ClassExt<db::LoadLayoutOptions> gds2_reader_options (
gsi::method_ext ("gds2_box_mode=", &set_gds2_box_mode,
"@brief Sets a value specifying how to treat BOX records\n"
"This property specifies how BOX records are treated.\n"
"Allowed values are 0 (ignore), 1 (treat as rectangles), 2 (treat as boundaries) or 3 (treat as errors). The default is 1.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_box_mode", &get_gds2_box_mode,
"@brief Gets a value specifying how to treat BOX records\n"
"See \\gds2_box_mode= method for a description of this mode."
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_allow_multi_xy_records=", &set_gds2_allow_multi_xy_records,
"@brief Allows the use of multiple XY records in BOUNDARY elements for unlimited large polygons\n"
"\n"
"Setting this property to true allows big polygons that span over multiple XY records.\n"
"For strict compatibility with the standard, this property should be set to false. The default is true.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_allow_multi_xy_records?|#gds2_allow_multi_xy_records", &get_gds2_allow_multi_xy_records,
"@brief Gets a value specifying whether to allow big polygons with multiple XY records.\n"
"See \\gds2_allow_multi_xy_records= method for a description of this property."
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_allow_big_records=", &set_gds2_allow_big_records,
"@brief Allows big records with more than 32767 bytes\n"
"\n"
"Setting this property to true allows larger records by treating the record length as unsigned short, which for example "
"allows larger polygons (~8000 points rather than ~4000 points) without using multiple XY records.\n"
"For strict compatibility with the standard, this property should be set to false. The default is true.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_allow_big_records?|#gds2_allow_big_records", &get_gds2_allow_big_records,
"@brief Gets a value specifying whether to allow big records with a length of 32768 to 65535 bytes.\n"
"See \\gds2_allow_big_records= method for a description of this property."
"\nThis property has been added in version 0.18.\n"
),
""
);
}

View File

@ -1,408 +0,0 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "dbGDS2.h"
#include "dbGDS2Writer.h"
#include "dbSaveLayoutOptions.h"
#include "layCellView.h"
#include "layGDS2WriterPlugin.h"
#include "ui_GDS2WriterOptionPage.h"
#include "gsiDecl.h"
#include <QFrame>
namespace lay
{
// ---------------------------------------------------------------
// GDS2WriterOptionPage definition and implementation
GDS2WriterOptionPage::GDS2WriterOptionPage (QWidget *parent)
: StreamWriterOptionsPage (parent)
{
mp_ui = new Ui::GDS2WriterOptionPage ();
mp_ui->setupUi (this);
connect (mp_ui->multi_xy_cbx, SIGNAL (clicked ()), this, SLOT (multi_xy_clicked ()));
}
GDS2WriterOptionPage::~GDS2WriterOptionPage ()
{
delete mp_ui;
mp_ui = 0;
}
void
GDS2WriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const lay::Technology * /*tech*/)
{
const db::GDS2WriterOptions *options = dynamic_cast<const db::GDS2WriterOptions *> (o);
if (options) {
mp_ui->write_timestamps->setChecked (options->write_timestamps);
mp_ui->write_cell_properties->setChecked (options->write_cell_properties);
mp_ui->write_file_properties->setChecked (options->write_file_properties);
mp_ui->no_zero_length_paths->setChecked (options->no_zero_length_paths);
mp_ui->multi_xy_cbx->setChecked (options->multi_xy_records);
mp_ui->max_vertex_le->setEnabled (! options->multi_xy_records);
mp_ui->max_vertex_le->setText (tl::to_qstring (tl::to_string (options->max_vertex_count)));
mp_ui->cell_name_length_le->setText (tl::to_qstring (tl::to_string (options->max_cellname_length)));
mp_ui->libname_le->setText (tl::to_qstring (tl::to_string (options->libname)));
}
}
void
GDS2WriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const lay::Technology * /*tech*/, bool /*gzip*/)
{
db::GDS2WriterOptions *options = dynamic_cast<db::GDS2WriterOptions *> (o);
if (options) {
unsigned int n;
options->multi_xy_records = mp_ui->multi_xy_cbx->isChecked ();
options->write_timestamps = mp_ui->write_timestamps->isChecked ();
options->write_cell_properties = mp_ui->write_cell_properties->isChecked ();
options->write_file_properties = mp_ui->write_file_properties->isChecked ();
options->no_zero_length_paths = mp_ui->no_zero_length_paths->isChecked ();
tl::from_string (tl::to_string (mp_ui->max_vertex_le->text ()), n);
if (! options->multi_xy_records) {
if (n > 8191) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum number of vertices must not exceed 8191")));
}
if (n < 4) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum number of vertices must be 4 at least")));
}
}
options->max_vertex_count = n;
n = 32000;
tl::from_string (tl::to_string (mp_ui->cell_name_length_le->text ()), n);
if (n > 32000) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum cell name length must not exceed 32000")));
}
if (n < 8) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum cell name length must be 8 at least")));
}
options->max_cellname_length = n;
options->libname = tl::to_string (mp_ui->libname_le->text ());
}
}
void
GDS2WriterOptionPage::multi_xy_clicked ()
{
mp_ui->max_vertex_le->setEnabled (! mp_ui->multi_xy_cbx->isChecked ());
}
// ---------------------------------------------------------------
// GDS2WriterPluginDeclaration definition and implementation
class GDS2WriterPluginDeclaration
: public StreamWriterPluginDeclaration
{
public:
GDS2WriterPluginDeclaration ()
: StreamWriterPluginDeclaration (db::GDS2WriterOptions ().format_name ())
{
// .. nothing yet ..
}
StreamWriterOptionsPage *format_specific_options_page (QWidget *parent) const
{
return new GDS2WriterOptionPage (parent);
}
db::FormatSpecificWriterOptions *create_specific_options () const
{
return new db::GDS2WriterOptions ();
}
virtual tl::XMLElementBase *xml_element () const
{
return new lay::WriterOptionsXMLElement<db::GDS2WriterOptions> ("gds2",
tl::make_member (&db::GDS2WriterOptions::write_timestamps, "write-timestamps") +
tl::make_member (&db::GDS2WriterOptions::write_cell_properties, "write-cell-properties") +
tl::make_member (&db::GDS2WriterOptions::write_file_properties, "write-file-properties") +
tl::make_member (&db::GDS2WriterOptions::no_zero_length_paths, "no-zero-length-paths") +
tl::make_member (&db::GDS2WriterOptions::multi_xy_records, "multi-xy-records") +
tl::make_member (&db::GDS2WriterOptions::max_vertex_count, "max-vertex-count") +
tl::make_member (&db::GDS2WriterOptions::max_cellname_length, "max-cellname-length") +
tl::make_member (&db::GDS2WriterOptions::libname, "libname")
);
}
void initialize_options_from_layout_handle (db::FormatSpecificWriterOptions *o, const lay::LayoutHandle &lh) const
{
// Initialize the libname property from meta data with key "libname".
db::GDS2WriterOptions *options = dynamic_cast<db::GDS2WriterOptions *> (o);
if (options) {
for (db::Layout::meta_info_iterator meta = lh.layout().begin_meta (); meta != lh.layout().end_meta (); ++meta) {
if (meta->name == "libname" && !meta->value.empty ()) {
options->libname = meta->value;
}
}
}
}
};
/**
* @brief A dummy plugin for GDS2Text
*
* GDS2Text shares the options with GDS2, although some limitations do not exist.
* There is not specific option set for GDS2Text. The writer will take the options from GDS2.
*/
class GDS2TextWriterPluginDeclaration
: public StreamWriterPluginDeclaration
{
public:
GDS2TextWriterPluginDeclaration ()
: StreamWriterPluginDeclaration ("GDS2Text")
{
// .. nothing yet ..
}
};
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl1 (new lay::GDS2WriterPluginDeclaration (), 10000, "GDS2Writer");
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl2 (new lay::GDS2TextWriterPluginDeclaration (), 10001, "GDS2TextWriter");
// ---------------------------------------------------------------
// gsi Implementation of specific methods
static void set_gds2_max_vertex_count (db::SaveLayoutOptions *options, unsigned int n)
{
options->get_options<db::GDS2WriterOptions> ().max_vertex_count = n;
}
static unsigned int get_gds2_max_vertex_count (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().max_vertex_count;
}
static void set_gds2_max_cellname_length (db::SaveLayoutOptions *options, unsigned int n)
{
options->get_options<db::GDS2WriterOptions> ().max_cellname_length = n;
}
static unsigned int get_gds2_max_cellname_length (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().max_cellname_length;
}
static void set_gds2_multi_xy_records (db::SaveLayoutOptions *options, bool n)
{
options->get_options<db::GDS2WriterOptions> ().multi_xy_records = n;
}
static bool get_gds2_multi_xy_records (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().multi_xy_records;
}
static void set_gds2_write_file_properties (db::SaveLayoutOptions *options, bool n)
{
options->get_options<db::GDS2WriterOptions> ().write_file_properties = n;
}
static bool get_gds2_write_file_properties (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().write_file_properties;
}
static void set_gds2_write_cell_properties (db::SaveLayoutOptions *options, bool n)
{
options->get_options<db::GDS2WriterOptions> ().write_cell_properties = n;
}
static bool get_gds2_write_cell_properties (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().write_cell_properties;
}
static void set_gds2_no_zero_length_paths (db::SaveLayoutOptions *options, bool n)
{
options->get_options<db::GDS2WriterOptions> ().no_zero_length_paths = n;
}
static bool get_gds2_no_zero_length_paths (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().no_zero_length_paths;
}
static void set_gds2_write_timestamps (db::SaveLayoutOptions *options, bool n)
{
options->get_options<db::GDS2WriterOptions> ().write_timestamps = n;
}
static bool get_gds2_write_timestamps (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().write_timestamps;
}
static void set_gds2_libname (db::SaveLayoutOptions *options, const std::string &n)
{
options->get_options<db::GDS2WriterOptions> ().libname = n;
}
static std::string get_gds2_libname (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().libname;
}
static void set_gds2_user_units (db::SaveLayoutOptions *options, double n)
{
options->get_options<db::GDS2WriterOptions> ().user_units = n;
}
static double get_gds2_user_units (const db::SaveLayoutOptions *options)
{
return options->get_options<db::GDS2WriterOptions> ().user_units;
}
// extend lay::SaveLayoutOptions with the GDS2 options
static
gsi::ClassExt<db::SaveLayoutOptions> gds2_writer_options (
gsi::method_ext ("gds2_max_vertex_count=", &set_gds2_max_vertex_count,
"@brief Set the maximum number of vertices for polygons to write\n"
"@args count\n"
"This property describes the maximum number of point for polygons in GDS2 files.\n"
"Polygons with more points will be split.\n"
"The minimum value for this property is 4. The maximum allowed value is about 4000 or 8000, depending on the\n"
"GDS2 interpretation. If \\gds2_multi_xy_records is true, this\n"
"property is not used. Instead, the number of points is unlimited.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_max_vertex_count", &get_gds2_max_vertex_count,
"@brief Get the maximum number of vertices for polygons to write\n"
"See \\gds2_max_vertex_count= method for a description of the maximum vertex count."
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_multi_xy_records=", &set_gds2_multi_xy_records,
"@brief Use multiple XY records in BOUNDARY elements for unlimited large polygons\n"
"@args flag\n"
"\n"
"Setting this property to true allows to produce unlimited polygons \n"
"at the cost of incompatible formats. Setting it to true disables the \\gds2_max_vertex_count setting.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_multi_xy_records?", &get_gds2_multi_xy_records,
"@brief Get the property enabling multiple XY records for BOUNDARY elements\n"
"See \\gds2_multi_xy_records= method for a description of this property."
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_write_timestamps=", &set_gds2_write_timestamps,
"@brief Write the current time into the GDS2 timestamps if set to true\n"
"@args flag\n"
"\n"
"If this property is set to false, the time fields will all be zero. This somewhat simplifies compare and diff "
"applications.\n"
"\n"
"\nThis property has been added in version 0.21.16.\n"
) +
gsi::method_ext ("gds2_write_timestamps?", &get_gds2_write_timestamps,
"@brief Gets a value indicating whether the current time is written into the GDS2 timestamp fields\n"
"\nThis property has been added in version 0.21.16.\n"
) +
gsi::method_ext ("gds2_no_zero_length_paths=", &set_gds2_no_zero_length_paths,
"@brief Eliminates zero-length paths if true\n"
"@args flag\n"
"\n"
"If this property is set to true, paths with zero length will be converted to BOUNDARY objects.\n"
"\n"
"\nThis property has been added in version 0.23.\n"
) +
gsi::method_ext ("gds2_no_zero_length_paths?|#gds2_no_zero_length_paths", &get_gds2_no_zero_length_paths,
"@brief Gets a value indicating whether zero-length paths are eliminated\n"
"\nThis property has been added in version 0.23.\n"
) +
gsi::method_ext ("gds2_write_cell_properties=", &set_gds2_write_cell_properties,
"@brief Enables writing of cell properties if set to true\n"
"@args flag\n"
"\n"
"If this property is set to true, cell properties will be written as PROPATTR/PROPVALUE records immediately "
"following the BGNSTR records. This is a non-standard extension and is therefore disabled by default.\n"
"\n"
"\nThis property has been added in version 0.23.\n"
) +
gsi::method_ext ("gds2_write_cell_properties?|#gds2_write_cell_properties", &get_gds2_write_cell_properties,
"@brief Gets a value indicating whether cell properties are written\n"
"\nThis property has been added in version 0.23.\n"
) +
gsi::method_ext ("gds2_write_file_properties=", &set_gds2_write_file_properties,
"@brief Enables writing of file properties if set to true\n"
"@args flag\n"
"\n"
"If this property is set to true, layout properties will be written as PROPATTR/PROPVALUE records immediately "
"following the BGNLIB records. This is a non-standard extension and is therefore disabled by default.\n"
"\n"
"\nThis property has been added in version 0.24.\n"
) +
gsi::method_ext ("gds2_write_file_properties?|#gds2_write_file_properties", &get_gds2_write_file_properties,
"@brief Gets a value indicating whether layout properties are written\n"
"\nThis property has been added in version 0.24.\n"
) +
gsi::method_ext ("gds2_max_cellname_length=", &set_gds2_max_cellname_length,
"@brief Maximum length of cell names\n"
"@args length\n"
"\n"
"This property describes the maximum number of characters for cell names. \n"
"Longer cell names will be shortened.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_max_cellname_length", &get_gds2_max_cellname_length,
"@brief Get the maximum length of cell names\n"
"See \\gds2_max_cellname_length= method for a description of the maximum cell name length."
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_libname=", &set_gds2_libname,
"@brief Set the library name\n"
"@args libname\n"
"\n"
"The library name is the string written into the LIBNAME records of the GDS file.\n"
"The library name should not be an empty string and is subject to certain limitations in the character choice.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_libname", &get_gds2_libname,
"@brief Get the library name\n"
"See \\gds2_libname= method for a description of the library name."
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_user_units=", &set_gds2_user_units,
"@brief Set the users units to write into the GDS file\n"
"@args uu\n"
"\n"
"The user units of a GDS file are rarely used and usually are set to 1 (micron).\n"
"The intention of the user units is to specify the display units. KLayout ignores the user unit and uses microns as the display unit.\n"
"The user unit must be larger than zero.\n"
"\nThis property has been added in version 0.18.\n"
) +
gsi::method_ext ("gds2_user_units", &get_gds2_user_units,
"@brief Get the user units\n"
"See \\gds2_user_units= method for a description of the user units."
"\nThis property has been added in version 0.18.\n"
),
""
);
}

View File

@ -27,8 +27,6 @@ FORMS = \
DuplicateLayerDialog.ui \
EditStipplesForm.ui \
FlattenInstOptionsDialog.ui \
GDS2ReaderOptionPage.ui \
GDS2WriterOptionPage.ui \
GridNetConfigPage.ui \
LayerMappingWidget.ui \
LayerSourceDialog.ui \
@ -121,8 +119,6 @@ SOURCES = \
layFileDialog.cc \
layFinder.cc \
layFixedFont.cc \
layGDS2ReaderPlugin.cc \
layGDS2WriterPlugin.cc \
layGridNet.cc \
layHierarchyControlPanel.cc \
layLayerControlPanel.cc \
@ -215,8 +211,6 @@ HEADERS = \
layFileDialog.h \
layFinder.h \
layFixedFont.h \
layGDS2ReaderPlugin.h \
layGDS2WriterPlugin.h \
layGridNet.h \
layHierarchyControlPanel.h \
layLayerControlPanel.h \

View File

@ -0,0 +1,9 @@
include($$PWD/../klayout.pri)
TEMPLATE = lib
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC
LIBS += -L$$DESTDIR/.. -lklayout_db -lklayout_tl -lklayout_gsi

View File

@ -0,0 +1,8 @@
include($$PWD/../klayout.pri)
TEMPLATE = lib
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC
LIBS += -L$$DESTDIR/.. -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay

View File

@ -1,25 +0,0 @@
DESTDIR_KLP = $$OUT_PWD/../../..
DESTDIR = $$OUT_PWD/..
include($$PWD/../klayout.pri)
TEMPLATE = lib
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC
LIBS += -L$$DESTDIR_KLP -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay
# Only on Windows, DESTDIR_TARGET is usable. On this platform, a blank happens to appear between
# $(DESTDIR) and $(TARGET)
win32 {
QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_KLP/$${TARGET}.klp
# to avoid the major version being appended to the dll name - in this case -lxyz won't link it again
# because the library is called xyx0.dll.
CONFIG += skip_target_version_ext
} else {
QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_KLP/$${TARGET}.klp
}

View File

@ -3,7 +3,7 @@ TEMPLATE = subdirs
# Automatically include all sub-folders, but not the .pro file
SUBDIR_LIST = $$files($$PWD/*)
SUBDIR_LIST -= $$PWD/plugins.pro
SUBDIR_LIST -= $$PWD/plugin.pri
SUBDIR_LIST -= $$PWD/plugin_ut.pri
SUBDIR_LIST -= $$PWD/db_plugin.pri
SUBDIR_LIST -= $$PWD/lay_plugin.pri
SUBDIRS = $$SUBDIR_LIST

View File

@ -93,8 +93,5 @@ class GDS2TextFormatDeclaration
static tl::RegisteredClass<db::StreamFormatDeclaration> format_txt_decl (new GDS2TextFormatDeclaration(), 1, "GDS2Text");
// provide a symbol to force linking against
int force_link_GDS2Text = 0;
}

View File

@ -69,8 +69,5 @@ class GDS2FormatDeclaration
static tl::RegisteredClass<db::StreamFormatDeclaration> format_decl (new GDS2FormatDeclaration (), 0, "GDS2");
// provide a symbol to force linking against
int force_link_GDS2 = 0;
}

View File

@ -26,9 +26,6 @@
#include <stdint.h>
// place this macro to force linking of GDS2 plugin
#define FORCE_LINK_GDS2 void force_link_GDS2_f () { extern int force_link_GDS2; force_link_GDS2 = 0; }
namespace db
{

View File

@ -0,0 +1,114 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "dbGDS2.h"
#include "dbGDS2Reader.h"
#include "dbLoadLayoutOptions.h"
#include "layGDS2ReaderPlugin.h"
#include "ui_GDS2ReaderOptionPage.h"
#include <QFrame>
namespace lay
{
// ---------------------------------------------------------------
// GDS2ReaderOptionPage definition and implementation
GDS2ReaderOptionPage::GDS2ReaderOptionPage (QWidget *parent)
: StreamReaderOptionsPage (parent)
{
mp_ui = new Ui::GDS2ReaderOptionPage ();
mp_ui->setupUi (this);
}
GDS2ReaderOptionPage::~GDS2ReaderOptionPage ()
{
delete mp_ui;
mp_ui = 0;
}
void
GDS2ReaderOptionPage::setup (const db::FormatSpecificReaderOptions *o, const lay::Technology * /*tech*/)
{
static const db::GDS2ReaderOptions default_options;
const db::GDS2ReaderOptions *options = dynamic_cast<const db::GDS2ReaderOptions *> (o);
if (!options) {
options = &default_options;
}
mp_ui->big_records_cbx->setChecked (! options->allow_big_records);
mp_ui->big_poly_cbx->setChecked (! options->allow_multi_xy_records);
mp_ui->box_mode_cb->setCurrentIndex (options->box_mode);
}
void
GDS2ReaderOptionPage::commit (db::FormatSpecificReaderOptions *o, const lay::Technology * /*tech*/)
{
db::GDS2ReaderOptions *options = dynamic_cast<db::GDS2ReaderOptions *> (o);
if (options) {
options->allow_big_records = ! mp_ui->big_records_cbx->isChecked ();
options->allow_multi_xy_records = ! mp_ui->big_poly_cbx->isChecked ();
options->box_mode = mp_ui->box_mode_cb->currentIndex ();
}
}
// ---------------------------------------------------------------
// GDS2ReaderPluginDeclaration definition and implementation
class GDS2ReaderPluginDeclaration
: public StreamReaderPluginDeclaration
{
public:
GDS2ReaderPluginDeclaration ()
: StreamReaderPluginDeclaration (db::GDS2ReaderOptions ().format_name ())
{
// .. nothing yet ..
}
StreamReaderOptionsPage *format_specific_options_page (QWidget *parent) const
{
return new GDS2ReaderOptionPage (parent);
}
db::FormatSpecificReaderOptions *create_specific_options () const
{
return new db::GDS2ReaderOptions ();
}
virtual tl::XMLElementBase *xml_element () const
{
return new lay::ReaderOptionsXMLElement<db::GDS2ReaderOptions> ("gds2",
tl::make_member (&db::GDS2ReaderOptions::box_mode, "box-mode") +
tl::make_member (&db::GDS2ReaderOptions::allow_big_records, "allow-big-records") +
tl::make_member (&db::GDS2ReaderOptions::allow_multi_xy_records, "allow-multi-xy-records")
);
}
};
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl (new lay::GDS2ReaderPluginDeclaration (), 10000, "GDS2Reader");
}

View File

@ -0,0 +1,186 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "dbGDS2.h"
#include "dbGDS2Writer.h"
#include "dbSaveLayoutOptions.h"
#include "layCellView.h"
#include "layGDS2WriterPlugin.h"
#include "ui_GDS2WriterOptionPage.h"
#include <QFrame>
namespace lay
{
// ---------------------------------------------------------------
// GDS2WriterOptionPage definition and implementation
GDS2WriterOptionPage::GDS2WriterOptionPage (QWidget *parent)
: StreamWriterOptionsPage (parent)
{
mp_ui = new Ui::GDS2WriterOptionPage ();
mp_ui->setupUi (this);
connect (mp_ui->multi_xy_cbx, SIGNAL (clicked ()), this, SLOT (multi_xy_clicked ()));
}
GDS2WriterOptionPage::~GDS2WriterOptionPage ()
{
delete mp_ui;
mp_ui = 0;
}
void
GDS2WriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const lay::Technology * /*tech*/)
{
const db::GDS2WriterOptions *options = dynamic_cast<const db::GDS2WriterOptions *> (o);
if (options) {
mp_ui->write_timestamps->setChecked (options->write_timestamps);
mp_ui->write_cell_properties->setChecked (options->write_cell_properties);
mp_ui->write_file_properties->setChecked (options->write_file_properties);
mp_ui->no_zero_length_paths->setChecked (options->no_zero_length_paths);
mp_ui->multi_xy_cbx->setChecked (options->multi_xy_records);
mp_ui->max_vertex_le->setEnabled (! options->multi_xy_records);
mp_ui->max_vertex_le->setText (tl::to_qstring (tl::to_string (options->max_vertex_count)));
mp_ui->cell_name_length_le->setText (tl::to_qstring (tl::to_string (options->max_cellname_length)));
mp_ui->libname_le->setText (tl::to_qstring (tl::to_string (options->libname)));
}
}
void
GDS2WriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const lay::Technology * /*tech*/, bool /*gzip*/)
{
db::GDS2WriterOptions *options = dynamic_cast<db::GDS2WriterOptions *> (o);
if (options) {
unsigned int n;
options->multi_xy_records = mp_ui->multi_xy_cbx->isChecked ();
options->write_timestamps = mp_ui->write_timestamps->isChecked ();
options->write_cell_properties = mp_ui->write_cell_properties->isChecked ();
options->write_file_properties = mp_ui->write_file_properties->isChecked ();
options->no_zero_length_paths = mp_ui->no_zero_length_paths->isChecked ();
tl::from_string (tl::to_string (mp_ui->max_vertex_le->text ()), n);
if (! options->multi_xy_records) {
if (n > 8191) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum number of vertices must not exceed 8191")));
}
if (n < 4) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum number of vertices must be 4 at least")));
}
}
options->max_vertex_count = n;
n = 32000;
tl::from_string (tl::to_string (mp_ui->cell_name_length_le->text ()), n);
if (n > 32000) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum cell name length must not exceed 32000")));
}
if (n < 8) {
throw tl::Exception (tl::to_string (QObject::tr ("Maximum cell name length must be 8 at least")));
}
options->max_cellname_length = n;
options->libname = tl::to_string (mp_ui->libname_le->text ());
}
}
void
GDS2WriterOptionPage::multi_xy_clicked ()
{
mp_ui->max_vertex_le->setEnabled (! mp_ui->multi_xy_cbx->isChecked ());
}
// ---------------------------------------------------------------
// GDS2WriterPluginDeclaration definition and implementation
class GDS2WriterPluginDeclaration
: public StreamWriterPluginDeclaration
{
public:
GDS2WriterPluginDeclaration ()
: StreamWriterPluginDeclaration (db::GDS2WriterOptions ().format_name ())
{
// .. nothing yet ..
}
StreamWriterOptionsPage *format_specific_options_page (QWidget *parent) const
{
return new GDS2WriterOptionPage (parent);
}
db::FormatSpecificWriterOptions *create_specific_options () const
{
return new db::GDS2WriterOptions ();
}
virtual tl::XMLElementBase *xml_element () const
{
return new lay::WriterOptionsXMLElement<db::GDS2WriterOptions> ("gds2",
tl::make_member (&db::GDS2WriterOptions::write_timestamps, "write-timestamps") +
tl::make_member (&db::GDS2WriterOptions::write_cell_properties, "write-cell-properties") +
tl::make_member (&db::GDS2WriterOptions::write_file_properties, "write-file-properties") +
tl::make_member (&db::GDS2WriterOptions::no_zero_length_paths, "no-zero-length-paths") +
tl::make_member (&db::GDS2WriterOptions::multi_xy_records, "multi-xy-records") +
tl::make_member (&db::GDS2WriterOptions::max_vertex_count, "max-vertex-count") +
tl::make_member (&db::GDS2WriterOptions::max_cellname_length, "max-cellname-length") +
tl::make_member (&db::GDS2WriterOptions::libname, "libname")
);
}
void initialize_options_from_layout_handle (db::FormatSpecificWriterOptions *o, const lay::LayoutHandle &lh) const
{
// Initialize the libname property from meta data with key "libname".
db::GDS2WriterOptions *options = dynamic_cast<db::GDS2WriterOptions *> (o);
if (options) {
for (db::Layout::meta_info_iterator meta = lh.layout().begin_meta (); meta != lh.layout().end_meta (); ++meta) {
if (meta->name == "libname" && !meta->value.empty ()) {
options->libname = meta->value;
}
}
}
}
};
/**
* @brief A dummy plugin for GDS2Text
*
* GDS2Text shares the options with GDS2, although some limitations do not exist.
* There is not specific option set for GDS2Text. The writer will take the options from GDS2.
*/
class GDS2TextWriterPluginDeclaration
: public StreamWriterPluginDeclaration
{
public:
GDS2TextWriterPluginDeclaration ()
: StreamWriterPluginDeclaration ("GDS2Text")
{
// .. nothing yet ..
}
};
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl1 (new lay::GDS2WriterPluginDeclaration (), 10000, "GDS2Writer");
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl2 (new lay::GDS2TextWriterPluginDeclaration (), 10001, "GDS2TextWriter");
}

View File

@ -20,8 +20,6 @@
*/
#include "dbGDS2Reader.h"
#include "dbLayoutDiff.h"
#include "dbTestSupport.h"
@ -227,11 +225,11 @@ TEST(1)
db::Manager m;
db::Layout layout (&m);
tl::InputStream file (im);
db::GDS2Reader reader (file);
db::Reader reader (file);
db::LayerMap map = reader.read (layout);
EXPECT_EQ (fabs (layout.dbu () / 0.001 - 1.0) < 1e-6, true);
EXPECT_EQ (reader.libname (), "LIB.DB");
EXPECT_EQ (layout.meta_info_value ("libname"), "LIB.DB");
EXPECT_EQ (layout.layers (), size_t (11));
EXPECT_EQ (map.mapping_str (0), "2/0 : 2/0");
@ -272,7 +270,7 @@ TEST(2)
db::LayerMap map_full;
{
tl::InputStream file (im);
db::GDS2Reader reader (file);
db::Reader reader (file);
map_full = reader.read (layout);
}
@ -288,10 +286,10 @@ TEST(2)
im.reset ();
options = empty_options;
tl::InputStream file (im);
db::GDS2Reader reader (file);
db::Reader reader (file);
map = reader.read (layout_none, options);
EXPECT_EQ (fabs (layout_none.dbu () / 0.001 - 1.0) < 1e-6, true);
EXPECT_EQ (reader.libname (), "LIB.DB");
EXPECT_EQ (layout.meta_info_value ("libname"), "LIB.DB");
}
EXPECT_EQ (layout_none.layers (), size_t (0));
@ -324,7 +322,7 @@ TEST(2)
im.reset ();
tl::InputStream file (im);
db::GDS2Reader reader (file);
db::Reader reader (file);
reader.read (layout_layer, options);
EXPECT_EQ (layout_layer.layers (), size_t (1));
@ -358,13 +356,13 @@ TEST(Bug_121_1)
{
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121a.gds");
db::GDS2Reader reader (file);
db::Reader reader (file);
reader.read (layout);
}
{
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121b.gds");
db::GDS2Reader reader (file);
db::Reader reader (file);
reader.read (layout);
}
@ -379,13 +377,13 @@ TEST(Bug_121_2)
{
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121a.gds");
db::GDS2Reader reader (file);
db::Reader reader (file);
reader.read (layout);
}
{
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121c.gds");
db::GDS2Reader reader (file);
db::Reader reader (file);
reader.read (layout);
}

View File

@ -49,10 +49,11 @@ void run_test (tl::TestBase *_this, const char *file, const char *file_ref, bool
{
tl::OutputStream stream (tmp_file);
db::GDS2Writer writer;
db::SaveLayoutOptions options;
options.set_format ("GDS2");
options.set_options (new db::GDS2WriterOptions (opt));
writer.write (layout_org, stream, options);
db::Writer writer (options);
writer.write (layout_org, stream);
}
db::Layout layout_read (&m);
@ -108,13 +109,13 @@ TEST(2)
{
tl::OutputStream stream (tmp_file);
db::GDS2Writer writer;
db::SaveLayoutOptions options;
db::GDS2WriterOptions *opt = new db::GDS2WriterOptions ();
opt->multi_xy_records = true;
options.set_options (opt);
options.set_format (opt->format_name ());
writer.write (layout_org, stream, options);
db::Writer writer (options);
writer.write (layout_org, stream);
}
db::Layout layout_read (&m);
@ -145,13 +146,13 @@ TEST(3)
{
tl::OutputStream stream (tmp_file);
db::GDS2Writer writer;
db::SaveLayoutOptions options;
db::GDS2WriterOptions *opt = new db::GDS2WriterOptions ();
opt->max_vertex_count = 4;
options.set_options (opt);
options.set_format (opt->format_name ());
writer.write (layout_org, stream, options);
db::Writer writer (options);
writer.write (layout_org, stream);
}
db::Layout layout_read (&m);
@ -211,9 +212,9 @@ TEST(4)
{
tl::OutputStream stream (tmp_file);
db::GDS2Writer writer;
db::SaveLayoutOptions options;
writer.write (layout_org, stream, options);
db::Writer writer (options);
writer.write (layout_org, stream);
}
db::Layout layout_read (&m);