Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
Fortran 90 Compiler for HP-UX: Fortran 90 Programmer's Guide > Chapter 2 Compiling and linking

Special-purpose compilations

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

The default behavior of the HP Fortran 90 compiler has been designed to handle typical compilations. Most applications should require no more than a few of the f90 options to compile successfully (see Table 2-1 “Commonly-used f90 options” for a list of commonly used options).

However, the compiler can also meet the needs of more specialized compilations. This section explains how to use the f90 command for the following purposes:

  • To compile programs that contain Fortran 90 modules.

  • To compile programs that will execute on different PA-RISC machines.

  • To create object files for shared libraries.

  • To process source files that contain C preprocessor directives.

  • To create demand-loadable programs.

  • To create shareable executable programs.

  • To compile 32-bit programs in 64-bit mode.

Compiling programs with modules

One of the features of standard Fortran 90 is the module, a program unit that facilitates shared access to data and procedures. Modules are fully described in the HP Fortran 90 Programmer's Reference.

A benefit to using modules is that they provide interface information to the compiler, allowing it to catch mismatch errors between (for example) dummy arguments and actual arguments. When the HP Fortran 90 compiler processes a file that defines a module, it generates a .mod file with the interface information. Later, when the compiler processes a file that uses the module, it reads the .mod file and checks that module entities that are referenced in the using file correctly match the information in the .mod file.

To make the .mod files available to the compiler, you must therefore compile the files that define modules before the files that use modules. Likewise, if you make changes to a file that defines a module, you must recompile that file as well as any files that use the module, in that order.

Also, if a module is defined and used in the same file, the definition must lexically precede any USE statements that reference the module. This requirement allows the compiler to generate the .mod file first, so that it can resolve the references in any USE statements.

This section discusses the following topics:

  • How to compile a program that uses modules

  • How to design makefiles to work with modules

  • How to use the -I and +moddir options to manage .mod files

Examples

Consider, for example, a program that consists of three files: main.f90, code.f90, and data.f90. The main program unit is in main.f90, as follows.

Example 2-2 main.f90

PROGRAM keep_stats
! stats_code contains module procedures for operating
! on statistical database
USE stats_code
INTEGER :: n

! print prompt, using nonadvancing I/O
WRITE (*, FMT="(A)", ADVANCE="NO") "Enter an integer "// &
"(hint: 77 is current average): "
READ *, n
IF (n == 0) THEN
PRINT *, "But not that one."
ELSE
CALL update_db(n)
IF (n >= get_avg()) THEN ! get_avg is in stats_code
PRINT *, "Average or better."
ELSE
PRINT *, "Below average."
END IF
END IF
END PROGRAM keep_stats

The first specification statement (USE) in the main program indicates that it uses the module stats_code. This module is defined in code.f90, as follows:

Example 2-3 code.f90

! stats_code:  a (partial!) package of module procedures for
! performing statistical operations
MODULE stats_code ! shared data to be used by procedures declared below
USE stats_db

CONTAINS ! module procedures

! update_db: updates shared variables in module stats_db
SUBROUTINE update_db (new_item)
INTEGER :: new_item

n_items = n_items +1
item(n_items) = new_item
sum = sum + new_item
END SUBROUTINE update_db

! get_avg: returns arithmetic mean
INTEGER FUNCTION get_avg ()
get_avg = sum / n_items
END FUNCTION get_avg
END MODULE stats_code

This program unit also begins with a USE statement, which identifies the module it uses as stats_db. This module is defined in data.f90, as follows:

Example 2-4 data.f90

! stats_db:  shared data declared here
MODULE stats_db
INTEGER, PARAMETER :: size = 100 ! max number of items in array

! n_items, sum, and item hold the data for statistical analysis
INTEGER :: n_items, sum
INTEGER, DIMENSION(size) :: item

! the initializations are just to start the program going
DATA n_items, sum, item/3, 233, 97, 22, 114, 97*0/
END MODULE stats_db

The use of modules in this program creates dependencies between the files because a file that uses a module that is defined in another file is dependent on that other file. These dependencies affect the order in which the program files must be compiled. The dependencies in the example program are:

  • main.f90 is dependent upon code.f90.

  • code.f90 is dependent upon data.f90.

These dependencies require that data.f90 be compiled before code.f90, and that code.f90 be compiled before main.f90. This order ensures that the compiler will have created each of the .mod files before it needs to read them.

The order of the source files listed in the following command line ensures that they will compile and link successfully:

$ f90 -o do_stats data.f90 code.f90
main.f90

During compilation, f90 will create two .mod files, STATS_CODE.mod and STATS_DB.mod. These will be written to the current working directory, along with the object files and the executable program, do_stats. Following is a sample run of the executable program:

$ do_stats
Enter an integer (hint: 77 is current average): 77
Average or better.

If instead of the preceding compile line, the program had been compiled as follows:

$ f90 -o do_stats main.f90 data.f90
code.f90

the compilation would fail and f90 would print the error message:

Error FCE37 : Module STATS_CODE not found

The compilation would fail because the compiler cannot process main.f90 without STATS_CODE.mod. But the order in which the program files appear on the compile line prevents the compiler from processing code.f90 (and thereby creating STATS_CODE.mod) until after it has processed main.f90.

Compiling with make

If you use the make utility to compile Fortran 90 programs, the description file should take into account the dependencies created by modules. For example, to compile the do_stats program using the make utility, the description file should express the dependencies as follows:

Example 2-5 makefile

# description for building do_stats
do_stats : main.o code.o data.o
f90 -o do_stats main.o code.o data.o

# main.o is dependent on main.f90 and code.f90
main.o : main.f90 code.o
f90 -c main.f90
# code.o is dependent on code.f90 and data.f90
code.o : code.f90 data.o
f90 -c code.f90
# data.o is dependent only its source, data.f90
data.o : data.f90
f90 -c data.f90

Note that the dependencies correspond to the order in which the source files are specified in the following f90 compile line:

$ f90 -o do_stats data.f90 code.f90
main.f90

Assuming that you name the description file makefile, the command line to compile the program with make is:

$ make

Managing .mod files

By default, the compiler writes .mod files to the current working directory and looks there when it has to read them. The +moddir=directory and -I directory options enable you to specify different directories. The +moddir option causes the compiler to write .mod files in directory, and the -I option causes the compiler to search directory for .mod files to read. (The space character between -I and directory is optional.)

Using the example of the do_stats program, the following command line compiles (without linking) data.f90 and writes a .mod file to the subdirectory mod_files:

$ f90 -c +moddir=mod_files data.f90

The command line:

$ f90 -c +moddir=mod_files -I
mod_files code.f90

uses both the +moddir and -I options, as follows:

  • The +moddir option causes f90 to write the .mod file for code.f90 in the subdirectory mod_files.

  • The -I option causes f90 to look in the same subdirectory for the .mod file to read when compiling code.f90.

The command line:

$ f90 -odo_stats -I mod_files
main.f90 code.o data.o

causes f90 to compile main.f90, look for the .mod file in the subdirectory mod_files, and link all of the object files into an executable program named do_stats.

Compiling for different PA-RISC machines

When you compile an HP Fortran 90 program, the object code that the compiler generates by default is based on the PA-RISC model of the machine that is running the compiler. If your program will execute on a different PA-RISC model machine, the code may run less efficiently or (in the case of PA2.0 code that attempts to run on a PA1.1 machine) may not run at all.

Also, some libraries (for example, the math library) are available in different PA-RISC versions. By default, the compiler selects the version that is based on the PA-RISC model of the compiling machine. If your program will execute on a different model machine, it may not be linked with the appropriate libraries.

Compiling with the +DAmodel option ensures that the compiler generates code that is based on the architecture specified by model and that the linker selects libraries that are compatible with model. model must be one of the following:

  • A PA-RISC version number—1.1, 2.0, or 2.0W. Use +DA2.0W to compile in 64-bit mode; see “Compiling in 64-bit mode”.

  • A model number—for example, 750 or 870.

  • A PA-RISC processor name—for example, PA7100 or PA8000.

  • portable—code that is compatible across all models. Use +DAportable only if you want to ensure that your program will run on different models.

Use the uname -m command to learn the model of your machine, as follows:

$ uname -m
9000/879

Alternatively, you can use the grep command to look up the model number in the file /opt/langtools/lib/sched.models and find its architecture type, as follows:

$ grep 879 /opt/langtools/lib/sched.models
879 2.0 PA8000

You can also use the +DSmodel option to specify an architecture-specific instruction scheduler, where model has the same meaning as it does for the +DA option. Like the +DA option, the +DS option is unnecessary if the program will run on the same machine as you use to compile it. Also, if you compile with +DAmodel, the compiler will select the scheduling algorithm based on the same architecture—unless you use the +DS option to specify a different architecture.

NOTE: Code generated for PA1.1 systems will execute PA2.0 systems, but the reverse is not true: the loader will not allow PA2.0 code to run on a PA1.1 system.

For detailed descriptions of +DA and +DS, see the HP Fortran 90 Programmer's Reference.

Creating shared libraries

As mentioned in “Linking to shared libraries”, many of the HP-UX as well as HP Fortran 90 libraries are available in shared as well as archive versions. Linking with shared libraries can make the executable program smaller and can ensure that it always has the most current version of the library.

