WIP: made pymod functional on Windows (without Qt). Tests pass.

This commit is contained in:
klayoutmatthias 2018-07-10 23:34:30 +02:00
parent 32b6439704
commit 616c2942e1
21 changed files with 187 additions and 80 deletions

View File

@ -37,6 +37,7 @@ RUBYVERSIONCODE=""
PYTHONINCLUDE=""
PYTHONLIBFILE=""
PYTHONEXTSUFFIX=""
QMAKE=""
RUBY=""
@ -111,6 +112,10 @@ while [ "$*" != "" ]; do
PYTHONLIBFILE="$1"
shift
;;
-pyextsuffix)
PYTHONEXTSUFFIX="$1"
shift
;;
-qmake)
QMAKE="$1"
shift
@ -414,6 +419,11 @@ if [ "$PYTHON" != "" ] && [ "$PYTHON" != "-" ]; then
echo " Python headers found: $PYTHONINCLUDE"
fi
if [ "$PYTHONEXTSUFFIX" = "" ]; then
PYTHONEXTSUFFIX=`$PYTHON -c "import sysconfig; print(sysconfig.get_config_vars('EXT_SUFFIX')[0])" 2>/dev/null`
echo " Python extension suffix: $PYTHONEXTSUFFIX"
fi
echo " Python installation is in:"
echo " - $PYTHONLIBFILE (lib)"
echo " - $PYTHONINCLUDE (includes)"
@ -552,6 +562,7 @@ qmake_options=(
PYTHON="$PYTHON"
PYTHONLIBFILE="$PYTHONLIBFILE"
PYTHONINCLUDE="$PYTHONINCLUDE"
PYTHONEXTSUFFIX="$PYTHONEXTSUFFIX"
HAVE_PYTHON="$HAVE_PYTHON"
HAVE_QTBINDINGS="$HAVE_QTBINDINGS"
HAVE_64BIT_COORD="$HAVE_64BIT_COORD"

View File

@ -22,6 +22,7 @@
#include "tlUnitTest.h"
#include "tlStream.h"
#include "tlFileUtils.h"
// Testing the converter main implementation (CIF)
TEST(1)
@ -29,7 +30,7 @@ TEST(1)
std::string fp (tl::testsrc ());
fp += "/testdata/bd/strmrun.py";
std::string path = "./strmrun " + fp;
std::string path = tl::combine_path (".", "strmrun ") + fp;
tl::InputPipe pipe (path);
tl::InputStream is (pipe);
std::string data = is.read_all ();

View File

@ -59,7 +59,7 @@ static PluginDescriptor load_plugin (const std::string &pp)
#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 ());
HINSTANCE handle = LoadLibraryW (tl::to_wstring (pp).c_str ());
if (! handle) {
throw tl::Exception (tl::to_string (tr ("Unable to load plugin: %s with error message: %s ")), pp, GetLastError ());
return desc;

View File

@ -20,6 +20,7 @@ SOURCES = \
gsiObject.cc \
gsiSerialisation.cc \
gsiTypes.cc \
gsiSignals.cc \
gsiObjectHolder.cc \
HEADERS = \

32
src/gsi/gsi/gsiSignals.cc Normal file
View File

@ -0,0 +1,32 @@
/*
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 "gsiSignals.h"
namespace gsi
{
// .. nothing yet ..
}

View File

@ -38,11 +38,17 @@
#include "tlStream.h"
#include "tlTimer.h"
#include "tlFileUtils.h"
#include "tlString.h"
#if defined(HAVE_QT)
# include <QCoreApplication>
#endif
// For the installation path
#ifdef _WIN32
# include <windows.h>
#endif
namespace pya
{
@ -195,37 +201,41 @@ PythonInterpreter::PythonInterpreter ()
try {
QString path;
std::string path;
QDir inst_dir (QCoreApplication::applicationDirPath ());
QFileInfo fi (inst_dir.absoluteFilePath (tl::to_qstring(".python-paths.txt")));
if (fi.exists ()) {
wchar_t buffer[MAX_PATH];
int len;
if ((len = GetModuleFileName (NULL, buffer, MAX_PATH)) > 0) {
tl::log << tl::to_string (tr ("Reading Python path from ")) << tl::to_string (fi.filePath ());
std::string inst_dir = tl::absolute_path (tl::to_string (std::wstring (buffer, len)));
std::string path_file = tl::combine_path (inst_dir, ".python-paths.txt");
if (tl::file_exists (path_file)) {
QFile paths_txt (fi.filePath ());
paths_txt.open (QIODevice::ReadOnly);
tl::log << tl::to_string (tr ("Reading Python path from ")) << path_file;
tl::Eval eval;
eval.set_global_var ("inst_path", tl::Variant (tl::to_string (inst_dir.absolutePath ())));
tl::Expression ex;
eval.parse (ex, paths_txt.readAll ().constData ());
tl::Variant v = ex.execute ();
tl::InputStream path_file_stream (path_file);
std::string path_file_text = path_file_stream.read_all ();
if (v.is_list ()) {
for (tl::Variant::iterator i = v.begin (); i != v.end (); ++i) {
if (! path.isEmpty ()) {
path += tl::to_qstring (";");
tl::Eval eval;
eval.set_global_var ("inst_path", tl::Variant (inst_dir));
tl::Expression ex;
eval.parse (ex, path_file_text.c_str ());
tl::Variant v = ex.execute ();
if (v.is_list ()) {
for (tl::Variant::iterator i = v.begin (); i != v.end (); ++i) {
if (! path.empty ()) {
path += ";";
}
path += i->to_string ();
}
path += tl::to_qstring (i->to_string ());
}
}
}
// note: this is a hack, but linking with toWCharArray fails since wchar_t is treated
// as a built-in type in our build
Py_SetPath ((const wchar_t *) path.utf16 ());
Py_SetPath (tl::to_wstring (path).c_str ());
} catch (tl::Exception &ex) {
tl::error << tl::to_string (tr ("Evaluation of Python path expression failed")) << ": " << ex.msg ();

View File

@ -103,7 +103,7 @@ PYTHONTEST (dbPCellsTest, "dbPCells.py")
PYTHONTEST (dbPolygonTest, "dbPolygonTest.py")
PYTHONTEST (dbTransTest, "dbTransTest.py")
PYTHONTEST (tlTest, "tlTest.py")
#if defined(HAVE_QTBINDINGS)
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
PYTHONTEST (qtbinding, "qtbinding.py")
#endif

View File

@ -20,26 +20,22 @@ QMAKE_CXXFLAGS_WARN_ON += \
# $(DESTDIR) and $(TARGET)
win32 {
QMAKE_POST_LINK += $(MKDIR) $$DESTDIR_PYMOD && $(COPY) $(DESTDIR_TARGET) $$DESTDIR_PYMOD/$${TARGET}.dll
QMAKE_POST_LINK += $(MKDIR) $$DESTDIR_PYMOD && $(COPY) $(DESTDIR_TARGET) $$DESTDIR_PYMOD/$${TARGET}$${PYTHONEXTSUFFIX}
# 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
lib_target.path = $$PREFIX/pymod/klayout
lib_target.files += $$DESTDIR_PYMOD/$${TARGET}.dll
INSTALLS = lib_target
} else {
QMAKE_POST_LINK += $(MKDIR) $$DESTDIR_PYMOD && $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_PYMOD/$${TARGET}.so
lib_target.path = $$PREFIX/pymod/klayout
# This would be nice:
# lib_target.files += $$DESTDIR_PYMOD/$${TARGET}.so
# but some Qt versions need this explicitly:
lib_target.extra = $(INSTALL_PROGRAM) $$DESTDIR_PYMOD/$${TARGET}.so $(INSTALLROOT)$$PREFIX/pymod/klayout
INSTALLS = lib_target
QMAKE_POST_LINK += $(MKDIR) $$DESTDIR_PYMOD && $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_PYMOD/$${TARGET}$${PYTHONEXTSUFFIX}
}
lib_target.path = $$PREFIX/pymod/klayout
# This would be nice:
# lib_target.files += $$DESTDIR_PYMOD/$${TARGET}$${PYTHONEXTSUFFIX}
# but some Qt versions need this explicitly:
lib_target.extra = $(INSTALL_PROGRAM) $$DESTDIR_PYMOD/$${TARGET}$${PYTHONEXTSUFFIX} $(INSTALLROOT)$$PREFIX/pymod/klayout
INSTALLS = lib_target

View File

@ -66,7 +66,7 @@ PYMODTEST (import_tl, "import_tl.py")
PYMODTEST (import_db, "import_db.py")
PYMODTEST (import_rdb, "import_rdb.py")
#if defined(HAVE_QTBINDINGS)
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
PYMODTEST (import_lay, "import_lay.py")

View File

@ -34,6 +34,7 @@
#include "tlTimer.h"
#include "tlExpression.h"
#include "tlFileUtils.h"
#include "tlStream.h"
#include "rba.h"
#include "rbaInspector.h"
@ -1812,21 +1813,21 @@ RubyInterpreter::initialize (int &main_argc, char **main_argv, int (*main_func)
wchar_t buffer[MAX_PATH];
int len;
if ((len = GetModuleFileName(NULL, buffer, MAX_PATH)) > 0) {
if ((len = GetModuleFileName (NULL, buffer, MAX_PATH)) > 0) {
QDir inst_dir (QString::fromUtf16 ((const ushort *) buffer, len));
QFileInfo fi (inst_dir.absoluteFilePath (tl::to_qstring(".ruby-paths.txt")));
if (fi.exists ()) {
std::string inst_dir = tl::absolute_path (tl::to_string (std::wstring (buffer, len)));
std::string path_file = tl::combine_path (inst_dir, ".ruby-paths.txt");
if (tl::file_exists (path_file)) {
tl::log << tl::to_string (tr ("Reading Ruby path from ")) << tl::to_string (fi.filePath ());
tl::log << tl::to_string (tr ("Reading Ruby path from ")) << path_file;
QFile paths_txt (fi.filePath ());
paths_txt.open (QIODevice::ReadOnly);
tl::InputStream path_file_stream (path_file);
std::string path_file_text = path_file_stream.read_all ();
tl::Eval eval;
eval.set_global_var ("inst_path", tl::Variant (tl::to_string (inst_dir.absolutePath ())));
eval.set_global_var ("inst_path", tl::Variant (inst_dir));
tl::Expression ex;
eval.parse (ex, paths_txt.readAll ().constData ());
eval.parse (ex, path_file_text.c_str ());
tl::Variant v = ex.execute ();
if (v.is_list ()) {

View File

@ -34,7 +34,7 @@ TEST (1)
{
EXPECT_EQ (gsi::has_class ("Value"), true);
EXPECT_EQ (gsi::has_class ("DoesNotExist"), false);
#if defined(HAVE_QTBINDINGS)
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
EXPECT_EQ (gsi::has_class ("QDialog"), true);
EXPECT_EQ (gsi::has_class ("QApplication"), true);
#endif
@ -131,7 +131,7 @@ RUBYTEST (layMenuTest, "layMenuTest.rb")
RUBYTEST (laySession, "laySession.rb")
RUBYTEST (layTechnologies, "layTechnologies.rb")
RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb")
#if defined(HAVE_QTBINDINGS)
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
RUBYTEST (qtbinding, "qtbinding.rb")
#endif
RUBYTEST (rdbTest, "rdbTest.rb")

View File

@ -31,6 +31,11 @@
#include <unistd.h>
#include <dirent.h>
#if defined(_WIN32)
# include <dir.h>
# include <windows.h>
#endif
namespace tl
{
@ -306,7 +311,7 @@ std::vector<std::string> dir_entries (const std::string &s, bool with_files, boo
do {
std::string e = tl::to_string fileinfo.name);
std::string e = tl::to_string (std::wstring (fileinfo.name));
if (e.empty () || e == "." || e == "..") {
continue;
}
@ -320,7 +325,7 @@ std::vector<std::string> dir_entries (const std::string &s, bool with_files, boo
}
_wfindclose (h);
_findclose (h);
#else
@ -615,24 +620,35 @@ std::string absolute_file_path (const std::string &s)
}
}
static int stat_func (const std::string &s, struct stat &st)
{
#if defined(_WIN32)
typedef struct _stat stat_struct;
static int stat_func (const std::string &s, stat_struct &st)
{
return _wstat (tl::to_wstring (s).c_str (), &st);
#else
return stat (tl::to_local (s).c_str (), &st);
#endif
}
#else
typedef struct stat stat_struct;
static int stat_func (const std::string &s, stat_struct &st)
{
return stat (tl::to_local (s).c_str (), &st);
}
#endif
bool file_exists (const std::string &p)
{
struct stat st;
stat_struct st;
return stat_func (p, st) == 0;
}
bool is_dir (const std::string &p)
{
struct stat st;
stat_struct st;
if (stat_func (p, st) != 0) {
return false;
} else {
@ -700,7 +716,7 @@ bool is_same_file (const std::string &a, const std::string &b)
#else
struct stat sta, stb;
stat_struct sta, stb;
if (stat_func (a, sta) != 0 || stat_func (b, stb) != 0) {
return false;
}

View File

@ -469,7 +469,7 @@ InputFile::InputFile (const std::string &path)
{
m_source = path;
#if defined(_WIN32)
int fd = _wopen ((const wchar_t *) tl::to_qstring (path).constData (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL);
int fd = _wopen (tl::to_wstring (path).c_str (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL);
if (fd < 0) {
throw FileOpenErrorException (m_source, errno);
}
@ -550,7 +550,7 @@ InputZLibFile::InputZLibFile (const std::string &path)
{
m_source = path;
#if defined(_WIN32)
int fd = _wopen ((const wchar_t *) tl::to_qstring (path).constData (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL);
int fd = _wopen (tl::to_wstring (path).c_str (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL);
if (fd < 0) {
throw FileOpenErrorException (m_source, errno);
}
@ -763,7 +763,7 @@ OutputFile::OutputFile (const std::string &path)
{
m_source = path;
#if defined(_WIN32)
int fd = _wopen ((const wchar_t *) tl::to_qstring (path).constData (), _O_CREAT | _O_TRUNC | _O_BINARY | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE );
int fd = _wopen (tl::to_wstring (path).c_str (), _O_CREAT | _O_TRUNC | _O_BINARY | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE );
if (fd < 0) {
throw FileOpenErrorException (m_source, errno);
}
@ -824,7 +824,7 @@ OutputZLibFile::OutputZLibFile (const std::string &path)
{
m_source = path;
#if defined(_WIN32)
FILE *file = _wfopen ((const wchar_t *) tl::to_qstring (path).constData (), L"wb");
FILE *file = _wfopen (tl::to_wstring (path).c_str (), L"wb");
if (file == NULL) {
throw FileOpenErrorException (m_source, errno);
}
@ -871,7 +871,7 @@ InputPipe::InputPipe (const std::string &path)
{
std::wstring wpath = tl::to_wstring (path);
m_source = path;
m_file = _wpopen (wpath.c_str (), "r");
m_file = _wpopen (wpath.c_str (), L"r");
if (m_file == NULL) {
throw FilePOpenErrorException (m_source, errno);
}
@ -919,7 +919,7 @@ OutputPipe::OutputPipe (const std::string &path)
{
std::wstring wpath = tl::to_wstring (path);
m_source = path;
m_file = _wpopen (wpath.c_str (), "w");
m_file = _wpopen (wpath.c_str (), L"w");
if (m_file == NULL) {
throw FilePOpenErrorException (m_source, errno);
}

View File

@ -86,6 +86,7 @@ std::string to_string (const std::wstring &ws)
++c;
c32 = (c32 & 0x3ff) << 10;
c32 |= uint32_t (*c) & 0x3ff;
c32 += 0x10000;
}
if (c32 >= 0x10000) {
@ -497,7 +498,7 @@ to_quoted_string (const std::string &s)
r += "\\r";
} else if (*c == '\t') {
r += "\\t";
} else if (! isprint (*c)) {
} else if (! isprint (*c) || (unsigned char) *c >= 0x80) {
char b [20];
::sprintf (b, "\\%03o", int ((unsigned char) *c));
r += b;

View File

@ -28,7 +28,11 @@
#include <map>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#if defined(_WIN32)
# include <windows.h>
#endif
namespace tl
{
@ -274,6 +278,23 @@ bool Thread::wait (unsigned long time)
end_time.tv_sec += 1;
}
#if defined(_WIN32)
// wait if the thread terminated or the timeout has expired
while (isRunning ()) {
struct timespec current_time;
clock_gettime (CLOCK_REALTIME, &current_time);
if (end_time.tv_sec < current_time.tv_sec || (end_time.tv_sec == current_time.tv_sec && end_time.tv_nsec < current_time.tv_nsec)) {
return false;
}
Sleep (1);
}
#else
int res = pthread_timedjoin_np (mp_data->pthread, &mp_data->return_code, &end_time);
if (res == ETIMEDOUT) {
return false;
@ -281,6 +302,8 @@ bool Thread::wait (unsigned long time)
tl::error << tr ("Could not join threads");
}
#endif
return true;
} else {

View File

@ -839,7 +839,11 @@ TEST(6)
v = e.parse ("absolute_file_path('./x.gds')").execute ();
// EXPECT_EQ (v.to_string (), std::string ()); // not universal
v = e.parse ("path('../irgendwas/file.tar.gz')").execute ();
#if defined(_WIN32)
EXPECT_EQ (v.to_string (), std::string ("..\\irgendwas"));
#else
EXPECT_EQ (v.to_string (), std::string ("../irgendwas"));
#endif
v = e.parse ("basename('../irgendwas/file.tar.gz')").execute ();
EXPECT_EQ (v.to_string (), std::string ("file"));
v = e.parse ("extension('../irgendwas/file.tar.gz')").execute ();

View File

@ -138,6 +138,10 @@ TEST(1_timed_wait)
}
int s_mythread2_increment = 1;
void inc (volatile int &value)
{
value += s_mythread2_increment;
}
class MyThread2 : public tl::Thread
{
@ -155,11 +159,11 @@ public:
for (int i = 0; i < 10000000; ++i) {
tl::MutexLocker locker (&m_lock);
// Do it more elaborate than ++m_value to prevent compiler optimization
m_value += s_mythread2_increment;
inc (m_value);
}
} else {
for (int i = 0; i < 10000000; ++i) {
m_value += s_mythread2_increment;
inc (m_value);
}
}
}

View File

@ -61,8 +61,10 @@
# include <Windows.h>
#endif
// required to force linking of the "ext", "lib" and "drc" module
// required to force linking of the "rdb", "lib" and "drc" module
// (some in non-Qt case)
#include "libForceLink.h"
#include "rdbForceLink.h"
#if defined(HAVE_RUBY) && defined(HAVE_QT)
#include "drcForceLink.h"
#endif

View File

@ -26,12 +26,17 @@ HEADERS += \
LIBS += -lklayout_gsi_test
INCLUDEPATH += $$QTBASIC_INC
DEPENDPATH += $$QTBASIC_INC
!equals(HAVE_QT, "0") {
equals(HAVE_QTBINDINGS, "1") {
LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml
equals(HAVE_QT5, "1") {
LIBS += -lklayout_QtWidgets
INCLUDEPATH += $$QTBASIC_INC
DEPENDPATH += $$QTBASIC_INC
equals(HAVE_QTBINDINGS, "1") {
LIBS += -lklayout_QtXml
equals(HAVE_QT5, "1") {
LIBS += -lklayout_QtWidgets
}
}
}

View File

@ -16,10 +16,10 @@ LIBS += $$PYTHONLIBFILE $$RUBYLIBFILE -L$$DESTDIR -lklayout_tl -lklayout_gsi -lk
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
}
equals(HAVE_QTBINDINGS, "1") {
LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtCore
}
equals(HAVE_RUBY, "1") {

View File

@ -89,17 +89,17 @@ END
assert_equal(tech.default_base_path, "/default/path")
assert_equal(tech.base_path, "/default/path")
assert_equal(tech.correct_path("/default/path/myfile.xml"), "myfile.xml")
assert_equal(tech.eff_path("myfile.xml"), "/default/path/myfile.xml")
assert_equal(tech.eff_path("myfile.xml").gsub("\\", "/"), "/default/path/myfile.xml")
tech.explicit_base_path = "/basic/path"
assert_equal(tech.explicit_base_path, "/basic/path")
assert_equal(tech.base_path, "/basic/path")
assert_equal(tech.correct_path("/basic/path/myfile.xml"), "myfile.xml")
assert_equal(tech.eff_path("myfile.xml"), "/basic/path/myfile.xml")
assert_equal(tech.eff_path("myfile.xml").gsub("\\", "/"), "/basic/path/myfile.xml")
tech.layer_properties_file = "x.lyp"
assert_equal(tech.layer_properties_file, "x.lyp")
assert_equal(tech.eff_layer_properties_file, "/basic/path/x.lyp")
assert_equal(tech.eff_layer_properties_file.gsub("\\", "/"), "/basic/path/x.lyp")
tech.add_other_layers = true
assert_equal(tech.add_other_layers?, true)