Skip to content

Commit

Permalink
Several fixes and patches (#89)
Browse files Browse the repository at this point in the history
* minor improvements in code and unit tests 
* disable warnings for deprecated declarations
* add -Wpedantic and even -Werror for src, but relax some warnings
* fix undefined behavior
* fix memory leaks
* use QT_NO_CAST_TO_ASCII  to prevent incorrect behavior on non-Latin1 input

* Improvements in build and CI:
** add parallel build
** add `make check` support
** fix `debug`/`release` builds
** force C++11
** introduce UBSan into CI
** fixes for macOS build with clang
** add pkg-config support:
  if PKGCONFIG is set, skip old-style lookup (useful on Linux and macOS GHA, 
  when `python-config` returns incorrect linkage options with missing `-Ldirs`)
** add macOS GHA CI
  • Loading branch information
iakov authored Jan 30, 2023
1 parent 8336c6f commit 1e794e5
Show file tree
Hide file tree
Showing 44 changed files with 381 additions and 188 deletions.
91 changes: 87 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ jobs:
echo ======= SYSTEM INFO ========
uname -a; gcc --version | grep "gcc"; python3 --version; qmake --version
echo ============================
qmake -r PythonQt.pro \
qmake -r PythonQt.pro CONFIG+=release CONFIG+=sanitizer CONFIG+=sanitize_undefined \
PYTHON_VERSION=$(python3 --version | cut -d " " -f 2 | cut -d "." -f1,2) \
PYTHON_DIR=$(which python3 | xargs dirname | xargs dirname)
make
make -j 2 && make check TESTARGS="-platform offscreen"
- name: Generate Wrappers
run: |
Expand Down Expand Up @@ -113,10 +113,10 @@ jobs:
echo ======= SYSTEM INFO ========
uname -a; gcc --version | grep "gcc"; python --version; qmake-qt5 --version
echo ============================
qmake-qt5 -r PythonQt.pro \
qmake-qt5 -r PythonQt.pro CONFIG+=release \
PYTHON_VERSION=$(python --version | cut -d " " -f 2 | cut -d "." -f1,2) \
PYTHON_DIR=$(which python | xargs dirname | xargs dirname)
make
make -j 2 && make check TESTARGS="-platform offscreen"
- name: Generate Wrappers
run: |
Expand All @@ -131,3 +131,86 @@ jobs:
with:
name: wrappers_centos7
path: generated_cpp

macOS:
strategy:
fail-fast: false
matrix:
macos-version: ['10.15']
python-version: ['2.7']
qt-version: ['5.9.*']
include:
- macos-version: '11'
python-version: '3.6'
qt-version: '5.11.*'
- macos-version: '12'
python-version: '3.10'
qt-version: '5.12.*'
runs-on: macos-${{ matrix.macos-version }}
steps:
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
aqtversion: '==2.1.*'
version: ${{ matrix.qt-version }}
host: 'mac'
target: 'desktop'
arch: 'clang_64'
modules: 'qtscript'
archives: 'qtmultimedia qtmacextras qtbase qttools'

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: '${{ matrix.python-version }}'

- name: Checkout PythonQt
uses: actions/checkout@v3

- name: Detect exact versions
id : versions
run : |
set -eu
PYTHON_VERSION_FULL=$(python --version 2>&1 | cut -f 2 -d ' ')
PYTHON_VERSION_SHORT=$(cut -f 1,2 -d . <<< $PYTHON_VERSION_FULL)
QT_VERSION_FULL=$($Qt5_DIR/bin/qmake -query QT_VERSION)
QT_VERSION_SHORT=$(cut -f 1,2 -d . <<< $QT_VERSION_FULL)
MACOS_VERSION_FULL=$(sw_vers -productVersion)
MACOS_VERSION_SHORT=$(cut -f 1,2 -d . <<< $MACOS_VERSION_FULL)
echo "PYTHON_VERSION_FULL=$PYTHON_VERSION_FULL" | tee -a $GITHUB_OUTPUT
echo "PYTHON_VERSION_SHORT=$PYTHON_VERSION_SHORT" | tee -a $GITHUB_OUTPUT
echo "QT_VERSION_FULL=$QT_VERSION_FULL" | tee -a $GITHUB_OUTPUT
echo "QT_VERSION_SHORT=$QT_VERSION_SHORT" | tee -a $GITHUB_OUTPUT
echo "MACOS_VERSION_FULL=$MACOS_VERSION_FULL" | tee -a $GITHUB_OUTPUT
echo "MACOS_VERSION_SHORT=$MACOS_VERSION_SHORT" | tee -a $GITHUB_OUTPUT
- name: Build PythonQt
run: |
set -ue
echo ======= SYSTEM INFO ========
uname -a; gcc --version | head -n 1; python --version; qmake --version
echo ============================
PYTHON_VERSION_MAJOR=$(cut -d . -f1 <<< ${{ steps.versions.outputs.PYTHON_VERSION_SHORT }})
for i in "python${{ steps.versions.outputs.PYTHON_VERSION_SHORT }}-embed" "python${{ steps.versions.outputs.PYTHON_VERSION_SHORT }}" \
"python${PYTHON_VERSION_MAJOR}-embed" "python${PYTHON_VERSION_MAJOR}"
do if pkg-config --exists "$i"; then PYTHON_PKGCONFIG_NAME="$i"; break; fi; done
qmake CONFIG+=release CONFIG+=sanitizer CONFIG+=sanitize_undefined \
PYTHON_VERSION=${{ steps.versions.outputs.PYTHON_VERSION_SHORT }} \
PYTHON_DIR="$pythonLocation" \
PKGCONFIG+=$PYTHON_PKGCONFIG_NAME \
-r PythonQt.pro
make -j 2 && make check TESTARGS="-platform offscreen"
- name: Generate Wrappers
run: |
cd generator
# workaround to allow to find the Qt include dirs for installed standard qt packages
QTDIR=-UNDEFINED- ./pythonqt_generator --include-paths=$Qt5_DIR/lib
- name: Upload Wrappers
uses: actions/upload-artifact@v3
with:
name: wrappers_macos${{ steps.versions.outputs.MACOS_VERSION_SHORT }}_qt${{ steps.versions.outputs.QT_VERSION_SHORT }}
path: generated_cpp

4 changes: 3 additions & 1 deletion PythonQt.pro
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
TEMPLATE = subdirs

CONFIG += ordered
SUBDIRS = generator src extensions tests examples
tests.depends += src extensions
extensions.depends += src
examples.depends += src extensions
3 changes: 2 additions & 1 deletion build/common.prf
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ PYTHONQT_GENERATED_PATH = $$PWD/../generated_cpp
VERSION = 3.2.0

win32: CONFIG += skip_target_version_ext
unix: QMAKE_CXXFLAGS += -std=c++11
unix: CONFIG += c++11
gcc: QMAKE_CXXFLAGS += -Wno-deprecated-declarations
40 changes: 30 additions & 10 deletions build/python.prf
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,27 @@ isEmpty( PYTHON_DIR ) {
PYTHON_DIR=$${PYTHON_DIR}/
}

message(Using Python version $${PYTHON_VERSION})
PYTHON_VERSION_MAJOR=$$section(PYTHON_VERSION, ., 0, 0)
PYTHON_VERSION_MINOR=$$section(PYTHON_VERSION, ., 1, 1)

macx {
!equals(PYTHON_VERSION, $${PYTHON_VERSION_MAJOR}.$${PYTHON_VERSION_MINOR}) {
error("Failed to parse PYTHON_VERSION:\"$$PYTHON_VERSION\"")
} else {
message(Using Python version $${PYTHON_VERSION})
}


# Python 2.x has problems:
# 1) https://wiki.gentoo.org/wiki/Project:Python/Strict_aliasing
# 2) deprecated implicit cast of string literals to char*
equals(PYTHON_VERSION_MAJOR, 2):gcc:QMAKE_CXXFLAGS *= -fno-strict-aliasing -Wno-error=write-strings
contains(PKGCONFIG, "python.*"){
CONFIG += link_pkgconfig
PYTHON_PKGCONFIG = $$member($$unique($$find(PKGCONFIG, "python.*")), 1, 1)
# add rpath
PYTHON_LIBDIR = $$system($$pkgConfigExecutable() --libs-only-L $$PYTHON_PKGCONFIG)
QMAKE_RPATHDIR += $$replace(PYTHON_LIBDIR,-L,)
} else:macx:isEmpty(PYTHON_DIR){
# for macx you need to have the Python development kit installed as framework
INCLUDEPATH += /System/Library/Frameworks/Python.framework/Headers
LIBS += -F/System/Library/Frameworks -framework Python
Expand Down Expand Up @@ -52,15 +70,17 @@ macx {
# make sure that you have installed a matching python-dev package.

PYTHON_CONFIG = $${PYTHON_DIR}/bin/python$${PYTHON_VERSION}-config
system($${PYTHON_CONFIG} --embed --libs) {
unix:LIBS += $$system($${PYTHON_CONFIG} --embed --libs)
} else: unix:LIBS += $$system($${PYTHON_CONFIG} --libs)
unix:QMAKE_CXXFLAGS += $$system($${PYTHON_CONFIG} --includes)
PYTHON_CONFIG_OPTIONS_LIBS = --libs
equals(PYTHON_VERSION_MAJOR, 3):!lessThan(PYTHON_VERSION_MINOR, 8) {
# Since 3.8 `--embed` is needed
PYTHON_CONFIG_OPTIONS_LIBS += --embed
}
LIBS += $$system($${PYTHON_CONFIG} $${PYTHON_CONFIG_OPTIONS_LIBS})
QMAKE_CXXFLAGS += $$system($${PYTHON_CONFIG} --includes)
PYTHON_LFLAGS = $$system($${PYTHON_CONFIG} --ldflags)
unix:QMAKE_LFLAGS += $${PYTHON_LFLAGS}
QMAKE_LFLAGS += $${PYTHON_LFLAGS}
# add rpath
PYTHON_LIBDIR = $$find(PYTHON_LFLAGS,-L.*)
RPATH = -Wl,-rpath,
PYTHON_RPATH = $$replace(PYTHON_LIBDIR,-L,$${RPATH})
unix:QMAKE_LFLAGS += $${PYTHON_RPATH}
PYTHON_RPATH = $$replace(PYTHON_LIBDIR,-L,)
QMAKE_RPATHDIR += $$PYTHON_RPATH
}
6 changes: 2 additions & 4 deletions extensions/PythonQt_QtAll/PythonQt_QtAll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,5 @@ namespace PythonQt_QtAll
#ifdef PYTHONQT_WITH_UITOOLS
PythonQt_init_QtUiTools(0);
#endif
};
};


}
}
2 changes: 1 addition & 1 deletion extensions/PythonQt_QtAll/PythonQt_QtAll.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ namespace PythonQt_QtAll
{
//! initialize the Qt binding
PYTHONQT_QTALL_EXPORT void init();
};
}

