Difference between revisions of "C Preprocessor"

From WikiROMS
Jump to navigationJump to search
 
(29 intermediate revisions by 4 users not shown)
Line 1: Line 1:
ROMS extensively uses the C preprocessor (cpp) during compilation to replace code statements,  
<div class="title">C Preprocessor</div>
ROMS extensively uses the C preprocessor ('''cpp''') during compilation to replace code statements,  
insert files into the code, and select relevant parts of the code depending on its
insert files into the code, and select relevant parts of the code depending on its
directives. There are numerous cpp options that can be activated in header files [[cppdefs.h]]
directives. There are numerous cpp [[Options|options]] that can be activated in header files [[cppdefs.h]]
and [[globaldefs.h]].
and [[globaldefs.h]].


Cpp is in the ANSI C standard, but that version isn't quite right for preprocessing of Fortran. We therefore use the -traditional flag with the Gnu cpp and similar flags with others.
The plain '''cpp''' program is in the ANSI C standard, but that version is not quite right for preprocessing of Fortran. We therefore use the '''-traditional''' flag with the [http://gcc.gnu.org/onlinedocs/cpp/ GNU cpp] and similar flags with others.
__TOC__
==Preprocessor Directives==


==Preprocessor Directives:==
* The <span class="red">#define</span> directive comes in three flavors:
#Turning on a logical switch. For example, the following definition will activate tidal forcing in the open boundary conditions to the barotropic momentum equations:<div class="box"><span class="red">#define</span> <span class="blue">[[UV_TIDES]]</span></div>
#String substitution. The preprocessor will replace the symbolic name with the specified text everywhere in the code. For example, the following assigment is used to set the dimensions of private, automatic 2D arrays:<div class="box"><span class="red">#define</span> <span class="blue">[[PRIVATE_2D_SCRATCH_ARRAY]]</span> '''Istr-3:Iend+3,Jstr-3:Jend+3'''</div>
#Macro substitution. This functionality is better done through statement functions or inline functions which allow the Fortran compiler to do type checking.
* The <span class="red">#undef</span> directive undefines or deactiaves symbolic names. For example, the following option is used in parallel debugging to turn on/off the writing of current date and cpp options in ROMS history [[NetCDF]] files:<div class="box"><span class="red">#undef</span> <span class="blue">[[DEBUGGING]]</span></div>


* The <span class="blue">#define</span> directive comes in three flavors:
* The <span class="red">#include</span> directive allows one to insert the contents of another file into the source code. For example, the following statement is used to insert the tile-bounds header file that computes the horizontal sub-domain indices of RHO-, U- and V-type variables.<div class="box"><span class="red">#include</span> <span class="blue">"[[set_bounds.h]]"</span></div>


# Turning on a logical switch: <br /><span class="blue">#define</span> <span class="red">[[UV_TIDES]]</span><br />will turn on tidal forcing in the barotropic momentum equations.
* The <span class="red">#ifdef, #endif</span> directive or its equivalent <span class="red">#if defined, #endif</span> allows to control whether the preprocessor omits and includes part of the source code. For example, the following code section is used to activate time profiling during execution:<div class="box"><span class="red">#ifdef</span> <span class="blue">[[PROFILE]]</span><br /><code>'''CALL wclock_on (ng, iNLM, 13)'''</code><br /><span class="red">#endif</span></div>
# String substitution - the preprocessor will replace the symbolic name with the specified text everywhere in the code. For example: <br /><span class="blue">#define</span> <span class="red">PRIVATE_2D_SCRATCH_ARRAY</span> Istr-3:Iend+3,Jstr-3:Jend+3<br />is used to set the dimensions of private, automatic 2D arrays.
# Macro substitution - this functionality is better done through statement functions or inline functions which allow the Fortran compiler to do type checking.


* The <span class="blue">#undef</span> directive undefines or deactiaves symbolic names. For example:
* The <span class="red">#ifndef, #endif</span> directive or its equivalent <span class="red">#if !defined, #endif</span> is the opposite. It is executed only when the symbol is not defined or activated. For example, the following statement is used to reference to the equation of state module only when the option [[TS_FIXED]] is not activated.<div class="box"><span class="red">#ifndef</span> <span class="blue">[[TS_FIXED]]</span><br /><code>'''USE rho_eos_mod, ONLY: rho_eos'''</code><br /><span class="red">#endif</span></div>


:<span class="blue">#undef</span> <span class="red">[[DEBUGGING]]</span>
* The <span class="red">#if <test1>, #elif <test2> #endif</span> is a more general case of the above. In this case, the tests are often of the form:<div class="box"><span class="red">#if defined</span><span class="blue"> [[BBL_MODEL]]</span> && (<span class="red">defined</span> <span class="blue">[[MB_BBL]]</span> || <span class="red">defined</span><span class="blue"> [[SSW_BBL]]</span>)</div>Here, <span class="red">&&</span> is a logical <span class="red">and</span> while <span class="red">||</span> is a logical <span class="red">or</span>. Notice that conditional expressions as used in ROMS require the <span class="red">defined </span> syntax.


:is used during parallel debugging to turn off writing current date and cpp options in ROMS history [[NetCDF]] files.
* The conditional tests are a matter of style and the GNU coding standards use a different style. Theirs is to always:<div class="box"><span class="red">#define</span> <span class="blue">[[FLOATS]] 1</span></div>instead of simply:<div class="box"><span class="red">#define</span> <span class="blue">[[FLOATS]]</span></div>This allows a test to be on the tag rather than <span class="red">defined </span> tag.
* The <span class="blue">#include</span> directive allows one to insert the contents of another file into the source code. For example:


:<span class="blue">#include</span> <span class="red">"[[set_bounds.h]]"</span>
==C and C++ Comments==


:is used to insert the tile-bounds header file that computes the horizontal sub-domain indices of RHO-, U- and V-type variables.
* C language comments are text between <span class="red">/*</span> and <span class="red">*/</span>. These comments are removed by the C preprocessor.


* The <span class="blue">#ifdef, #endif</span> directive allows to control whether the preprocessor omits and includes part of the source code. For example:
* C++ comments are text between <span class="red">//</span> and the end of the line. Since this is also a valid Fortran operator, it is best to tell the C preprocessor not to remove these if possible. Using GNU '''cpp''' with the '''-traditional''' flag does this. We also have the source code to an older '''cpp''' that behaves the way we want if the GNU '''cpp''' is not available.


:<span class="blue">#ifdef</span> <span class="red">[[PROFILE]]</span>
==cpp_clean==
::CALL wclock_on (ng, iNLM, 13)
:<span class="blue">#endif</span>


:is used to activate time profiling during execution. The <span class="blue">#if defined, #endif</span> directive is equivalent.
The preprocessor reads the source file ('''*.F''') and builds a target file ('''*.f90''') according to activated cpp options. This target *.f90 file is then processed by the [http://www.cs.cmu.edu/cgi-bin/perl-man perl] script '''cpp_clean''' to clean all commented (<span class="red">#</span>) lines inserted by '''cpp''' to make it more readable. This is actually the file that is compiled by the Fortran compiler.
 
* The <span class="blue">#ifndef, #endif</span> directive is the opposite, it is executed only when the symbol is not defined or activated. For example:
 
:<span class="blue">#ifndef</span> <span class="red">[[TS_FIXED]]</span>
::USE rho_eos_mod, ONLY: rho_eos
:<span class="blue">#endif</span>
 
:is used to reference to the equation of state module only when the option [[TS_FIXED]] is not activated. The <span class="blue">#if !defined, #endif</span> directive is equivalent.
 
* The <span class="blue">#if <test1>, #elif <test2> #endif</span> is a more general case of the above. In this case, the tests are often of the form:
:<span class="blue">defined </span> <span class="red">[[UV_TIDES]]</span> ||<span class="blue"> defined </span><span class="red">[[SSH_TIDES]]</span>
:Here, "||" is a logical "or" while "&&" is a logical "and". Notice that conditional expressions require the <span class="blue">defined </span> syntax.

Latest revision as of 19:35, 11 June 2007

C Preprocessor

ROMS extensively uses the C preprocessor (cpp) during compilation to replace code statements, insert files into the code, and select relevant parts of the code depending on its directives. There are numerous cpp options that can be activated in header files cppdefs.h and globaldefs.h.

The plain cpp program is in the ANSI C standard, but that version is not quite right for preprocessing of Fortran. We therefore use the -traditional flag with the GNU cpp and similar flags with others.

Preprocessor Directives

  • The #define directive comes in three flavors:
  1. Turning on a logical switch. For example, the following definition will activate tidal forcing in the open boundary conditions to the barotropic momentum equations:
    #define UV_TIDES
  2. String substitution. The preprocessor will replace the symbolic name with the specified text everywhere in the code. For example, the following assigment is used to set the dimensions of private, automatic 2D arrays:
    #define PRIVATE_2D_SCRATCH_ARRAY Istr-3:Iend+3,Jstr-3:Jend+3
  3. Macro substitution. This functionality is better done through statement functions or inline functions which allow the Fortran compiler to do type checking.
  • The #undef directive undefines or deactiaves symbolic names. For example, the following option is used in parallel debugging to turn on/off the writing of current date and cpp options in ROMS history NetCDF files:
    #undef DEBUGGING
  • The #include directive allows one to insert the contents of another file into the source code. For example, the following statement is used to insert the tile-bounds header file that computes the horizontal sub-domain indices of RHO-, U- and V-type variables.
    #include "set_bounds.h"
  • The #ifdef, #endif directive or its equivalent #if defined, #endif allows to control whether the preprocessor omits and includes part of the source code. For example, the following code section is used to activate time profiling during execution:
    #ifdef PROFILE
    CALL wclock_on (ng, iNLM, 13)
    #endif
  • The #ifndef, #endif directive or its equivalent #if !defined, #endif is the opposite. It is executed only when the symbol is not defined or activated. For example, the following statement is used to reference to the equation of state module only when the option TS_FIXED is not activated.
    #ifndef TS_FIXED
    USE rho_eos_mod, ONLY: rho_eos
    #endif
  • The #if <test1>, #elif <test2> #endif is a more general case of the above. In this case, the tests are often of the form:
    #if defined BBL_MODEL && (defined MB_BBL || defined SSW_BBL)
    Here, && is a logical and while || is a logical or. Notice that conditional expressions as used in ROMS require the defined syntax.
  • The conditional tests are a matter of style and the GNU coding standards use a different style. Theirs is to always:
    #define FLOATS 1
    instead of simply:
    #define FLOATS
    This allows a test to be on the tag rather than defined tag.

C and C++ Comments

  • C language comments are text between /* and */. These comments are removed by the C preprocessor.
  • C++ comments are text between // and the end of the line. Since this is also a valid Fortran operator, it is best to tell the C preprocessor not to remove these if possible. Using GNU cpp with the -traditional flag does this. We also have the source code to an older cpp that behaves the way we want if the GNU cpp is not available.

cpp_clean

The preprocessor reads the source file (*.F) and builds a target file (*.f90) according to activated cpp options. This target *.f90 file is then processed by the perl script cpp_clean to clean all commented (#) lines inserted by cpp to make it more readable. This is actually the file that is compiled by the Fortran compiler.