This chapter describes how you compile Fortran 90 source modules, link them into executable units (programs or dynamic shared objects), and run them. These are the main sections:
“Using the Driver” gives an overview of the operation of the f90 compiler driver.
“Linking” gives an overview of static and dynamic linking and the creation of dynamic shared objects (DSOs) from Fortran 90.
“Driver Options” summarizes the many f90 options in groups of related options.
“Execution Environment” describes how you set up and execute a program, including memory allocation and file disposition.
A Fortran 90 source module is converted from text to executable code in several phases. The phases are called and controlled by the f90 command, which is conventionally called the driver for the compiler because it “drives” the phases through their execution. The phases of compilation are shown in Figure 1-1.
The first step of compilation is the cpp macro preprocessor. If you specify the -nocpp driver option, this step is skipped and the source file passes directly to the front end.
The Fortran 90 front end parses the syntax of the source text, reduces it to simpler forms, and detects syntax errors. This phase also writes a module.kmo file for each MODULE statement, and reads a module.kmo file for each USE statement.
The processed program can pass through the Parallel Optimizer if MIPSpro POWER Fortran 90 is installed.
The processed, parallelized program is converted to optimized machine language code in the code generator. If you specify the -c driver option, the machine code is written to a name.o file and the compilation ends.
The linker combines one or more object files into an executable. The executable is named a.out by default, but you can specify another name with the -o driver option.
The cpp macro preprocessor can be used to include standard header files, to generate sequences of code, and to make parts of a program conditional on defined values. The following names are predefined by the driver (you can see their definitions using the -show driver option):
_ABI64=3 or 4 | _COMPILER_VERSION=602 |
__DSO__ | __host_mips |
_LANGUAGE_FORTRAN | LANGUAGE_FORTRAN |
_LANGUAGE_FORTRAN90 | LANGUAGE_FORTRAN90 |
__mips=3 or 4 | MIPSEB |
_MIPSEB | _MIPS_ISA=3 or 4 |
_MIPS_FPSET=32 | _MIPS_SZINT=32 or 64 |
_MIPS_SIM=_ABI64 | _MIPS_SZLONG=64 |
_MIPS_SZPTR=64 | _PIC |
__sgi | _SYSTYPE_SVR4 |
_SVR4_SOURCE | __unix |
![]() | Tip: The name LANGUAGE_FORTRAN (with and without a leading underscore) is defined by both Fortran drivers. Use it to control statements that are applicable to any Fortran program. LANGUAGE_FORTRAN77 is defined only by the f77 driver, while the f90 driver defines LANGUAGE_FORTRAN90. Use these names to generate code unique to one version of the language. |
To link is to combine object files, resolving the connections between names that are defined in one file but called from another. Linking is discussed in greater detail in the MIPS Compiling and Performance Tuning Guide.
The object files that are linked come from one of these sources:
Fortran 90 source files, compiled in this use of the driver
Object files, previously compiled and saved as name.o files
Archives of object files built with the ar command
Dynamic shared objects (DSOs) built by the linker
Library files, included by default or named with the -l driver option
A DSO is normally stored in a file with the suffix .so. The building of DSOs is described under “Creating Dynamic Shared Objects”.
Archives are collections of object files in a single file, normally given a suffix of .a. The use of the archive-builder ar is covered in the MIPS Compiling and Performance Tuning Guide.
Any kind of object file—compiled .o, DSO .so, or archive .ar—can be specified as an input file on the f90 command line.
You specify the name of a library indirectly, using the -L and -l driver options. The compiler adds the prefix lib to the name specified with -l, and searches for libname.so or libname.a in the directories where libraries are kept. For example, if you specify -lblas, the driver searches for a file libblas.so or libblas.a. If you specify -L/usr/f90/objects, the driver searches that directory when looking for library files.
The end result is that the library (which is simply a DSO or archive file) is included in the link phase of the compile. You can achieve the same result by giving the full name of the library as an input to f90.
The driver searches for libraries first in directories named by the -L option, and then in /usr/lib64 and in /usr/lib64/mips4t.
The driver includes certain libraries by default:
libftn90.so and libftn.so, Fortran run-time support
libm.so, the math library
libc.so, the C run-time library
Some libraries that are often included using the -l option are libfpe for floating-point exceptions, libfGL, the Fortran bindings to Open GL, and libblas, the BLAS math procedures.
When the object code of a procedure is included as part of the executable file, it is statically linked; that is, the connection between the call and the entry point is permanently fixed in the executable file. Procedures defined in object files and archive files are always statically linked.
When the object code of a procedure is found in a DSO, the procedure is dynamically linked; that is, only the names of the procedure and the DSO are included in the executable program file. When the executable program is loaded, the DSO is also loaded, and the linkage between the call and the procedure is resolved at that time.
Most run-time libraries distributed with Fortran 90 are in DSO form, so the Fortran run-time support code and intrinsic procedures are dynamically linked.
A large program is normally divided into many source files, each compiled separately. These files may all be written in Fortran 90; or some of them may be written in a different language—Fortran 77 or C, for example.
Exactly one of these files must be a main module. In Fortran 90 or Fortran 77, a main program is one that contains a PROGRAM statement. In C or C++, a main module contains a main() function definition.
To compile and link a multiple-file program, first compile each file using the -o driver option to produce an object file for that source file. Then compile all the .o files, using the driver for the language of the main module. (Any of the MIPSpro compiler drivers can perform the link step for any combination of object files.)
For example, imagine a program consisting of these files:
A main module in Fortran 90 named master.f90
A module of procedures in Fortran 77 named procs.f
A module containing C functions, named funcs.c
This program could be compiled into an executable named master using the commands shown in Example 1-1.
f90 -O3 -64 -c master.f90 f77 -O3 -64 -c procs.f cc -O3 -64 -c funcs.c f90 -o master master.o procs.o funcs.o |
You perform the final step using the language for the main program because that driver includes the appropriate program-setup procedure and library code by default.
The concepts and use of dynamic shared objects (DSOs) are covered in the MIPS Compiling and Performance Tuning Guide, and in the dso(5) and rld(1) reference pages. For example, the MIPS Compiling and Performance Tuning Guide covers details of how different versions of DSOs are created and used.
You can create a DSO based on one or more Fortran 90 source files, provided that they are not main program files. Then other Fortran 90 programs can link dynamically to the procedures in that DSO.
The source of a small MODULE is displayed in Example B-12. Suppose this source is stored in a file dgrtrig.f90. It can be converted into a DSO using the commands shown in Example 1-2.
f90 -O3 -64 -c dgrtrig.f90 ld -shared -64 dgrtrig.o -o dgrtrig.so |
The compilation step produces the object file dgrtrig.o, which could be statically linked with any other program. (The compilation also produces a file DEGREE_TRIG.kmo, containing a summary of the module; this file is used to compile a USE DEGREE_TRIG statement that appears in any later compile.) The ld command in Example 1-2 produces the DSO, dgrtrig.so.
When a program uses a procedure that is defined in a DSO, you must take two steps.
Include the DSO as input when the program is linked.
Store the DSO where it can be found by the loader when the program is executed.
You can simply name the DSO as an input file on the driver command line. The short program in Example 1-3 uses the module that is converted to a DSO in Example 1-2.
use degree_trig print *,"sin",dgr,dsind(45.0_8) end |
Suppose that the DSO dgrtrig.so is in the current directory. Then the program in Example 1-3 could be compiled as follows:
f90 -g -64 -o usedgr usedgr.f90 dgrtrig.so |
While compiling the program, the compiler reads DEGREE_TRIG.kmo to learn the public names in the module. While linking the program, the linker resolves external references using entry point information in dgrtrig.so, but does not include the DSO contents in the executable file.
![]() | Tip: If you specify the full path to a DSO when linking, the path is recorded in the executable file and the loader does not need to search for the DSO when loading the program. |
Another way to present object files to the linker is to include them as libraries. In order to do this,
The DSO must have a name that begins with the letters lib.
The DSO must be stored in a directory where the linker searches for library files.
For example, suppose that dgrtrig.so has been renamed to libdgr.so and stored in a directory /usr/local/f90/objects. Now the program in Example 1-3 can be compiled as follows:
f90 -g -64 -L/usr/local/f90/objects \ -ldgr -o usedgr usedgr.f90 |
The -L option causes the linker to search for all needed libraries first in the specified directory. The -ldgr option tells it to include libdgr.so from that directory. Again, the linker resolves the external references from the contents of the DSO, but does not include the DSO in the executable file.
When a program that uses a DSO is loaded, the DSO files that it was linked with must be loaded also. (If they have already been loaded for use by some other program, they are not loaded again but simply shared.) In order to find them, the loader searches directories named in the LD_LIBRARY_PATH environment variable as well as other directories and environment variables documented in the rld(1) reference page.
Ordinarily you store the DSOs you create in one of the default directories, or in a directory named in LD_LIBRARY_PATH. For more about how DSOs are loaded, see the MIPS Compiling and Performance Tuning Guide.
This section contains an overview of the Fortran–specific driver options. The f90(1) reference page has a complete description of the compiler options. This discussion only covers the relationships between some of the options. In addition, you should review:
the MIPS Compiling and Performance Tuning Guide for a discussion of the compiler options that are common to all MIPSpro compilers
the pfa(1) and fopt(1) reference pages for options related to the parallel optimizer
the ld(1) reference page for a description of the linker options
chapters 5-7 of this Guide for options related to optimization features
![]() | Tip: The command f90 -help lists all compiler options for quick reference. Use the -show option to have the compiler display the exact default and nondefault options passed to each phase. |
When you are compiling a program that does not have high performance requirements, you need only a very few compiler options. Examples of such programs include
test cases used to explore algorithms or Fortran language features
programs that are principally interactive
programs you will execute under a debugger
In these cases you need only specify -g for debugging, the target machine architecture, and the word-length. For example, to compile a single source file to execute under dbx on a Power Challenge XL, you could use the following commands:
f90 -g3 -O0 -o testcase testcase.f dbx testcase |
A program compiled in this way will take little advantage of the performance features of the machine. In particular, its speed when doing heavy floating-point calculations will be far slower than the machine is capable of. For simple programs, that is usually not relevant.
The options summarized in Table 1-1 tell the compiler how to treat the program source file.
Table 1-1. Compile Options for Source File Format
Options | Purpose |
---|---|
-bytereclen | Always treat the RECL= specifier in OPEN as a count of bytes, including unformatted direct I/O |
-fixedform, -col72, -col120, -extend_source, -noextend_source | Specify fixed-format input and set margin columns of source lines. |
-freeform | Specify free-form input and Fortran 90 syntax. |
![]() | Note: The Silicon Graphics Fortran 77 compiler supports a -dlines option that permits comment lines to begin with a “D” in column 1. This option is not supported by Fortran 90, and such comments will cause syntax errors. |
The options summarized in Table 1-2 direct the operation of the cpp preprocessor.
Table 1-2. Compile Options to Control cpp
Options | Purpose |
---|---|
-nocpp | Do not run cpp; pass source directly to front end. |
-A:assertion | Add a cpp assertion. |
-Dname, -Dname=def , -Uname | Define and undefine names to the C preprocessor. |
-M, -Mupdate, -Mtarget filename | Run only the C preprocessor, requesting makefile-dependency output. |
The options summarized in Table 1-3 tell the compiler what input files to use.
Table 1-3. Compile Options That Select Input Files
Options | Purpose |
---|---|
-I, -Idir | Specify location of all types of source inclusions—see note. |
-nostdinc | Do not search for include files in default directories (search only directories given with -I options). |
-Ldir | Specify location of library files. |
-lname | Include libname in the link. |
-nostdlib | Do not search for libraries in default directories (search only directories given with -L options). |
-objectlist filename | Read filename for a list of object files to include in the link. |
![]() | Note: The -I option is used to specify search locations for three kinds of included files: |
files included by the macro preprocessor from a #include statement
files included by the compiler front end from an INCLUDE statement
module (.kmo) files included by the compiler from a USE statement
The options summarized in Table 1-4 tell the compiler what output files to generate.
Table 1-4. Compile Options That Select Output Files
Options | Purpose |
---|---|
-c | Generate a single object file for each input file; do not link. |
-E, -P | Run only the macro preprocessor and write its output to standard output (-E) or to source.i (-P). |
-keep | Retain compiler intermediate and work files (debugging compiler problems only). |
-listing | Request a listing file. |
-LIST: listoption [,...] | Specify detailed options regarding the listing file. |
-o | Specify name of output executable or DSO file. |
-S | Write the generated object code in assembly-language form as source.s; do not link. |
The options summarized in Table 1-5 are used to specify the characteristics of the machine where the compiled program will be used. The TARG and TENV options are discussed in the MIPS Compiling and Performance Tuning Guide.
Table 1-5. Compile Options for Target Machine Features
Options | Purpose |
---|---|
-mips3, -mips4 (not suptd in 6.2 release) | The instruction architecture available in the target machine: use -mips3 for MIPS R4x00 machines in 64-bit mode; use -mips4 for MIPS R8000 and R10000 machines. |
-n32, -n64 | Specify the binary format. -n64 (64-bit addressing) is the default. |
-TARG:option,... | Specify certain details of the target CPU. Most of these options have correct default values based on the preceding options. |
-TENV:option,... | Specify certain details of the software environment in which the source module will execute. Most of these options have correct default values based on other, more general values. |
The options summarized in Table 1-6 tell the compiler how to allocate memory and how to align variables in it. These options can have a strong effect on both program size and program speed.
Table 1-6. Compile Options for Memory Allocation and Alignment
Options | Purpose |
---|---|
-align8, -align16, | Align all variables size n on n-byte address boundaries. |
-d8, -d16 | Specify the size of DOUBLE and DOUBLE COMPLEX variables. |
-i2, -i4, -i8 | Specify the size of INTEGER and LOGICAL variables. |
-r4, -r8 | Specify the size of REAL and COMPLEX variables. |
-static | Allocate all local variables statically, not dynamically on the stack. |
-Gsize, -xgot | Specify use of the global option table. |
The options summarized in Table 1-7 direct the compiler to include more or less extra information in the object file for debugging or profiling.
Table 1-7. Compile Options for Debugging and Profiling
Options | Purpose |
---|---|
-g0, -g2, -g3, -g | Leave more or less symbol-table information in the object file for use with dbx or Workshop Pro cvd. |
-p | Cause profiling to be enabled when the program is loaded. |
For more information on debugging and profiling, see the MIPS Compiling and Performance Tuning Guide.
The MIPSpro Fortran 90 compiler contains three optimizer phases. One is part of the compiler “back end”; that is, it operates on the generated code, after all syntax analysis and source transformations are complete. The use of this standard optimizer, which is common to all MIPSpro compilers, is discussed in the MIPS Compiling and Performance Tuning Guide.
In addition, two phases of accelerators, one for scalar optimization and one for parallel array optimization, can be applied to the output of the front end. These optimizing phases are available only with the optional POWER Fortran 90 product. The options of the scalar optimizer are detailed in the fopt(1) reference page. The options of the parallel optimizer are detailed in the pfa(1) reference page.
The options summarized in Table 1-8 are used to communicate to the different optimization phases.
Table 1-8. Compile Options for Optimization Control
Options | Purpose |
---|---|
-O, -O0, -O1, | Select basic level of optimization, setting defaults for all optimization phases. |
-GCM:option,... | Specify details of global code motion performed by the back-end optimizer. |
-OPT:option,... | Specify miscellaneous details of optimization. |
-SWP:option,... | Specify details of pipelining done by back-end optimizer. |
-sopt[,option,...] | Request execution of the scalar optimizer, and pass options to it. |
-mp, -pfa, -pfalist, -pfakeep | Request automatic parallelization (POWER Fortran 90 only), and optionally retain its work files. |
-WK,option,... | Pass options to the parallelizing optimizer. |
The GCM, OPT, and SWP options are discussed in detail in the MIPS Compiling and Performance Tuning Guide.
For the options that can follow -sopt, refer to the fopt(1) reference page. For the options that can follow -WK, refer to the pfa(1) reference page. For examples of -WK, see Table 1-9.
When you use -O to specify the optimization level, the compiler assumes default options for the accelerator phases. These defaults are listed in Table 1-9. Remember, to see all options that are passed to a compiler phase, use the -show option.
Table 1-9. Defaults for Optimization Levels
Optimization Level | Power Fortran Defaults Passed |
---|---|
-O0 | –WK,–roundoff=0,–scalaropt=0,–optimize=0 |
-O1 | –WK,–roundoff=0,–scalaropt=0,–optimize=0 |
-O2 | –WK,–roundoff=0,–scalaropt=0,–optimize=0 |
-O3 | –WK,–roundoff=2,–scalaropt=3,–optimize=5 |
-sopt | –WK,–roundoff=0,–scalaropt=3,–optimize=5 |
In addition to optimizing options, the compiler system provides other options that can improve the performance of your programs:
Two linker options, –Gsize and –bestG, control the size of the global data area, which can produce significant performance improvements. See Chapter 2 of the Compiling, Debugging, and Performance Tuning Guide and the ld(1) reference page for more information.
The –jmpopt option permits the linker to fill certain instruction delay slots not filled by the compiler front end. This option can improve the performance of smaller programs that do not require large blocks of virtual memory. See the ld(1) reference page for more information.
The options summarized in Table 1-10 control the execution of the compiler phases.
Table 1-10. Compile Options for Compiler Phase Control
Options | Purpose |
---|---|
-E, -P, -M | Execute only the C preprocessor. |
-nocpp | Do not execute the C preprocessor. |
-fe | Stop compilation immediately after the front-end runs (for compiler debugging only). |
-sopt, -pfa | Run the parallelizing optimizer phase. |
-S, -c | Stop compilation after the back-end runs, saving the output as assembly source (-S) or object code (-c). |
-Y c,path | Load the compiler phase specified by c from the specified path. |
-W c,option,... | Pass the specified list of options to the compiler phase specified by c. |
The -Yc and -Wc options take a single letter c to specify which compiler phase is meant. The letters are as follows:
p | cpp |
f | front-end |
b | back-end |
a | assembler |
l | linker |
K | parallel optimizer, and Fortran 90 front end parser |
For examples of using -W, see Table 1-9.
The execution environment of a Fortran 90 program includes its command-line arguments; the memory it can allocate; the files it uses; and the policies for handling execution errors.
To execute a program, invoke it by name as a command. In the command environment where this happens, the run-time loader rld must be able to find all needed DSOs (see “Loading DSOs at Execution Time”).
A program can recover the command-line arguments using the getarg subroutine and iargc function (see the getarg(3f) reference page). The program in Example 1-4 lists its arguments using these functions.
external getarg, iargc integer iargc character(80) anarg do j = 1, iargc() call getarg(j,anarg) write (6,"(i3,' = ',a)") j, anarg end do end ! program |
In general, a program may use as much memory as necessary. There are some limits on individual allocations to 2 gigabytes (2,048 megabytes); and IRIX places global limits on run-time use of stack and allocated memory.
There is no limit on the size of a variable created with the ALLOCATE statement, other than the IRIX limit on total data space and total swap space.
When compiling with the -static flag, global data is allocated as part of the compiled object (.o) file. The total size of any single .o file may not exceed 2 GB. However, the total size of an executable program or a DSO linked from multiple .o files is not restricted.
An individual common block may not exceed 2 GB. However, you can declare multiple common blocks, each having that size.
An array allocated on the process stack (that is, as a local variable of a procedure) must not exceed 2 GB, but the total of all local variables can exceed that limit. The subroutine in Example 1-5 has several gigabytes of local space.
subroutine bloat(arg) integer arg integer, parameter :: ndim = 16380 integer(8) xmat(ndim,ndim), ymat(ndim,ndim), & zmat(ndim,ndim) xmat = arg return end |
However, there is no limit on the size of an array that is passed as an argument. The function in Example 1-6 takes a 34 GB argument. An argument of this size could be created with ALLOCATE.
function bigarg(rodan) integer rodan(8589934592_8) bigarg = rodan(4294967296_8) end |
No user can have a stack larger than the current IRIX stack allocation limit nor can allocate total data memory greater than the IRIX data limit. Both these limits can be examined using the sh or csh command limit.
% limit stacksize stacksize 512000 kbytes % limit datasize datasize unlimited |
![]() | Note: There is no warning or diagnostic message when a program exceeds the data or stack limit. The program ends with a segmentation fault. |
You can use the limit command to set a smaller or larger limit, up to a system maximum. The system maximum (rlimit_data_max or rlimit_stack_max) is set using the systune command (refer to the systune(1) reference page).
Regardless of the amount of space that a user is permitted by the IRIX limits, the total of all writable virtual memory for all processes in the system cannot exceed the virtual swap allocation. The total of all virtual memory actually written into cannot exceed the actual swap allocation. Thus a program that allocates a very large array may not be able to start running because it exceeds the size of virtual swap. A program may be able to allocate a very large array (which is not larger than the virtual swap allocation), but then may terminate while assigning values into the array because it has exceeded the size of actual swap space.
The current swap allocations can be checked and changed using the swap command; refer to the swap(1) reference page.
This section covers the details of using files at runtime.
Table 1-11 shows the standard preconnected files at program start.
All other units are also preconnected when execution begins. Unit n is connected to a file named fort.n. These files need not exist, nor will they be created unless their units are used without first executing an OPEN with an explicit filename. The default connection is for sequentially formatted I/O.
In the FILE= argument of OPEN or INQUIRE, you may specify any valid IRIX path or filename. The string is case-sensitive. If the string begins with a dot or a slash, it is treated as an absolute path; otherwise it is interpreted in the context of the current working directory. (You can change the current working directory dynamically using the chdir() function; see “Support for IRIX Kernel Functions”.)
Three predefined filenames are supported. When one of the following names is specified, the file is opened to the system I/O stream shown:
SYS$INPUT | standard input (same as logical unit 5) |
SYS$OUTPUT | standard output (same as logical unit 6) |
SYS$ERROR | standard error (same as logical unit 0) |
By using these names you can associate an arbitrary unit number to a standard stream. However, if you access a stream alternately through different unit numbers, the results are unpredictable.
The I/O system positions a file at start of file for both input and output. The execution of an OPEN statement followed by a WRITE on an existing file causes the file to be overwritten, erasing any data in the file.
In a program called from a parent process, units 0, 5, and 6 remain where they were positioned by the parent process.
When the parameter STATUS="UNKNOWN" is specified in an OPEN statement, the following occurs:
If the file does not exist, it is created and positioned at start of file.
If the file exists, it is opened and positioned at start of file.
When a file is opened without specifying the ACTION= argument, the default action is READWRITE.
When the Fortran 90 run-time system detects an error that is not handled by the program, the following action takes place:
A message describing the error is written to the standard error unit (unit 0). See Appendix A, “Run-Time Error Codes,” for a list of the error messages.
A core file is produced if the f77_dump_flag environment variable is set (the variable has the same name for both Fortran 77 and Fortran 90).
You can use dbx to locate the point of failure in the core file. To invoke dbx using the core file, enter this command:
% dbx executable-file |
where executable-file is the name of the executable program. The dbx command where displays a stack trace showing the procedures that were active when the error took place.
![]() | Tip: When a program ends with a segmentation fault, a likely cause is that a memory size limit was exceeded. See “Program and Memory Size Limits”. |
The library libfpe provides two methods for handling floating point exceptions.
![]() | Note: Owing to the different architecture of the MIPS R8000 and R10000 processors, library libfpe is not available with the current compiler. It will be provided in a future release. When porting Fortran 77 programs that depend on trapping exceptions using the facilities in libfpe, you will have to temporarily change the programs to do without it. |
The library provides the subroutine handle_sigfpes and the environment variable TRAP_FPE. Both methods provide mechanisms for handling and classifying floating point exceptions, and for substituting new values. They also provide mechanisms to count, trace, exit, or abort on enabled exceptions. See the handle_sigfpes(3F) reference page for more information