#endif
68 changes: 37 additions & 31 deletions extensions/PythonQt_QtAll/PythonQt_QtAll.pro
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# get external pythonqtall config or enable all by default

isEmpty( PYTHONQTALL_CONFIG ) {
PYTHONQTALL_CONFIG = $$(PYTHONQTALL_CONFIG)
}

isEmpty( PYTHONQTALL_CONFIG ) {
message("using default PythonQt_QtAll Configuration")
CONFIG += PythonQtCore
CONFIG += PythonQtGui
CONFIG += PythonQtSvg
CONFIG += PythonQtSql
CONFIG += PythonQtNetwork
CONFIG += PythonQtOpengl
CONFIG += PythonQtXml
CONFIG += PythonQtXmlpatterns
CONFIG += PythonQtMultimedia
CONFIG += PythonQtQml
CONFIG += PythonQtQuick
CONFIG += PythonQtUiTools
qtHaveModule(gui):qtHaveModule(widgets):CONFIG += PythonQtGui
qtHaveModule(svg):CONFIG += PythonQtSvg
qtHaveModule(sql):CONFIG += PythonQtSql
qtHaveModule(network):CONFIG += PythonQtNetwork
qtHaveModule(opengl):CONFIG += PythonQtOpengl
qtHaveModule(xml):CONFIG += PythonQtXml
qtHaveModule(xmlpatterns):CONFIG += PythonQtXmlpatterns
qtHaveModule(multimedia):CONFIG += PythonQtMultimedia
qtHaveModule(qml):CONFIG += PythonQtQml
qtHaveModule(quick):CONFIG += PythonQtQuick
qtHaveModule(uitools):CONFIG += PythonQtUiTools

qtHaveModule(webkit):CONFIG += PythonQtWebKit
} else {
Expand All @@ -36,10 +40,10 @@ CONFIG += dll qt
DEFINES += PYTHONQT_QTALL_EXPORTS

HEADERS += \
PythonQt_QtAll.h
$$PWD/PythonQt_QtAll.h

SOURCES += \
PythonQt_QtAll.cpp
$$PWD/PythonQt_QtAll.cpp

unix {
CONFIG += create_pc create_prl no_install_prl
Expand All @@ -60,79 +64,81 @@ headers.path = /include

INSTALLS += target headers

defineTest(Xinclude) {
f=$$PYTHONQT_GENERATED_PATH/$$1/$${1}.pri
exists($$f):include($$f):export(HEADERS):export(SOURCES):export(DEFINES)

}


PythonQtCore {
DEFINES += PYTHONQT_WITH_CORE
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_core/com_trolltech_qt_core.pri)
Xinclude (com_trolltech_qt_core)
}

PythonQtGui {
DEFINES += PYTHONQT_WITH_GUI
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_gui/com_trolltech_qt_gui.pri)
Xinclude (com_trolltech_qt_gui)
QT += gui widgets printsupport
}

