This chapter describes how to use the Fortran 77 and Fortran 90 compilers.
The principal use of any compiler is to transform a program written in a procedural language like Fortran into a data file that is executable by the target computer hardware. As part of its job, the compiler may also automatically invoke a system linker to generate the executable file.
The Sun Fortran 77 and Fortran 90 compilers can also be used to:
Generate a parallelized executable file for multiple processors (-parallel).
Analyze program consistency across source files and subroutines and generate a report (-Xlist).
Transform source files into:
Relocatable binary (.o) files, to be linked later into an executable file or static library (.a) file.
A dynamic shared library (.so) file (-G).
Link or relink files into an executable file.
Compile an executable file with runtime debugging enabled (-g).
Compile with runtime statement or procedure level profiling (-pg).
Compile an executable file with runtime parallelized loop profiling (-Zlp).
Check source code for ANSI standards conformance (-ansi).
This section provides a quick overview of how to use the Sun Fortran compilers to compile and run Fortran programs. A full reference to command-line options appears in the next chapter.
The command line examples in this chapter primarily show f77 usages. Except where noted, equivalent usages of f90 are similarly valid; however, the printed output may be slightly different.
The very basic steps to running a Fortran application involve using an editor to create a Fortran source file with a .f, .for, .f90, .F, or .F90 filename suffix; invoking the compiler to produce an executable; and finally, launching the program into execution by typing the name of the file:
Example: This program displays a message on the screen:
demo% cat greetings.f PROGRAM GREETINGS PRINT *, 'Real programmers write Fortran!' END demo% f77 greetings.f greetings.f: MAIN greetings: demo% a.out Real programmers write Fortran! demo%
In the example, f77 compiles source file greetings.f and compiles the executable program onto the file, a.out, by default. To launch our program, the name of the executable file, a.out, is typed at the command prompt
Traditionally, UNIX compilers write executable output to the default file called a.out. It can be awkward to have each compilation write to the same file. Moreover, if such a file already exists, it will be overwritten by the next run of the compiler. Instead, use the -o compiler option to explicitly specify the name of the executable output file:
demo% f77 -o greetings greetings.f greetings.f: MAIN greetings: demo%
In the preceeding example, to -o option tells the compiler to write the executable code to the file greetings. (By convention, executable files usually are given the same name as the main source file, but without an extension.)
Alternatively, the default a.out file could be renamed via the mv command after each compilation. Either way, run the program by typing the name of the executable file:
demo% greetings Real programmers write Fortran! demo%
The next sections of this chapter discuss the conventions used by the f77 and f90 commands, compiler source line directives, and other issues concerning the use of these compilers. The next chapter describes the command-line syntax and all the options in detail.
The syntax of a simple compiler command invoked at a shell prompt is:
f77 [options] files... invokes the Fortran 77 compiler |
f90 [options] files... invokes the Fortran 90 compiler |
Here files... is one or more Fortran source file names ending in .f, .F, .f90, .F90, or .for; options is one or more of the compiler option flags. (Files with names ending in a .f90 or .F90 extension are "free-format" Fortran 90 source files recognized only by the f90 compiler.)
In the example below, f90 is used to compile two source files to produce an executable file named growth with runtime debugging enabled:
demo% f90 -g -o growth growth.f fft.f90
In the previous example, the compiler will automatically generate the loader object files, growth.o and fft.o, and then invoke the system linker to create the executable program on the file growth.
After compilation, the object files, growth.o and fft.o, will remain. This convention permits easy relinking and recompilation of files.
If the compilation fails, you will receive a message for each error. No .o files are generated for those source files with errors, and no executable program is written
The suffix extension attached to file names appearing on the command-line determine how the compiler will process the file. File names with a suffix extension other than one of those listed below, or without an extension, are passed to the linker.
Table 2-1 File Name Suffixes Recognized by Sun Fortran Compilers
Suffix |
Language |
Action |
---|---|---|
.f |
Fortran 77 or Fortran 90 fixed-format |
Compile Fortran source files, put object files in current directory; default name of object file is that of the source but with .o suffix. |
.f90 |
Fortran 90 free-format |
Same action as .f (f90 only) |
.for |
Fortran 77 |
Same action as .f. |
.F |
Fortran 77 or Fortran 90 fixed-format |
Apply the Fortran (or C) preprocessor to the Fortran 77 source file before compilation. |
.F90 |
Fortran 90 free-format |
Apply the Fortran (or C) preprocessor to the Fortran 90 free-format source file before Fortran compiles it. |
.s |
Assembler |
Assemble source files with the assembler. |
.S |
Assembler |
Apply the C preprocessor to the assembler source file before assembling it. |
.il |
Inline expansion |
Process template files for inline expansion. The compiler will use templates to expand inline calls to selected routines. (Template files are special assembler files; see the inline(1) man page.) |
.o |
Object files |
Pass object files through to the linker. |
.a,.so, .so.n |
Libraries |
Pass names of libraries to the linker. .a files are static libraries, .so and .so.n files are dynamic libraries. |
Fortran 90 free-format is described in Appendix C of this manual.
The Fortran compilers will accept multiple source files on the command line. A single source file, also called a compilation unit, may contain any number of procedures (main program, subroutine, function, block data, module, and so on). There are advantages for organizing an application with one procedure per file, as there are for gathering procedures that work together into a single file. Some of these are described in the Sun Fortran Programming Guide.
Both f77 and f90 support two source file preprocessors, fpp and cpp. Either can be invoked by the compiler to expand source code "macros" and symbolic definitions prior to compilation. The compilers will use fpp by default; the -xpp=cpp option changes the default from fpp to cpp. (See also the discussion of the -Dname option).
fpp is a source preprocessor specifically for the Fortran language. See the fpp(1) man page, and the fpp white paper in the READMEs directory for details. It is invoked by default by f77 on files with a .F extension, and by f90 on files with a .F or .F90 extension.
The cpp program is the C language preprocessor. See cpp(1). Use of fpp over cpp is recommended.
You can compile and link in separate steps. The -c option compiles source files and generates .o object files, but does not create an executable. Without the -c option the compiler will invoke the linker. By splitting the compile and link steps in this manner, a complete recompilation is not needed just to fix one file, as shown in the following example:
Compile one file and link with others in separate steps:
demo% f77 -c file1.f (Make new object file) demo% f77 -o prgrm file1.o file2.o file3.o (Make executable file)
Be sure that the link step lists all the object files needed to make the complete program. If any object files are missing from this step, the link will fail with undefined external reference errors (missing routines).
Ensuring a consistent choice of compiling and linking options is critical whenever compilation and linking are done in separate steps. Compiling any part of a program with any of the following options requires linking with the same options:
-a, -autopar, -Bx, -dbl, -fast, -G, -Lpath, -lname, -mt, -nolib, -norunpath, -p, -pg, -xlibmopt, -xlic_lib=name, -xprofile=p
Example: Compiling sbr.f with -a and smain.f without it, then linking in separate steps (-a invokes tcov old-style profiling):
demo% f77 -c -a sbr.f demo% f77 -c smain.f demo% f77 -a sbr.o smain.o link step; passes -a to the linker
Also, a number of options require that all source files be compiled with that option, including the link step. These include:
-autopar, -cg92, -dx, -dalign, -explicitpar, -f, -misalign, -native, -parallel, -pentium, -r8, -xarch=a, -xcache=c, -xchip=c, -xF, -xtarget=t, -ztext
As a general rule, if any of the object files that make up a program were compiled with f90, then the final link step must be done with f90. Use f77 to produce the executable file only if none of the .o object files were compiled with f90.
Any arguments on the command-line that the compiler does not recognize are interpreted as being possibly linker options, object program file names, or library names.
The basic distinctions are:
Unrecognized options (with a -) generate warnings.
Unrecognized non-options (no -) generate no warnings. However, they are passed to the linker and if the linker does not recognize them, they generate linker error messages.
demo% f77 -bit move.f <- -bit is not a recognized f77 option f77: Warning: Option -bit passed to ld, if ld is invoked, ignored otherwise move.f: MAIN move: demo% f77 fast move.f <- The user meant to type -fast move.f: MAIN move: ld: fatal: file fast: cannot open file; errno=2 ld: fatal: File processing errors. No output written to a.out
Note that in the first example, -bit is not recognized by f77 and the option is passed on to the linker (ld), who tries to interpret it. Because single letter ld options may be strung together, the linker sees -bit as -b -i -t, which are all legitimate ld options! This may (or may not) be what the user expects, or intended.
In the second example, the user intended to type the f77/f90 option -fast but neglected the leading dash. The compiler again passes the argument to the linker which, in turn, interprets it as a file name.
These examples indicate that extreme care should be observed when composing compiler command lines!
f90 automatically creates module information files for each MODULE declaration encountered in the source files, and searches for modules referenced by a USE statement. All the modules appearing in a source file are compiled into a single file with the primary name of the MODULE and .mod suffix. For example, f90 generates the module information file list.mod for the MODULE list unit found on file mysrc.f90 .
The compiler searches the current directory for module files referenced in USE statements. Modules files must be compiled before compiling any source file referencing a MODULE in a USE statement. Directories can be added to the search path with the -M command-line option. However, individual .mod files cannot be specified directly on the command line.
Use a source code directive, a form of Fortran comment, to pass specific information to the compiler regarding special optimization or parallelization choices. Compiler directives are also called pragmas.
Directives unique to f90 are described in Appendix C.
Directives are not part of the Fortran standard.
The various forms of a Sun general Fortran directive are:
C$PRAGMA keyword C$PRAGMA keyword ( a [ , a ] ) [ , keyword ( a [ , a ] ) ] , C$PRAGMA SUN keyword
The variable keyword identifies the specific directive; the a's are arguments.
The general directives recognized only by f77 are:
C(...) -- The listed arguments are external functions written in C.
WEAK (name1[=name2]) -- Define weak symbol bindings.
OPT=n -- Compile subprogram at specified optimization level n.
Other general directives recognized by both f77 and f90 are:
UNROLL=n -- Request optimizer to attempt loop unrolling to depth n.
PIPELOOP=n -- Assert to the optimizer that a loop can be pipelined to a length n.
A general directive has the following syntax:
In column one, any of the comment-indicator characters c, C, !, or *
The next seven characters are $PRAGMA, no blanks, any uppercase or lowercase
In any column, the ! comment-indicator character
Observe the following restrictions:
After the first eight characters, blanks are ignored, and uppercase and lowercase are equivalent, as in Fortran text.
Because it is a comment, a directive cannot be continued, but you can have many C$PRAGMA lines, one after the other, as needed.
If a comment satisfies the above syntax, it is expected to contain one or more directives recognized by the compiler; if it does not, a warning is issued.
The C preprocessor, cpp, will expand macro symbol definitions within a comment or directive line; the Fortran preprocessor, fpp, will not expand macros in comment lines, and will recognizes legitimate f77 and f90 directives and allows limited substitution outside directive keywords. However, be careful with directives that require the keyword SUN. cpp will replace lower-case sun with a predefined value. Also, if you define a cpp macro SUN it may interfere with the SUN directive keyword. A general rule might be to spell those pragmas in mixed case if the source will be processed by cpp or fpp, as in:
C$PRAGMA Sun UNROLL=3
The C() directive specifies that its arguments are external functions written in the C language. It is equivalent to an EXTERNAL declaration except that unlike ordinary external names, the Fortran compiler will not append an underscore to these argument names. See the Sun Fortran Programming Guide for more details.
The C() directive for a particular function should appear before the first reference to that function in each subprogram that contains such a reference.
Example - compiling ABC and XYZ for C:
EXTERNAL ABC, XYZ C$PRAGMA C(ABC, XYZ)
The UNROLL directive requires that you specify SUN after C$PRAGMA.
The C$PRAGMA SUN UNROLL=n directive instructs the compiler to unroll loops n times during its optimization pass.
n is a positive integer. The choices are:
If n=1, this directive directs the optimizer not to unroll any loops.
If n>1, this directive suggests to the optimizer that it unroll loops n times.
If any loops are actually unrolled, the executable file becomes larger. For further information, see the Fortran Programming Guide chapter on performance and optimization.
Example - unrolling loops two times:
C$PRAGMA SUN UNROLL=2
The WEAK directive defines a symbol to have less precedence than an earlier definition of the same symbol. This pragma is used mainly in sources files for building libraries. The linker does not produce an error message if it is unable to resolve a weak symbol.
C$PRAGMA WEAK (name1 [=name2])
WEAK (name1) defines name1 to be a weak symbol. The linker does not produce an error message if it does not find a definition for name1.
WEAK (name1=name2) defines name1 to be a weak symbol and an alias for name2.
If your program calls but does not define name1, the linker uses the definition from the library. However, if your program defines its own version of name1, then the program's definition is used and the weak global definition of name1 in the library is not used. If the program directly calls name2, the definition from library is used; a duplicate definition of name2 causes and error. See the Solaris Linker and Libraries Guide for more information.
The OPT directive requires that you specify SUN after C$PRAGMA.
The OPT directive sets the optimization level for a subprogram, overriding the level specified on the compilation command line. The directive must appear immediately before the target subprogram, and only applies to that subprogram. For example:
C$PRAGMA SUN OPT=2 SUBROUTINE smart(a,b,c,d,e) ...etc
When the above is compiled with an f77 command that specifies -O4, the directive will override this level and compile the subroutine at -O2. Unless there is another directive following this routine, the next subprogram will be compiled at -O4.
The routine must also be compiled with the -xmaxopt=n option for the directive to be recognized. This compiler option specifies a maximum optimization value for PRAGMA OPT directives: if a PRAGMA OPT specifies an optimization level greater than the -xmaxopt level, the -xmaxopt level is used.
The PIPELOOP=n directive requires that you specify SUN after C$PRAGMA.
This directive must appear immediately before a DO loop. n is a positive integer constant, or zero, and asserts to the optimizer a dependency between loop iterations. A value of zero indicates that the loop has no inter-iteration dependencies and can be freely pipelined by the optimizer. A positive n value implies that the I-th iteration of the loop has a dependency on the (I-n)-th iteration, and can be pipelined at best for only n iterations at a time.
C We know that the value of K is such that there can be no C cross-iteration dependencies (E.g. K>N) C$PRAGMA SUN PIPELOOP=0 DO I=1,N A(I)=A(I+K) + D(I) B(I)=B(I) + A(I) END DO
For more information on optimization, see the Fortran Programming Guide.
Parallelization directives explicitly request the compiler attempt to parallelize the DO loop that follows the directive. The syntax differs from general directives. Parallelization directives are only recognized when compilation options -parallel or -explicitpar are used. ( expanded f90 parallelization directives are described in Appendix C; details of Fortran parallelization can be found in the Fortran Programming Guide.)
Parallelization directives have the following syntax:
The first character must be in column one.
The first character can be any one of c, C, *, or !.
The next four characters are $PAR, no blanks, either upper or lower case.
Next follows the directive keyword and options, separated by blanks. The explicit parallelization directive keywords are:
TASKCOMMON, DOALL, DOSERIAL, and DOSERIAL*
Each parallelization directive has its own set of optional qualifiers that follow the keyword.
Example: Specifying a loop with a shared variable:
C$PAR DOALL SHARED(yvalue)
See the Fortran Programming Guide for details about parallelization and these directives.
The next sections suggest a number of ways to use the Sun Fortran compilers efficiently. A complete compiler options reference follows in the next chapter.
Some compiler flags allow the user to tune code generation to a specific set of hardware platform options. The utility command fpversion displays the hardware platform specifications for the native processor:
demo% fpversion A SPARC-based CPU is available. CPU's clock rate appears to be approximately 356.2 MHz. Kernel says CPU's clock rate is 360.0 MHz. Kernel says main memory's clock rate is 120.0 MHz. Sun-4 floating-point controller version 0 found. An UltraSPARC chip is available. FPU's frequency appears to be approximately 369.5 MHz. Use "-xtarget=ultra2i -xcache=16/32/1:2048/64/1" code option. Hostid = 0x808Z2211.
It may take a number of seconds before fpversion responds while it dynamically calculates apparent hardware clock rates of the CPU and FPU. (The values printed depend on the load on the system at the moment fpversion is called.)
See fpversion(1) and the Numerical Computation Guide for details.
You can simplify complicated compiler commands by defining special shell aliases or using the $FFLAGS environment variable.
Example: Define an alias for a command with frequently used options:
demo% alias f77fx "f77 -silent -fast -Xlist"
Example: Using the alias f77fx:
demo% f77fx any.f
The command f77fx is now the same as:
f77 -silent -fast -Xlist any.f
You can specify options by setting the FFLAGS or OPTIONS variables.
Either FFLAGS or OPTIONS can be used explicitly in the command line. When you are using make files implicit compilation rules, FFLAGS is used automatically by the make program.
Example: Set FFLAGS: (C Shell)
demo% setenv FFLAGS '-silent -fast -Xlist'
Example: Use FFLAGS explicitly:
demo% f77 $FFLAGS any.f
When using make, if the FFLAGS variable is set as above and the makefile's compilation rules are implicit, that is, there is no explicit f77/f90 compile line, then invoking make will result in a compilation equivalent to:
f77 -silent -fast -Xlist files...
make is a very powerful program development tool that can easily be used with all Sun compilers. See the make(1) man page and the Program Development chapter in the Fortran Programming Guide.
A compilation may need to use a lot of memory. This will depend on the optimization level chosen and the size and complexity of the files being compiled. On SPARC platforms, if the optimizer runs out of memory, it tries to recover by retrying the current procedure at a lower level of optimization and resumes subsequent routines at the original level specified in the -On option on the command line.
A workstation should have at least 24 megabytes of memory; 32 megabytes are recommended. Memory usage depends on the size of each procedure, the level of optimization, the limits set for virtual memory, the size of the disk swap file, and various other parameters.
Compiling a single source file containing many routines could cause the compiler to run out of memory or swap space.
If the compiler runs out of memory, try reducing the level of optimization, or split multiple-routine source files into files with one routine per file, using fsplit(1).
The SunOS command, swap -s, displays available swap space. See swap(1M).
Example: Use the swap command:
demo% swap -s total: 40236k bytes allocated + 7280k reserved = 47516k used, 1058708k available
demo% /usr/sbin/dmesg | grep mem mem = 655360K (0x28000000) avail mem = 602476544
Use mkfile(1M) and swap(1M) to increase the size of the swap space on a workstation. You must become superuser to do this. mkfile creates a file of a specific size, and swap -a adds the file to the system swap space:
demo# mkfile -v 90m /home/swapfile /home/swapfile 94317840 bytes demo# /usr/sbin/swap -a /home/swapfile
Compiling very large routines (thousands of lines of code in a single procedure) at optimization level -O3 or higher may require an unreasonable amount of memory. In such cases, performance of the system may degrade. You can control this by limiting the amount of virtual memory available to a single process.
In a sh shell, use the ulimit command. See sh(1).
Example: Limit virtual memory to 16 Mbytes:
demo$ ulimit -d 16000
In a csh shell, use the limit command. See csh(1).
Example: Limit virtual memory to 16 Mbytes:
demo% limit datasize 16M
Each of these command lines causes the optimizer to try to recover at 16 Mbytes of data space.
This limit cannot be greater than the system's total available swap space and, in practice, must be small enough to permit normal use of the system while a large compilation is in progress.
Be sure that no compilation consumes more than half the space.
Example: With 32 Mbytes of swap space, use the following commands:
demo$ ulimit -d 1600
demo% limit datasize 16M
The best setting depends on the degree of optimization requested, and the amount of real memory and virtual memory available.
In 64-bit Solaris 7 environments, the soft limit for the size of an application data segment is 2 Gbytes. If your application needs to allocate more space, use the shell's limit or ulimit command to remove the limit. For csh use:
demo% limit datasize unlimited
demo$ ulimit -d unlimited
See the Solaris 7 64-bit Developer's Guide for more information.