diff options
-rw-r--r-- | setup.py | 21 | ||||
-rw-r--r-- | sources/pyside2/PySide2/QtCore/typesystem_core_common.xml | 8 | ||||
-rw-r--r-- | sources/pyside2/libpyside/CMakeLists.txt | 7 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pyside.cpp | 130 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pyside.h | 13 | ||||
-rw-r--r-- | sources/pyside2/tests/CMakeLists.txt | 2 |
6 files changed, 176 insertions, 5 deletions
@@ -61,6 +61,15 @@ without rebuilding entire PySide2 every time: # Then we create bdist_egg reusing PySide2 build with option --only-package python setup.py bdist_egg --only-package --qmake=c:\Qt\4.8.5\bin\qmake.exe --cmake=c:\tools\cmake\bin\cmake.exe --opnessl=c:\libs\OpenSSL32bit\bin +You can use the option --qt-conf-prefix to pass a path relative to the PySide2 installed package, +which will be embedded into an auto-generated qt.conf registered in the Qt resource system. This +path will serve as the PrefixPath for QLibraryInfo, thus allowing to choose where Qt plugins +should be loaded from. This option overrides the usual prefix chosen by --standalone option, or when +building on Windows. +To temporarily disable registration of the internal qt.conf file, a new environment variable called +PYSIDE_DISABLE_INTERNAL_QT_CONF is introduced. You should assign the integer "1" to disable the +internal qt.conf, or "0" (or leave empty) to keep use the internal qt.conf file. + For development purposes the following options might be of use, when using "setup.py build": --reuse-build option allows recompiling only the modified sources and not the whole world, shortening development iteration time, @@ -241,6 +250,7 @@ OPTION_SKIP_CMAKE = has_option("skip-cmake") OPTION_SKIP_MAKE_INSTALL = has_option("skip-make-install") OPTION_SKIP_PACKAGING = has_option("skip-packaging") OPTION_RPATH_VALUES = option_value("rpath") +OPTION_QT_CONF_PREFIX = option_value("qt-conf-prefix") if OPTION_QT_VERSION is None: OPTION_QT_VERSION = "5" @@ -854,6 +864,17 @@ class pyside_build(_build): if self.build_type.lower() == 'debug': cmake_cmd.append("-DPYTHON_DEBUG_LIBRARY=%s" % self.py_library) + if extension.lower() == "pyside2": + pyside_qt_conf_prefix = '' + if OPTION_QT_CONF_PREFIX: + pyside_qt_conf_prefix = OPTION_QT_CONF_PREFIX + else: + if OPTION_STANDALONE: + pyside_qt_conf_prefix = '"Qt"' + if sys.platform == 'win32': + pyside_qt_conf_prefix = '"."' + cmake_cmd.append("-DPYSIDE_QT_CONF_PREFIX=%s" % pyside_qt_conf_prefix) + if extension.lower() == "shiboken2": cmake_cmd.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes") if sys.version_info[0] > 2: diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index 951d943ee..65f68882d 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -74,6 +74,10 @@ <function signature="qrand()" /> <function signature="qsrand(uint)" /> + <inject-code class="native" position="beginning"> + #include <pyside.h> + </inject-code> + <template name="use_stream_for_format_security"> // Uses the stream version for security reasons // see gcc man page at -Wformat-security @@ -1039,12 +1043,10 @@ Shiboken::Conversions::registerConverterName(SbkPySide2_QtCoreTypeConverters[SBK_QSTRING_IDX], "str"); Shiboken::Conversions::registerConverterName(SbkPySide2_QtCoreTypeConverters[SBK_QTCORE_QLIST_QVARIANT_IDX], "QVariantList"); + PySide::registerInternalQtConf(); PySide::init(module); Py_AtExit(QtCoreModuleExit); </inject-code> - <inject-code class="native" position="beginning"> - #include <pyside.h> - </inject-code> <inject-code class="native" position="beginning"> // Define a global variable to handle qInstallMessageHandler callback diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt index 1cddebc07..de29269a4 100644 --- a/sources/pyside2/libpyside/CMakeLists.txt +++ b/sources/pyside2/libpyside/CMakeLists.txt @@ -111,6 +111,13 @@ if(QML_SUPPORT) target_compile_definitions(pyside2 PUBLIC PYSIDE_QML_SUPPORT=1) endif() +if(PYSIDE_QT_CONF_PREFIX) + set_property(SOURCE pyside.cpp + APPEND + PROPERTY COMPILE_DEFINITIONS + PYSIDE_QT_CONF_PREFIX=${PYSIDE_QT_CONF_PREFIX}) +endif() + # # install stuff # diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 17366ce6e..b223edc6c 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -61,14 +61,20 @@ #include <typeinfo> #include <cstring> #include <cctype> -#include <QStack> +#include <QByteArray> #include <QCoreApplication> #include <QDebug> +#include <QDir> +#include <QFileInfo> #include <QSharedPointer> +#include <QStack> static QStack<PySide::CleanupFunction> cleanupFunctionList; static void* qobjectNextAddr; +extern bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, + const unsigned char *); + namespace PySide { @@ -387,5 +393,127 @@ void setQuickRegisterItemFunction(QuickRegisterItemFunction function) } #endif // PYSIDE_QML_SUPPORT +// Inspired by Shiboken::String::toCString; +QString pyStringToQString(PyObject *str) { + if (str == Py_None) + return QString(); + +#ifdef IS_PY3K + if (PyUnicode_Check(str)) { + const char *unicodeBuffer = _PyUnicode_AsString(str); + if (unicodeBuffer) + return QString::fromUtf8(unicodeBuffer); + } +#endif + if (PyBytes_Check(str)) { + const char *asciiBuffer = PyBytes_AS_STRING(str); + if (asciiBuffer) + return QString::fromLatin1(asciiBuffer); + } + return QString(); +} + +static const unsigned char qt_resource_name[] = { + // qt + 0x0,0x2, + 0x0,0x0,0x7,0x84, + 0x0,0x71, + 0x0,0x74, + // etc + 0x0,0x3, + 0x0,0x0,0x6c,0xa3, + 0x0,0x65, + 0x0,0x74,0x0,0x63, + // qt.conf + 0x0,0x7, + 0x8,0x74,0xa6,0xa6, + 0x0,0x71, + 0x0,0x74,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x66 +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, + // :/qt + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2, + // :/qt/etc + 0x0,0x0,0x0,0xa,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3, + // :/qt/etc/qt.conf + 0x0,0x0,0x0,0x16,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0 +}; + +bool registerInternalQtConf() +{ + // Guard to ensure single registration. +#ifdef PYSIDE_QT_CONF_PREFIX + static bool registrationAttempted = false; +#else + static bool registrationAttempted = true; +#endif + static bool isRegistered = false; + if (registrationAttempted) + return isRegistered; + registrationAttempted = true; + + // Allow disabling the usage of the internal qt.conf. This is necessary for tests to work, + // because tests are executed before the package is installed, and thus the Prefix specified + // in qt.conf would point to a not yet existing location. + bool disableInternalQtConf = + qEnvironmentVariableIntValue("PYSIDE_DISABLE_INTERNAL_QT_CONF") > 0 ? true : false; + if (disableInternalQtConf) { + registrationAttempted = true; + return false; + } + + PyObject *pysideModule = PyImport_ImportModule("PySide2"); + if (!pysideModule) + return false; + + // Querying __file__ should be done only for modules that have finished their initialization. + // Thus querying for the top-level PySide2 package works for us whenever any Qt-wrapped module + // is loaded. + PyObject *pysideInitFilePath = PyObject_GetAttrString(pysideModule, "__file__"); + Py_DECREF(pysideModule); + if (!pysideInitFilePath) + return false; + + QString initPath = pyStringToQString(pysideInitFilePath); + Py_DECREF(pysideInitFilePath); + if (initPath.isEmpty()) + return false; + + // pysideDir - absolute path to the directory containing the init file, which also contains + // the rest of the PySide2 modules. + // prefixPath - absolute path to the directory containing the installed Qt (prefix). + QDir pysideDir = QFileInfo(QDir::fromNativeSeparators(initPath)).absoluteDir(); + QString setupPrefix; +#ifdef PYSIDE_QT_CONF_PREFIX + setupPrefix = QStringLiteral(PYSIDE_QT_CONF_PREFIX); +#endif + QString prefixPath = pysideDir.absoluteFilePath(setupPrefix); + + // rccData needs to be static, otherwise when it goes out of scope, the Qt resource system + // will point to invalid memory. + static QByteArray rccData = QByteArray("[Paths]\nPrefix = ") + prefixPath.toLocal8Bit(); + rccData.append('\n'); + + // The RCC data structure expects a 4-byte size value representing the actual data. + int size = rccData.size(); + + for (int i = 0; i < 4; ++i) { + rccData.prepend((size & 0xff)); + size >>= 8; + } + + const int version = 0x01; + isRegistered = qRegisterResourceData(version, qt_resource_struct, qt_resource_name, + reinterpret_cast<const unsigned char *>( + rccData.constData())); + + return isRegistered; +} + + + } //namespace PySide diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h index 3619e2875..becb92208 100644 --- a/sources/pyside2/libpyside/pyside.h +++ b/sources/pyside2/libpyside/pyside.h @@ -150,6 +150,19 @@ PYSIDE_API QuickRegisterItemFunction getQuickRegisterItemFunction(); PYSIDE_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function); #endif // PYSIDE_QML_SUPPORT +/** + * Given A PyObject repesenting ASCII or Unicode data, returns an equivalent QString. + */ +PYSIDE_API QString pyStringToQString(PyObject *str); + +/** + * Registers a dynamic "qt.conf" file with the Qt resource system. + * + * This is used in a standalone build, to inform QLibraryInfo of the Qt prefix (where Qt libraries + * are installed) so that plugins can be successfully loaded. + */ +PYSIDE_API bool registerInternalQtConf(); + } //namespace PySide diff --git a/sources/pyside2/tests/CMakeLists.txt b/sources/pyside2/tests/CMakeLists.txt index 2b7e3b0e1..34a2e2501 100644 --- a/sources/pyside2/tests/CMakeLists.txt +++ b/sources/pyside2/tests/CMakeLists.txt @@ -43,7 +43,7 @@ else() set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${CTEST_TESTING_TIMEOUT} WILL_FAIL ${EXPECT_TO_FAIL} - ENVIRONMENT "PYTHONPATH=${TEST_PYTHONPATH};${LIBRARY_PATH_VAR}=${TEST_LIBRARY_PATH}") + ENVIRONMENT "PYTHONPATH=${TEST_PYTHONPATH};${LIBRARY_PATH_VAR}=${TEST_LIBRARY_PATH};PYSIDE_DISABLE_INTERNAL_QT_CONF=1") endmacro() add_subdirectory(pysidetest) |