Read an Excerpt
Chapter 2: Developing POSIX Applications
In this chapter, we discuss how to access the C language bindings as well as the POSIX libraries. We look at what a system vendor must provide for a system to be POSIX-compliant. We demonstrate two different program development problems-porting an existing program to a POSIX-conforming system, and developing a program that is designed to be POSIX-compliant.
The POSIX Development Environment
POSIX provides portability at the source level. This means that you transport your source program to the target machine, compile it with the Standard C compiler using conforming headers, and link it with the standard libraries. The system vendor provides the compiler, the libraries, and headers. Strictly speaking, these are all black boxes and you do not need to know how they work. However, it is instructive to look into some of these black boxes, and we will do that in this chapter.
The Standard C Compiler
Each POSIX-conforming system must provide a POSIX-conformance document. This document describes the behavior of the system for all implementation-defined features identified in the standard. For maximum portability, applications should not depend upon any particular behavior that is implementation-specific. The conformance document is dull reading, but it is valuable because it contains information on how to access the standard C language bindings.
For AT&T UNIX System V Release 4, the Standard C language bindings are accessed by specifying -Xc on the cc command line. The command:
cc -Xc subs.c main.c -o prog
will compile subs. c and main. c and link them together to form prog.
The Open SoftwareFoundation's OSF/1 operating system comes with the GNU C compiler.* The Standard C bindings are accessed by specifying -ansi on the cc command line. A command there looks like:
cc -ansi subs.c main.c -o Prog
For other systems, you will have to buy (or at least look at) the conformance document, look for on-line manual pages, or ask someone.
On most systems, the default is not Standard C but a C compiler that is compatible with the historic behavior of that system. in many cases, your program will not notice the difference. The historic behavior probably includes defining symbols that are not part of Standard C and POSIX. It is easier to specify strict conformance and clean up small problems as you go than to deal with a large mess at the end of the project.
Strict ANSI conformance is a good answer to the question: "What can I do to make my programs more portable?"
POSIX and C Libraries
POSIX defines a library of functions for conforming programs to use. Many of these functions are also defined in the Standard C library.
Each function in the library requires you to include at least one header. This is done with a statement like:
The header provides a prototype for the function, plus any necessary types and additional macros to facilitate using the function.
The POSIX and C standards do not require headers to be source files. They may be some sort of magic command to the compiler. The standards specify only the net effect of including a header. On most systems (and all UNIX systems) the headers are files that live in the directory /usr/ include.
Many systems support multiple development environments. How do you get the POSIX headers? You must define the symbol _POSIX_SOURCE before including any of the standard headers. The best way to do this is to place the statement:
at the start of each file.
You could also place the option -D_POSIX_SOURCE on the cc command-line; however, this is error prone. It is better to put the #define into your source file along with the rest of your program. As a rule of thumb, restrict command-line macro definitions to things that change from one compile to the next. For example, -DNDEBUG turns off the debug test in assert ( ). Use #define statements for symbols that must always be defined, such as _POSIX_SOURCE.
On some systems the header files you include do not do much. They merely select one of several possible other headers based on the symbols that you have defined. This might look like:
#include common/stdio.h #ifdef _SYSV_SOURCE #include
sysv/stdio.h #endif #ifdef _BSD_SOURCE #include
BSD/stdio.h #endif #ifdef _POSIX_SOURCE #include
Under most circumstances, you do not need to know how the system defines the correct symbols. The Header Files section in this book details every POSIX and Standard C header file. If you follow the rules in this section, the standards guarantee the following:
1. Every symbol required by the standards will be defined with a meaningful value.
2. No symbol not permitted by the standards will be defined. This protects your application from namespace pollution.* Of course, if you include a header not specified by the standard, all bets are off.
Converting Existing Programs
Porting an existing application to run on a new system requires two major steps. These tasks can range from very easy to almost impossible. First, you have to transport the program to the target computer. Second, you have to modify the program to run in the new environment. The POSIX standard (and this book) can help you in both steps.
The POSIX standard defines the format of both the cpio and tar archives. You can create an archive with the command:
1s files cpio -oc archive
tar -cf archive files
and load it onto the target with the command:
cpio -ic archive
tar -xvf archive
See your system documentation for the exact details. You will still need some form of compatible disk, tape, or network to move the archive file to the target.
Once the files are moved, you will have to convert system-specific function calls to calls defined by the POSIX standard. There are several aids in the reference guide in this book that are designed to make conversion easier. For every function defined by either POSIX or Standard C, there is a conversion entry in the Functions section. This entry points out the changes that may be required to convert the function from older UNIX systems to ones that conform to the POSIX standard. The Porting section covers functions in BSD and System V that are not in POSIX and suggests ways to build equivalent functions using POSIX calls....