What is the correct way to build a thread-safe, multiplatform C library?

c, gcc, pthreads, thread-safety

Solution

I don't have access to any Solaris machine at the moment, so I can't test this. But what happens when you put `#define _POSIX_C_SOURCE 200112L` as the very first line in `test.c` (before inclusion of `<errno.h>`)? If your Solaris is POSIX-compliant, then that should make `errno` expand to the thread-safe version. This is because POSIX defines `errno` as below:

For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.

Accordingly, this is portable to any POSIX-compliant system. In fact, if you want to write POSIX-compliant application code, then you should always define `_POSIX_C_SOURCE` to the value appropriate for the minimum version of POSIX you are targeting. The definition should be at the top of every source file before including any headers. From the 2001 version of the standard:

A Strictly Conforming POSIX Application is an application that requires only the facilities described in IEEE Std 1003.1-2001. Such an application:

...

8. For the C programming language, shall define _POSIX_C_SOURCE to be 200112L before any header is included

Problem

Consider the following trivial C program, ``` #include <errno.h> int main(int argc, char* argv[]) { return errno; } ``` When compiled on Solaris, the behavior of this code is dependent on the presence of `-D_REENTRANT`. ``` solaris$ cc -E test.c | grep return return errno; solaris$ cc -D_REENTRANT -E test.c | grep return return ( * ( ___errno ( ) ) ); ``` with the latter version being thread-safe. If we compile the same code on Linux, we get the same behavior independent of `-D_REENTRANT` ``` linux$ gcc -E test.c | grep return return (*__errno_location ()); linux$ gcc -D_REENTRANT -E test.c | grep return return (*__errno_location ()); ``` Solaris' `cc` has the option `-mt`, which implies `-D_REENTRANT`, as does `gcc`'s `-pthread`. However, for a library, specifying these multi-threaded options seems poor, as it injects an unnecessary dependency on the threading runtime. However, if the library needs to be thread-safe (including errno), then the thread-safe semantics are needed at both compile time of the library and of the deriving code. On Linux, this is easy, because errno is always thread-local, but that's not guaranteed on other systems as just demonstrated. That results in the question: how is a thread-safe library properly compiled and distributed with headers? One option would be to `#define _REENTRANT` in the main header, but this would cause issues if `#include <errno.h>` occurs before the library header inclusion. Another option is to compile the library with `-D_REENTRANT`, and have the main header `#error` if `_REENTRANT` is not defined. What's the correct/best way to make a thread-safe library and ensure it correctly inter-operates with the code it is linked with?

Original source