The C preprocessor (cpp) is a powerful, versatile tool for manipulating source code. Any version of cpp should always come with complete documentation, so the purpose of this document is to point out the subset of features that we will use. The first is the ability to include files in our source code. The normal use of this function is to include common block definitions from a single source file. This guarantees that all common block references will be consistent.
The syntax for the include command is shown below. It also includes an optional C style comment. Only C style comments are allowed on cpp command lines. C style comments begin with ``/*'' and end with ``*/''.
#include "file" /* Momentum fits common block */File is the name of the file to be included. The C preprocessor will look for the file in the current directory, then in any directories specified on the command line with the ``-I'' option, and then in the directory /usr/include, which contains system include files. There may be more than one ``-I'' option. A sample UNIX command line where cpp has been called from fortran is shown below.
f77 -c -cpp -DUNIX -DIRIX -I$E781_INCLUDE name.F
The environment variable $E781_INCLUDEpoints to the actual directory where the include files are kept. The ability to search the local directory and then a list of other directories gives equivalent functionality to the use of logical variables in the include statements on VMS. On most systems the fortran compiler recognizes the extension of .F and calls cpp before compiling the code.
A sample VMS command line is given below, where the first line is a symbol definition for cpp on the FNALV cluster and could included in a login.com file.
cpp:="$prj$root13:[e781_prj.precompiler.gcc-2.4.5]gcc-cpp.exe ""-P""" cpp "-DVMS" "-Ioff781$root:[source]" tpread.F tpread.forHere both an input and output file have to be given. They .for file would then have to be compiled.
The second function of cpp that we will use is the ability to turn on and off various sections of the code. As much as we would like to write totally portable code, we will not be able to. Some constructs like OPEN statements can be incompatible across different computers. Cpp has an if construct that allows you to select which parts of the code to use.
#if defined(VMS) ... some VMS code goes here #endif
The defined function checks to see if the cpp macro VMS is defined and returns true if it is. We will define macros on the command line using the ``-D'' option. The example compile command above has defined two macros UNIX and IRIX.
There is an abbreviation for the if defined construct, which is shown below.
#ifdef VMS ... some VMS code goes here #endif
Sometimes, knowing what the machine is not is as useful as knowing what it is. The logical negation operator ``!'' can handle this. Either of the two forms shown below will select code whenever the program is not compiled on a VAX.
#if !defined(VMS) ... some code not for VMS goes here #endifor
#ifndef VMS ... some code not for VMS goes here #endif
It is possible to logically combine these arguments to the #if statement. For example, the VAX and Decstations have the same byte order. Code that assumed that byte order could be selected with.
#if defined(VMS) || defined(ULTRIX) ... some code using VAX byte ordering goes here #endifIn this case, the defined form has to be used. There is also an operator for logical and, &&.
Just like there are ``else'' and ``else if'' concepts in fortran, cpp has constructs to handle these concepts, which the example below illustrates.
#ifdef VMS /* VMS needs readonly */ open (unit=iounit, ... , readonly) #elif defined(IRIX) /* IRIX needs a special option */ open (unit=iounit, special, ...) #else /* all other machines */ open (unit=iounit, ...) #endif
In order to be able to compile all our codes with a small set of macro definitions, we need to set some standards. You should choose the least restrictive macro definition that you can. If your code runs on all UNIX platforms, then you should use the macro UNIX. If it is particular to just SGI then you should use IRIX. In general, if you wish to select some code for a particular machine then you should use the operating system name for your macro. Here is a list of the currently defined macro names.
There are predefined macros on most UNIX systems. We have chosen to avoid them by using uppercase macro names, since they are not consistent from one machine to another.
Sometimes problems will occur that are specific to a version of the operating system. This seems to be a particularly acute problem for IRIX. The introduction of IRIX 5.0 caused many problems. Macro names for problems like this should be constructed as needed. If special code is needed for IRIX version 5.1 then the macro IRIX_V5_1should be defined. We will not predefine these macros, since we want to avoid them. If the need occurs, then the offline coordinator or software librarian should be consulted.
Appendix A Sample Coding Template
We are not going enforce strict use of this coding template, but we feel it contains many useful ideas that people should be using. The more people who use it the more useful it will be. A copy of this template will be stored in the software documentation area, so that people can access it.
The CVS keywords are absolutely necessary, so that CVS can record change messages into the source code. Putting ``IMPLICIT NONE'' into the template means you cannot forget to include it. Separating the declarations for arguments, commons and local variables helps others determine where the variables are filled. The SAVE statement is already included, so you can't forget. In long routines it is very useful to mark important points in the code, so they can be found easily. The sample template has comments to label the initialization code and the code which is executed each time.
subroutine name(argument) * CVS keywords * $Id$ * $Author$ * $Log$ implicit none * * Argument declarations * * * Include files * * * Local declarations * * * Data statements * * * Save statements * save * * ----------Initialization Code---------- * * * -----Code executed each time starts here------ * return * * Format statements * end