User: Password:
|
|
Subscribe / Log in / New account

Glibc feature test macros

This article brought to you by LWN subscribers

Subscribers to LWN.net made this article — and everything that surrounds it — possible. If you appreciate our content, please buy a subscription and make the next set of articles possible.

March 12, 2014

This article was contributed by Michael Kerrisk.

As evidenced by the frequency of misreported bugs to the Linux man-pages project, feature test macros (FTMs) would appear to be one of the topics that are most widely misunderstood by C programmers. The fundamental idea of FTMs is simple, but there are quite a few subtle details to master, and at least one pitfall that regularly traps programmers. This article will look at how FTMs are used in the GNU C library (glibc) and how to avoid some common problems.

FTMs are a technique used to control the definitions exposed by C header files. For example, in the clock_getres(3) manual page, we see the following text in the SYNOPSIS section:

    Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       clock_getres(), clock_gettime(), clock_settime():
              _POSIX_C_SOURCE >= 199309L

This text tells us that the <time.h> header file will expose the declarations of these three system calls (or, more precisely, their C library wrapper functions) if _POSIX_C_SOURCE is defined with the value 199309L or greater. Beginning with man-pages version 2.64 in 2007, I started adding FTM annotations such as the above to various manual pages. By now, all of the pages that require such annotations (some 350) have them. (Any omissions or errors are bugs that should be reported.)

Feature test macros and formal standards

There are several different FTMs, and a full list can be found in the feature_test_macros(7) manual page. Many of the FTMs fall into two broad classes. The first of these are the FTMs that relate to various formal standards—for example, the C language standards or Unix standards such as POSIX and the Single Unix Specification. These macros have names such as _ISOC99_SOURCE, _POSIX_C_SOURCE, and _XOPEN_SOURCE. The purpose of these macros is to cause a header file to expose definitions in a manner that conforms to a particular standard.

To take an example, we can define _POSIX_C_SOURCE with different values in order to have header files expose definitions and declarations associated with different versions of POSIX. This FTM was specified in the first (1990) edition of POSIX; defining it with the value 1 causes various header files to expose definitions associated with that POSIX version. As that standard evolved, a more coherent numbering scheme was devised, based on the year and month that the standard was released. Thus, the 1993 POSIX.1b (realtime) standard specifies that the value 199309L should cause header files to expose definitions relating to that standard. Similarly, the value 200112L causes definitions associated with the POSIX.1-2001 standard to be exposed, and the value 200809L causes definitions associated with the POSIX.1-2008 standard to be exposed.

In the snippet from the clock_getres(2) manual page shown above, the value 199309L is required because those three APIs were first standardized in POSIX.1b (1993). Standards tend to be cumulative, so that most of the APIs specified in POSIX.1b were also specified in POSIX.1-2001 and POSIX.1-2008, which is why defining _POSIX_C_SOURCE with any value greater than 199309L will also cause the POSIX.1b declarations to be exposed.

There are a number of other FTMs associated with various standards. For example, defining _ISOC99_SOURCE (with any value) causes header files to expose definitions associated with the C99 standard. The _XOPEN_SOURCE macro causes header files to expose definitions associated with various versions of the Single Unix Specification (SUS): 1 (or greater) to get definitions for SUSv1, 500 (or greater) to get definitions associated with SUSv2, 600 (or greater) to get definitions associated with SUSv3, and so on.

The "00" numbering scheme used for the _XOPEN_SOURCE values relates to the XPG (X/Open Portability Guide) standards out of which SUS grew. Thus, SUSv2 is also (occasionally) known as XPG5, and so the number 500 was used for the corresponding FTM. The next SUS release, version 3, adopted the value 600, and SUSv4 adopted the value 700. Adding a couple of zeroes to the numbers presumably permits the standard to assign meaning to intermediate values between those numbers, for something like minor revisions of the standard, although in practice no intermediate values have so far been defined.

Feature test macros and implementation standards

A second class of glibc-specific FTMs relate to historical implementation standards, in particular System V and BSD. Defining one of these macros was sometimes helpful when porting older software from one of those implementations to Linux.

