Unsolved QMQTT
-
Hi,
I always preface my questions with the disclaimer that I am what I would call an advanced beginner! I know enough to write some simple programs to do some simple things, but when an issue comes up that looks like it's 'behind the curtain', I need to ask for help. I recently updated to Qt6, and have been getting used to using CMake rather than QMake.
I'm trying to get an implementation of MQTT working with Qt - I can think of a bunch of projects I could have fun with using an MQTT service, but I'm not having any luck so far. I've been trying the MQTT implementation from here: GitHub-emqx/qmqtt
When I try to run the included example code, it gives an error: 'conversion from "QMQTT::ConnectionState' to 'QChar' is ambiguous". Here is a snip of the full error text (there is more that references Qt libraries):
C:\Users\Documents\Qt\build-qmqtt-master-Desktop_Qt_6_0_0_MinGW_64_bit-Debug\qmqtt_autogen\TYW5ZMGRGA\moc_qmqtt_client.cpp:400: error: conversion from 'QMQTT::ConnectionState' to 'QChar' is ambiguous
I tried running it in Qt5 with a similar (but different) error, and I also tried using QMake, and changing the kit to MSCV (right now using MinGW).
Here is the MyExample.cpp file:
#include <qmqtt.h> #include <QCoreApplication> #include <QTimer> const QHostAddress EXAMPLE_HOST = QHostAddress::LocalHost; const quint16 EXAMPLE_PORT = 1883; //NOTE: had to add (QLatin1String()) around the string, otherwise fails - 2x const QString EXAMPLE_TOPIC (QLatin1String( "qmqtt/exampletopic" )); class Publisher : public QMQTT::Client { Q_OBJECT public: explicit Publisher(const QHostAddress& host = EXAMPLE_HOST, const quint16 port = EXAMPLE_PORT, QObject* parent = NULL) : QMQTT::Client(host, port, parent) , _number(0) { connect(this, &Publisher::connected, this, &Publisher::onConnected); connect(&_timer, &QTimer::timeout, this, &Publisher::onTimeout); connect(this, &Publisher::disconnected, this, &Publisher::onDisconnected); } virtual ~Publisher() {} QTimer _timer; quint16 _number; public slots: void onConnected() { subscribe(EXAMPLE_TOPIC, 0); _timer.start(1000); } void onTimeout() { // Had to add (QLatin1String()) to clear an error I think related to QT_NO_CAST_FROM_ASCII QMQTT::Message message(_number, EXAMPLE_TOPIC, QString(QLatin1String("Number is %1")).arg(_number).toUtf8()); publish(message); _number++; if(_number >= 10) { _timer.stop(); disconnectFromHost(); } } void onDisconnected() { QTimer::singleShot(0, qApp, &QCoreApplication::quit); } }; class Subscriber : public QMQTT::Client { Q_OBJECT public: explicit Subscriber(const QHostAddress& host = EXAMPLE_HOST, const quint16 port = EXAMPLE_PORT, QObject* parent = NULL) : QMQTT::Client(host, port, parent) , _qout(stdout) { connect(this, &Subscriber::connected, this, &Subscriber::onConnected); connect(this, &Subscriber::subscribed, this, &Subscriber::onSubscribed); connect(this, &Subscriber::received, this, &Subscriber::onReceived); } virtual ~Subscriber() {} QTextStream _qout; public slots: void onConnected() { //NOTE: had to add Qt:: before 'endl' 3x _qout << "connected" << Qt::endl; subscribe(EXAMPLE_TOPIC, 0); } void onSubscribed(const QString& topic) { _qout << "subscribed " << topic << Qt::endl; } void onReceived(const QMQTT::Message& message) { _qout << "publish received: \"" << QString::fromUtf8(message.payload()) << "\"" << Qt::endl; } }; int main(int argc, char** argv) { QCoreApplication app(argc, argv); Subscriber subscriber; subscriber.connectToHost(); Publisher publisher; publisher.connectToHost(); return app.exec(); } #include "MyExample.moc"
Here is the CMakeLists.text file - I had to tweak it a bit (Two places marked with # CHANGE):
cmake_minimum_required(VERSION 3.9) project( qmqtt VERSION 0.3.1 ) # version from src/mqtt/qmqtt_client.h #include( GNUInstallDirs ) # needed to define vars used in install() directives. # =================================================================== # Configurable options set( CMAKE_PREFIX_PATH "C:/Qt6/6.0.0/mingw81_64/lib/cmake" ) set( CMAKE_INCLUDE_CURRENT_DIR ON) option( ${PROJECT_NAME}_SHARED "Build a shared library. Turn off for static." ON ) option( ${PROJECT_NAME}_WEBSOCKETS "Enable WebSockets for MQTT" OFF ) option( ${PROJECT_NAME}_SSL "Enable SSL support for MQTT" OFF ) if ( ${PROJECT_NAME}_SHARED ) set( library_build_type SHARED ) set( library_install_component Library ) else() set( library_build_type STATIC ) set( library_install_component Devel ) endif() set( ws_component ) set( ws_libname ) set( qt6_min_version "6.0.0" ) if ( ${PROJECT_NAME}_WEBSOCKETS ) set( ws_component WebSockets ) set( ws_libname Qt5::WebSockets ) set( qt6_min_version "6.0.0" ) endif() if ( NOT ${PROJECT_NAME}_SSL) set( ssl_defs QT_NO_SSL ) endif() find_package( Qt6 ${qt6_min_version} COMPONENTS Core Network ${ws_component} CONFIG REQUIRED ) set( CMAKE_AUTOMOC ON ) set( CMAKE_AUTOUIC ON ) set( CMAKE_AUTORCC ON ) cmake_policy( SET CMP0020 NEW ) # Automatically link Qt executables to qtmain target on Windows. # =================================================================== # Project files set( PUBLIC_HEADERS src/mqtt/qmqtt_global.h src/mqtt/qmqtt.h src/mqtt/qmqtt_client.h src/mqtt/qmqtt_frame.h src/mqtt/qmqtt_message.h src/mqtt/qmqtt_routesubscription.h src/mqtt/qmqtt_routedmessage.h src/mqtt/qmqtt_router.h src/mqtt/qmqtt_networkinterface.h src/mqtt/qmqtt_socketinterface.h src/mqtt/qmqtt_timerinterface.h ) set( PRIVATE_HEADERS src/mqtt/qmqtt_client_p.h src/mqtt/qmqtt_message_p.h src/mqtt/qmqtt_network_p.h src/mqtt/qmqtt_socket_p.h src/mqtt/qmqtt_timer_p.h ) set( SOURCES src/mqtt/MyExample.cpp src/mqtt/qmqtt_client_p.cpp src/mqtt/qmqtt_client.cpp src/mqtt/qmqtt_frame.cpp src/mqtt/qmqtt_message.cpp src/mqtt/qmqtt_network.cpp src/mqtt/qmqtt_routesubscription.cpp src/mqtt/qmqtt_router.cpp src/mqtt/qmqtt_socket.cpp src/mqtt/qmqtt_timer.cpp ) if ( ${PROJECT_NAME}_WEBSOCKETS ) list( APPEND PRIVATE_HEADERS src/mqtt/qmqtt_websocket_p.h src/mqtt/qmqtt_websocketiodevice_p.h ) list( APPEND SOURCES src/mqtt/qmqtt_websocket.cpp src/mqtt/qmqtt_websocketiodevice.cpp ) endif() if ( ${PROJECT_NAME}_SSL) list( APPEND PRIVATE_HEADERS src/mqtt/qmqtt_ssl_socket_p.h ) list( APPEND SOURCES src/mqtt/qmqtt_ssl_socket.cpp ) endif() # Mark public headers as such set_source_files_properties( ${PUBLIC_HEADERS} PROPERTIES PUBLIC_HEADER 1 ) # =================================================================== # Library target # Library has the same name as the project add_library( ${PROJECT_NAME} ${library_build_type} ${SOURCES} ${PUBLIC_HEADERS} ${PRIVATE_HEADERS} ) # CHANGE - had to specify Qt6 - failed to find Qt5 (while using Qt6) target_link_libraries( ${PROJECT_NAME} PUBLIC Qt6::Core Qt6::Network ${ws_libname} ) target_compile_definitions( ${PROJECT_NAME} PRIVATE QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII QT_BUILD_QMQTT_LIB ${ssl_defs} ) # Where to look for headers while compiling the target or when compiling against # the target. target_include_directories( ${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/mqtt> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ) set_target_properties( ${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} CXX_STANDARD 11 CXX_STANDARD_REQUIRED OFF # Whether CXX_STANDARD is enforced ) if ( ${CMAKE_HOST_WIN32} ) # On Windows, libraries are not generally prefixed with "lib". # If left unchanged, cmake will still add this prefix. set_target_properties( ${PROJECT_NAME} PROPERTIES PREFIX "" IMPORT_PREFIX "" ) endif() # =================================================================== # Installation # Rule to install runtime components (ie: the shared library) # CHANGE: had to add the following line set( CMAKE_INSTALL_INCLUDEDIR "/src/mqtt/src") set( CMAKE_INSTALL_LIBDIR "/src/mqtt/include") install( TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} COMPONENT ${library_install_component} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) install( EXPORT ${PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" FILE ${PROJECT_NAME}Targets.cmake COMPONENT Devel ) install( FILES ${PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Devel OPTIONAL ) # Generate a CMake file into the installation, to easily use the library install( EXPORT ${PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" COMPONENT Devel OPTIONAL ) include( CMakePackageConfigHelpers ) file( WRITE "${CMAKE_CURRENT_BINARY_DIR}/qmqttConfig.cmake.in" "@PACKAGE_INIT@\ninclude( \${CMAKE_CURRENT_LIST_DIR}/qmqttTargets.cmake )" ) configure_package_config_file( "${CMAKE_CURRENT_BINARY_DIR}/qmqttConfig.cmake.in" "qmqttConfig.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} PATH_VARS CMAKE_INSTALL_LIBDIR ) write_basic_package_version_file( "qmqttConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/qmqttConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/qmqttConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} COMPONENT Devel ) # =================================================================== # Package creation set( CPACK_PACKAGE_NAME ${PROJECT_NAME} ) set( CPACK_PACKAGE_VENDOR "emqtt" ) # Github project owner set( CPACK_PACKAGE_DESCRIPTION_SUMMARY "mqtt client for Qt" ) set( CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/emqtt/qmqtt" ) set( CPACK_PACKAGE_CONTACT "https://github.com/emqtt/qmqtt" ) set( CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} ) set( CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR} ) set( CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH} ) set( CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH} ) set( CPACK_PACKAGE_INSTALL_DIRECTORY ${PROJECT_NAME} ) set( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/edl-v10" ) set( CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md" ) set( CPACK_COMPONENT_Library_DISPLAY_NAME "QMQTT Library" ) set( CPACK_COMPONENT_Library_DESCRIPTION "The QMQTT binary library." ) set( CPACK_COMPONENT_Library_REQUIRED 1 ) set( CPACK_COMPONENT_Devel_DISPLAY_NAME "QMQTT Development Files" ) set( CPACK_COMPONENT_Devel_DESCRIPTION "Development files for compiling against QMQTT." ) set( CPACK_COMPONENT_Devel_REQUIRED 0 ) if( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" ) if ( "${CPACK_PACKAGE_ARCHITECTURE}" STREQUAL "" ) # Note: the architecture should default to the local architecture, but it # in fact comes up empty. We call `uname -m` to ask the kernel instead. EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE ) endif() set( CPACK_INCLUDE_TOPLEVEL_DIRECTORY 1 ) set( CPACK_PACKAGE_RELEASE 1 ) # RPM - https://cmake.org/cmake/help/latest/cpack_gen/rpm.html set( CPACK_RPM_PACKAGE_RELEASE ${CPACK_PACKAGE_RELEASE} ) set( CPACK_RPM_PACKAGE_ARCHITECTURE ${CPACK_PACKAGE_ARCHITECTURE} ) set( CPACK_RPM_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY} ) set( CPACK_RPM_PACKAGE_URL ${CPACK_PACKAGE_HOMEPAGE_URL} ) set( CPACK_RPM_PACKAGE_LICENSE "EPL-1 AND EDL-1" ) set( CPACK_RPM_COMPONENT_INSTALL 1 ) set( CPACK_RPM_COMPRESSION_TYPE "xz" ) set( CPACK_RPM_PACKAGE_AUTOPROV 1 ) set( CPACK_RPM_Library_PACKAGE_SUMMARY ${CPACK_COMPONENT_Library_DESCRIPTION} ) set( CPACK_RPM_Library_PACKAGE_ARCHITECTURE ${CPACK_RPM_PACKAGE_ARCHITECTURE} ) set( CPACK_RPM_Library_PACKAGE_NAME ${CPACK_PACKAGE_NAME} ) set( CPACK_RPM_Library_FILE_NAME "RPM-DEFAULT" ) set( CPACK_RPM_Devel_PACKAGE_REQUIRES "cmake >= ${CMAKE_MINIMUM_REQUIRED_VERSION},qmqtt >= ${CPACK_PACKAGE_VERSION}" ) set( CPACK_RPM_Devel_PACKAGE_SUMMARY ${CPACK_COMPONENT_Devel_DESCRIPTION} ) set( CPACK_RPM_Devel_PACKAGE_ARCHITECTURE ${CPACK_RPM_PACKAGE_ARCHITECTURE} ) set( CPACK_RPM_Devel_PACKAGE_NAME "${CPACK_PACKAGE_NAME}-devel" ) set( CPACK_RPM_Devel_FILE_NAME "RPM-DEFAULT" ) # DEB - https://cmake.org/cmake/help/latest/cpack_gen/deb.html set( CPACK_DEBIAN_PACKAGE_RELEASE ${CPACK_PACKAGE_RELEASE} ) set( CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PACKAGE_HOMEPAGE_URL} ) set( CPACK_DEB_COMPONENT_INSTALL 1 ) set( CPACK_DEBIAN_COMPRESSION_TYPE "xz") if ( ${CPACK_PACKAGE_ARCHITECTURE} STREQUAL "x86_64" ) set( CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64" ) # DEB doesn't always use the kernel's arch name else() set( CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${CPACK_PACKAGE_ARCHITECTURE} ) endif() set( CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT" ) # Use default naming scheme set( CPACK_DEBIAN_LIBRARY_PACKAGE_NAME ${CPACK_PACKAGE_NAME} ) set( CPACK_DEBIAN_LIBRARY_PACKAGE_SHLIBDEPS 1 ) set( CPACK_DEBIAN_DEVEL_PACKAGE_DEPENDS "cmake (>= ${CMAKE_MINIMUM_REQUIRED_VERSION}), qmqtt (>= ${CPACK_PACKAGE_VERSION})" ) set( CPACK_DEBIAN_DEVEL_PACKAGE_NAME "${CPACK_PACKAGE_NAME}-dev" ) elseif( ${CMAKE_HOST_WIN32} ) set( CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON ) set( CPACK_NSIS_DISPLAY_NAME ${PROJECT_NAME} ) set( CPACK_NSIS_PACKAGE_NAME ${PROJECT_NAME} ) set( CPACK_NSIS_URL_INFO_ABOUT ${CPACK_PACKAGE_HOMEPAGE_URL} ) endif() # This must always be last! include(CPack)
-
Hi,
Before going further, did you consider using the official QtMqtt module ? It would be simpler to integrate with your project.
-
Hi @SGaist - my understanding is that module is only available in the paid 'Qt for Automation' release?
-
module is only available in the paid 'Qt for Automation' release?
No. Please check the license conditions of the module.
The module is not distributed with the Qt framework itself, but nothing prevents you from grabbing the sources and build the module yourself. In that case, keep in mind it's licensed under the GPL v3.
-
I guess I knew that was possible to do, but have never looked into it much, as I never have much luck building from source, even on Linux based machines. I can't seem to find a clear instruction on how to do it. Here is what I tried:
-Downloaded the files from GitHub and extracted them into my Qt installation folder: /Qt/5.2.13/Src/qtmqtt-dev
-Started a QtMinGW-32 terminal window (MinGW 7.3.0 64-bit) and navigated into the qtmqtt-dev folder
-tried executing mingw32-make: "***No targets specified and no makefile found"
-tried executing qmake and it created a few files and ended
-tried executing mingw32 again (seeing that maybe it had a makefile to use now?) and it actually started doing something, but terminated with this message:In file included from qmqttauthenticationproperties.cpp:30:0:
qmqttauthenticationproperties.h:33:10: fatal error: QtMqtt/qmqttglobal.h: No such file or directory
#include <QtMqtt/qmqttglobal.h>
^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
mingw32-make[3]: *** [Makefile.Release:570: .obj/release/qmqttauthenticationproperties.o] Error 1
mingw32-make[3]: Leaving directory 'C:/Qt/5.12.3/Src/qtmqtt-dev/src/mqtt'
mingw32-make[2]: *** [Makefile:42: release-all] Error 2
mingw32-make[2]: Leaving directory 'C:/Qt/5.12.3/Src/qtmqtt-dev/src/mqtt'
mingw32-make[1]: *** [Makefile:43: sub-mqtt-make_first] Error 2
mingw32-make[1]: Leaving directory 'C:/Qt/5.12.3/Src/qtmqtt-dev/src'
mingw32-make: *** [Makefile:45: sub-src-make_first] Error 2 -
You likely have the code for the dev branch which is Qt 6. Please clone the module properly and checkout the branch that matches your Qt version.
-
Hi @SGaist, you were right, of course - I had the dev branch.
I downloaded the branch for 5.12.3, followed the same steps as above, and had the exact same error. Then I tried the same for the other versions of Qt that I have on my computer: 5.12.2 and 6.0.0 (each in the respective /Src directory), all with the same exact error:
In file included from qmqttauthenticationproperties.cpp:30:0:
qmqttauthenticationproperties.h:33:10: fatal error: QtMqtt/qmqttglobal.h: No such file or directory
#include <QtMqtt/qmqttglobal.h>
^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
mingw32-make[3]: *** [Makefile.Release:553: .obj/release/qmqttauthenticationproperties.o] Error 1
mingw32-make[3]: Leaving directory 'C:/Qt/5.12.3/Src/qtmqtt-5.12.3/src/mqtt'
mingw32-make[2]: *** [Makefile:42: release-all] Error 2
mingw32-make[2]: Leaving directory 'C:/Qt/5.12.3/Src/qtmqtt-5.12.3/src/mqtt'
mingw32-make[1]: *** [Makefile:43: sub-mqtt-make_first] Error 2
mingw32-make[1]: Leaving directory 'C:/Qt/5.12.3/Src/qtmqtt-5.12.3/src'
mingw32-make: *** [Makefile:45: sub-src-make_first] Error 2 -
Do you have
PearlPerl installed ? -
Pearl...haven't heard of it. Do you mean PERL the programming language? Either way, not on purpose - maybe if it snuck in as a part of another IDE, but I don't think so. Do I need it?
-
Indeed, auto-correct helped again...
When building from git yes, you need it as there are scripts that are run one of which generates the forward headers.
-
Huh! Okay - do I just grab the binary (Windows) from perl.org? Can I install that and just make sure the executable is in my Path?
-
-
So there were two options for Perl downloads from perl.org. ActivePerl, and StrawberryPerl - I chose ActivePerl. I installed, made sure it was in my path, rebooted for good luck, and tried the above steps again with the same result (failed on same file).
Did I download the wrong Perl?
-
Did you nuke the build folder before restarting ?
-
Ah - no I didn't. Shall I delete the whole folder and move in a fresh copy? Also, am I using the correct methods - qmake, then mingw32-make?
-
Yes, delete the folder, you can then recreate it.
And yes, if you use the MinGW build of Qt. Note that you can also open the module in Qt Creator to do the build if you want.
-
Argghh!
Okay - I deleted the folder 'qtmqtt-5.12.3' in the /Src directory, and copied in a fresh version. Followed same steps as above, with the same results. I'm using the mingw32 terminal window from the same version of Qt to execute the commands.
How do I do it from within Qt Creator?
Also - thank you for the help so far.
-
I meant the build folder. Please use out of source builds so you keep the sources clean.
Just open the module as any other project.
Did you inspect the console output ? Was there any mention of a script failing ?
-
@SGaist - it didn't get as far as creating a build folder, and there still isn't one that I can find. I think I have some other weirdness going on...I haven't really done much in Qt5 after installing Qt6 (no time).
I tried opening the QtMqtt module in Qt5 Creator, and when it was time to select the kit to use there were two new ones called 'Replacement for "Desktop Qt 5.12.3 MinGW 64-bin"' and 'Replacement for "Desktop Qt 5.11.2 MinGW 32-bit"'. I could still select the usual kit I use, but now when 'Shadow build" is checked the path text is red and says the build directory doesn't exist.
Also tried building the Qt6 version of the module, in Qt6 Creator, which was also successful, but it also will not find the module with either qmake or cmake.
So my questions now are: -where does that usually point? Why do I have those two new kits (did Qt6 interfere?). And, can I put things back to 'normal'?
Oh, I did get the QtMqtt module to build after unchecking Shadow build, but when I try to add it to a new project (Qt += mqtt) it doesn't find the module.
-