Skip to content
This repository has been archived by the owner on Jul 8, 2022. It is now read-only.

CMake: Add compile check to test for correct ZeroMQ C++ headers #530

Closed

Conversation

t-b
Copy link
Collaborator

@t-b t-b commented Feb 6, 2019

We are relying on the presence of convertability from zmq::socket_t to void *.

Add a cmake check so that we know that we have the correct version.

Close #273.

@Ingvord.

@t-b t-b force-pushed the feature/check-zmq-hpp-version branch 2 times, most recently from 9f3ca3a to ebfd0b2 Compare February 8, 2019 18:47
We are relying on the presence of convertability from zmq::socket_t to void *.

Add a cmake check so that we know that we have the correct version.
@t-b t-b force-pushed the feature/check-zmq-hpp-version branch from ebfd0b2 to 8873b16 Compare February 26, 2019 22:23
@t-b
Copy link
Collaborator Author

t-b commented Feb 26, 2019

@Ingvord @bourtemb How do I locally debug the travis test failures? I have docker but it's not clear for me what scripts I have to run.

And I'm not just doing it with trial and error with travis as that is way too slow for debugging.

@tango-controls tango-controls deleted a comment Feb 26, 2019
@Ingvord
Copy link
Member

Ingvord commented Feb 27, 2019

@t-b , well I do not run travis locally, I run the build process and tests (all in one run, or just a single one) from CLion. Taking into account that I am on Debian 8 build process finishes fine. Which is not the case for this particular PR for non-Debian 8 configurations.

As I see cmake complains about cppzmq:

-- Looking for C++ include zmq.hpp - found
CMake Error at configure/CMakeLists.txt:161 (message):
  Please use a compatible version of cppzmq

On Debian 9&7 where we build our own version of cppzmq (on Debian 8 we use apt-get to fetch libzmq).

The error message is added in this PR so the answer is easy - what we build is not compatible or maybe the reason is that cmake compiles against wrong version of cppzmq :)

Fetching cppzmq code is in .travis.yml and the build is in install_cppzmq.sh

Hope this helps

${CMAKE_BINARY_DIR}/configure
SOURCES ${CMAKE_SOURCE_DIR}/configure/test_zmq_hpp.cpp
CMAKE_FLAGS "-I ${CPPZMQ_BASE}/include -I ${ZMQ_PKG_INCLUDE_DIRS}/include"
LINK_LIBRARIES ${ZMQ_PKG_LIBRARIES})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we need to avoid ${ZMQ_PKG_XXX} here and use ${CPPZMQ_BASE} everywhere. As it is now - cmake compiles against cppzmq from pkg-config (from apt-get) which is indeed incompatible on Debian 9&7

@bourtemb
Copy link
Member

@Ingvord @bourtemb How do I locally debug the travis test failures? I have docker but it's not clear for me what scripts I have to run.

Hi @t-b,

The scripts to run the tests are actually described in https://github.com/tango-controls/cppTango/blob/tango-9-lts/INSTALL.md file and on the wiki for running the tests from CLion: https://github.com/tango-controls/cppTango/wiki/Contribution-Guide

@mliszcz
Copy link
Collaborator

mliszcz commented May 22, 2019

Why can't we simply use explicit conversions to void* to compile Tango with libzmq3-dev from Ubuntu 16 repos?

diff --git a/cppapi/client/zmqeventconsumer.cpp b/cppapi/client/zmqeventconsumer.cpp
index 25128a25..2b0f676a 100644
--- a/cppapi/client/zmqeventconsumer.cpp
+++ b/cppapi/client/zmqeventconsumer.cpp
@@ -181,9 +181,9 @@ void *ZmqEventConsumer::run_undetached(TANGO_UNUSED(void *arg))
        zmq::pollitem_t *items = new zmq::pollitem_t [MAX_SOCKET_SUB];
        int nb_poll_item = 3;