Defining the macro _BSD_SOURCE (with any value) causes header files to expose definitions derived from BSD. Thus, the setgroups(2) manual page says that we must define _BSD_SOURCE to obtain the declaration of that system call:

    Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       setgroups(): _BSD_SOURCE

This corresponds to the fact that setgroups() is originally a BSD invention that is not specified in any formal standard.

Explicitly defining the _BSD_SOURCE macro has one other effect: in a very few cases where standards conflict, it causes BSD definitions to be favored. One example of such a conflict is the getpgrp() function, which exists in two forms in glibc: a POSIX version and a BSD version. By default, <unistd.h> exposes the POSIX version, unless _BSD_SOURCE is explicitly defined.

Analogously, the _SVID_SOURCE macro is used to obtain some definitions derived from the System V Interface Definition, a vendor-defined standard for System V.

The _GNU_SOURCE macro is an FTM invented by the glibc developers. Defining this macro (with any value) serves two main purposes. First, this macro is commonly used to guard Linux-specific and GNU-specific definitions that are part of standard header files. Thus, to get the declaration of the Linux-specific ppoll() system call from <poll.h>, which also provides the poll() call specified by various Unix standards, we must define _GNU_SOURCE.

The second purpose of _GNU_SOURCE is to say "give me everything". Defining this macro causes almost all of the other FTMs to be defined (with their maximum meaningful values), with the result that header files expose (almost) all of the definitions they contain.

It's complicated

Standards evolve and sometimes conflict; glibc has evolved to follow the standards, and occasionally changed its use of FTMs to fix bugs or be more consistent. Furthermore, sometimes standards are subtractive, meaning that a standard can remove an interface. A notable example occurred in the C11 standard, which removed the dangerous gets() function. Thus, recent versions of glibc don't expose this function if the _ISOC11_SOURCE FTM is defined.

The syntax used in the man pages reflects these complexities. Thus, for example, in the dprintf(3) page we see:

    Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       dprintf(), vdprintf():
           Since glibc 2.10:
               _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
           Before glibc 2.10:
               _GNU_SOURCE

This tells us that before glibc version 2.10, it was necessary to define _GNU_SOURCE to obtain the declarations of these functions. However, these functions were eventually standardized in the combined POSIX.1-2008/SUSv4 standard, and glibc 2.10 and later adjusted to that fact, so that now it suffices either to define _XOPEN_SOURCE with a value greater than or equal to 700 or to define _POSIX_C_SOURCE with a value greater than or equal to 200809L.

The <features.h> header file

The logic dealing with FTMs is implemented within the <features.h> header file. That header file defines various internal macros which are used within each of the other glibc header files to control which definitions are exposed by the header file. (Programs never need to explicitly include <features.h>: it is implicitly included by each glibc header file that makes use of FTMs.)

The internal macros have names such as __USE_GNU (for _GNU_SOURCE), __USE_BSD (for _BSD_SOURCE), __USE_SVID (for _SVID_SOURCE), and __USE_MISC (defined if either _BSD_SOURCE or _SVID_SOURCE is defined). FTMs that can take different values are implemented as multiple internal macros. So, for example, there are __USE_POSIX199309, __USE_POSIX199506, __USE_XOPEN2K, and __USE_XOPEN2K8, each set when _POSIX_C_SOURCE is greater than or equal to, respectively, 199309L, 199506L, 200112L, and 200809L.

Certain FTMs are defined by default, principally _BSD_SOURCE, _SVID_SOURCE, and _POSIX_C_SOURCE with the value 200909L (which causes the definitions for the POSIX.1-2008 base standard to be exposed).

Individual macros can be explicitly defined, using either #define in the C source code or -D directives on the compiler command line. Multiple definitions are additive. However, there is a potential surprise: in most cases, if any FTM is explicitly defined, then the default FTMs are not defined by default, and they too must be explicitly defined. The details of the default definitions, as well as certain other implicit definitions that take place when certain FTMs are explicitly defined, have varied across glibc versions. Most of those details can be found in the feature_test_macros(7) manual page.