PythonQtSvg {
DEFINES += PYTHONQT_WITH_SVG
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_svg/com_trolltech_qt_svg.pri)
Xinclude (com_trolltech_qt_svg)
QT +=svg
}

PythonQtSql {
DEFINES += PYTHONQT_WITH_SQL
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_sql/com_trolltech_qt_sql.pri)
Xinclude (com_trolltech_qt_sql)
QT += sql
}

PythonQtNetwork {
DEFINES += PYTHONQT_WITH_NETWORK
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_network/com_trolltech_qt_network.pri)
Xinclude (com_trolltech_qt_network)
QT += network
}

PythonQtOpengl {
DEFINES += PYTHONQT_WITH_OPENGL
PythonQtCore: include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_opengl/com_trolltech_qt_opengl.pri)
QT += opengl
}

PythonQtXml {
DEFINES += PYTHONQT_WITH_XML
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_xml/com_trolltech_qt_xml.pri)
PythonQtCore: Xinclude (com_trolltech_qt_opengl)
QT += xml
}

PythonQtXmlpatterns {
DEFINES += PYTHONQT_WITH_XMLPATTERNS
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_xmlpatterns/com_trolltech_qt_xmlpatterns.pri)
Xinclude (com_trolltech_qt_xmlpatterns)
QT += xmlpatterns
}

PythonQtMultimedia {
DEFINES += PYTHONQT_WITH_MULTIMEDIA
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_multimedia/com_trolltech_qt_multimedia.pri)
QT += multimedia multimediawidgets
Xinclude (com_trolltech_qt_multimedia)
QT += multimedia multimediawidgets
}

PythonQtQml {
DEFINES += PYTHONQT_WITH_QML
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_qml/com_trolltech_qt_qml.pri)
Xinclude (com_trolltech_qt_qml)
QT += qml
}

PythonQtQuick {
DEFINES += PYTHONQT_WITH_QUICK
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_quick/com_trolltech_qt_quick.pri)
Xinclude (com_trolltech_qt_quick)
QT += quick quickwidgets
}

PythonQtUiTools {
DEFINES += PYTHONQT_WITH_UITOOLS
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_uitools/com_trolltech_qt_uitools.pri)
Xinclude (com_trolltech_qt_uitools)
QT += uitools
}

PythonQtWebKit {
DEFINES += PYTHONQT_WITH_WEBKIT
include ($$PYTHONQT_GENERATED_PATH/com_trolltech_qt_webkit/com_trolltech_qt_webkit.pri)
Xinclude (com_trolltech_qt_webkit)
QT += webkit webkitwidgets
}
11 changes: 8 additions & 3 deletions generator/abstractmetabuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,7 @@ int AbstractMetaBuilder::figureOutEnumValue(const QString &stringValue,
AbstractMetaEnum *meta_enum,
AbstractMetaFunction *meta_function)
{
Q_UNUSED(meta_function)
if (stringValue.isEmpty())
return oldValuevalue;

Expand Down Expand Up @@ -1619,12 +1620,15 @@ AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem fu

// If we where not able to translate the default argument make it
// reset all default arguments before this one too.
for (int i=0; i<first_default_argument; ++i)
for (int i=0; i<first_default_argument; ++i) {
meta_arguments[i]->setDefaultValueExpression(QString());
}

if (ReportHandler::debugLevel() == ReportHandler::FullDebug)
foreach(AbstractMetaArgument *arg, meta_arguments)
if (ReportHandler::debugLevel() == ReportHandler::FullDebug) {
foreach(AbstractMetaArgument *arg, meta_arguments) {
ReportHandler::debugFull(" - " + arg->toString());
}
}

return meta_function;
}
Expand Down Expand Up @@ -1944,6 +1948,7 @@ QString AbstractMetaBuilder::translateDefaultValue(ArgumentModelItem item, Abstr
AbstractMetaFunction *fnc, AbstractMetaClass *implementing_class,
int argument_index)
{
Q_UNUSED(type)
QString function_name = fnc->name();
QString class_name = implementing_class->name();

Expand Down
Loading

0 comments on commit 1e794e5

Please sign in to comment.