diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8411305..284c4dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,18 +8,20 @@ jobs: fail-fast: false matrix: version: - - 5.14.0 + - 5.15.0 platform: - gcc_64 - android - wasm_32 - - msvc2017_64 - - msvc2017 - - winrt_x64_msvc2017 - - winrt_x86_msvc2017 - - winrt_armv7_msvc2017 - - mingw73_64 - - mingw73_32 + - msvc2019_64 + - msvc2019 + - winrt_x64_msvc2019 + - winrt_x86_msvc2019 + - winrt_armv7_msvc2019 +# - msvc2017_64 +# - msvc2017 + - mingw81_64 + - mingw81_32 - clang_64 - ios @@ -30,20 +32,24 @@ jobs: os: ubuntu-latest - platform: wasm_32 os: ubuntu-latest - emsdk: sdk-fastcomp-1.38.27-64bit - - platform: msvc2017_64 - os: windows-2016 - - platform: msvc2017 - os: windows-2016 - - platform: winrt_x64_msvc2017 - os: windows-2016 - - platform: winrt_x86_msvc2017 - os: windows-2016 - - platform: winrt_armv7_msvc2017 - os: windows-2016 - - platform: mingw73_64 + emsdk: sdk-fastcomp-1.39.8-64bit + - platform: msvc2019_64 os: windows-latest - - platform: mingw73_32 + - platform: msvc2019 + os: windows-latest + - platform: winrt_x64_msvc2019 + os: windows-latest + - platform: winrt_x86_msvc2019 + os: windows-latest + - platform: winrt_armv7_msvc2019 + os: windows-latest + # - platform: msvc2017_64 + # os: windows-latest + # - platform: msvc2017 + # os: windows-latest + - platform: mingw81_64 + os: windows-latest + - platform: mingw81_32 os: windows-latest - platform: clang_64 os: macos-latest @@ -56,30 +62,16 @@ jobs: with: submodules: recursive - uses: actions/setup-python@v1 - - name: actions/cache emsdk - uses: actions/cache@v1 - if: matrix.platform == 'wasm_32' - with: - path: emsdk-cache - key: ${{runner.os}}-emsdk-${{matrix.emsdk}} - - uses: mymindstorm/setup-emsdk@v3 + - uses: mymindstorm/setup-emsdk@v5 if: matrix.platform == 'wasm_32' with: version: ${{matrix.emsdk}} actions-cache-folder: emsdk-cache - - name: actions/cache qt - uses: actions/cache@v1 - id: cache - with: - path: qt/${{matrix.version}}/${{matrix.platform}} - key: qt-${{matrix.version}}-${{matrix.platform}} - uses: Skycoder42/action-setup-qt@master id: qt with: version: ${{matrix.version}} platform: ${{matrix.platform}} - install-args: --verbose - cachedir: qt/${{matrix.version}}/${{matrix.platform}} - name: Install systemd deps if: matrix.platform == 'gcc_64' run: | @@ -114,21 +106,13 @@ jobs: run: | ${{steps.qt.outputs.make}} doxygen cd doc && ${{steps.qt.outputs.make}} INSTALL_ROOT="${{steps.qt.outputs.installdir}}" install - - name: upload module to releases - uses: Skycoder42/action-upload-release@master - if: startsWith(github.ref, 'refs/tags/') - with: - repo_token: ${{secrets.GITHUB_TOKEN}} - directory: ${{steps.qt.outputs.outdir}}/${{matrix.version}} - asset_name: qtservice-${{matrix.platform}}-${{matrix.version}} - tag: ${{github.ref}} - overwrite: true - name: upload examples to releases uses: Skycoder42/action-upload-release@master if: matrix.platform == 'gcc_64' && startsWith(github.ref, 'refs/tags/') with: repo_token: ${{secrets.GITHUB_TOKEN}} - directory: ${{steps.qt.outputs.outdir}}/Examples + directory: ${{steps.qt.outputs.outdir}} + platform: examples asset_name: qtservice-examples-${{matrix.version}} tag: ${{github.ref}} overwrite: true @@ -137,10 +121,21 @@ jobs: if: matrix.platform == 'gcc_64' && startsWith(github.ref, 'refs/tags/') with: repo_token: ${{secrets.GITHUB_TOKEN}} - directory: ${{steps.qt.outputs.outdir}}/Docs + directory: ${{steps.qt.outputs.outdir}} + platform: doc asset_name: qtservice-doc-${{matrix.version}} tag: ${{github.ref}} overwrite: true + - name: upload module to releases + uses: Skycoder42/action-upload-release@master + if: startsWith(github.ref, 'refs/tags/') + with: + repo_token: ${{secrets.GITHUB_TOKEN}} + directory: ${{steps.qt.outputs.outdir}} + platform: ${{matrix.platform}} + asset_name: qtservice-${{matrix.platform}}-${{matrix.version}} + tag: ${{github.ref}} + overwrite: true deploy: if: startsWith(github.ref, 'refs/tags/') @@ -155,7 +150,7 @@ jobs: - uses: Skycoder42/action-deploy-qt@master with: token: ${{secrets.GITHUB_TOKEN}} - version: 5.14.0 + version: 5.15.0 host: ${{secrets.SSHFS_HOST}} key: ${{secrets.SSHFS_KEY}} port: ${{secrets.SSHFS_PORT}} diff --git a/README.md b/README.md index b32dc9b..b6e008b 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ A platform independent library to easily create system services and use some of [![Codacy Badge](https://api.codacy.com/project/badge/Grade/8596bb56c0df40c0bba7ddd28da65fee)](https://www.codacy.com/app/Skycoder42/QtService) [![AUR](https://img.shields.io/aur/version/qt5-service.svg)](https://aur.archlinux.org/packages/qt5-service/) +> Looking for a maintainer! If anyone is interested in continuing development of the library, please write me here: https://github.com/Skycoder42/QtService/issues/30 + ## Features - Allows you to create system (and user) services for various systems - Provides a single Interface to implement only once without having to care to much about the platform @@ -135,6 +137,27 @@ exec /path/to/service --backend systemd --terminal "$@" ### Service Control The `QtService::ServiceControl` allows you to control services by sending commands to them and retrieving the status. However, what exactly is possible greatly varies for each platform. Always use `QtService::ServiceControl::supportFlags` to figure out what you can actually do on the current platform. You can also check the doxygen documentation to get an overview over all the backends and their features. +### Trouble shooting +Sometimes, a service just won't start, without any apparent reason. This can be very hard to debug, as you cannot debug a service with traditional means. The best tricks I came by this problems are: + +1. Enable as much debugging as possible, by setting the `QT_LOGGING_RULES` environment variable to `qt.service.*.debug=true`. This will enable debug logging for the service internals, which might help. To access the system logs, refer to your service managers documentation. +2. Sometimes, logs are empty or the service crashes before starting. This often indicates, that the service plugins cannot be found. In that case, make sure that: + 1. If you deployed your application, check that the `servicebackends` plugin folder exists and that the plugin you want to use is in there (for example, `qwindows[d].dll` for the windows backend). + 2. Check or generate the `qt.conf` file. It should contain an enty named `Plugins` that points to the directory that *contains* the `servicebackends` folder. + 3. If that still does not help, you can try to manually specify the plugin folder via an environment variable. Simply set `QT_PLUGIN_PATH` to the directory that *contains* the `servicebackends` folder. Use an absolute path if possible. + +**Important:** Some service managers (like windows) do not allow to set environment variables for services from the outside. In such cases, you must set the variables in your main, before loading the service. For example, to set `QT_PLUGIN_PATH`, you would do: + +``` +int main(int argc, char **argv) { + const auto appDir = QFileInfo{QString::fromUtf8(argv[0])}.dir(); + qputenv("QT_PLUGIN_PATH", appDir.absolutePath().toUtf8()); + + QtService::Service service{argc, argv}; + return service.exec(); +} +``` + ## Documentation The documentation is available on [github pages](https://skycoder42.github.io/QtService/). It was created using [doxygen](http://www.doxygen.org/). The HTML-documentation and Qt-Help files are shipped together with the module for both the custom repository and the package on the release page. Please note that doxygen docs do not perfectly integrate with QtCreator/QtAssistant. diff --git a/qtservice.pro b/qtservice.pro index d3befe5..ee52755 100644 --- a/qtservice.pro +++ b/qtservice.pro @@ -22,4 +22,5 @@ QMAKE_EXTRA_TARGETS += lupdate DISTFILES += .qmake.conf \ sync.profile \ + .github/workflows/build.yml \ ProjectTemplate/* diff --git a/src/plugins/servicebackends/standard/standardservicecontrol.cpp b/src/plugins/servicebackends/standard/standardservicecontrol.cpp index bc9c909..4214228 100644 --- a/src/plugins/servicebackends/standard/standardservicecontrol.cpp +++ b/src/plugins/servicebackends/standard/standardservicecontrol.cpp @@ -193,7 +193,7 @@ QString StandardServiceControl::serviceName() const if (info.isExecutable()) return QFileInfo{serviceId()}.completeBaseName(); else - return serviceId().split(QLatin1Char('/'), QString::SkipEmptyParts).last(); + return serviceId().split(QLatin1Char('/'), Qt::SkipEmptyParts).last(); } QSharedPointer StandardServiceControl::statusLock() const diff --git a/src/plugins/servicebackends/windows/windowsservicebackend.cpp b/src/plugins/servicebackends/windows/windowsservicebackend.cpp index b37a2eb..0bdb407 100644 --- a/src/plugins/servicebackends/windows/windowsservicebackend.cpp +++ b/src/plugins/servicebackends/windows/windowsservicebackend.cpp @@ -88,7 +88,7 @@ int WindowsServiceBackend::runService(int &argc, char **argv, int flags) if(_status.dwWin32ExitCode != NO_ERROR) return EXIT_FAILURE; // generate "local" arguments - auto sArgc = _svcArgs.size(); + int sArgc = _svcArgs.size(); QVector sArgv; sArgv.reserve(sArgc); for(auto &arg : _svcArgs) @@ -98,7 +98,7 @@ int WindowsServiceBackend::runService(int &argc, char **argv, int flags) // create and prepare the coreapp qCDebug(logBackend) << "setting status to start pending"; setStatus(SERVICE_START_PENDING); - QCoreApplication app(sArgc, sArgv.data(), flags); + QCoreApplication app(sArgc, sArgv.data(), flags); app.installNativeEventFilter(new SvcEventFilter{}); setStatus(SERVICE_START_PENDING); if(!preStartService()) @@ -368,8 +368,13 @@ void WindowsServiceBackend::SvcControlThread::run() } - -bool WindowsServiceBackend::SvcEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +bool WindowsServiceBackend::SvcEventFilter::nativeEventFilter( + const QByteArray &eventType, void *message, long *result) +#else +bool WindowsServiceBackend::SvcEventFilter::nativeEventFilter( + const QByteArray &eventType, void *message, long long *result) +#endif { if(eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG") { diff --git a/src/plugins/servicebackends/windows/windowsservicebackend.h b/src/plugins/servicebackends/windows/windowsservicebackend.h index f3a0b1e..e08ca11 100644 --- a/src/plugins/servicebackends/windows/windowsservicebackend.h +++ b/src/plugins/servicebackends/windows/windowsservicebackend.h @@ -44,7 +44,11 @@ private Q_SLOTS: class SvcEventFilter : public QAbstractNativeEventFilter { public: - bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); +#else + bool nativeEventFilter(const QByteArray &eventType, void *message, long long *result); +#endif }; static QPointer _backendInstance; diff --git a/src/service/service.h b/src/service/service.h index a494820..e5fa209 100644 --- a/src/service/service.h +++ b/src/service/service.h @@ -168,11 +168,11 @@ protected Q_SLOTS: //! Overload for qHash Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(QtService::Service::CommandResult key, uint seed = 0) Q_DECL_NOTHROW { - return ::qHash(static_cast(key), seed); + return static_cast(::qHash(static_cast(key), seed)); } //! Overload for qHash Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(QtService::Service::TerminalMode key, uint seed = 0) Q_DECL_NOTHROW { - return ::qHash(static_cast(key), seed); + return static_cast(::qHash(static_cast(key), seed)); } template diff --git a/src/service/servicebackend.h b/src/service/servicebackend.h index fda2f7c..28fc928 100644 --- a/src/service/servicebackend.h +++ b/src/service/servicebackend.h @@ -90,7 +90,7 @@ private Q_SLOTS: //! Overload for qHash Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(QtService::ServiceBackend::ServiceCommand key, uint seed = 0) Q_DECL_NOTHROW { - return ::qHash(static_cast(key), seed); + return static_cast(::qHash(static_cast(key), seed)); } template diff --git a/src/service/servicecontrol.h b/src/service/servicecontrol.h index ae9e4ff..eeed56c 100644 --- a/src/service/servicecontrol.h +++ b/src/service/servicecontrol.h @@ -201,15 +201,15 @@ public Q_SLOTS: //! Overload for qHash Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(QtService::ServiceControl::SupportFlags key, uint seed = 0) Q_DECL_NOTHROW { - return ::qHash(static_cast(key), seed); + return static_cast(::qHash(static_cast(key), seed)); } //! Overload for qHash Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(QtService::ServiceControl::Status key, uint seed = 0) Q_DECL_NOTHROW { - return ::qHash(static_cast(key), seed); + return static_cast(::qHash(static_cast(key), seed)); } //! Overload for qHash Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(QtService::ServiceControl::BlockMode key, uint seed = 0) Q_DECL_NOTHROW { - return ::qHash(static_cast(key), seed); + return static_cast(::qHash(static_cast(key), seed)); } // ------------- Generic Implementations ------------- diff --git a/src/service/terminal.cpp b/src/service/terminal.cpp index 295f606..b51beb2 100644 --- a/src/service/terminal.cpp +++ b/src/service/terminal.cpp @@ -30,7 +30,7 @@ Terminal::Terminal(TerminalPrivate *d_ptr, QObject *parent) : connect(d->socket, &QLocalSocket::disconnected, this, &Terminal::terminalDisconnected); - connect(d->socket, QOverload::of(&QLocalSocket::error), + connect(d->socket, &QLocalSocket::errorOccurred, this, [this](QLocalSocket::LocalSocketError e) { if(e != QLocalSocket::PeerClosedError) { setErrorString(d->socket->errorString()); @@ -283,7 +283,7 @@ TerminalPrivate::TerminalPrivate(QLocalSocket *socket, QObject *parent) : connect(socket, &QLocalSocket::disconnected, this, &TerminalPrivate::disconnected); - connect(socket, QOverload::of(&QLocalSocket::error), + connect(socket, &QLocalSocket::errorOccurred, this, &TerminalPrivate::error); connect(socket, &QLocalSocket::readyRead, this, &TerminalPrivate::readyRead); @@ -328,7 +328,7 @@ void TerminalPrivate::readyRead() terminalMode = static_cast(tMode); isLoading = false; //disconnect all but "disconencted" - that one is needed for auto-delete - disconnect(socket, QOverload::of(&QLocalSocket::error), + disconnect(socket, &QLocalSocket::errorOccurred, this, &TerminalPrivate::error); disconnect(socket, &QLocalSocket::readyRead, this, &TerminalPrivate::readyRead); diff --git a/src/service/terminalclient.cpp b/src/service/terminalclient.cpp index b025044..1b29a3e 100644 --- a/src/service/terminalclient.cpp +++ b/src/service/terminalclient.cpp @@ -255,7 +255,7 @@ void TerminalClient::setupChannels() this, &TerminalClient::connected); connect(_socket, &QLocalSocket::disconnected, this, &TerminalClient::disconnected); - connect(_socket, QOverload::of(&QLocalSocket::error), + connect(_socket, &QLocalSocket::errorOccurred, this, &TerminalClient::error); connect(_socket, &QLocalSocket::readyRead, this, &TerminalClient::socketReady, diff --git a/tests/auto/service/testlib.pri b/tests/auto/service/testlib.pri index 89a27ea..702b4f9 100644 --- a/tests/auto/service/testlib.pri +++ b/tests/auto/service/testlib.pri @@ -7,17 +7,15 @@ CONFIG -= app_bundle DEFINES += SRCDIR=\\\"$$_PRO_FILE_PWD_/\\\" -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../TestBaseLib/release/ -ltestbase -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../TestBaseLib/debug/ -ltestbase -else:unix: LIBS += -L$$OUT_PWD/../TestBaseLib/ -ltestbase +win32:!win32-g++:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../TestBaseLib/release/ -ltestbase +else:win32:!win32-g++:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../TestBaseLib/debug/ -ltestbase +else: LIBS += -L$$OUT_PWD/../TestBaseLib/ -ltestbase INCLUDEPATH += $$PWD/TestBaseLib DEPENDPATH += $$PWD/TestBaseLib -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/release/libtestbase.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/debug/libtestbase.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/release/testbase.lib +win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/release/testbase.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/debug/testbase.lib -else:unix: PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/libtestbase.a +else: PRE_TARGETDEPS += $$OUT_PWD/../TestBaseLib/libtestbase.a include(../testrun.pri) diff --git a/tests/auto/testrun.pri b/tests/auto/testrun.pri index d666f70..9d9ca07 100644 --- a/tests/auto/testrun.pri +++ b/tests/auto/testrun.pri @@ -1,4 +1,4 @@ -win32:!ReleaseBuild:!DebugBuild { +debug_and_release:!ReleaseBuild:!DebugBuild { runtarget.target = run-tests runtarget.CONFIG = recursive runtarget.recurse_target = run-tests