From 7a60f5957be5d3697fb2f5870697df435b443aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Tue, 3 Mar 2020 22:19:31 +0100 Subject: [PATCH 1/2] Enable Qt-less build of unit tests on Windows in debug mode and without iterator assertions --- build.bat | 13 +++++++ src/klayout.pri | 4 ++ src/klayout.pro | 2 +- src/unit_tests/unit_test_main.cc | 66 ++++++++++++++++++++++++++++++-- src/unit_tests/unit_tests.pro | 4 ++ 5 files changed, 85 insertions(+), 4 deletions(-) diff --git a/build.bat b/build.bat index 64dcc84ce..532ef80a9 100644 --- a/build.bat +++ b/build.bat @@ -17,6 +17,9 @@ set HAVE_64BIT_COORD=0 set HAVE_PYTHON=1 set HAVE_RUBY=1 set MAKE_OPT= +set HAVE_CURL=0 +set HAVE_EXPAT=0 +set HAVE_PTHREADS=0 set arch=x64 set compiler=msvc2017 @@ -64,6 +67,10 @@ for %%a in (%*) do ( set "HAVE_QTBINDINGS=0" ) else if "!arg!" equ "-without-qt" ( set "HAVE_QT=0" + set "HAVE_CURL=1" + set "HAVE_EXPAT=1" + set "HAVE_PTHREADS=1" + set "HAVE_QTBINDINGS=0" ) else if "!arg!" equ "-with-64bit-coord" ( set "HAVE_64BIT_COORD=1" ) else if "!arg!" equ "-without-64bit-coord" ( @@ -211,6 +218,9 @@ echo HAVE_QT: %HAVE_QT% echo HAVE_64BIT_COORD: %HAVE_64BIT_COORD% echo HAVE_PYTHON: %HAVE_PYTHON% echo HAVE_RUBY: %HAVE_RUBY% +echo HAVE_CURL: %HAVE_CURL% +echo HAVE_PTHREADS: %HAVE_PTHREADS% +echo HAVE_EXPAT: %HAVE_EXPAT% echo MAKE_OPT: %MAKE_OPT% echo. echo qmake binary: %option-qmake% @@ -245,6 +255,9 @@ echo on "KLAYOUT_VERSION_REV=%KLAYOUT_VERSION_REV%" ^ "HAVE_QTBINDINGS=%HAVE_QTBINDINGS%" ^ "HAVE_QT=%HAVE_QT%" ^ + "HAVE_EXPAT=%HAVE_EXPAT%" ^ + "HAVE_CURL=%HAVE_CURL%" ^ + "HAVE_PTHREADS=%HAVE_PTHREADS%" ^ "HAVE_RUBY=%HAVE_RUBY%" ^ "HAVE_PYTHON=%HAVE_PYTHON%" ^ "HAVE_64BIT_COORD=%HAVE_64BIT_COORD%" ^ diff --git a/src/klayout.pri b/src/klayout.pri index 645211009..d9d1fdc41 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -120,6 +120,10 @@ msvc { QMAKE_CXXFLAGS_WARN_ON += \ + # as we're using default-constructed iterators as "null" we can't have + # checked iterators with MSVC + DEFINES += _ITERATOR_DEBUG_LEVEL=0 + } else { CONFIG(gcov) { diff --git a/src/klayout.pro b/src/klayout.pro index 0f96adf0a..0293b6315 100644 --- a/src/klayout.pro +++ b/src/klayout.pro @@ -99,7 +99,7 @@ plugins.depends += lib rdb db } -unit_tests.depends += plugins $$MAIN_DEPENDS +unit_tests.depends += plugins $$MAIN_DEPENDS $$LANG_DEPENDS RESOURCES += \ plugins/tools/import/lay_plugin/layResources.qrc \ diff --git a/src/unit_tests/unit_test_main.cc b/src/unit_tests/unit_test_main.cc index 04cd2c14b..cca0f4281 100644 --- a/src/unit_tests/unit_test_main.cc +++ b/src/unit_tests/unit_test_main.cc @@ -73,18 +73,78 @@ static int main_cont (int &argc, char **argv); -int -main (int argc, char **argv) +#ifdef _WIN32 // for VC++ + +// for VC++/MinGW provide a wrapper for main. +#include + +extern "C" +int WINAPI +WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*prevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/) { - int ret = rba::RubyInterpreter::initialize (argc, argv, &main_cont); + int argCount = 0; + LPWSTR *szArgList = CommandLineToArgvW(GetCommandLineW(), &argCount); + + // fail safe behaviour + if (!szArgList) { + MessageBox(NULL, L"Unable to parse command line", L"Error", MB_OK); + return 10; + } + + char **argv = new char *[argCount]; + for (int i = 0; i < argCount; i++) { + std::wstring a; + for (WCHAR *wc = szArgList [i]; *wc; ++wc) { + a += wchar_t ((unsigned int) *wc); + } + std::string aa = tl::to_string (a); + argv [i] = new char [aa.size () + 1]; + strcpy (argv [i], aa.c_str ()); + } + + int ret = rba::RubyInterpreter::initialize (argCount, argv, &main_cont); // NOTE: this needs to happen after the Ruby interpreter went down since otherwise the GC will // access objects that are already cleaned up. tl::StaticObjects::cleanup (); + for (int i = 0; i < argCount; i++) { + delete[] argv [i]; + } + delete[] argv; + + LocalFree(szArgList); return ret; } +#else + +int +main(int a_argc, const char **a_argv) +{ + char **argv = new char *[a_argc]; + for (int i = 0; i < a_argc; i++) { + tl::string aa = tl::system_to_string (a_argv[i]); + argv [i] = new char [aa.size () + 1]; + strcpy (argv [i], aa.c_str ()); + } + + int ret = rba::RubyInterpreter::initialize (a_argc, argv, &main_cont); + + // NOTE: this needs to happen after the Ruby interpreter went down since otherwise the GC will + // access objects that are already cleaned up. + tl::StaticObjects::cleanup (); + + for (int i = 0; i < a_argc; i++) { + delete[] argv [i]; + } + delete[] argv; + + return ret; +} + +#endif + static bool run_test (tl::TestBase *t, bool editable, bool slow, int repeat) { diff --git a/src/unit_tests/unit_tests.pro b/src/unit_tests/unit_tests.pro index 648d1ec65..a5eb77c46 100644 --- a/src/unit_tests/unit_tests.pro +++ b/src/unit_tests/unit_tests.pro @@ -22,6 +22,8 @@ HEADERS += \ !win32 { LIBS += -ldl +} else { + LIBS += -lshell32 } LIBS += -lklayout_gsi_test @@ -38,5 +40,7 @@ LIBS += -lklayout_gsi_test } } +} else { + CONFIG -= qt } From ef4c9313ab0c79b6ddd4858e8b64fd8d45250ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Tue, 3 Mar 2020 22:24:03 +0100 Subject: [PATCH 2/2] Fixed a severe bug in join_symmetric_nets --- src/db/db/dbNetlistCompare.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 3b423f2d1..39be51719 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -3627,7 +3627,7 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG } } -static bool derive_symmetry_groups (const db::NetGraph &graph, const tl::equivalence_clusters &identical_nodes, std::set &considered_nodes, const std::set &symmetry_group, std::list > &symmetry_groups) +static bool derive_symmetry_groups (const db::NetGraph &graph, const tl::equivalence_clusters &identical_nodes, std::set &considered_nodes, const std::set &symmetry_group, std::vector > &symmetry_groups) { std::set cids; std::set new_symmetry_group; @@ -3752,7 +3752,7 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) } } - std::list > symmetry_groups; + std::vector > symmetry_groups; std::set visited; for (std::vector::const_iterator np = nodes.begin (); np != nodes.end (); ++np) { @@ -3774,10 +3774,13 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) } + std::sort (symmetry_groups.begin (), symmetry_groups.end ()); + symmetry_groups.erase (std::unique (symmetry_groups.begin (), symmetry_groups.end ()), symmetry_groups.end ()); + if (! symmetry_groups.empty () && tl::verbosity () >= 30) { tl::info << tl::to_string (tr ("Symmetry groups:")); int index = 0; - for (std::list >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { + for (std::vector >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { tl::info << " [" << index << "] " << tl::noendl; for (std::set::const_iterator i = g->begin (); i != g->end (); ++i) { tl::info << (i == g->begin () ? "" : ",") << (graph.node (*i).net () ? graph.node (*i).net ()->expanded_name ().c_str () : "(null)") << tl::noendl; @@ -3789,7 +3792,7 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) // join the nets - for (std::list >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { + for (std::vector >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { for (std::set::const_iterator i = g->begin (); i != g->end (); ++i) { if (i != g->begin ()) { circuit->join_nets (const_cast (graph.net_by_node_index (*g->begin ())), const_cast (graph.net_by_node_index (*i)));