Source Preprocessing

Source preprocessing helps port a program from one platform to another by allowing source text to be specified that is platform specific.

Source preprocessing helps port a program from one platform to another by allowing source text to be specified that is platform specific.

For a source file to be preprocessed automatically, it must have an uppercase extension, either .F or .FOR (for a file in fixed source form), or .F90, F95,.F03, .F08, or .FTN (for a file in free source form). To specify preprocessing of source files with other extensions, including lowercase ones, use the -eP or -eZ options described in Command Line Options.

General Rules

Alter the source code through source preprocessing directives. These directives are fully explained below in Directives. The directives must be used according to the following rules:
  • Do not use source preprocessor (#) directives within multiline compiler directives (CDIR$, !DIR$, CSD$, !CSD$, C$OMP, or !$OMP).
  • A source file that contains an #if directive can not be included without a balancing #endif directive within the same file.
  • The #if directive includes the #ifdef and #ifndef directives.
  • If a directive is too long for one source line, the backslash character (\) is used to continue the directive on successive lines. Successive lines of the directive can begin in any column.
  • The backslash character (\) can appear in any location within a directive in which white space can occur. A backslash character (\) in a comment is treated as a comment character. It is not recognized as signaling continuation.
  • Every directive begins with the pound character (#), and the pound character (#) must be in column 1.
  • Blank and tab (HT) characters can appear between the pound character (#) and the directive keyword.
  • Form feed (FF) or vertical tab (VT) characters cannot be written to separate tokens on a directive line. That is, a source preprocessing line must be continued, by using a backslash character (\), if it spans source lines.
  • Blanks are significant, so the use of spaces within a source preprocessing directive is independent of the source form of the file. The fields of a source preprocessing directive must be separated by blank or tab (HT) characters.
  • Any user-specified identifier that is used in a directive must follow Fortran rules for identifier formation. The exceptions to this rule are as follows:
    • The first character in a source preprocessing name (a macro name) can be an underscore character (_).
    • Source preprocessing names are significant in their first 132 characters whereas a typical Fortran identifier is significant only in its first 63 characters.
  • Source preprocessing identifier names are case sensitive.
  • Numeric literal constants must be integer literal constants or real literal constants, as defined for Fortran.
  • Comments written in the style of the C language, beginning with /* and ending with */, can appear anywhere within a source preprocessing directive in which blanks or tabs can appear. The comment, however, must begin and end on a single source line.
  • Directive syntax allows an identifier to contain the ! character. Therefore, placing the ! character to start a Fortran comment on the same line as the directive should be avoided.

Directives

The blanks shown in the syntax descriptions of the source preprocessing directives are significant. The tab character (HT) can be used in place of a blank. Multiple blanks can appear wherever a single blank appears in a syntax description.

  • #include Directive
    The #include directive directs the system to use the content of a file. Just as with the INCLUDE line path processing defined by the Fortran standard, an #include directive effectively replaces that directive line by the content of filename. This directive has the following formats:
    #include "filename"
    #include <filename>
    filename
    A file or directory to be used.
    In the first form, if filename does not begin with a slash (/) character, the system searches for the named file, first in the directory of the file containing the #include directive, then in the sequence of directories specified by the -I option(s) on the ftn command line, and then the standard (default) sequence. If filename begins with a slash (/) character, it is used as is and is assumed to be the full path to the file.
    The second form directs the search to begin in the sequence of directories specified by the -I option(s) on the ftn command line and then search the standard (default) sequence.

    The Fortran standard prohibits recursion in INCLUDE files, so recursion is also prohibited in the #include form.

    The #include directives can be nested.

    When the compiler is invoked to do only source preprocessing, not compilation, text will be included by #include directives but not by Fortran INCLUDE lines.

  • #define Directive
    The #define directive allows for the declaration of a variable and assign a value to the variable. It also allows the definition of a function-like macro. This directive has the following format:
    #define identifier value
    #define identifier (dummy_arg_list) value
    The first format defines an object-like macro (also called a source preprocessing variable), and the second defines a function-like macro. In the second format, the left parenthesis that begins the dummy_arg_list must immediately follow the identifier, with no intervening white space.
    identifier
    The name of the variable or macro being defined.
    Rules for Fortran variable names apply; that is, the name cannot have a leading underscore character (_). For example, ORIG is a valid name, but _ORIG is invalid.
    dummy_arg_list
    A list of dummy argument identifiers.
    value
    The value is a sequence of tokens. The value can be continued onto more than one line using backslash (\) characters.

    If a preprocessor identifier appears in a subsequent #define directive without being the subject of an intervening #undef directive, and the value in the second #define directive is different from the value in the first #define directive, then the preprocessor issues a warning message about the redefinition. The second directive's value is used.

    When an object-like macro's identifier is encountered as a token in the source file, it is replaced with the value specified in the macro's definition. This is referred to as an invocation of the macro.

    The invocation of a function-like macro is more complicated. It consists of the macro's identifier, immediately followed by a left parenthesis with no intervening white space, then a list of actual arguments separated by commas, and finally a terminating right parenthesis. There must be the same number of actual arguments in the invocation as there are dummy arguments in the #define directive. Each actual argument must be balanced in terms of any internal parentheses. The invocation is replaced with the value given in the macro's definition, with each occurrence of any dummy argument in the definition replaced with the corresponding actual argument in the invocation.

    For example, the following program prints Hello, world. when compiled and run:
         PROGRAM P
    #define GREETING 'Hello, world.'
          PRINT *, GREETING
          END PROGRAM P
    The following program prints Hello, world. when compiled and run:
         PROGRAM P
    #define GREETING(str1, str2) str1, str1, str2
          PRINT *, GREETING('Hello, ', 'world.')
          END PROGRAM P
  • #undef Directive
    The #undef directive sets the definition state of identifier to an undefined value. If identifier is not currently defined, the #undef directive has no effect. This directive has the following format:
    #undef identifier
    identifier
    The name of the variable or macro being defined.
  • # (Null) Directive

    The null directive simply consists of the pound character (#) in column 1 with no significant characters following it. That is, the remainder of the line is typically blank or is a source preprocessing comment. This directive is generally used for spacing out other directive lines.

  • Conditional Directives
    Conditional directives cause lines of code to either be produced by the source preprocessor or to be skipped. The conditional directives within a source file form if-groups. An if-group begins with an #if, #ifdef, or #ifndef directive, followed by lines of source code that may or may not be skipped. Several similarities exist between the Fortran IF construct and if-groups:
    • The #elif directive corresponds to the ELSE IF statement.
    • The #else directive corresponds to the ELSE statement.
    • Just as an IF construct must be terminated with an END IF statement, an if-group must be terminated with an #endif directive.
    • Just as with an IF construct, any of the blocks of source statements in an if-group can be empty. For example, the following directives can be written:
      #if MIN_VALUE == 1
      #else
        ...
      #endif

    Determining which group of source lines (if any) to compile in an if-group is essentially the same as the Fortran determination of which block of an IF construct should be executed.

  • #if Directive
    The #if directive has the following format:
    #if expression
    expression
    An expression. The values in expression must be integer literal constants or previously defined preprocessor variables. The expression is an integer constant expression as defined by the C language standard. All the operators in the expression are C operators, not Fortran operators. The expression is evaluated according to C language rules, not Fortran expression evaluation rules.
    Note that unlike the Fortran IF construct and IF statement logical expressions, expression in an #if directive need not be enclosed in parentheses.
    The #if expression can also contain the unary defined operator, which can be used in either of the following formats:
    • defined identifier
    • defined (identifier)

    When the defined subexpression is evaluated, the value is 1 if identifier is currently defined, and 0 if it is not.

    All currently defined source preprocessing variables in expression, except those that are operands of defined unary operators, are replaced with their values. During this evaluation, all source preprocessing variables that are undefined evaluate to 0.

    Note that the following two directives are not equivalent:
    • #if X
    • #if defined(X)

    In the first case, the condition is true if X has a nonzero value. In the second case, the condition is true only if X has been defined (has been given a value that could be 0).

  • #ifdef Directive
    The #ifdef directive is used to determine if identifier is predefined by the source preprocessor, has been named in a #define directive, or has been named in a ftn -D command line option. This directive has the following format:
    #ifdef identifier
    The #ifdef directive is equivalent to either of the following two directives:
    • #ifdefined identifier
    • #ifdefined (identifier)
  • #ifndef Directive
    The #ifndef directive tests for the presence of an identifier that is not defined. This directive has the following format:
    #ifndef identifier
    This directive is equivalent to either of the following two directives:
    • #if ! defined identifier
    • #if ! defined (identifier)
  • #elif Directive
    The #elif directive serves the same purpose in an if-group as does the ELSE IF statement of a Fortran IF construct. This directive has the following format:
    #elif expression
    expression
    The expression follows all the rules of the integer constant expression in an #if directive.
  • #else Directive
    The #else directive serves the same purpose in an if-group as does the ELSE statement of a Fortran IF construct. This directive has the following format:
    #else
  • #endif Directive
    The #endif directive serves the same purpose in an if-group as does the END IF statement of a Fortran IF construct. This directive has the following format:
    #endif

Predefined Macros

The Cray Fortran compiler source preprocessing supports a number of predefined macros. They are divided into groups as follows:
  • Macros based on the host machine
  • Macros based on CLE system targets
  • Macros based on the Cray Fortran compiler
  • Macros based on the source file
    The following predefined macros are based on the host system (the system upon which the compilation is being done):
    unix, __unix, __unix__
    Always defined. (The leading characters in the second form consist of 2 consecutive underscores; the third form consists of 2 leading and 2 trailing underscores.)
    The following predefined macros are based on CLE systems as targets:
    _ADDR64
    Defined for CLE systems as targets. The target system must have 64-bit address registers.
    _OPENMP
    Defined as the publication date of the OpenMP standard supported, as a string of the form yyyymm.
    _MAXVL_8
    Defined as 16, the number of 8-bit elements that fit in an XMM register ("vector length"). On targets that support AVX, defined as 32, the number of 8-bit elements that fit in a YMM register ("vector length").
    _MAXVL_16
    Defined as 8. On targets that support AVX, defined as 16.
    _MAXVL_32
    Defined as 4. On targets that support AVX, defined as 8.
    _MAXVL_64
    Defined as 2. On targets that support AVX, defined as 4.
    _MAXVL_128
    Defined as 0. On targets that support AVX, defined as 2.
    The following macros are based on the Cray Fortran Compiler:
    _CRAYFTN
    Defined as 1.
    _CRAY_COARRAY
    Defined as 1 if -hcaf is specified on the command line. If -hnocaf is specified, this macro is undefined.
The following predefined macros are based on the source file:
__line__, __LINE__
Defined to be the line number of the current source line in the source file.
__file__, __FILE__
Defined to be the name of the current source file.
__date__, __DATE__
Defined to be the current date in the form mm/dd/yy.
__time__, __TIME__
Defined to be the current in the form hh:mm:ss.

Command Line Options

The following ftn command line options affect source preprocessing:
  • The -D identifier=value option, which defines variables used for source preprocessing. For more information about this option, see -D identifier=value.
  • The -dF option, which controls macro expansion in Fortran source statements. For more information about this option, see -d disable_opt and -e enable_opt.
  • The -eP option, which performs source preprocessing on file.f90,file.F90, file.F95, file.F03, file.F08, file.ftn, or file.FTN but does not compile. The -eP option produces file.i. For more information about this option, see -d disable_opt and -e enable_opt.
  • The -eZ option, which performs source preprocessing and compilation on file.f90, file.F90, file.F95, file.F03, file.F08, file.ftn, or file.FTN. The -eZ option produces file.i. For more information about this option, see -d disable_opt and -e enable_opt.
  • The -U identifier , identifier ... option, which undefines variables used for source preprocessing. For more information about this option, see -U identifier ,identifier....
    The -D identifier =value and -U identifier , identifier ... options are ignored unless one of the following is true:
    • The Fortran input source file is specified as either file.f90,file.F90, file.F95, file.F03, file.F08, file.ftn, or file.FTN.
    • The -eP or -eZ options have been specified.