Macros like _GNU_SOURCE, what do they mean? - c

Lot many times while referring to linux header files or man files, I see the following macros used..
Ex : man mkstemp
In this man page we can see that the below macros are featured.
_GNU_SOURCE
_BSD_SOURCE
_SVID_SOURCE
_XOPEN_SOURCE
_XOPEN_SOURCE_EXTENDED
What am I supposed to understand to write a correct program if I am using these API's/Headers?

Read feature_test_macros(7) man page (and the §1.3.4 Feature Test Macros chapter of GNU libc documentation).
You might compile your whole program with some special feature symbols. For instance, I often compile a program with -D_GNU_SOURCE. This means that I want all the extra GNU specific features provided on my system by GNU libc etc. You could instead compile with -D_POSIX_C_SOURCE=200112L if you want strict POSIX 2001 compliance (and nothing more).
Alternatively, if all your .c files are just #include-ing only your own header, that header could start with #define _GNU_SOURCE 1 followed by several system #include ....
The point is that a GNU/Linux system obey to several standards (with GNU providing its own standard), and you might choose which ones.
GNU libc (which is the most common libc available on Linux, but you could use some other libc, like musl-libc ....) provides a lot of functions, features and headers not available on other systems, e.g. <argp.h> (header), fopencookie (function), %m format control directive in printf feature.
It is also relevant if you intend to code a program portable to other POSIX systems (e.g. to MacOSX). On MacOSX or AIX systems you don't have getopt_long since it is a GNU specific function.

Related

How to include -D_POSIX_C_SOURCE=200809 when you compile the code

I am doing an assignment which states: "The skeleton code given uses getopt. If you compile the code with -std=c99, there will be compilation
error. To fix the error, include -D_POSIX_C_SOURCE=200809 when you compile the code."
I am very new to this. Ordinarily I compile a C program with GCC (program name) and then I type ./a.out.
What am I required to do here?
The sentence “To fix the error, include -D_POSIX_C_SOURCE=200809 when you compile the code” means to include the characters -D_POSIX_C_SOURCE=200809 in the command you use to compile the program.
For example, if you normally use gcc -o foo foo.c, change it to gcc -o foo -D_POSIX_C_SOURCE=200809 foo.c.
This is a command line argument that tells the compiler to define a preprocessor macro named _POSIX_C_SOURCE to be replaced by 200809. This preprocessor macro is used by various header files to adapt to different versions of POSIX (by using #if statements to test the macro). For example, if you specify _POSIX_C_SOURCE to be 200809 or leave it undefined, the headers will not declare routines that were only added to POSIX after the 2008-09 version of POSIX. Among other things, this avoids causing conflicts with programs written before then that might have happened to use names of those routines for other purposes (since they would have had no way of knowing what names POSIX header would define in the future).
You can also define the macro in your source code, before any headers that use it are included, with:
#define _POSIX_C_SOURCE 200809
The getopt function is a relatively recent addition to the Single UNIX Specification/POSIX Standard. While Linux doesn't comply with POSIX, it does roughly use this standard as a reference point. However, it's mostly implementing XSH (System Headers) of POSIX '03 or earlier by default for compatibility. If you want more recent additions exposed (Note: #JonathanLeffler mentions that getopt is there for quite some time already, but Linux doesn't expose it by default anyway), you can tell the GNU libc (the C Library commonly used on GNU/Linux systems) to also provide some of that functionality which are hidden behind Feature Test Macros. Lookup the man-page man -s 7 feature_test_macros 2 in combination with man -s 3 getopt 1 for more. Basically, in the respective headers there's some code similar to the following:
#if _POSIX_C_SOURCE >= 200809L
/* declaration of getopt() and other newer functions */
#endif
If you then include that file and do not define the feature test macro to have a value greater than (newer/more recent than) the date of that POSIX standard you need (2008-09), the C Preprocessor will throw away all those forward declarations, making your code error out.
Using -DFOO=bar you #define FOO bar on the command line for the standard C Compiler. By the way, the GNU C Compiler also sets some of such flags when you use -std=c99.
In the end, your command line should look more or less like this:
$ c99 -D_POSIX_C_SOURCE=200809L -o foo foo.c
This will compile and link foo.c to the output file foo adhering to the C99 standard and using features from POSIX '08 3.

Why do Windows and Linux have different strdup implementations: strdup() and _strdup()?

When working with strdup on Windows I found out that _strdup is Windows specific, but when I ran the same code on Linux it required strdup without the underscore. Does anyone know the history behind this difference, as-well as some information on how you have dealt with this problem when writing cross-platform code?
There are several functions that are part of the POSIX specification, i.e. Linux and most other UNIX variants, that are not part of standard C. These include strdup, write, read, and others.
The reasoning for the leading underscore is as follows, taken from the MSDN docs:
The Universal C Run-Time Library (UCRT) supports most of the C
standard library required for C++ conformance. It implements the C99
(ISO/IEC 9899:1999) library, with certain exceptions: The type-generic
macros defined in , and strict type compatibility in
. The UCRT also implements a large subset of the POSIX.1
(ISO/IEC 9945-1:1996, the POSIX System Application Program Interface)
C library. However, it's not fully conformant to any specific POSIX
standard. The UCRT also implements several Microsoft-specific
functions and macros that aren't part of a standard.
Functions specific to the Microsoft implementation of Visual C++ are
found in the vcruntime library. Many of these functions are for
internal use and can't be called by user code. Some are documented for
use in debugging and implementation compatibility.
The C++ standard reserves names that begin with an underscore in the
global namespace to the implementation. Both the POSIX functions and
Microsoft-specific runtime library functions are in the global
namespace, but aren't part of the standard C runtime library. That's
why the preferred Microsoft implementations of these functions have a
leading underscore. For portability, the UCRT also supports the
default names, but the Microsoft C++ compiler issues a deprecation
warning when code that uses them is compiled. Only the default names
are deprecated, not the functions themselves. To suppress the warning,
define _CRT_NONSTDC_NO_WARNINGS before including any headers in code
that uses the original POSIX names.
I've handled that by having a #define that check if the program is being compiled for Windows, and if so create another #define to map the POSIX name to the Windows specific name. There are a few choices you can check, although probably the most reliable is _MSC_VER which is defined if MSVC is the compiler.
#ifdef _MSC_VER
#define strdup(p) _strdup(p)
#endif

access a POSIX function using dlopen

POSIX 2008 introduces several file system functions, which rely on directory descriptor when determining a path to the file (I'm speaking about -at functions, such as openat, renameat, symlinkat, etc.). I doubt if all POSIX platforms support it (well, at least the most recent versions seem to support) and I'm looking for a way to determine if platform supports such functions. Of course one may use autoconf and friends for compile-time determination, but I'm looking for a possibility to find out whether implementation supports -at functions dynamically.
The first that comes to my mind is a dlopen()/dlsym()/dlclose() combo; at least I've successfully loaded the necessary symbols from /usr/libc.so.6 shared library. However, libc may be (or is?) named differently on various platforms. Is there a list of standard locations to find libc? At least on Linux /lib/libc.so appears to be not a symbolic link to shared library, but a ld script. May be there exist some other way to examine during runtime if a POSIX function is supported? Thanks in advance!
#define _GNU_SOURCE 1
#include <dlfcn.h>
#include <stdio.h>
int main ()
{
void * funcaddr = dlsym(RTLD_DEFAULT, "symlinkat");
/* -----------------------^ magic! */
printf ("funcaddr = %p\n", funcaddr);
}
Output:
funcaddr = 0x7fb62e44c2c0
Magic explanation: your program is already linked with libc, no need to load it again.
Note, this is actually GNU libc feature, as hinted by _GNU_SOURCE. POSIX reserves RTLD_DEFAULT "for future use", and then proceeds to define it exactly like GNU libc does. So strictly speaking it is not guaranteed to work on all POSIX systems.

c89 and POSIX at the same time

Is it possible to use POSIX functions even in strict std=c89? When I try to compile executable on Linux in strict ANSI C mode, both gcc and clang know nothing about functions like readlink or realpath, though headers are included. Since I have to use POSIX functions even in ANSI C mode, I'm looking for way to do it. I've thought about dlsym, but I don't know which library I'll have to open. Such calls are surrounded with #ifdef's, so they won't rise an alarm on the other system. Cross-platform solution needed. Thanks in advance!
You're looking for "feature-test macros". See the Single Unix Specification, Issue 6: System Interfaces Chapter 2.2, "The Compilation Environment"
Edit:
To quote that page:
The _POSIX_C_SOURCE Feature Test Macro
A POSIX-conforming application should ensure that the feature test macro
_POSIX_C_SOURCE is defined before inclusion of any header.
GCC and clang currently define _POSIX_C_SOURCE for you by default unless one of c89, c99, c11, or any behaviorally equivalent string is passed to the compiler's -std option.
Additionally:
The _XOPEN_SOURCE Feature Test Macro
An XSI-conforming application should ensure that the feature test macro
_XOPEN_SOURCE is defined with the value 600 before inclusion of any header.
This is needed to enable the functionality described in The _POSIX_C_SOURCE
Feature Test Macro and in addition to enable the XSI extension.
In other words, to guarantee your program (a.k.a. application) can use POSIX, either #define _POSIX_C_SOURCE 200112L before any header is included or pass the -D_POSIX_C_SOURCE=200112L option to the compiler. For the XSI functionality, you must define _XOPEN_SOURCE to a value of 600.
There is also a newer version of the Single Unix Specification — Issue 7. Very similar text can be found in Issue 7. The only real differences with respect to the text above are the numbers for _POSIX_C_SOURCE and _XOPEN_SOURCE have been changed.
At least when a combination of gcc and glibc on linux, you can turn on non standard functions (e.g. those defined by posix) with #define's , see man feature_test_macros
e.g. #define _POSIX_C_SOURCE 200809L before including any header files, or by adding it to the compiler arguments:
gcc -std=c99 -D_POSIX_C_SOURCE=200809L ...

Requesting GNU extensions but otherwise POSIX-conformant functions?

Is there a way with feature test macros to have glibc expose GNU extensions (functions not specified in POSIX, and additional flag/argument macros for standard functions, like MAP_ANONYMOUS), but still prefer POSIX semantics whenever the POSIX and GNU definitions conflict? I'm thinking things like basename, strerror_r, etc.
For the specific case of basename(), including <libgen.h> header gives you the XPG / POSIX definition.
MAP_ANONYMOUS isn't a GNU extension (_GNU_SOURCE), it's defined if either _BSD_SOURCE or _SVID_SOURCE is defined.

Resources