dermesser / libsocket

The ultimate socket library for C and C++, supporting TCP, UDP and Unix sockets (DGRAM and STREAM) on Linux, FreeBSD, Solaris. See also my uvco library for a refreshed version!
https://borgac.net/~lbo/doc/libsocket/
Other
797 stars 195 forks source link

Alpine Linux build errors #70

Closed djfy closed 4 years ago

djfy commented 4 years ago

Hello, I was trying to build libsocket in an Alpine Linux based Docker container and came across two errors. The errors occur at the same time and in the same file, but I've separated them for clarity.

Error 1:

In file included from /workspace/libsocket/headers/streamclient.hpp:5,
                 from /workspace/libsocket/C++/streamclient.cpp:48:
/workspace/libsocket/headers/socket.hpp:92:22: error: 'socklen_t' has not been declared
   92 |                      socklen_t optlen) const;
      |                      ^~~~~~~~~
make[2]: *** [C++/CMakeFiles/socket++_o.dir/build.make:154: C++/CMakeFiles/socket++_o.dir/streamclient.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:268: C++/CMakeFiles/socket++_o.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

I think the reason for this error is because of where and how the definition for socklen_t can be acquired on Alpine versus, for example, Ubuntu 18.04.

On Ubuntu 18.04 when compiling streamclient.cpp, the definition for socklen_t is acquired by including <unistd.h> on line 37. This puts the definition into the global scope, granting visibility of socklen_t to the contents of the "socket.hpp" include, and therefore resulting in a successful compliation.

On Alpine, it seems like the primary way to get socklen_t is by including <sys/socket.h>, which includes <bits/alltypes.h> in the following manner:

// Alpine <sys/socket.h>
// ...

#define __NEED_socklen_t

// ...

#include <bits/alltypes.h>

// ...

Satisfying the following definition in <bits/alltypes.h>:

// Alpine <bits/alltypes.h>
// ...

#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t)
typedef unsigned socklen_t;
#define __DEFINED_socklen_t
#endif

// ...

The header <unistd.h> also includes <bits/alltypes.h>, but the explicit requirement of the __NEED_socklen_t definition on Alpine breaks the manner in which the streamclient.cpp file acquires the globally scoped definition of socklen_t.


Error 2:

In file included from /usr/include/fortify/sys/socket.h:22,
                 from /workspace/libsocket/C++/streamclient.cpp:42:
/workspace/libsocket/C++/streamclient.cpp: In member function 'void libsocket::stream_client_socket::shutdown(int)':
/workspace/libsocket/C++/streamclient.cpp:290:21: error: expected unqualified-id before numeric constant
  290 |     using BERKELEY::SHUT_RD;
      |                     ^~~~~~~
/workspace/libsocket/C++/streamclient.cpp:290:21: error: expected ';' before numeric constant
  290 |     using BERKELEY::SHUT_RD;
      |                     ^
      |                     ;
In file included from /usr/include/fortify/sys/socket.h:22,
                 from /workspace/libsocket/C++/streamclient.cpp:42:
/workspace/libsocket/C++/streamclient.cpp:291:21: error: expected unqualified-id before numeric constant
  291 |     using BERKELEY::SHUT_RDWR;
      |                     ^~~~~~~~~
/workspace/libsocket/C++/streamclient.cpp:291:21: error: expected ';' before numeric constant
  291 |     using BERKELEY::SHUT_RDWR;
      |                     ^
      |                     ;
In file included from /usr/include/fortify/sys/socket.h:22,
                 from /workspace/libsocket/C++/streamclient.cpp:42:
/workspace/libsocket/C++/streamclient.cpp:292:21: error: expected unqualified-id before numeric constant
  292 |     using BERKELEY::SHUT_WR;
      |                     ^~~~~~~
/workspace/libsocket/C++/streamclient.cpp:292:21: error: expected ';' before numeric constant
  292 |     using BERKELEY::SHUT_WR;
      |                     ^
      |                     ;
make[2]: *** [C++/CMakeFiles/socket++_o.dir/build.make:154: C++/CMakeFiles/socket++_o.dir/streamclient
.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:268: C++/CMakeFiles/socket++_o.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

I think the reason for these errors is because SHUT_RD, SHUT_WR, and SHUT_RDWR are only #defined in the header <sys/socket.h> on Alpine:

// Alpine <sys/sock.h>:
// ...

#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2

// ...

While on Ubuntu 18.04, for example, the header <sys/socket.h> is as follows:

// Ubuntu 18.04 <sys/sock.h>:
// ...

enum
{
  SHUT_RD = 0,      /* No more receptions.  */
#define SHUT_RD     SHUT_RD
  SHUT_WR,      /* No more transmissions.  */
#define SHUT_WR     SHUT_WR
  SHUT_RDWR     /* No more receptions or transmissions.  */
#define SHUT_RDWR   SHUT_RDWR
};

// ...

Thus, wrapping the #include <sys/socket.h> in the BERKELEY namespace in streamclient.cpp on line 42-44 and the subsequent using directives at the lines seen in the error message will break on Alpine Linux due to the nonexistance of the enum.


Reproduction steps: Build the following Docker image:

FROM alpine:3.11

RUN apk update && \
    apk upgrade && \
    apk add git bash wget curl cmake make && \
    apk add build-base

WORKDIR /workspace

RUN git clone https://github.com/dermesser/libsocket.git && \
    cd libsocket && \
    mkdir build && \
    cd build && \
    cmake .. -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ && \
    make
dermesser commented 4 years ago

Thank you for reporting this! Please check if this works for you as well; I built it in an Alpine image myself and the change seems to have fixed the error.

djfy commented 4 years ago

Yes, the fix works. Thank you very much!