-       items[0].socket = *control_sock;
-       items[1].socket = *heartbeat_sub_sock;
-       items[2].socket = *event_sub_sock;
+       items[0].socket = static_cast<void*>(*control_sock);
+       items[1].socket = static_cast<void*>(*heartbeat_sub_sock);
+       items[2].socket = static_cast<void*>(*event_sub_sock);

        for (int loop = 0;loop < nb_poll_item;loop++)
        {
@@ -1063,7 +1063,7 @@ bool ZmqEventConsumer::process_ctrl(zmq::message_t &received_ctrl,zmq::pollitem_
 // Update poll item list
 //

-                poll_list[old_poll_nb].socket = *tmp_sock;
+                poll_list[old_poll_nb].socket = static_cast<void*>(*tmp_sock);
                 poll_list[old_poll_nb].fd = 0;
                 poll_list[old_poll_nb].events = ZMQ_POLLIN;
                 poll_list[old_poll_nb].revents = 0;
diff --git a/cppapi/server/zmqeventsupplier.cpp b/cppapi/server/zmqeventsupplier.cpp
index b1752101..f5bfb11e 100644
--- a/cppapi/server/zmqeventsupplier.cpp
+++ b/cppapi/server/zmqeventsupplier.cpp
@@ -686,7 +686,7 @@ void ZmqEventSupplier::create_mcast_socket(string &mcast_data,int rate,McastSock
 // Bind the publisher socket to the specified port
 //

-    if (zmq_bind(*(ms.pub_socket),ms.endpoint.c_str()) != 0)
+    if (zmq_bind(static_cast<void*>(*ms.pub_socket),ms.endpoint.c_str()) != 0)
     {
         TangoSys_OMemStream o;
         o << "Can't bind ZMQ socket with endpoint ";

In some older implementations of zmq.hpp, void* conversion is explicit in C++11 (and above):

#if __cplusplus >= 201103L
#define ZMQ_CPP11
#define ZMQ_NOTHROW noexcept
#define ZMQ_EXPLICIT explicit
#else
    #define ZMQ_CPP03
    #define ZMQ_NOTHROW
    #define ZMQ_EXPLICIT
#endif

// ...

        //  Be careful with this, it's probably only useful for
        //  using the C api together with an existing C++ api.
        //  Normally you should never need to use this.
        inline ZMQ_EXPLICIT operator void* () ZMQ_NOTHROW
        {
            return ptr;
        }

// ...

@t-b
Copy link
Collaborator Author

t-b commented May 25, 2019

@mliszcz Good point.

I think we should do something along these lines.

Looking at https://github.com/zeromq/cppzmq/blob/d25c58a05dc981a63a92f8b1f7ce848e7f21d008/zmq.hpp#L1272

also shows that operator void* is gone so we have to find different solutions for different zmq versions

How about something like (from the top of my head):

template<typename T>
void* ConvertToZMQPlainSocket(const T &s)
{
#if CPPZMQ_VERSION >= ZMQ_MAKE_VERSION(A, B, C)
    return s.handle();
#elif CPPZMQ_VERSION >= ZMQ_MAKE_VERSION(D, E, F)
    return static_cast<void*>(s);
#else
    return s;
#endif
}

With that wrapper we have a chance of getting rid of the code again at some point in the future.

@mliszcz
Copy link
Collaborator

mliszcz commented May 25, 2019

Looks good to me. Two comments:

  • zmq::socket_base is a new thing starting from 4.3.1. The wrapper needs to accept zmq::socket_t.
  • instead of checking for particular zmq version in preprocessor, SFINAE could be used to detect if socket provides handle() method (but it may be tricky and verbose without c++11)

@t-b
Copy link
Collaborator Author

t-b commented Jun 5, 2019

@bourtemb @mliszcz So I nearly finished the code to detect all the different cppzmq variants. But looking closer into the latest version of cppzmq showed that socket_t is still available and it also has a implicit operator *void() again (used to be implicit, now explicit, then implicit again). So I think Michal's solution is the way to go. I'll prepare a PR.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can not compile libtango on Ubuntu 16 using libzmq3-dev package from apt
4 participants