mirror of https://github.com/KLayout/klayout.git
Enabled Qt-less unit tests, some basic implementation of Qt-less threads based on pthread and an atomics library. A lot missing.
This commit is contained in:
parent
eec1843459
commit
43243ae162
|
|
@ -11,12 +11,12 @@ SUBDIRS = \
|
|||
lib \
|
||||
buddies \
|
||||
plugins \
|
||||
unit_tests \
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
# TODO: make unit_tests capable of running without Qt
|
||||
SUBDIRS += \
|
||||
unit_tests \
|
||||
klayout_main \
|
||||
laybasic \
|
||||
lay \
|
||||
|
|
@ -94,7 +94,7 @@ plugins.depends += lib rdb db
|
|||
lym.depends += gsi $$LANG_DEPENDS
|
||||
lay.depends += laybasic ant img edt lym
|
||||
klayout_main.depends += plugins $$MAIN_DEPENDS
|
||||
unit_tests.depends += plugins $$MAIN_DEPENDS
|
||||
|
||||
}
|
||||
|
||||
unit_tests.depends += plugins $$MAIN_DEPENDS
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
#include "tlInternational.h"
|
||||
#include "tlHttpStream.h"
|
||||
#include "tlArch.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QDir>
|
||||
|
|
@ -219,7 +220,7 @@ ApplicationBase::ApplicationBase (bool non_ui_mode)
|
|||
m_appdata_path = lay::get_appdata_path ();
|
||||
|
||||
// get the installation path
|
||||
m_inst_path = lay::get_inst_path ();
|
||||
m_inst_path = tl::get_inst_path ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "laySystemPaths.h"
|
||||
#include "tlFileUtils.h"l"
|
||||
#include "tlString.h"
|
||||
|
||||
#include <QDir>
|
||||
|
|
@ -68,53 +69,6 @@ get_appdata_path ()
|
|||
return tl::to_string (appdata_dir.absoluteFilePath (appdata_folder));
|
||||
}
|
||||
|
||||
static std::string
|
||||
get_inst_path_internal ()
|
||||
{
|
||||
// Note: the QCoreApplication::applicationDirPath cannot be used before
|
||||
// a QApplication object is instantiated. Hence this custom implementation.
|
||||
#ifdef _WIN32
|
||||
|
||||
wchar_t buffer[MAX_PATH];
|
||||
int len;
|
||||
if ((len = GetModuleFileName(NULL, buffer, MAX_PATH)) > 0) {
|
||||
QFileInfo fi (QString::fromUtf16 ((const ushort *) buffer, len));
|
||||
return tl::to_string (fi.absolutePath ());
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
|
||||
char buffer[PROC_PIDPATHINFO_MAXSIZE];
|
||||
int ret = proc_pidpath (getpid (), buffer, sizeof (buffer));
|
||||
if (ret > 0) {
|
||||
// TODO: does this correctly translate paths? (MacOS uses UTF-8 encoding with D-like normalization)
|
||||
return tl::to_string (QFileInfo (QString::fromUtf8 (buffer)).absolutePath ());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
QFileInfo proc_exe (tl::to_qstring (tl::sprintf ("/proc/%d/exe", getpid ())));
|
||||
if (proc_exe.exists () && proc_exe.isSymLink ()) {
|
||||
return tl::to_string (QFileInfo (proc_exe.canonicalFilePath ()).absolutePath ());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// As a fallback use QCoreApplication::applicationDirPath, which however is not
|
||||
// available before QCoreApplication is initialized
|
||||
return tl::to_string (QCoreApplication::applicationDirPath ());
|
||||
}
|
||||
|
||||
std::string
|
||||
get_inst_path ()
|
||||
{
|
||||
static std::string s_inst_path;
|
||||
if (s_inst_path.empty ()) {
|
||||
s_inst_path = get_inst_path_internal ();
|
||||
}
|
||||
return s_inst_path;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void
|
||||
get_other_system_paths (std::vector <std::string> &p)
|
||||
|
|
@ -198,7 +152,7 @@ get_klayout_path ()
|
|||
split_path (tl::system_to_string (env), klayout_path);
|
||||
} else {
|
||||
get_other_system_paths (klayout_path);
|
||||
klayout_path.push_back (get_inst_path ());
|
||||
klayout_path.push_back (tl::get_inst_path ());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -41,12 +41,6 @@ namespace lay
|
|||
*/
|
||||
LAY_PUBLIC std::string get_appdata_path ();
|
||||
|
||||
/**
|
||||
* @brief Gets the installation path
|
||||
* The installation path is the path where the current application is installed.
|
||||
*/
|
||||
LAY_PUBLIC std::string get_inst_path ();
|
||||
|
||||
/**
|
||||
* @brief Gets the KLayout path
|
||||
* This is a path (in the sense of a search path - i.e. multiple paths)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ DEFINES += MAKE_TL_LIBRARY
|
|||
|
||||
LIBS += -lz
|
||||
|
||||
equals(HAVE_QT, "0") {
|
||||
LIBS += -lpthread
|
||||
}
|
||||
|
||||
equals(HAVE_CURL, "1") {
|
||||
LIBS += -lcurl
|
||||
win32 {
|
||||
|
|
|
|||
|
|
@ -710,4 +710,45 @@ bool is_same_file (const std::string &a, const std::string &b)
|
|||
#endif
|
||||
}
|
||||
|
||||
static std::string
|
||||
get_inst_path_internal ()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
wchar_t buffer[MAX_PATH];
|
||||
int len;
|
||||
if ((len = GetModuleFileName (NULL, buffer, MAX_PATH)) > 0) {
|
||||
return tl::absolute_path (tl::to_string (std::wstring (buffer)));
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
|
||||
char buffer[PROC_PIDPATHINFO_MAXSIZE];
|
||||
int ret = proc_pidpath (getpid (), buffer, sizeof (buffer));
|
||||
if (ret > 0) {
|
||||
// TODO: does this correctly translate paths? (MacOS uses UTF-8 encoding with D-like normalization)
|
||||
return tl::absolute_path (buffer);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::string pf = tl::sprintf ("/proc/%d/exe", getpid ());
|
||||
if (tl::file_exists (pf)) {
|
||||
return tl::absolute_path (pf);
|
||||
}
|
||||
|
||||
#endif
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
std::string
|
||||
get_inst_path ()
|
||||
{
|
||||
static std::string s_inst_path;
|
||||
if (s_inst_path.empty ()) {
|
||||
s_inst_path = get_inst_path_internal ();
|
||||
}
|
||||
return s_inst_path;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,11 @@ std::string TL_PUBLIC current_dir ();
|
|||
*/
|
||||
std::vector<std::string> TL_PUBLIC split_path (const std::string &p, bool keep_last = false);
|
||||
|
||||
/**
|
||||
* @brief Gets the path of the currently running process
|
||||
*/
|
||||
std::string TL_PUBLIC get_inst_path ();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ ProgressAdaptor::prev ()
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
// Progress implementation
|
||||
|
||||
// Hint: we don't want the QThreadStorage take ownership over the object. Hence we don't
|
||||
// Hint: we don't want the ThreadStorage take ownership over the object. Hence we don't
|
||||
// store a pointer but a pointer to a pointer.
|
||||
static tl::ThreadStorage<ProgressAdaptor **> s_thread_data;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,3 +20,232 @@
|
|||
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_QT)
|
||||
|
||||
#include "tlThreads.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlInternational.h"
|
||||
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// WaitCondition implementation
|
||||
|
||||
WaitCondition::WaitCondition ()
|
||||
{
|
||||
// @@@
|
||||
}
|
||||
|
||||
bool WaitCondition::wait (Mutex *mutex, unsigned long /*time*/)
|
||||
{
|
||||
mutex->unlock();
|
||||
// @@@
|
||||
mutex->lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitCondition::wakeAll ()
|
||||
{
|
||||
// @@@
|
||||
}
|
||||
|
||||
void WaitCondition::wakeOne ()
|
||||
{
|
||||
// @@@
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Thread implementation
|
||||
|
||||
class ThreadPrivateData
|
||||
{
|
||||
public:
|
||||
ThreadPrivateData ()
|
||||
: pthread (), initialized (false), return_code (0), running (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
pthread_t pthread;
|
||||
bool initialized;
|
||||
void *return_code;
|
||||
bool running;
|
||||
};
|
||||
|
||||
void *start_thread (void *data)
|
||||
{
|
||||
((Thread *) data)->do_run ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Thread::Thread ()
|
||||
: mp_data (new ThreadPrivateData ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Thread::~Thread ()
|
||||
{
|
||||
delete mp_data;
|
||||
mp_data = 0;
|
||||
}
|
||||
|
||||
void Thread::do_run ()
|
||||
{
|
||||
try {
|
||||
mp_data->running = true;
|
||||
run ();
|
||||
mp_data->running = false;
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << tr ("Exception from thread : ") << ex.msg ();
|
||||
mp_data->running = false;
|
||||
} catch (...) {
|
||||
tl::error << tr ("Unspecific exception from thread");
|
||||
mp_data->running = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::exit (int return_code)
|
||||
{
|
||||
pthread_exit (reinterpret_cast<void *> (size_t (return_code)));
|
||||
}
|
||||
|
||||
bool Thread::isFinished () const
|
||||
{
|
||||
if (! mp_data->initialized) {
|
||||
return false;
|
||||
} else {
|
||||
return ! mp_data->running;
|
||||
}
|
||||
}
|
||||
|
||||
bool Thread::isRunning () const
|
||||
{
|
||||
if (! mp_data->initialized) {
|
||||
return false;
|
||||
} else {
|
||||
return mp_data->running;
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::quit ()
|
||||
{
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void Thread::start ()
|
||||
{
|
||||
if (isRunning ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! mp_data->initialized) {
|
||||
mp_data->initialized = true;
|
||||
if (pthread_create (&mp_data->pthread, NULL, &start_thread, (void *) this) != 0) {
|
||||
tl::error << tr ("Failed to create thread");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::terminate ()
|
||||
{
|
||||
if (isRunning () && pthread_cancel (mp_data->pthread) != 0) {
|
||||
tl::error << tr ("Failed to terminate thread");
|
||||
}
|
||||
}
|
||||
|
||||
bool Thread::wait (unsigned long /*time*/)
|
||||
{
|
||||
if (! mp_data->initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// @@@ TODO: timed join
|
||||
if (pthread_join (mp_data->pthread, &mp_data->return_code) != 0) {
|
||||
tl::error << tr ("Could not join threads");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// ThreadStorage implementation
|
||||
|
||||
class ThreadStorageObjectList
|
||||
{
|
||||
public:
|
||||
ThreadStorageObjectList () { }
|
||||
|
||||
~ThreadStorageObjectList ()
|
||||
{
|
||||
for (std::map<void *, ThreadStorageHolderBase *>::iterator i = m_objects.begin (); i != m_objects.end (); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
m_objects.clear ();
|
||||
}
|
||||
|
||||
void add (void *index, ThreadStorageHolderBase *holder)
|
||||
{
|
||||
std::map<void *, ThreadStorageHolderBase *>::iterator h = m_objects.find (holder);
|
||||
if (h != m_objects.end ()) {
|
||||
delete h->second;
|
||||
h->second = holder;
|
||||
} else {
|
||||
m_objects.insert (std::make_pair (index, holder));
|
||||
}
|
||||
}
|
||||
|
||||
ThreadStorageHolderBase *get (void *index)
|
||||
{
|
||||
std::map<void *, ThreadStorageHolderBase *>::const_iterator h = m_objects.find (index);
|
||||
return h != m_objects.end () ? h->second : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<void *, ThreadStorageHolderBase *> m_objects;
|
||||
};
|
||||
|
||||
static pthread_key_t s_storage_key;
|
||||
static pthread_once_t s_keycreated = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void free_key (void *data)
|
||||
{
|
||||
delete (ThreadStorageObjectList *) data;
|
||||
}
|
||||
|
||||
static void create_key ()
|
||||
{
|
||||
pthread_key_create (&s_storage_key, free_key);
|
||||
}
|
||||
|
||||
ThreadStorageBase::ThreadStorageBase ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void ThreadStorageBase::add (ThreadStorageHolderBase *holder)
|
||||
{
|
||||
pthread_once (&s_keycreated, create_key);
|
||||
if (! pthread_getspecific (s_storage_key)) {
|
||||
pthread_setspecific (s_storage_key, new ThreadStorageObjectList ());
|
||||
}
|
||||
|
||||
((ThreadStorageObjectList *) pthread_getspecific (s_storage_key))->add ((void *) this, holder);
|
||||
}
|
||||
|
||||
ThreadStorageHolderBase *ThreadStorageBase::holder ()
|
||||
{
|
||||
pthread_once (&s_keycreated, create_key);
|
||||
if (! pthread_getspecific (s_storage_key)) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((ThreadStorageObjectList *) pthread_getspecific (s_storage_key))->get ((void *) this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
# include <QWaitCondition>
|
||||
# include <QThread>
|
||||
# include <QThreadStorage>
|
||||
#else
|
||||
// atomics taken from https://github.com/mbitsnbites/atomic
|
||||
# include "atomic/spinlock.h"
|
||||
#endif
|
||||
|
||||
namespace tl
|
||||
|
|
@ -56,11 +59,10 @@ public:
|
|||
|
||||
// The non-Qt version is a dummy implementation as threading is not supported (yet)
|
||||
class TL_PUBLIC Mutex
|
||||
: public atomic::spinlock
|
||||
{
|
||||
public:
|
||||
Mutex () { }
|
||||
void lock () { }
|
||||
void unlock () { }
|
||||
Mutex () : atomic::spinlock () { }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -88,10 +90,10 @@ public:
|
|||
class TL_PUBLIC WaitCondition
|
||||
{
|
||||
public:
|
||||
WaitCondition () { }
|
||||
bool wait (Mutex * /*mutex*/, unsigned long /*time*/ = std::numeric_limits<unsigned long>::max ()) { return true; }
|
||||
void wakeAll () { }
|
||||
void wakeOne () { }
|
||||
WaitCondition ();
|
||||
bool wait (Mutex * /*mutex*/, unsigned long /*time*/ = std::numeric_limits<unsigned long>::max ());
|
||||
void wakeAll ();
|
||||
void wakeOne ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -136,23 +138,29 @@ public:
|
|||
|
||||
#else
|
||||
|
||||
// TODO: this is a non-threaded dummy implementation
|
||||
class ThreadPrivateData;
|
||||
|
||||
class TL_PUBLIC Thread
|
||||
{
|
||||
public:
|
||||
Thread () { }
|
||||
virtual ~Thread () { }
|
||||
Thread ();
|
||||
virtual ~Thread ();
|
||||
|
||||
void exit (int /*returnCode*/ = 0) { }
|
||||
bool isFinished () const { return true; }
|
||||
bool isRunning () const { return false; }
|
||||
void quit () { }
|
||||
void start () { run (); }
|
||||
void terminate () { }
|
||||
bool wait (unsigned long /*time*/ = std::numeric_limits<unsigned long>::max ()) { return true; }
|
||||
void exit (int /*returnCode*/ = 0);
|
||||
bool isFinished () const;
|
||||
bool isRunning () const;
|
||||
void quit ();
|
||||
void start ();
|
||||
void terminate ();
|
||||
bool wait (unsigned long /*time*/ = std::numeric_limits<unsigned long>::max ());
|
||||
|
||||
protected:
|
||||
virtual void run () { }
|
||||
|
||||
private:
|
||||
friend void *start_thread (void *);
|
||||
ThreadPrivateData *mp_data;
|
||||
void do_run ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -175,21 +183,69 @@ public:
|
|||
|
||||
#else
|
||||
|
||||
// TODO: this is the non-threaded dummy implementation
|
||||
template <class T>
|
||||
class TL_PUBLIC ThreadStorage
|
||||
class TL_PUBLIC ThreadStorageHolderBase
|
||||
{
|
||||
public:
|
||||
ThreadStorage () : m_t (), m_has_data (false) { }
|
||||
ThreadStorageHolderBase (void *obj) : mp_obj (obj) { }
|
||||
virtual ~ThreadStorageHolderBase () { }
|
||||
|
||||
bool hasLocalData () const { return m_has_data; }
|
||||
T &localData () { return m_t; }
|
||||
T localData () const { return m_t; }
|
||||
void setLocalData (const T &data) { m_t = data; m_has_data = true; }
|
||||
protected:
|
||||
void *obj () { return mp_obj; }
|
||||
void *mp_obj;
|
||||
};
|
||||
|
||||
private:
|
||||
T m_t;
|
||||
bool m_has_data;
|
||||
template <class T>
|
||||
class ThreadStorageHolder
|
||||
: public ThreadStorageHolderBase
|
||||
{
|
||||
public:
|
||||
ThreadStorageHolder (T *t) : ThreadStorageHolderBase ((void *) t) { }
|
||||
~ThreadStorageHolder () { delete data (); }
|
||||
T *data () { return (T *) obj (); }
|
||||
};
|
||||
|
||||
class TL_PUBLIC ThreadStorageBase
|
||||
{
|
||||
public:
|
||||
ThreadStorageBase ();
|
||||
|
||||
protected:
|
||||
void add (ThreadStorageHolderBase *holder);
|
||||
ThreadStorageHolderBase *holder ();
|
||||
|
||||
const ThreadStorageHolderBase *holder () const
|
||||
{
|
||||
return (const_cast<ThreadStorageBase *> (this)->holder ());
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: this is the non-threaded dummy implementation
|
||||
template <class T>
|
||||
class ThreadStorage
|
||||
: public ThreadStorageBase
|
||||
{
|
||||
public:
|
||||
ThreadStorage () : ThreadStorageBase () { }
|
||||
|
||||
bool hasLocalData () const
|
||||
{
|
||||
return dynamic_cast<const ThreadStorageHolder<T> *> (holder ()) != 0;
|
||||
}
|
||||
|
||||
T &localData ()
|
||||
{
|
||||
return *(dynamic_cast<ThreadStorageHolder<T> *> (holder ())->data ());
|
||||
}
|
||||
|
||||
T localData () const
|
||||
{
|
||||
return *(dynamic_cast<const ThreadStorageHolder<T> *> (holder ())->data ());
|
||||
}
|
||||
|
||||
void setLocalData (const T &data)
|
||||
{
|
||||
add (new ThreadStorageHolder<T> (new T (data)));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ TEST(15)
|
|||
EXPECT_EQ (tl::to_string_from_local (tl::to_local ("Hällo\tWörld!").c_str ()), "Hällo\tWörld!");
|
||||
EXPECT_EQ (std::string ("Ä").size (), size_t (2));
|
||||
EXPECT_EQ (tl::to_string (std::wstring (L"Ä")), "Ä");
|
||||
EXPECT_EQ (tl::to_wstring (std::string ("Ä")).size (), 1);
|
||||
EXPECT_EQ (tl::to_wstring (std::string ("Ä")).size (), size_t (1));
|
||||
EXPECT_EQ (tl::to_string (tl::to_wstring ("Utf8 supports emoticons: \xF0\x9F\x98\x81\nand Umlauts: äüö")).c_str (), "Utf8 supports emoticons: \xF0\x9F\x98\x81\nand Umlauts: äüö");
|
||||
|
||||
EXPECT_EQ (tl::to_upper_case ("äÄüÜöÖß"), "ÄÄÜÜÖÖß");
|
||||
|
|
|
|||
|
|
@ -28,22 +28,31 @@
|
|||
#include "tlStaticObjects.h"
|
||||
#include "tlTimer.h"
|
||||
#include "tlCommandLineParser.h"
|
||||
#include "layApplication.h"
|
||||
#include "laySystemPaths.h"
|
||||
#include "layVersion.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlGlobPattern.h"
|
||||
#include "rba.h"
|
||||
#include "pya.h"
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiExternalMain.h"
|
||||
#include "dbStatic.h"
|
||||
#include "dbInit.h"
|
||||
|
||||
// This hard-links the GSI test classes
|
||||
#include "../gsi_test/gsiTestForceLink.h"
|
||||
|
||||
#include "version.h"
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QTextCodec>
|
||||
# include "layApplication.h"
|
||||
# include "laySystemPaths.h"
|
||||
# include "layVersion.h"
|
||||
|
||||
# include "version.h"
|
||||
|
||||
# include <QDir>
|
||||
# include <QFileInfo>
|
||||
# include <QTextCodec>
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# include <dlfcn.h>
|
||||
|
|
@ -54,7 +63,7 @@
|
|||
|
||||
// required to force linking of the "ext", "lib" and "drc" module
|
||||
#include "libForceLink.h"
|
||||
#if defined(HAVE_RUBY)
|
||||
#if defined(HAVE_RUBY) && defined(HAVE_QT)
|
||||
#include "drcForceLink.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -87,7 +96,7 @@ run_test (tl::TestBase *t, bool editable, bool slow, int repeat)
|
|||
}
|
||||
|
||||
static int
|
||||
run_tests (const std::vector<tl::TestBase *> &selected_tests, bool editable, bool non_editable, bool slow, int repeat, lay::ApplicationBase &app, bool gsi_coverage, const std::vector<std::string> &class_names_vector)
|
||||
run_tests (const std::vector<tl::TestBase *> &selected_tests, bool editable, bool non_editable, bool slow, int repeat, bool gsi_coverage, const std::vector<std::string> &class_names_vector)
|
||||
{
|
||||
std::set<std::string> class_names;
|
||||
class_names.insert (class_names_vector.begin (), class_names_vector.end ());
|
||||
|
|
@ -109,7 +118,11 @@ run_tests (const std::vector<tl::TestBase *> &selected_tests, bool editable, boo
|
|||
|
||||
ut::noctrl << tl::replicate ("=", ut::TestConsole::instance ()->real_columns ());
|
||||
ut::noctrl << "Running tests in " << mode << " mode ...";
|
||||
app.set_editable (e != 0);
|
||||
|
||||
db::set_default_editable_mode (e != 0);
|
||||
#if defined(HAVE_QT)
|
||||
lay::ApplicationBase::instance ()->set_editable (e != 0);
|
||||
#endif
|
||||
|
||||
int failed = 0;
|
||||
std::vector <tl::TestBase *> failed_tests;
|
||||
|
|
@ -339,6 +352,11 @@ run_tests (const std::vector<tl::TestBase *> &selected_tests, bool editable, boo
|
|||
static int
|
||||
main_cont (int &argc, char **argv)
|
||||
{
|
||||
std::auto_ptr<rba::RubyInterpreter> ruby_interpreter;
|
||||
std::auto_ptr<pya::PythonInterpreter> python_interpreter;
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
// install the version strings
|
||||
lay::Version::set_exe_name (prg_exe_name);
|
||||
lay::Version::set_name (prg_name);
|
||||
|
|
@ -349,12 +367,15 @@ main_cont (int &argc, char **argv)
|
|||
subversion += prg_rev;
|
||||
lay::Version::set_subversion (subversion.c_str ());
|
||||
|
||||
#endif
|
||||
|
||||
int result = 0;
|
||||
|
||||
ut::TestConsole console (stdout);
|
||||
|
||||
try {
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
pya::PythonInterpreter::initialize ();
|
||||
gsi::initialize_external ();
|
||||
|
||||
|
|
@ -372,35 +393,60 @@ main_cont (int &argc, char **argv)
|
|||
QTextCodec::setCodecForTr (QTextCodec::codecForName ("utf8"));
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
// initialize the modules (load their plugins from the paths)
|
||||
db::init ();
|
||||
|
||||
// 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.
|
||||
gsi::initialize ();
|
||||
|
||||
// initialize the tl::Expression subsystem with GSI-bound classes
|
||||
gsi::initialize_expressions ();
|
||||
|
||||
// instantiate the interpreters
|
||||
|
||||
ruby_interpreter.reset (new rba::RubyInterpreter ());
|
||||
ruby_interpreter->push_console (&console);
|
||||
|
||||
python_interpreter.reset (new pya::PythonInterpreter ());
|
||||
python_interpreter->push_console (&console);
|
||||
|
||||
#endif
|
||||
|
||||
// Search and initialize plugin unit tests
|
||||
|
||||
QStringList name_filters;
|
||||
name_filters << QString::fromUtf8 ("*.ut");
|
||||
std::string inst_dir = tl::get_inst_path ();
|
||||
std::vector<std::string> inst_modules = tl::dir_entries (inst_dir, true, false);
|
||||
std::sort (inst_modules.begin (), inst_modules.end ());
|
||||
|
||||
QDir inst_dir (tl::to_qstring (lay::get_inst_path ()));
|
||||
QStringList inst_modules = inst_dir.entryList (name_filters);
|
||||
inst_modules.sort ();
|
||||
tl::GlobPattern pat ("*.ut");
|
||||
|
||||
for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
|
||||
for (std::vector<std::string>::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
|
||||
|
||||
QFileInfo ut_file (inst_dir.path (), *im);
|
||||
if (ut_file.exists () && ut_file.isReadable ()) {
|
||||
if (! pat.match (*im)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string pp = tl::to_string (ut_file.absoluteFilePath ());
|
||||
tl::log << "Loading unit tests " << pp;
|
||||
std::string ut_file = tl::absolute_file_path (tl::combine_path (inst_dir, *im));
|
||||
if (tl::file_exists (ut_file)) {
|
||||
|
||||
tl::log << "Loading unit tests " << ut_file;
|
||||
|
||||
// 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 ());
|
||||
HINSTANCE handle = LoadLibraryW (tl::to_wstring (ut_file).c_str ());
|
||||
if (! handle) {
|
||||
throw tl::Exception (tl::sprintf ("Unable to load plugin tests: %s with error message: %s", pp.c_str (), GetLastError ()));
|
||||
throw tl::Exception (tl::sprintf ("Unable to load plugin tests: %s with error message: %s", ut_file.c_str (), GetLastError ()));
|
||||
}
|
||||
#else
|
||||
void *handle;
|
||||
handle = dlopen (tl::string_to_system (pp).c_str (), RTLD_LAZY);
|
||||
handle = dlopen (tl::string_to_system (ut_file).c_str (), RTLD_LAZY);
|
||||
if (! handle) {
|
||||
throw tl::Exception (tl::sprintf ("Unable to load plugin tests: %s", pp.c_str ()));
|
||||
throw tl::Exception (tl::sprintf ("Unable to load plugin tests: %s", ut_file.c_str ()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -486,7 +532,7 @@ main_cont (int &argc, char **argv)
|
|||
ut::noctrl << "Entering KLayout test suite";
|
||||
|
||||
ut::noctrl << "TESTSRC=" << tl::testsrc ();
|
||||
ut::noctrl << "TESTTMP=" << tl::to_string (QDir (tl::to_qstring (tl::testtmp ())).absolutePath ());
|
||||
ut::noctrl << "TESTTMP=" << tl::absolute_file_path (tl::testtmp ());
|
||||
|
||||
const std::vector<tl::TestBase *> *selected_tests = 0;
|
||||
std::vector<tl::TestBase *> subset;
|
||||
|
|
@ -500,15 +546,19 @@ 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 () && !exclude; ++m) {
|
||||
QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) {
|
||||
tl::GlobPattern re (*m);
|
||||
re.set_case_sensitive (false);
|
||||
re.set_header_match (true);
|
||||
if (re.match ((*i)->name ())) {
|
||||
exclude = true;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
tl::GlobPattern re (*m);
|
||||
re.set_case_sensitive (false);
|
||||
re.set_header_match (true);
|
||||
if (re.match ((*i)->name ())) {
|
||||
ut::noctrl << " " << (*i)->name ();
|
||||
subset.push_back (*i);
|
||||
break;
|
||||
|
|
@ -521,7 +571,7 @@ main_cont (int &argc, char **argv)
|
|||
selected_tests = &tl::TestRegistrar::instance()->tests ();
|
||||
}
|
||||
|
||||
result = run_tests (*selected_tests, editable, non_editable, slow, repeat, app, gsi_coverage, class_names);
|
||||
result = run_tests (*selected_tests, editable, non_editable, slow, repeat, gsi_coverage, class_names);
|
||||
|
||||
ut::ctrl << "</testsuites>";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,22 @@
|
|||
|
||||
INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC $$LAYBASIC_INC $$LAY_INC $$ANT_INC $$IMG_INC $$EDT_INC $$LIB_INC $$RBA_INC $$PYA_INC $$VERSION_INC
|
||||
DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC $$LAYBASIC_INC $$LAY_INC $$ANT_INC $$IMG_INC $$EDT_INC $$LIB_INC $$RBA_INC $$PYA_INC $$VERSION_INC
|
||||
INCLUDEPATH += $$RBA_INC $$PYA_INC $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC $$LAYBASIC_INC $$LAY_INC $$ANT_INC $$IMG_INC $$EDT_INC $$LIB_INC $$VERSION_INC
|
||||
DEPENDPATH += $$RBA_INC $$PYA_INC $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC $$LAYBASIC_INC $$LAY_INC $$ANT_INC $$IMG_INC $$EDT_INC $$LIB_INC $$VERSION_INC
|
||||
|
||||
LIBS += $$PYTHONLIBFILE $$RUBYLIBFILE -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_db -lklayout_rdb -lklayout_lym -lklayout_laybasic -lklayout_lay -lklayout_ant -lklayout_img -lklayout_edt -lklayout_lib
|
||||
LIBS += $$PYTHONLIBFILE $$RUBYLIBFILE -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_db -lklayout_rdb -lklayout_lib
|
||||
|
||||
# Note: this accounts for UI-generated headers placed into the output folders in
|
||||
# shadow builds:
|
||||
INCLUDEPATH += $$DESTDIR/laybasic $$DESTDIR/lay $$DESTDIR/ext
|
||||
DEPENDPATH += $$DESTDIR/laybasic $$DESTDIR/lay $$DESTDIR/ext
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
INCLUDEPATH += $$LYM_INC $$LAYBASIC_INC $$LAY_INC $$ANT_INC $$IMG_INC $$EDT_INC
|
||||
DEPENDPATH += $$LYM_INC $$LAYBASIC_INC $$LAY_INC $$ANT_INC $$IMG_INC $$EDT_INC
|
||||
|
||||
LIBS += -L$$DESTDIR -lklayout_lym -lklayout_laybasic -lklayout_lay -lklayout_ant -lklayout_img -lklayout_edt
|
||||
|
||||
# Note: this accounts for UI-generated headers placed into the output folders in
|
||||
# shadow builds:
|
||||
INCLUDEPATH += $$DESTDIR/laybasic $$DESTDIR/lay $$DESTDIR/ext
|
||||
DEPENDPATH += $$DESTDIR/laybasic $$DESTDIR/lay $$DESTDIR/ext
|
||||
|
||||
}
|
||||
|
||||
equals(HAVE_QTBINDINGS, "1") {
|
||||
LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtCore
|
||||
|
|
@ -25,9 +34,11 @@ equals(HAVE_PYTHON, "1") {
|
|||
LIBS += -lklayout_pyastub
|
||||
}
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
# DRC is only available with Ruby
|
||||
INCLUDEPATH += $$DRC_INC
|
||||
DEPENDPATH += $$DRC_INC
|
||||
LIBS += -lklayout_drc
|
||||
!equals(HAVE_QT, "0") {
|
||||
equals(HAVE_RUBY, "1") {
|
||||
# DRC is only available with Ruby
|
||||
INCLUDEPATH += $$DRC_INC
|
||||
DEPENDPATH += $$DRC_INC
|
||||
LIBS += -lklayout_drc
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue