The purpose of this article is to present in a general way the Unix standards and how can we write portable code on Unix systems, not only on Linux ones.
In the Unix world at present, there are three important standards:
- the C language (ISO C standard) and the standard C library (
libc
), which are included in the POSIX standard - the POSIX standard (Portable Operating System Interface for Unix), which has the last version from 2008
- the SUS standard (Single Unix Specification), which includes as a subset the POSIX standard, with the last version from 2010 (SUSv4).
The POSIX standard consists of:
- POSIX.1: core services
- POSIX.1b: real-time extensions
- POSIX.1c: threads extensions
- POSIX.2: shell and utilities
We will be interested in this article only by POSIX.1 (last version: POSIX.1-2008, or IEEE Std 1003.1-2008) from the whole POSIX standard.
As implementations of the standard, we can name the GNU/Linux-based operating systems, the systems which descend from the BSD Unix version: FreeBSD, NetBSD, OpenBSD, DragonflyBSD, the certified and commercial UNIX-es, based on UNIX System V release 4 and, from case to case, with BSD elements: Oracle Solaris (known previously as Sun Solaris), HP-UX and Tru64 UNIX (HP), AIX (IBM), IRIX (SGI), Unixware and OpenServer (SCO), and also Mac OS X, which is also officially certified as a UNIX system, based on FreeBSD elements and not on UNIX System V.
The most “popular” Unix systems are at present Linux, FreeBSD, Solaris and Mac OS X. With regards to the C language, all these operating systems (Linux 3.x, FreeBSD >= 8.0, Mac OS X >= 10.6.8, Solaris >= 10) support the following LIB C headers:
assert.h
: verify program assertioncomplex.h
: complex arithmetic supportctype.h
: character classification and mapping supporterrno.h
: error codesfenv.h
: floating-point environmentfloat.h
: floating-point constants and characteristicsinttypes.h
: integer type format conversioniso646.h
: macros for assignment, relational, and unary operatorslimits.h
: implementation constantslocale.h
: locale categories and related definitionsmath.h
: mathematical functions and type declarations and constantssetjmp.h
: nonlocalgoto
signal.h
: signalsstdarg.h
: variable argument listsstdbool.h
: boolean type and valuesstddef.h
: standard definitionsstdint.h
: integer typesstdio.h
: standard I/O librarystdlib.h
: utility functionsstring.h
: string operationstgmath.h
: type-generic math macrostime.h
: time and datewchar.h
: extended multibyte and wide character supportwctype.h
: wide character classification and mapping support
They also support the following POSIX headers (in the C language):
aio.h
: asynchronous I/Ocpio.h
: cpio archive valuesdirent.h
: directory entriesdlfcn.h
: dynamic linkingfcntl.h
: file controlfnmatch.h
: filename-matching typesglob.h
: pathname pattern-matching and generationsgrp.h
: group fileiconv.h
: codeset conversion utilitylanginfo.h
: language information constantsmonetary.h
: monetary types and functionsnetdb.h
: network database operationsnl_types.h
: message catalogspoll.h
:poll()
functionpthread.h
: threadspwd.h
: password fileregex.h
: regular expressionssched.h
: execution schedulingsemaphore.h
: semaphoresstrings.h
: string operationstar.h
: tar archive valuestermios.h
: terminal I/Ounistd.h
: symbolic constantswordexp.h
: word-expansion definitionsarpa/inet.h
: Internet definitionsnet/if.h
: socket local interfacesnetinet/in.h
: Internet address familynetinet/tcp.h
: TCP definitionssys/mman.h
: memory management declarationssys/select.h
:select()
functionsys/socket.h
: sockets interfacesys/stat.h
: file statussys/statvfs.h
: file system informationsys/times.h
: process timessys/types.h
: primitive system data typessys/un.h
: UNIX domain socket definitionssys/utsname.h
: system namesys/wait.h
: process controlfmtmsg.h
: message display structuresftw.h
: file tree walkinglibgen.h
: pathname management functionsndbm.h
: database operations (exception: Linux)search.h
: search tablessyslog.h
: system error loggingutmpx.h
: user accounting database (exception: FreeBSD)sys/ipc.h
: inter-processes communicationsys/msg.h
: XSI message queuessys/resource.h
: resource operationssys/sem.h
: XSI semaphoressys/shm.h
: XSI shared memorysys/time.h
: time typessys/uio.h
: vector I/O operationsmqueue.h
: message queues (exception: Mac OS X)spawn.h
: real-time spawn interface.
The SUS standard (the whole set of UNIX functions and constants) can be found online for SUSv2 (year 1997, naming UNIX 98), SUSv3 (year 2001-2002, naming UNIX 03) and SUSv4 (year 2010):
To write portable code which can be executed on any Unix systems we must know the C headers (defined by LIBC and by POSIX) which are recognized by the Unix systems. We can activate the operating system in order to use only POSIX.1 elements, or also SUSv1, SUSv2, SUSv3, or SUSv4 using the so-called “feature test macros”:
_POSIX_SOURCE
and_POSIX_C_SOURCE
, to activate POSIX functionality_XOPEN_SOURCE
, which activates SUSv1/2/3/4 functionality.
For older POSIX functionality we have to declare the following in our source file:
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 1 /* for POSIX 1990 */
/* use 2 for POSIX C bindings 1003.2-1992 */
For POSIX 2008 functionality, we define:
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 200809L
Or, we can compile with:
cc -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200809L filename.c
If our code is written, or it will run on UNIX certified systems (hence on systems who follow SUSv1, SUSv2, SUSv3, or SUSv4), we must define also _XOPEN_SOURCE
:
Thus, we would have to use
- for SUSv1:
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 2
#define _XOPEN_SOURCE
#define _XOPEN_SOURCE_EXTENDED 1
- for SUSv2:
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 199506L
#define _XOPEN_SOURCE 500
- for SUSv3:
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 200112L
#define _XOPEN_SOURCE 600
- for SUSv4:
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 700
If we write code only for Linux platforms, we will use the feature test macro _GNU_SOURCE
, which will activate GNU LIBC functionality, which sometimes isn’t POSIX compatible. There is also the feature test macro _SVID_SOURCE
(to activate System V functionality) and _BSD_SOURCE
(to activate BSD functionality). One important note is that a UNIX system (which follows SUSvX) can be activated to offer any SUSvX functionality.
This is the way we can write Unix portable code. Other methods to find out more about the operating system on which we compile are:
- LIBC functions:
sysconf(3)
,pathconf(3)
,fpathconf(3)
– functions which determine system constants autoconf
,automake
andlibtool
: utilities which determine at compile time, with scripts, what system and libc functions the operating system offers. (These will be part of the content of a following article.)
Happy Unix programming!