Compilation is an integral part of application development that requires careful
management since every piece of code requires its own set instructions to access
dependent components of the OpenFOAM library. In UNIX/Linux systems these
instructions are often organised and delivered to the compiler using the
standard UNIX make utility. OpenFOAM, however, is supplied with the wmake
compilation script that is based on make but is considerably more versatile and
easier to use; wmake can, in fact, be used on any code, not simply the
OpenFOAM library. To understand the compilation process, we first need to
explain certain aspects of C++ and its file structure, shown schematically
in Figure 3.1. A class is defined through a set of instructions such as
object construction, data storage and class member functions. The file
containing the class definition takes a .C extension, e.g. a class nc would
be written in the file nc.C. This file can be compiled independently of
other code into a binary executable library file known as a shared object
library with the .so file extension, i.e. nc.so. When compiling a piece of
code, say newApp.C, that uses the nc class, nc.C need not be recompiled,
rather newApp.C calls nc.so at runtime. This is known as dynamic linking.
Figure 3.1:
Header files, source files, compilation and linking.
As a means of checking errors, the piece of code being compiled must know that
the classes it uses and the operations they perform actually exist. Therefore
each class requires a class declaration, contained in a header file with
a .H file extension, e.g. nc.H, that includes the names of the class and
its functions. This file is included at the beginning of any piece of code
using the class, including the class declaration code itself. Any piece of .C
code can resource any number of classes and must begin with all the .H
files required to declare these classes. The classes in turn can resource
other classes and begin with the relevant .H files. By searching recursively
down the class hierarchy we can produce a complete list of header files
for all the classes on which the top level .C code ultimately depends;
these .H files are known as the dependencies. With a dependency list,
a compiler can check whether the source files have been updated since
their last compilation and selectively compile only those that need to
be.
Header files are included in the code using # include statements, e.g.
# include "otherHeader.H";
causes the compiler to suspend reading from the current file to read the file
specified. Any self-contained piece of code can be put into a header file and
included at the relevant location in the main code in order to improve
code readability. For example, in most OpenFOAM applications the code for
creating fields and reading field input data is included in a file createFields.H
which is called at the beginning of the code. In this way, header files
are not solely used as class declarations. It is wmake that performs the
task of maintaining file dependency lists amongst other functions listed
below.
Automatic generation and maintenance of file dependency lists, i.e.
lists of files which are included in the source files and hence on which
they depend.
Multi-platform compilation and linkage, handled through appropriate
directory structure.
Multi-language compilation and linkage, e.g. C, C++, Java.
Multi-option compilation and linkage, e.g. debug, optimised, parallel
and profiling.
Support for source code generation programs, e.g. lex, yacc, IDL, MOC.
Simple syntax for source file lists.
Automatic creation of source file lists for new codes.
Simple handling of multiple shared or static libraries.
Extensible to new machine types.
Extremely portable, works on any machine with: make; sh, ksh or csh;
lex, cc.
Has been tested on Apollo, SUN, SGI, HP (HPUX), Compaq (DEC),
IBM (AIX), Cray, Ardent, Stardent, PC Linux, PPC Linux, NEC, SX4,
Fujitsu VP1000.
OpenFOAM applications are organised using a standard convention that the source
code of each application is placed in a directory whose name is that of the
application. The top level source file takes the application name with the .C
extension. For example, the source code for an application called newApp would
reside is a directory newApp and the top level file would be newApp.C as shown in
Figure 3.2.
Figure 3.2:
Directory structure for an application
The directory must also contain a Make subdirectory containing 2 files,
options and files, that are described in the following sections.
Notice first that the directory names are preceeded by the -I flag and that the
syntax uses the \ to continue the EXE_INC across several lines, with no \ after the
final entry.
The compiler links to shared object library files in the following directory paths,
specified with the -L option in wmake:
the $OpenFOAM_LIBBIN directory;
platform dependent paths set in
files in the $WM_DIR/rules/$WM_ARCH/ directory, e.g. /usr/X11/lib
and $(MPICH_ARCH_PATH)/lib;
other directories specified in the Make/options file.
The actual library files to be linked must be specified using the -l option and
removing the lib prefix and .so extension from the library file name, e.g.libnew.so is included with the flag -lnew. By default, wmake loads the following
libraries:
the libfoam.so library from the $OpenFOAM_LIBBIN directory;
platform dependent libraries specified in set in files in the
$WM_DIR/rules/$WM_ARCH/ directory, e.g. libm.so from /usr/X11/lib
and liblam.so from $(LAM_ARCH_PATH)/lib;
other libraries specified in the Make/options file.
The Make/options file contains the full directory paths and library names using the
syntax:
The compiler requires a list of .C source files that must be compiled. The list must
contain the main .C file but also any other source files that are created for the
specific application but are not included in a class library. For example, users may
create a new class or some new functionality to an existing class for a particular
application. The full list of .C source files must be included in the Make/files
file. As might be expected, for many applications the list only includes
the name of the main .C file, e.g. newApp.C in the case of our earlier
example.
The Make/files file also includes a full path and name of the compiled
executable, specified by the EXE = syntax. Standard convention stipulates the
name is that of the application, i.e. newApp in our example. The OpenFOAM
release offers two useful choices for path: standard release applications are
stored in $OpenFOAM_APPBIN; applications developed by the user are stored in
$OpenFOAM_USER_APPBIN.
If the user is developing their own applications, we recommend they create an
applications subdirectory in their $WM_PROJECT_USER_DIR directory
containing the source code for personal OpenFOAM applications. As with standard
applications, the source code for each OpenFOAM application should be stored within
its own directory. The only difference between a user application and
one from the standard release is that the Make/files file should specify
that the user’s executables are written into their $OpenFOAM_USER_APPBIN
directory. The Make/files file for our example would appear as follows:
The <optionalDirectory> is the directory path of the application that is being
compiled. Typically, wmake is executed from within the directory of the
application being compiled, in which case <optionalDirectory> can be
omitted.
If a user wishes to build an application executable, then no <optionalArguments>
are required. However <optionalArguments> may be specified for building
libraries etc. as described in Table 3.1.
Argument
Type of compilation
lib
Build a statically-linked library
libso
Build a dynamically-linked library
libo
Build a statically-linked object file library
jar
Build a JAVA archive
exe
Build an application independent of the specified project library.
On execution, wmake builds a dependency list file with a .dep file extension, e.g.newApp.dep in our example, and a list of files in a Make/$WM_OPTIONS
directory. If the user wishes to remove these files, perhaps after making code
changes, the user can run the wclean script by typing:
wclean<optionalArguments><optionalDirectory>
Again, the <optionalDirectory> is a path to the directory of the application
that is being compiled. Typically, wclean is executed from within the directory of
the application, in which case the path can be omitted.
If a user wishes to remove the dependency files and files from the Make
directory, then no <optionalArguments> are required. However if lib is
specified in <optionalArguments> a local lnInclude directory will be deleted
also.
An additional script, rmdepall removes all dependency .dep files recursively
down the directory tree from the point at which it is executed. This can be useful
when updating OpenFOAM libraries.
The source code for application turbFoam is in the $OpenFOAM_APP/solvers/turbFoam
directory and the top level source file is named turbFoam.C. The turbFoam.C
source code is:
The code begins with a brief description of the application contained within
comments over 1 line (//) and multiple lines (/*...*/). Following that, the code
contains several # include statements, e.g. # include "fvCFD.H", which causes
the compiler to suspend reading from the current file, turbFoam.C to read the
fvCFD.H.
turbFoam resources the cfdTools, turbulenceModels and transportModels libraries
and therefore requires the necessary header files, specified by the EXE_INC =-I... option, and links to the libraries with the EXE_LIBS = -l... option. The
Make/options therefore contains the following:
turbFoam contains only the turbFoam.C source and the executable is written to the
$OpenFOAM_APPBIN directory as all standard applications are. The Make/files
therefore contains:
The user can now try recompiling and will receive a message similar to the
following to say that the executable is up to date and compiling is not necessary:
make: Nothing to be done for `allFiles'. make: `Make/linuxOptMPICH/dependencies' is up to date.
make: `/export/warhol/chris/foam/foam2.3/applications/bin/linuxOptMPICH/turbFoam' is up to date.
The user can compile the application from scratch by removing the dependency
list with
OpenFOAM provides a system of messaging that is written during runtime, most of
which are to help debugging problems encountered during running of a OpenFOAM
case. The switches are listed in the user’s $HOME/.foam2.3/controlDict file. The
list of possible switches is extensive and can be viewed by running the
foamDebugSwitches application. Most of the switches correspond to a class or
range of functionality and can be switched on by their inclusion in the controlDict
file, and by being set to 1. For example, OpenFOAM can perform the checking of
dimensional units in all calculations by setting the dimensionSet switch to 1.
There are some switches that control messaging at a higher level than most, listed
in Table 3.3.
In addition, there are some switches that control certain operational
and optimisation issues. These switches are also listed in Table 3.3. Of
particular importance is fileModificationSkew. OpenFOAM scans the write time
of data files to check for modification. When running over a NFS with
some disparity in the clock settings on different machines, field data files
appear to be modified ahead of time. This can cause a problem if OpenFOAM
views the files as newly modified and attempting to re-read this data. The
fileModificationSkew keyword is the time in seconds that OpenFOAM will subtract
from the file write time when assessing whether the file has been newly
modified.
High level debugging switches - subdictionary DebugSwitches
level
Overall level of debugging messaging for OpenFOAM- - 3 levels 0, 1, 2
FoamX
Debugging information messaging for FoamX
lduMatrix
Messaging for solver convergence during a run - 3 levels 0, 1, 2
A time in seconds that should be set higher than the maximum
delay in NFS updates and clock difference for running OpenFOAM over
a NFS.
nProcsSimpleSum
Optimises global sum for parallel processing; sets number of
processors above which hierarchical sum is performed rather than
a linear sum (default 16)
The situation may arise that a user creates a new library, say new, and wishes the
features within that library to be available across a range of applications. For
example, the user may create a new boundary condition, compiled into new, that
would need to be recognised by a range of solver applications, pre- and
post-processing utilities, mesh tools, etc. Under normal circumstances, the
user would need to recompile every application with the new linked to
it.
Instead, OpenFOAM uses a special library called foamUser to eliminate the need to
recompile. It works by first having the foamUser library compiled into each
application by default. The foamUser library is compiled from code located in
$OpenFOAM_SRC/foamUser directory. The user simply needs to add the new library to
the linked libraries in the Make/options file of foamUser and recompile
foamUser.
Taking the example already given, the user should therefore make a
local copy of the foamUser directory, and move to that directory, e.g.:
cp -r $OpenFOAM_USER/src/foamUser $WM_PROJECT_USER_DIR/applications cd $WM_PROJECT_USER_DIR/applications/foamUser
It is recommended to edit the Make/files file so that the foamUser library is
compiled locally into $OpenFOAM_USER_LIBBIN as follows: