Getting ZeroMQ 3.2.0 Compiling on Mac OS X 10.7 Lion

ZeroMQ

This afternoon I decided that maybe it was time to see if I could get ZeroMQ built and running on my MacBook Pro running OS X 10.7 as well as my Ubuntu 12.04 laptop. I'm thinking it might be nice to write a few little test apps again with the latest ZeroMQ APIs between the machines to make sure that I have everything I need - should it come to that and I need to implement a little ZeroMQ action into DKit, or some other library.

The first step is downloading it from the ZeroMQ site. I picked the POSIX tarball as it's the one with the created ./configure script, and I needed that in order to get things kicked off.

Next, we try to build it on OS X 10.7 and Ubuntu 12.04. There are a few changes that have to be made to the OpenPGM code in order for it to compile on OS X. They are basically the includes needed, and not allowing duplicate definition of values.

In ./foreign/openpgm/build-staging/openpgm/pgm/include/pgm/in.h :

Replace:

  1. /* sections 5 and 8.2 of RFC 3768: Multicast group request */
  2. struct group_req
  3. {
  4. uint32_t gr_interface; /* interface index */
  5. struct sockaddr_storage gr_group; /* group address */
  6. };
  7.  
  8. struct group_source_req
  9. {
  10. uint32_t gsr_interface; /* interface index */
  11. struct sockaddr_storage gsr_group; /* group address */
  12. struct sockaddr_storage gsr_source; /* group source */
  13. };

with:

  1. #ifndef __APPLE__
  2. /* sections 5 and 8.2 of RFC 3768: Multicast group request */
  3. struct group_req
  4. {
  5. uint32_t gr_interface; /* interface index */
  6. struct sockaddr_storage gr_group; /* group address */
  7. };
  8.  
  9. struct group_source_req
  10. {
  11. uint32_t gsr_interface; /* interface index */
  12. struct sockaddr_storage gsr_group; /* group address */
  13. struct sockaddr_storage gsr_source; /* group source */
  14. };
  15. #endif // __APPLE__

In ./foreign/openpgm/build-staging/openpgm/pgm/sockaddr.c :

Replace:

  1. #include <errno.h>
  2. #ifndef _WIN32
  3. # include <sys/socket.h>
  4. # include <netdb.h>
  5. #endif

with:

  1. #include <errno.h>
  2. /* Mac OS X 10.7 differences */
  3. #ifdef __APPLE__
  4. # define __APPLE_USE_RFC_3542
  5. # include <netinet/in.h>
  6. #endif
  7. #ifndef _WIN32
  8. # include <sys/socket.h>
  9. # include <netdb.h>
  10. #endif

In ./foreign/openpgm/build-staging/openpgm/pgm/recv.c :

Replace:

  1. #include <errno.h>
  2. #ifndef _WIN32

with:

  1. #include <errno.h>
  2. /* Mac OS X 10.7 differences */
  3. #ifdef __APPLE__
  4. # define __APPLE_USE_RFC_3542
  5. # include <netinet/in.h>
  6. #endif
  7. #ifndef _WIN32

The final change is to the ZeroMQ source itself:

In ./src/pgm_socket.cpp :

Remove lines 88-92, make this:

  1. pgm_error_t *pgm_error = NULL;
  2. struct pgm_addrinfo_t hints, *res = NULL;
  3. sa_family_t sa_family;
  4.  
  5. memset (&hints, 0, sizeof (hints));
  6. hints.ai_family = AF_UNSPEC;
  7. if (!pgm_getaddrinfo (network, NULL, &res, &pgm_error)) {

look like this:

  1. pgm_error_t *pgm_error = NULL;
  2. if (!pgm_getaddrinfo (network, NULL, addr, &pgm_error)) {

At this point, we can get ZeroMQ to compile on Mac OS X 10.7 as well as Ubuntu 12.04. But there's a slight wrinkle… while I'm fine with the linux library being a 64-bit only architecture:

  drbob@mao:~/Developer/zeromq-3.2.0$ file src/.libs/libzmq.so.3.0.0
  src/.libs/libzmq.so.3.0.0: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/
  Linux), dynamically linked, BuildID[sha1]=0x71a160f17833128c864811b25942cdacdb54
  f6d0, not stripped

I'd really like the Mac OS X 10.7 dynamic library to be Universal, with both 32-bit and 64-bit architectures in it. Currently, it's 64-bit only:

  peabody{drbob}82: file src/.libs/libzmq.3.dylib
  src/.libs/libzmq.3.dylib: Mach-O 64-bit dynamically linked shared library x86_64

Hmmm… it's really amazing why some folks choose to write Makefiles in a way that doesn't allow you to use multiple -arch arguments. There really aren't all that many way to mess this up, but it seems that the OpenPGM and ZeroMQ guys have done it really pretty nicely. I can't simply remove the offending compiler flags and add in the necessary -arch i386 -arch x86_64. So I have to make it twice: once for i386 and again for x86_64 and then use lipo to stitch them together.

In the Makefiles, I added the -arch i386 command to the CFLAGS and CPPFLAGS variables after successfully building the 64-bit version of the libraries. I then did a simple:

  $ make clean
  $ make

and then when I looked at the resulting libraries they were 32-bit. I then just created the Universal binary with the lipo commands:

  $ lipo -create libzmq.3.dylib .libs/libzmq.3.dylib -output .libs/libzmq.3.dylib
  $ lipo -create libpgm-5.1.0.dylib .libs/libpgm-5.1.0.dylib -output \
    .libs/libpgm-5.1.0.dylib

Now I can copy these away and install them in the right location for usage. Typically, I'll do a make install and place everything into /usr/local/ and then copy these Universal binaries over the installed mono-binaries and be ready to roll.

UPDATE: I can get ZeroMQ to work with the simple transports, but the OpenPGM encapsulated transport fails miserably. I'm looking at the code and I'm becoming convinced that no one is really using or testing this code. It's a mess and there's no way some of these method calls are going to work. It's all in the PGM portion, so if they stay away from that, it's fine. But that's not good enough for me. So I'm giving up for now. I have asked a few things in IRC, but there aren't any responses (yet), and I don't expect to get any about the OpenPGM part.

I think it's dead, and I need to just move on. Sad to see, but it happens.

[6/21] UPDATE: after a lot of work trying to get the OpenPGM 5.1.118 code to work, I see that the developer knows about the problems, and is just not ready to support Mac OS X 10.7 at this time. I can respect that, but the things he had to have done to make his code this non-standard must be pretty wild. So there's nothing I can do at this point. OpenPGM is a deal-breaker, and that's the entire reason I wanted ZeroMQ.