A regular pitfall

Over the years, probably the single most common recurrent bug report to the man-pages project is the claim that defining a particular FTM does not expose a definition as documented in a manual page. Often, the reporter has inspected the header files, and discovered that explicitly defining one of glibc's internal macros such as __USE_MISC (which should never be done outside of the glibc code), causes the desired definition to be exposed, and so the report includes a claim that the manual page should document the use of that macro.

Notwithstanding occasional bugs in the documented FTM requirements, the problem is always the same: FTMs must be defined before including any header files. The reason for this requirement is that various header files may implicitly include other header files, and any of those files may in turn include <features.h>. If a macro is defined after <features.h> is included, then it has no effect, since that header file (like most library header files) includes a guard macro that ensures that the contents of the file are processed only on the first inclusion of the file.

Changes in glibc 2.19 and 2.20

The original intent seems to have been that, within each of the glibc header files that employs FTMs, only one of the __USE_* internal macros should govern the exposure of any particular definition. Additionally, the macros should not be used in nested #ifdef directives. An inspection of the glibc header files quickly shows that the reality is far from the intent, a situation that led Roland McGrath to suggest that it was time for a major cleanup to bring things back to the intended situation. Roland thought that task could be simplified by eliminating the _BSD_SOURCE and _SVID_SOURCE FTMs, which, although they had a purpose historically, have ceased to be useful these days. Anymore, he said, the only macros that are needed for modern source code are those that relate to formal standards plus _GNU_SOURCE.

Joseph Myers duly obliged with a series of patches to implement the first steps in this work. The conservative approach encouraged by Roland meant that the deprecation of the _BSD_SOURCE and _SVID_SOURCE FTMs is taking place across two glibc versions. Version 2.19 of glibc added a new FTM, _DEFAULT_SOURCE. Defining this macro causes the default definitions to be exposed even when the explicit definition of other macros would cause that not to happen. The effect of defining this macro is equivalent to the effect of explicitly defining three macros in earlier glibc versions:

    cc -D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809C

In addition, glibc 2.19 removed the behavior that explicitly defining _BSD_SOURCE caused BSD definitions to be favored in the case of standards conflicts.

Some further patches from Joseph complete the deprecation of _BSD_SOURCE and _SVID_SOURCE for the upcoming glibc 2.20 release. The first of these patches converts _BSD_SOURCE and _SVID_SOURCE into synonyms for _DEFAULT_SOURCE. The deprecated macros remain effective, but cause compile-time warnings to be generated if they are used (unless _DEFAULT_SOURCE is also defined). The second patch (mechanically) converts all of the uses of the __USE_SVID and __USE_BSD internal macros in glibc header files into __USE_MISC.

The final patch does most of the real work: Joseph inspected all of the glibc header files to eliminate redundant uses of the __USE_MISC internal macro. These redundant uses range from doubled instances of __USE_MISC created by the preceding patch through to cases where __USE_MISC was combined (with a logical OR) with other macros that logically imply that __USE_MISC must also be defined. For example, in all cases where __USE_MISC is defined in glibc 2.20, __USE_XOPEN2K8 is also defined, meaning that conditionals such as the following in the glibc headers:

    #if defined __USE_MISC || defined __USE_XOPEN2K8

can be simplified to:

    #ifdef __USE_XOPEN2K8

From here on, there will probably be some further cleanups in the glibc headers. While it may not be practical in all cases to reach Roland's goal that only one of the internal __USE_* macros should govern the exposure of any particular definition, some simplifications can probably be achieved. There are likely also other cases similar to those involving __USE_MISC where there are conditionals involving two or more mutually dependent __USE_* macros that can be simplified by removing one of the macros.

Joseph has also hinted that there may be scope for obsoleting some interfaces or removing the __USE_MISC guard from conditionals such as __USE_MISC || __USE_UNIX98, so that some interfaces are not exposed by default. Certainly, there are currently a number of anomalous situations where some Linux-specific definitions are guarded by __USE_GNU and thus are exposed only if _GNU_SOURCE is defined (for example, the msgget() MSG_EXCEPT flag) while other (in some cases, closely related) Linux-specific definitions are guarded by __USE_MISC and are thus exposed by default (for example, the msgctl() MSG_STAT flag). Quite how the glibc developers will deal with issues like this, and what other FTM rationalizations and simplifications will be made for individual definitions, is matter that we are likely to see play out over the next couple of glibc releases.


(Log in to post comments)

Glibc feature test macros

Posted Mar 13, 2014 10:28 UTC (Thu) by ncm (subscriber, #165) [Link]

That cleanup must have been mind-numbing work. Thanks, Joe.

G++ defines _GNU_SOURCE

Posted Mar 13, 2014 10:53 UTC (Thu) by jwakely (guest, #60262) [Link]

To confuse things a bit, G++ unconditionally defines _GNU_SOURCE on systems using glibc, because the C++ standard library wants to be able to make use of GNU extensions, so uses the "give me everything" approach.

This unfortunately means that standard C++ headers such as <algorithm> pollute the global namespace with dozens of non-standard names (and horrible macros like "minor"!)

I'm going to fix this in the next few months by replacing _GNU_SOURCE with more fine-grained use of FTMs, and (I hope) some help from the glibc maintainers to redeclare the handful of GNU extensions libstdc++ actually needs using alternative names.

Once that's done C++ developers on GNU/Linux will probably find they've been unintentionally relying on _GNU_SOURCE for years and will have to learn how to use FTMs properly to get access to various POSIX APIs.

G++ defines _GNU_SOURCE

Posted Mar 13, 2014 14:15 UTC (Thu) by sorokin (subscriber, #88478) [Link]

I wonder if modules (C++1y) could help dealing with this problem?

Is it true that with modules libstdc++ could be compiled with _GNU_SOURCE enabled, but dependencies of libstdc++ won't be exposed (don't pollute global namespace) to user, unless they affect signature of functions or layout of classes?

G++ defines _GNU_SOURCE

Posted Mar 13, 2014 16:56 UTC (Thu) by jwakely (guest, #60262) [Link]

> I wonder if modules (C++1y) could help dealing with this problem?

Maybe. I'd like to think the answer is yes, but I bet I can solve the problem the old fashioned way before there's a modules proposal, let alone an implementation ;-)

> Is it true that with modules libstdc++ could be compiled with _GNU_SOURCE enabled, but dependencies of libstdc++ won't be exposed (don't pollute global namespace) to user, unless they affect signature of functions or layout of classes?

You're asking about the properties of a non-existent feature, so it's hard to give an accurate answer, but yes, I hope that will be true.

G++ defines _GNU_SOURCE

Posted Mar 14, 2014 15:03 UTC (Fri) by cesarb (subscriber, #6266) [Link]

> Once that's done C++ developers on GNU/Linux will probably find they've been unintentionally relying on _GNU_SOURCE for years and will have to learn how to use FTMs properly to get access to various POSIX APIs.

Both _GNU_SOURCE and _FILE_OFFSET_BITS=64 should be the default, since they are what most programmers expect.

_FILE_OFFSET_BITS=64, in particular, should always be set, or else it's easy to introduce latent bugs, which will show up once you have a file with more than 2G. I have seen that happen: the previous sysadmin(s) had a hand-compiled squid proxy, which one day stopped working, because the log file had grown to 2G (yeah, the log rotation was missing too). The immediate solution was to hand-rotate the log files; the real solution was to use a squid compiled correctly (and with working log rotation).

_GNU_SOURCE being missing, on the other hand, just leads to confused posts on programming forums questioning about missing functions. But I have yet to find a situation where it being set wasn't what the programmer wanted.

G++ defines _GNU_SOURCE

Posted Mar 14, 2014 15:21 UTC (Fri) by jwakely (guest, #60262) [Link]

> _GNU_SOURCE being missing, on the other hand, just leads to confused posts on programming forums questioning about missing functions.

Those people need to Read The Fantastic Article above :)

> But I have yet to find a situation where it being set wasn't what the programmer wanted.

http://gcc.gnu.org/PR60491
http://gcc.gnu.org/PR57582
http://gcc.gnu.org/PR59945
http://gcc.gnu.org/PR11196

These are all valid bug reports, the C++ standard library should not be polluting the global namespace and preventing users from declaring things called "clone" and "minor" which are not part of any C, C++ or POSIX standard. If you want those names there is a FTM you can use to get them, but 'g++ -std=c++11 -pedantic' should not force them on you.

_FILE_OFFSET_BITS default

Posted Mar 14, 2014 22:32 UTC (Fri) by giraffedata (subscriber, #1954) [Link]

_FILE_OFFSET_BITS=64, in particular, should always be set, or else it's easy to introduce latent bugs,

And you think that's a bigger risk than old programs, written in a day when file offsets greater than 32 bits were not even on the horizon, will have buffer overruns when you compile them for use on a new system?

_FILE_OFFSET_BITS default

Posted Mar 15, 2014 18:46 UTC (Sat) by kleptog (subscriber, #1183) [Link]

Perhaps I'm being insufficiently imaginative, but I can't think of a way that compiling an old program with _FILE_OFFSET_BITS=64 could lead to a buffer overrun. Do you have an example?

In my experience programs rarely do anything with fseek/ftell. So not compiling with _FILE_OFFSET_BITS=64 just means these programs fail reading/writing large files without there actually being an issue. Especially if a file is opened append-only, it breaks when reaching 2G, even though the program clearly doesn't care.

_FILE_OFFSET_BITS default

Posted Mar 15, 2014 21:58 UTC (Sat) by khim (subscriber, #9252) [Link]

Perhaps I'm being insufficiently imaginative, but I can't think of a way that compiling an old program with _FILE_OFFSET_BITS=64 could lead to a buffer overrun. Do you have an example?

Is this a joke? Something like this will overflow just fine with maliciously crafted file of size 2G+2*maxreqsize:
  int mail_size = lseek(fd, 0, SEEK_END);
  if (mail_size > MAX_MAIL_SIZE) {
    syslog(LOG_MAIL, "Mail is too big!\n");
    return;
  }
  lseek(fd, 0, SEEK_SET);
  read(fd, mail_bug, mail_size);
  

Is it sloppy programming? Yeah, sure. But even if so it's safe with _FILE_OFFSET_BITS=32 and unusafe with _FILE_OFFSET_BITS=64.

In my experience programs rarely do anything with fseek/ftell.

Indeed. Most of the code is probably out there will probably work fine with _FILE_OFFSET_BITS=64. Unfortunately you only need one piece of code which does something sloppy with longs/ints/size_ts to have an exploit.

fseek/fteel use long with or without _FILE_OFFSET_BITS=64 but without _FILE_OFFSET_BITS=64 the actual size always fit in int while as with _FILE_OFFSET_BITS=64 it's easy to get values which are negative when stored in int but positive when stored in size_t. Hilarity ensues.

_FILE_OFFSET_BITS default

Posted Mar 15, 2014 22:41 UTC (Sat) by kleptog (subscriber, #1183) [Link]

Nice example, thanks for that. I wouldn't write it that way, but I can imagine that kind of code being written.

In this example the reading in of 2G of data will probably fail but I can see now that it's not the quick win I think it was.

_FILE_OFFSET_BITS default

Posted Mar 15, 2014 23:00 UTC (Sat) by giraffedata (subscriber, #1954) [Link]

I was not as imaginative as khim; I was just thinking of data structures that have 4 bytes for the file offset.

Like struct stat. If you used struct stat in a binary interface, and then recompiled with _FILE_OFFSET_BITS=64, your program would be using a struct stat64 while your communication partner would still be using stat and the file size field, not to mention the whole structure, would overrun.

If you just had your own data structure - maybe a database index - with a 4 byte offset field and assigned an off_t value to it, you'd end up with an arithmetic overrun, which is almost as bad as a buffer overrun. (And that's even before considering the signedness issue khim raised).

I'm sure there are people saying it was never right to assume the width of off_t or struct stat, and therefore essentially nobody did it, but that's hindsight. There was a time when the concept of a file larger than 2 GB was too ridiculous, and the nature of such a system too unpredictable, to justify mucking up your code with an overflow test. One could easily have reasoned that if files ever did get that big, the designers of the new interface could deal with the 32 bit assumption then (which they did).

_FILE_OFFSET_BITS default

Posted Mar 17, 2014 12:12 UTC (Mon) by roblucid (subscriber, #48964) [Link]

Indeed, I remember when I got my hands on the first 1GB IBM SCSI disk, which seemed unbelievably large, given ones just 3 years older at 300MB were in boxes the size of midi-tower PCs. Files, reaching sizes of 2GiB, seemed to be just in perpetuity broken.. we knew the UNIX FS imposed limits. In fact who wants to open a 2GiB text logfile with vi(1)? Even today with current RAM sizes, back then 32MiB was very large and text files were "small" and loaded into memory. BSD introduced nvi(1) which handled large files better.

_FILE_OFFSET_BITS default

Posted Sep 8, 2014 22:22 UTC (Mon) by wahern (subscriber, #37304) [Link]

The compiler will complain loudly about the narrowing.

And 64-bit programs have been around since the early 1990s. The first full-blown Linux distribution supporting 64-bit Alpha came out in 1995.

Compared to Windows, 64-bit issues on Linux have been few and far between. Part of that is because back then FOSS developers tended to be battle-hardened portability experts who took these issues seriously. And at least with 64-bit, that cautionary attitude still lingers.

In today's FOSS world where portability is looked down upon as a needless chore, where there's x86 and ARM and nothing else, and where IBM actually ships a Power chip in little-endian mode because it's apparently too difficult for their Linux customers to not conflate representation and value, I can't imagine we'd be able to make such a transition so smoothly again.

Glibc feature test macros

Posted Mar 13, 2014 11:17 UTC (Thu) by mchapman (subscriber, #66589) [Link]

> Notwithstanding occasional bugs in the documented FTM requirements, the problem is always the same: FTMs must be defined before including any header files. The reason for this requirement is that various header files may implicitly include other header files, and any of those files may in turn include <features.h>. If a macro is defined after <features.h> is included, then it has no effect, since that header file (like most library header files) includes a guard macro that ensures that the contents of the file are processed only on the first inclusion of the file.

I wonder if it would be possible for <features.h> to detect that it was being re-included with a different set of FTMs enabled -- implying that some macros were defined (or redefined) after the first inclusion of the header. It could emit an appropriate #warning in this case.

Unfortunately, looking at how <features.h> is implemented I don't think this would be quite straight-forward. You wouldn't just be able to capture and compare a snapshot of the macros' values, as some of them are actually used to set the values of others. But it would be a worthwhile change if it cuts down on needless bug reports.

Glibc feature test macros

Posted Mar 14, 2014 19:09 UTC (Fri) by mathstuf (subscriber, #69389) [Link]

Wouldn't headers which use features.h then need to support being included multiple times so that extra functions could be picked up with the new feature macros?

Glibc feature test macros

Posted Mar 14, 2014 23:09 UTC (Fri) by jwakely (guest, #60262) [Link]

Many of them already do, so you can e.g. include <stdio.h> and only get the definition of FILE, then include it again and get everything else. Glibc is weird :)

Glibc feature test macros

Posted Mar 13, 2014 15:43 UTC (Thu) by ejr (subscriber, #51652) [Link]

If anyone wants to see true feature test macro insanity, check out AIX... I truly appreciate the glibc FTM approach and this latest work, thank you!

Glibc feature test macros

Posted Mar 16, 2014 13:45 UTC (Sun) by kleptog (subscriber, #1183) [Link]

The only time I've really had to fiddle with the feature test macros was when dealing with the structure definitions in netinet/ip.h, netinet/tcp.h and netinet/udp.h. If BSD_SOURCE is enabled the fields are called th_sport, uh_sport, etc. Otherwise the names are different. This usually happens when you've downloaded some source from the internet.

Given they're talking about eliminating the BSD/SysV macros, does that mean GLibc will pick one of the two and if you're using the other you'll just have to suck it up?

Glibc feature test macros

Posted Mar 24, 2014 18:04 UTC (Mon) by nix (subscriber, #2304) [Link]

They're both made available (via transparent unions).

The only place where you have to suck things up is the BSD-specific getpgrp(), but that hasn't actually worked as in BSD for ages, even if you built with -D_BSD_SOURCE. So we can safely say that this is basically unused.

Best practice?

Posted Apr 1, 2014 16:05 UTC (Tue) by bernat (subscriber, #51658) [Link]

What's the best practice when we want to write portable code?

Currently, each time I want to use, for example, asprintf, I have a define _GNU_SOURCE at the top of the file. Should I use -D_GNU_SOURCE=1 instead accross my whole project? Or should I stay away _GNU_SOURCE and try to use a more conservative _POSIX_C_SOURCE intead (and wrap asprintf in a dedicated file).

Best practice?

Posted Apr 3, 2014 5:54 UTC (Thu) by wahern (subscriber, #37304) [Link]

I compile and test all my projects on Linux, NetBSD, FreeBSD, OpenBSD, OS X, and Solaris. And I can say without a doubt that the last thing you should do, if you're writing portable programs, is to fiddle with POSIX or XOPEN feature macros!

Why?

Because most portable code actually uses one or more non-standard interfaces, and good luck making those routines visible again if you did something like -D_POSIX_C_SOURCE=200809L. FTM systems are wildly different on various platforms.

Also, many systems don't support the latest POSIX standard. For example, Solaris only supports POSIX up to 2001, even though it actually implements many of the new interfaces. So if you define _POSIX_C_SOURCE (to any value), you paradoxically _lose_ a ton of "POSIX" interfaces.

Or look at calls like mkstemp. It's in POSIX 2008, but previously it was only an X/Open extension. On Solaris there's no easy way to get it; if you define _POSIX_C_SOURCE, it disappears. If you define _XOPEN_SOURCE, you get it, but you lose the POSIX API. If you try to define both _POSIX_C_SOURCE and _XOPEN_SOURCE, the system headers barf.

Nope. In my experience, you define _GNU_SOURCE on Linux, and on every other system, leave well enough alone. Linux is the only widely used system that has a strict environment by default, AFAIK. Every other system exposes all their interfaces (excepting conflicting ones) by default, which means the last thing you want to do is define _POSIX_C_SOURCE or _XOPEN_SOURCE, unless you're a glutton for punishment, or are on some strict-POSIX crusade. Sometimes you want to define macros like _REENTRANT, _THREAD_SAFE, or the 64-bit FS macros, but those are orthogonal to the larger standards macros, and do not destroy visibility to other interfaces.

There's no substitute for testing your code on various systems. Virtual machines makes this easy-peasy. You're life is easier if you avoid FTMs. Then you can use convenient, de-facto standard APIs. It's 2014. Most of the interfaces you want are supported everywhere, but far fewer systems support the standard they were most recently specified in.

C standards are a slightly different issue, but fortunately you can have a compiler on a single platform warn you about certain constructs. Also, there's always the option of just using GCC everywhere. I try to support GCC, clang, and Solaris Studio (which require no special effort to get ahold of other than installing the OS), but you have to draw the line somewhere, because while being "portable" doesn't necessarily mean being less productive, it can make you less productive if you do it the wrong way.

Portability is a process, not a product. Most projects can be made way more portable than they are with little effort, especially if early in the development process you test-test-test, and don't code yourself into a corner.

Glibc feature test macros

Posted Sep 10, 2014 5:56 UTC (Wed) by troglobit (subscriber, #39178) [Link]

At first when I read this, I thought http://xkcd.com/927/ ... now I hope
I've interpreted it correctly, the old -D_BSD_SOURCE will still work right?


Copyright © 2014, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds