mirror of https://github.com/KLayout/klayout.git
Refactoring and first bd tests
The goal of the refactoring is to support unit tests for the db library. For this, a distributed unit test concept has been introduced (later to be extended to other libs). Unit tests are shared objects called ".ut" and are automatically loaded by the ut runner. The bd library now has two folders - one for sources and one for the unit tests. The sources are separated into lib and apps. First unit tests for the writer options have been provided.
This commit is contained in:
parent
b296cdd915
commit
a9b64d1e57
|
|
@ -1,24 +1,6 @@
|
|||
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = src unit_tests
|
||||
|
||||
SUBDIRS = \
|
||||
bd \
|
||||
strm2cif \
|
||||
strm2dxf \
|
||||
strm2gds \
|
||||
strm2gdstxt \
|
||||
strm2oas \
|
||||
strm2txt \
|
||||
strmclip \
|
||||
strmcmp \
|
||||
strmxor \
|
||||
unit_tests.depends += src
|
||||
|
||||
strm2cif.depends += bd
|
||||
strm2dxf.depends += bd
|
||||
strm2gds.depends += bd
|
||||
strm2gdstxt.depends += bd
|
||||
strm2oas.depends += bd
|
||||
strm2txt.depends += bd
|
||||
strmclip.depends += bd
|
||||
strmcmp.depends += bd
|
||||
strmxor.depends += bd
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
for x in *.cc; do
|
||||
xx=${x/.cc}
|
||||
echo "" >$xx/$xx.pro
|
||||
echo 'include($$PWD/../../klayout.pri)' >>$xx/$xx.pro
|
||||
echo "" >>$xx/$xx.pro
|
||||
echo "TEMPLATE = app" >>$xx/$xx.pro
|
||||
echo "" >>$xx/$xx.pro
|
||||
echo "TARGET = $xx" >>$xx/$xx.pro
|
||||
echo 'DESTDIR = $$OUT_PWD/../..' >>$xx/$xx.pro
|
||||
echo "" >> $xx/$xx.pro
|
||||
echo "SOURCES = $x" >>$xx/$xx.pro
|
||||
echo "" >> $xx/$xx.pro
|
||||
echo "INCLUDEPATH += ../../tl ../../db ../../gsi" >> $xx/$xx.pro
|
||||
echo "DEPENDPATH += ../../tl ../../db ../../gsi" >> $xx/$xx.pro
|
||||
echo 'LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi' >> $xx/$xx.pro
|
||||
done
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
DESTDIR = $$OUT_PWD/../..
|
||||
DESTDIR = $$OUT_PWD/../../..
|
||||
TARGET = klayout_bd
|
||||
|
||||
include($$PWD/../../klayout.pri)
|
||||
include($$PWD/../../../klayout.pri)
|
||||
|
||||
DEFINES += MAKE_BD_LIBRARY
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ HEADERS = \
|
|||
|
||||
RESOURCES = \
|
||||
|
||||
INCLUDEPATH += ../../tl ../../db ../../gsi ../../version
|
||||
DEPENDPATH += ../../tl ../../db ../../gsi ../../version
|
||||
INCLUDEPATH += ../../../tl ../../../db ../../../gsi ../../../version
|
||||
DEPENDPATH += ../../../tl ../../../db ../../../gsi ../../../version
|
||||
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ namespace bd
|
|||
|
||||
GenericWriterOptions::GenericWriterOptions ()
|
||||
: m_scale_factor (1.0), m_dbu (0.0),
|
||||
m_dont_write_empty_cells (false), m_keep_instances (false), m_write_context_info (false)
|
||||
m_dont_write_empty_cells (false), m_keep_instances (false), m_write_context_info (true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -81,9 +81,11 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
|||
|
||||
if (format.empty () || format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) {
|
||||
cmd << tl::arg (group +
|
||||
"#--write-context-info", &m_write_context_info, "Writes context information",
|
||||
"Include context information for PCell instances and other information in a format-specific "
|
||||
"way. The resulting layout may show unexpected features for other consumers."
|
||||
"!#--no-context-info", &m_write_context_info, "Does not write context information",
|
||||
"Context information is included to maintain PCell parameters and library connections. "
|
||||
"This information is kept inside the layout files in a proprietary way. This option disables "
|
||||
"this feature to maintain compatibility with other consumers of the file. If this option is "
|
||||
"used, PCell parameters and library links are lost."
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +172,8 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
|||
cmd << tl::arg (group +
|
||||
"-ok|--compression-level=level", &m_oasis_writer_options.compression_level, "Specifies the OASIS compression level",
|
||||
"This level describes how hard the OASIS writer will try to compress the shapes "
|
||||
"using shape arrays. Building shape arrays may take some time and requires some memory.\n"
|
||||
"using shape arrays. Building shape arrays may take some time and requires some memory. "
|
||||
"The default compression level is 2.\n"
|
||||
"* 0 - no shape array building\n"
|
||||
"* 1 - nearest neighbor shape array formation\n"
|
||||
"* 2++ - enhanced shape array search algorithm using 2nd and further neighbor distances as well\n"
|
||||
|
|
@ -188,8 +191,8 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
|||
)
|
||||
<< tl::arg (group +
|
||||
"#--write-std-properties", &m_oasis_writer_options.write_std_properties, "Writes some global standard properties",
|
||||
"This is an integer describing what standard properties shall be written. 0 is \"none\" (the default), "
|
||||
"1 means \"global standard properties such as S_TOP_CELL\" are produced. With 2 also per-cell bounding "
|
||||
"This is an integer describing what standard properties shall be written. 0 is \"none\", "
|
||||
"1 means \"global standard properties such as S_TOP_CELL\" are produced (the default). With 2 also per-cell bounding "
|
||||
"boxes are produced."
|
||||
)
|
||||
<< tl::arg (group +
|
||||
|
|
@ -209,7 +212,7 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
|||
cmd << tl::arg (group +
|
||||
"-op|--polygon-mode=mode", &m_dxf_writer_options.polygon_mode, "Specifies how to write polygons",
|
||||
"This option specifies how to write polygons:\n"
|
||||
"* 0: create POLYLINE\n"
|
||||
"* 0: create POLYLINE (default)\n"
|
||||
"* 1: create LWPOLYLINE\n"
|
||||
"* 2: decompose into SOLID\n"
|
||||
"* 3: create HATCH"
|
||||
|
|
@ -255,7 +258,6 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std
|
|||
bool without_children = ex.test ("(");
|
||||
std::string filter;
|
||||
ex.read_word_or_quoted (filter, "_-.*?{}$[]");
|
||||
|
||||
if (without_children) {
|
||||
ex.expect (")");
|
||||
}
|
||||
|
|
@ -270,15 +272,17 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std
|
|||
if (pat.match (layout.cell_name (c->cell_index ()))) {
|
||||
|
||||
std::set<db::cell_index_type> cells;
|
||||
cells.insert (c->cell_index ());
|
||||
if (! without_children) {
|
||||
c->collect_called_cells (cells);
|
||||
}
|
||||
cells.insert (c->cell_index ());
|
||||
|
||||
if (! remove) {
|
||||
selected.insert (cells.begin (), cells.end ());
|
||||
} else {
|
||||
selected.erase (cells.begin (), cells.end ());
|
||||
for (std::set<db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
|
||||
selected.erase (*c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
include($$PWD/../klayout.pri)
|
||||
include($$PWD/../../klayout.pri)
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
PRO_BASENAME = $$basename(_PRO_FILE_)
|
||||
TARGET = $$replace(PRO_BASENAME, ".pro", "")
|
||||
DESTDIR = $$OUT_PWD/../..
|
||||
DESTDIR = $$OUT_PWD/../../..
|
||||
|
||||
# Since the main function is entirely unspecific, we can put it into a common
|
||||
# place - it's not part of the bd sources.
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = \
|
||||
bd \
|
||||
strm2cif \
|
||||
strm2dxf \
|
||||
strm2gds \
|
||||
strm2gdstxt \
|
||||
strm2oas \
|
||||
strm2txt \
|
||||
strmclip \
|
||||
strmcmp \
|
||||
strmxor \
|
||||
|
||||
strm2cif.depends += bd
|
||||
strm2dxf.depends += bd
|
||||
strm2gds.depends += bd
|
||||
strm2gdstxt.depends += bd
|
||||
strm2oas.depends += bd
|
||||
strm2txt.depends += bd
|
||||
strmclip.depends += bd
|
||||
strmcmp.depends += bd
|
||||
strmxor.depends += bd
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
include($$PWD/../../../klayout.pri)
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
TARGET = strmxor
|
||||
DESTDIR = $$OUT_PWD/../../..
|
||||
|
||||
SOURCES = strmxor.cc
|
||||
|
||||
INCLUDEPATH += ../bd ../../../tl ../../../db ../../../gsi
|
||||
DEPENDPATH += ../bd ../../../tl ../../../db ../../../gsi
|
||||
LIBS += -L$$DESTDIR -lklayout_bd -lklayout_tl -lklayout_db -lklayout_gsi
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
include($$PWD/../../klayout.pri)
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
TARGET = strmxor
|
||||
DESTDIR = $$OUT_PWD/../..
|
||||
|
||||
SOURCES = strmxor.cc
|
||||
|
||||
INCLUDEPATH += ../bd ../../tl ../../db ../../gsi
|
||||
DEPENDPATH += ../bd ../../tl ../../db ../../gsi
|
||||
LIBS += -L$$DESTDIR -lklayout_bd -lklayout_tl -lklayout_db -lklayout_gsi
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include "bdWriterOptions.h"
|
||||
#include "bdReaderOptions.h"
|
||||
#include "tlCommandLineParser.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbCell.h"
|
||||
|
||||
#include "utHead.h"
|
||||
|
||||
// Testing writer options
|
||||
TEST(1)
|
||||
{
|
||||
bd::GenericWriterOptions opt;
|
||||
tl::CommandLineOptions cmd;
|
||||
|
||||
opt.add_options (cmd);
|
||||
|
||||
char *argv[] = { "x",
|
||||
"-os=1.25",
|
||||
"-od=0.125",
|
||||
"--drop-empty-cells",
|
||||
"--keep-instances",
|
||||
"--no-context-info",
|
||||
// CIF
|
||||
"--blank-separator",
|
||||
"--dummy-calls",
|
||||
// DXF
|
||||
"-op=2",
|
||||
// GDS2
|
||||
"-ol=MYLIBNAME",
|
||||
"-ov=250",
|
||||
"--multi-xy-records",
|
||||
"--no-timestamps",
|
||||
"--no-zero-length-paths",
|
||||
"--user-units=2.5",
|
||||
"--write-cell-properties",
|
||||
"--write-file-properties",
|
||||
// OASIS
|
||||
"-ob",
|
||||
"-ok=9",
|
||||
"-ot",
|
||||
"--recompress",
|
||||
"--subst-char=XY",
|
||||
"--write-std-properties=2"
|
||||
};
|
||||
|
||||
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
db::SaveLayoutOptions stream_opt;
|
||||
EXPECT_EQ (stream_opt.dont_write_empty_cells (), false);
|
||||
EXPECT_EQ (stream_opt.keep_instances (), false);
|
||||
EXPECT_EQ (stream_opt.write_context_info (), true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::CIFWriterOptions> ().blank_separator, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::CIFWriterOptions> ().dummy_calls, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::DXFWriterOptions> ().polygon_mode, 0);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().libname, "LIB");
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().max_vertex_count, (unsigned int) 8000);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().multi_xy_records, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().write_timestamps, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().no_zero_length_paths, false);
|
||||
EXPECT_EQ (tl::to_string (stream_opt.get_options<db::GDS2WriterOptions> ().user_units), "1");
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().write_cell_properties, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().write_file_properties, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().write_cblocks, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().compression_level, 2);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().strict_mode, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().recompress, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().subst_char, "*");
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().write_std_properties, 1);
|
||||
|
||||
opt.configure (stream_opt, layout);
|
||||
|
||||
EXPECT_EQ (stream_opt.scale_factor (), 1.25);
|
||||
EXPECT_EQ (stream_opt.dbu (), 0.125);
|
||||
EXPECT_EQ (stream_opt.dont_write_empty_cells (), true);
|
||||
EXPECT_EQ (stream_opt.keep_instances (), true);
|
||||
EXPECT_EQ (stream_opt.write_context_info (), false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::CIFWriterOptions> ().blank_separator, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::CIFWriterOptions> ().dummy_calls, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::DXFWriterOptions> ().polygon_mode, 2);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().libname, "MYLIBNAME");
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().max_vertex_count, (unsigned int) 250);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().multi_xy_records, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().write_timestamps, false);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().no_zero_length_paths, true);
|
||||
EXPECT_EQ (tl::to_string (stream_opt.get_options<db::GDS2WriterOptions> ().user_units), "2.5");
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().write_cell_properties, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::GDS2WriterOptions> ().write_file_properties, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().write_cblocks, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().compression_level, 9);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().strict_mode, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().recompress, true);
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().subst_char, "X");
|
||||
EXPECT_EQ (stream_opt.get_options<db::OASISWriterOptions> ().write_std_properties, 2);
|
||||
}
|
||||
|
||||
static std::string cells2string (const db::Layout &layout, const std::set<db::cell_index_type> &cells)
|
||||
{
|
||||
std::string res;
|
||||
for (std::set<db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
|
||||
if (c != cells.begin ()) {
|
||||
res += ",";
|
||||
}
|
||||
res += layout.cell_name (*c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Testing writer options: cell resolution
|
||||
TEST(2)
|
||||
{
|
||||
// Build a layout with the hierarchy
|
||||
// TOP -> A, B
|
||||
// A -> B
|
||||
// B -> C
|
||||
// C -> D
|
||||
db::Layout layout;
|
||||
db::cell_index_type itop = layout.add_cell ("TOP");
|
||||
db::cell_index_type ia = layout.add_cell ("A");
|
||||
db::cell_index_type ib = layout.add_cell ("B");
|
||||
db::cell_index_type ic = layout.add_cell ("C");
|
||||
db::cell_index_type id = layout.add_cell ("D");
|
||||
layout.cell (itop).insert (db::CellInstArray (ia, db::Trans ()));
|
||||
layout.cell (itop).insert (db::CellInstArray (ib, db::Trans ()));
|
||||
layout.cell (ia).insert (db::CellInstArray (ib, db::Trans ()));
|
||||
layout.cell (ib).insert (db::CellInstArray (ic, db::Trans ()));
|
||||
layout.cell (ic).insert (db::CellInstArray (id, db::Trans ()));
|
||||
|
||||
bd::GenericWriterOptions opt;
|
||||
tl::CommandLineOptions cmd;
|
||||
opt.add_options (cmd);
|
||||
|
||||
std::set <db::cell_index_type> cells;
|
||||
std::vector <std::pair <unsigned int, db::LayerProperties> > valid_layers;
|
||||
db::SaveLayoutOptions stream_opt;
|
||||
|
||||
{
|
||||
char *argv[] = { "x",
|
||||
"--write-cells=A,-C,(C)",
|
||||
};
|
||||
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||
}
|
||||
|
||||
opt.configure (stream_opt, layout);
|
||||
|
||||
cells.clear ();
|
||||
valid_layers.clear ();
|
||||
stream_opt.get_cells (layout, cells, valid_layers);
|
||||
|
||||
EXPECT_EQ (cells2string (layout, cells), "A,B,C");
|
||||
|
||||
{
|
||||
char *argv[] = { "x",
|
||||
"--write-cells=(C),(TOP)",
|
||||
};
|
||||
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||
}
|
||||
|
||||
opt.configure (stream_opt, layout);
|
||||
|
||||
cells.clear ();
|
||||
valid_layers.clear ();
|
||||
stream_opt.get_cells (layout, cells, valid_layers);
|
||||
|
||||
EXPECT_EQ (cells2string (layout, cells), "TOP,C");
|
||||
|
||||
{
|
||||
char *argv[] = { "x",
|
||||
"--write-cells=(TOP),+B",
|
||||
};
|
||||
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||
}
|
||||
|
||||
opt.configure (stream_opt, layout);
|
||||
|
||||
cells.clear ();
|
||||
valid_layers.clear ();
|
||||
stream_opt.get_cells (layout, cells, valid_layers);
|
||||
|
||||
EXPECT_EQ (cells2string (layout, cells), "TOP,B,C,D");
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
TARGET = bd_tests
|
||||
|
||||
include($$PWD/../../klayout.pri)
|
||||
include($$PWD/../../lib_ut.pri)
|
||||
|
||||
SOURCES = \
|
||||
bdBasicTests.cc \
|
||||
|
||||
INCLUDEPATH += ../src/bd
|
||||
DEPENDPATH += ../src/bd
|
||||
|
||||
LIBS += -L$$DESTDIR -lklayout_bd
|
||||
|
|
@ -265,7 +265,7 @@ public:
|
|||
template <class T>
|
||||
void set_options (const T &options)
|
||||
{
|
||||
m_options.insert (std::make_pair (options.format_name (), options.clone ()));
|
||||
set_options (options.clone ());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -280,7 +280,13 @@ public:
|
|||
template <class T>
|
||||
void set_options (T *options)
|
||||
{
|
||||
m_options.insert (std::make_pair (options->format_name (), options));
|
||||
std::map<std::string, FormatSpecificWriterOptions *>::iterator o = m_options.find (options->format_name ());
|
||||
if (o != m_options.end ()) {
|
||||
delete o->second;
|
||||
o->second = options;
|
||||
} else {
|
||||
m_options.insert (std::make_pair (options->format_name (), options));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
DESTDIR_UT = $$OUT_PWD/../..
|
||||
DESTDIR = $$OUT_PWD/..
|
||||
|
||||
TEMPLATE = lib
|
||||
|
||||
INCLUDEPATH += ../src ../../db ../../tl ../../gsi ../../laybasic ../../lay ../../ut
|
||||
DEPENDPATH += ../src ../../db ../../tl ../../gsi ../../laybasic ../../lay ../../ut
|
||||
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut
|
||||
|
||||
QMAKE_RPATHDIR += $$DESTDIR
|
||||
|
||||
# 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_UT/$${TARGET}.ut
|
||||
} else {
|
||||
QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut
|
||||
}
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
|
||||
DESTDIR_KLP = $$OUT_PWD/../../..
|
||||
DESTDIR_UT = $$OUT_PWD/../../..
|
||||
DESTDIR = $$OUT_PWD/..
|
||||
|
||||
TEMPLATE = lib
|
||||
|
||||
INCLUDEPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../common ../../../ut
|
||||
DEPENDPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../common ../../../ut
|
||||
LIBS += -L$$DESTDIR_KLP -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut
|
||||
INCLUDEPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../ut
|
||||
DEPENDPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../ut
|
||||
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut
|
||||
|
||||
QMAKE_RPATHDIR += $$DESTDIR
|
||||
|
||||
# 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_ut
|
||||
QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_UT/$${TARGET}.ut
|
||||
} else {
|
||||
QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_KLP/$${TARGET}.klp_ut
|
||||
QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,22 @@ ArgBase::is_option () const
|
|||
return !m_option.short_option.empty () || !m_option.long_option.empty ();
|
||||
}
|
||||
|
||||
std::string
|
||||
ArgBase::option_desc () const
|
||||
{
|
||||
std::string res;
|
||||
if (! m_option.short_option.empty ()) {
|
||||
res += "-" + m_option.short_option;
|
||||
}
|
||||
if (! m_option.long_option.empty ()) {
|
||||
if (! res.empty ()) {
|
||||
res += "|";
|
||||
}
|
||||
res += "--" + m_option.long_option;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal argument classes to implement info arguments
|
||||
|
||||
|
|
@ -531,43 +547,61 @@ CommandLineOptions::parse (int argc, char *argv[])
|
|||
|
||||
}
|
||||
|
||||
if (! arg->is_option ()) {
|
||||
try {
|
||||
|
||||
arg->take_value (ex);
|
||||
if (! arg->is_option ()) {
|
||||
|
||||
} else if (arg->wants_value ()) {
|
||||
|
||||
if (ex.test ("=")) {
|
||||
arg->take_value (ex);
|
||||
|
||||
} else if (arg->wants_value ()) {
|
||||
|
||||
if (ex.test ("=")) {
|
||||
arg->take_value (ex);
|
||||
} else {
|
||||
|
||||
ex.expect_end ();
|
||||
++i;
|
||||
if (i == argc) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Value missing")));
|
||||
}
|
||||
|
||||
std::string arg_as_utf8 = tl::to_string (QString::fromLocal8Bit (argv [i]));
|
||||
tl::Extractor ex_value (arg_as_utf8);
|
||||
arg->take_value (ex_value);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (! ex.at_end ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Syntax error in argument at \"..%1\" (use -h for help)").arg (tl::to_qstring (ex.get ()))));
|
||||
if (ex.test ("=")) {
|
||||
arg->take_value (ex);
|
||||
} else {
|
||||
arg->mark_present (arg->option ().inverted);
|
||||
}
|
||||
++i;
|
||||
if (i == argc) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Value missing for last argument (use -h for help)")));
|
||||
}
|
||||
|
||||
std::string arg_as_utf8 = tl::to_string (QString::fromLocal8Bit (argv [i]));
|
||||
tl::Extractor ex_value (arg_as_utf8);
|
||||
arg->take_value (ex_value);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// Execute the action if there is one
|
||||
arg->action (this);
|
||||
|
||||
if (ex.test ("=")) {
|
||||
arg->take_value (ex);
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
std::string msg = "Parser error ";
|
||||
if (i == argc) {
|
||||
msg += "at end of argument list";
|
||||
} else {
|
||||
arg->mark_present (arg->option ().inverted);
|
||||
msg += "at argument #" + tl::to_string (i);
|
||||
}
|
||||
if (! arg->is_option ()) {
|
||||
msg += " (option " + arg->option_desc () + ")";
|
||||
}
|
||||
msg += ":";
|
||||
msg += ex.msg ();
|
||||
|
||||
throw tl::Exception (msg);
|
||||
|
||||
}
|
||||
|
||||
// Execute the action if there is one
|
||||
arg->action (this);
|
||||
|
||||
}
|
||||
|
||||
if (next_plain_arg != plain_args.end () && !(*next_plain_arg)->option ().optional) {
|
||||
|
|
|
|||
|
|
@ -122,6 +122,12 @@ public:
|
|||
*/
|
||||
bool is_option () const;
|
||||
|
||||
/**
|
||||
* @brief Returns an option description string
|
||||
* This string is typically "-x|--xlong".
|
||||
*/
|
||||
std::string option_desc () const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value from the extractor into the target of the argument
|
||||
*/
|
||||
|
|
@ -173,21 +179,30 @@ private:
|
|||
|
||||
/**
|
||||
* @brief A helper for extracting values by type
|
||||
*
|
||||
* @param repeated_hint Is true, if the value is supposed to be repeated
|
||||
* @param enumerated Is true, if the value parser shall stop at a comma to allow for more entries in the next iteration
|
||||
*/
|
||||
template <class T>
|
||||
inline void extract (tl::Extractor &ex, T &t, bool /*for_list*/ = false)
|
||||
inline void extract (tl::Extractor &ex, T &t, bool /*repeated_hint*/, bool enumerated = false)
|
||||
{
|
||||
ex.read (t);
|
||||
if (! enumerated) {
|
||||
ex.expect_end ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A specialization for the string type
|
||||
*/
|
||||
inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false)
|
||||
inline void extract (tl::Extractor &ex, std::string &t, bool /*repeated_hint*/, bool enumerated = false)
|
||||
{
|
||||
if (*ex == '"' || *ex == '\'') {
|
||||
ex.read_quoted (t);
|
||||
} else if (for_list) {
|
||||
if (! enumerated) {
|
||||
ex.expect_end ();
|
||||
}
|
||||
} else if (enumerated) {
|
||||
ex.read (t, ",");
|
||||
} else {
|
||||
t = ex.get ();
|
||||
|
|
@ -203,13 +218,13 @@ inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false)
|
|||
* @brief A specialization for a list of any type (vector)
|
||||
*/
|
||||
template <class T>
|
||||
inline void extract (tl::Extractor &ex, std::vector<T> &t, bool for_list = false)
|
||||
inline void extract (tl::Extractor &ex, std::vector<T> &t, bool repeated_hint, bool /*enumerated*/ = false)
|
||||
{
|
||||
while (! ex.at_end ()) {
|
||||
t.push_back (T ());
|
||||
extract (ex, t.back (), for_list);
|
||||
if (for_list) {
|
||||
ex.test (",");
|
||||
extract (ex, t.back (), false, ! repeated_hint);
|
||||
if (! repeated_hint && ! ex.test (",")) {
|
||||
ex.expect_end ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -287,7 +302,7 @@ public:
|
|||
|
||||
virtual void take_value (tl::Extractor &ex)
|
||||
{
|
||||
extract (ex, *mp_value, !option ().repeated);
|
||||
extract (ex, *mp_value, option ().repeated);
|
||||
}
|
||||
|
||||
virtual void mark_present (bool inverted)
|
||||
|
|
@ -327,7 +342,7 @@ public:
|
|||
{
|
||||
typedef typename type_without_const_ref<T>::inner_type inner_type;
|
||||
inner_type t = inner_type ();
|
||||
extract (ex, t, !option ().repeated);
|
||||
extract (ex, t, option ().repeated);
|
||||
(mp_object->*mp_setter) (t);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -803,7 +803,7 @@ main_cont (int argc, char **argv)
|
|||
// Search and initialize plugin unit tests
|
||||
|
||||
QStringList name_filters;
|
||||
name_filters << QString::fromUtf8 ("*.klp_ut");
|
||||
name_filters << QString::fromUtf8 ("*.ut");
|
||||
|
||||
QDir inst_dir (tl::to_qstring (tl::get_inst_path ()));
|
||||
QStringList inst_modules = inst_dir.entryList (name_filters);
|
||||
|
|
@ -811,13 +811,13 @@ main_cont (int argc, char **argv)
|
|||
|
||||
for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
|
||||
|
||||
QFileInfo klp_file (inst_dir.path (), *im);
|
||||
if (klp_file.exists () && klp_file.isReadable ()) {
|
||||
QFileInfo ut_file (inst_dir.path (), *im);
|
||||
if (ut_file.exists () && ut_file.isReadable ()) {
|
||||
|
||||
std::string pp = tl::to_string (klp_file.absoluteFilePath ());
|
||||
std::string pp = tl::to_string (ut_file.absoluteFilePath ());
|
||||
tl::log << "Loading plugin unit tests " << pp;
|
||||
|
||||
// NOTE: since we are using a different suffix ("*.klp_ut"), we can't use QLibrary.
|
||||
// NOTE: since we are using a different suffix ("*.ut"), 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 ());
|
||||
|
|
@ -995,7 +995,7 @@ main_cont (int argc, char **argv)
|
|||
bool exclude = false;
|
||||
for (std::vector<std::string>::const_iterator m = exclude_test_list.begin (); m != exclude_test_list.end (); ++m) {
|
||||
QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
if (re.indexIn (tl::to_qstring ((*i)->name ())) >= 0) {
|
||||
if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1003,7 +1003,7 @@ main_cont (int argc, char **argv)
|
|||
|
||||
for (std::vector<std::string>::const_iterator m = test_list.begin (); !exclude && m != test_list.end (); ++m) {
|
||||
QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
if (re.indexIn (tl::to_qstring ((*i)->name ())) >= 0) {
|
||||
if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) {
|
||||
tl::info << " " << (*i)->name ();
|
||||
subset.push_back (*i);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in New Issue