You can make shared versions of your own libraries, using the +pic compile-line option and the -b linker option. The following sections describe how to use these options and show an example of how to create a shared library.

Compiling with +pic

The +pic option causes the compiler to generate Position- Independent Code (PIC) for use in a shared library. PIC contains no absolute addresses and can therefore be placed anywhere in a process's address space without addresses having to be relocated. This characteristic of PIC makes it shareable by multiple processes.

The syntax of the +pic option is:

+pic={short|long|no}

Although compiling with either +pic=short or +pic=long will generate PIC, in general you should use the +pic=short option. If the linker issues an error message saying that the number of referenced symbols in the shared library exceeds its limit, recompile with +pic=long, which will cause the compiler to allocate space for a longer symbol table.

The +pic=no is the default, which causes the compiler to generate absolute code, such as you would want for executable programs.

The following command line creates three object files—x.o, y.o, and z.o; the code in each file will be PIC:

$ f90 -c +pic=short x.f90 y.f90
z.f90

For more information about the +pic option, see the HP Fortran 90 Programmer's Reference.

Linking with -b

The -b option is a linker option. It causes the linker to bind PIC object files into a shared library, instead of creating a normal executable file. The -b option must be used with the ld command; you cannot use the f90 command to create a shared library. Also, the object files specified on the ld command line must consist of PIC; that is, they must have been created with either +pic=short or +pic=long.

The following command line links the object files x.o, y.o, and z.o into a shared library, named my_lib.sl:

$ ld -b -o my_lib.sl x.o y.o
z.o

Note that this ld command line is much simpler than the ld command line required to link an executable file (for example, see “Linking with f90 vs. ld”).

Examples

This section shows an example of how to create and link to a shared library. The shared library will consist of PIC object files compiled from the source files, hi.f90 and bye.f90. The library, my_lib.sl, will be linked to the executable program compiled from greet.f90. The code for three HP Fortran 90 source files follows:

Example 2-6 hi.f90

SUBROUTINE say_hi()
PRINT *, "Hi!"
END SUBROUTINE say_hi

Example 2-7 bye.f90

SUBROUTINE say_bye()
PRINT *, "Bye!"
END SUBROUTINE say_bye

Example 2-8 greet.f90

PROGRAM main
CALL say_hi()
CALL say_bye()
END PROGRAM main

The following command line creates the PIC object files (the -c option suppresses linking):

$ f90 -c +pic=short bye.f90
hi.f90

The next command line links the object files into the shared library:

$ ld -b -o my_lib.sl bye.o hi.o

The last command line compiles the source file greet.f90 and links the object code with the shared library to produce the executable program a.out:

$ f90 greet.f90 my_lib.sl

The following is the output from a sample run of the executable program:

$ a.out
Hi!
Bye!

Using the C preprocessor

You can use the f90 command to pass source files to the C preprocessor (cpp) before they are compiled. If the source files contain C preprocessor directives, cpp will act on the directives, modifying the source text accordingly. The f90 driver will then pass the preprocessed source text to the compiler. Adding cpp directives to program source files and having the cpp command preprocess them is a convenient way to maintain multiple versions of a program—for example, a debugging version and a production version—in one set of files.

cpp directives are similar to debugging lines, a feature of many Fortran implementations (see “Using debugging lines”). Like cpp directives, debugging lines enable the compiler to treat source lines as either compilable statements or comments to be removed before compilation. But debugging lines are nonstandard, available only in fixed-form source, and not nearly as powerful as the cpp directives. Although cpp directives are not a standard feature of Fortran 90, cpp is a de facto standard feature of UNIX systems.

This section discusses how to do the following:

  • Invoke cpp from the f90 command line.

  • Use the -D option to define cpp macros.

  • Save the preprocessed output generated by cpp.

For more information about the cpp command and the directives it supports, see the cpp(1) man page.

Processing cpp directives

By default, the f90 command passes source files ending in the .F extension to cpp. Compiling with the +cpp=yes option enables you to override this default and cause the f90 driver to pass all source files to cpp. If you do not compile with the +cpp=yes option and if the source file does not have the .F extension, the compiler treats any cpp directives (but not any embedded Fortran statements) as comments and ignores them. (As a language extension, HP Fortran 90 allows comments to begin with the # character, which is also the prefix character for all cpp directives.)

Consider the following program:

Example 2-9 cpp_direct.f90

PROGRAM main
REAL :: x

WRITE (6, FMT='(A)', ADVANCE='NO') 'Enter a real number: '
READ *, x
#ifdef DEBUG
PRINT *, 'The value of x in main: ', x
#endif
PRINT *, 'x =', double_it(x)
END PROGRAM main

REAL FUNCTION double_it(arg)
REAL :: arg

#ifdef DEBUG
PRINT *, 'The value of x in double_it: ', arg
#endif
double_it = 2.0 * arg
END FUNCTION double_it

The program uses the #ifdef and #endif directives around PRINT statements. If the macro DEBUG is defined, cpp will leave the PRINT statements in the source text that is passed to the compiler; if it is not defined, cpp will remove the statements. You can define the macro in the source text, using the #define directive; or you can define it on the command line, using the -D compile-line option. The advantage of the option is that it does not require editing the source file to define or undefine a macro.

The following command line uses the -D option to define the macro DEBUG (the space between -D and DEBUG is optional):

$ f90 +cpp=yes -D DEBUG cpp_direct.f90

Here is the output from a sample run of the executable program created by the preceding command line:

$ a.out
Enter a real number: 3
The value of x in main: 3.0
The value of x in double_it: 3.0
x = 6.0

The next command line does not use the -D option, so that DEBUG is undefined, causing cpp to remove the PRINT statements from the source text that is passed to the compiler:

$ f90 +cpp=yes cpp_direct.f90

Here is the output from the nondebugging version of the program:

$ a.out
Enter a real number: 3.3
x = 6.6

Saving the cpp output file

By default, the f90 command discards the source text as processed by cpp after compilation. However, you can preserve this text by compiling with the +cpp_keep option. If the source file has the .F or .f extension, the output from cpp is written to a file with the same name but with the .i extension. If the source file extension is .f90, the output file has the .i90 extension.

Here is the previous command line to preprocess and compile cpp_direct.f90, with the addition of the +cpp_keep option:

$ f90 +cpp_keep +cpp=yes cpp_direct.f90

After the PRINT statements have been removed, the resulting output file looks like this:

$ cat cpp_direct.i90
# 1 "cpp_direct.f90"
PROGRAM main
REAL :: x

WRITE (6, FMT="(A)", ADVANCE="NO") "Enter a real number: "
READ *, x



PRINT *, "x =", double_it(x)
END PROGRAM main

REAL FUNCTION double_it(arg)
REAL :: arg




double_it = 2.0 * arg
END FUNCTION double_it

Creating demand-loadable executables

By default, the loader loads the entire code for an executable program into virtual memory. For very large programs, this can increase startup time. You can override this default by causing the linker to mark your program demand load. A demand-loadable program is loaded into memory a page at a time, as it is accessed.

Use the +demand_load option to make your program demand loadable, as follows:

$ f90 +demand_load prog.f90

The f90 command passes this option to the linker, which marks the executable program demand load.

Demand loading allows a program to start up faster because page loading can be spread across the execution of the program. The disadvantage of demand loading is that it can degrade performance throughout execution.

Creating shared executables

By default, the linker marks an executable program as shared. A shared executable is shareable by all processes that use the program. The first process to run the program loads its code into virtual memory. If the program is already loaded by another process, then a process shares the code with the other process.

You can override this default with the +noshared option, which causes the linker to mark the executable as unshared, making the program's code nonshareable. The following command line causes the linker to mark prog.f90 as unshared:

$ f90 +noshared prog.f90

In some circumstances, it may help to debug a program or to improve its runtime performance by making it nonshareable. In general, however, it is not desirable because nonshareable executables place greater demands on memory resources.

Compiling in 64-bit mode

Compiling HP Fortran 90 programs with the +DA2.0W option causes f90 to produce 64-bit executable programs. You should consider compiling in 64-bit mode if your program does any of the following:

  • Accesses a large shared memory (greater than 1.75 gigabytes) or large data spaces (greater than 1 gigabyte or, if using EXEC_MAGIC, greater than 1.9 gigabytes)

  • Uses large data elements—greater than 32-bit words

  • Provides objects or libraries that might be used in a 64-bit application

There are no HP Fortran 90 language differences between 32-bit and 64-bit programs. Recompiling should suffice to convert a 32-bit Fortran program to run as a 64-bit program.

However, the C language has some differences in data type sizes. If your Fortran program calls functions written in C and is compiled in 64-bit mode, the size differences may require promoting the data items that are passed to or from the C functions. See Table 8-2 “Size differences between HP Fortran 90 and C data types” and Table 8-3 “Size differences after compiling with +autodbl for the size differences between Fortran and C data types when compiled in 64-bit mode.

NOTE: If your program does not need to run in 64-bit mode, there is no benefit to compiling it in 64-bit mode. In fact, the executable program may run slower than if compiled in 32-bit mode.
Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© Hewlett-Packard Development Company, L.P.