Oracle Solaris Studio 12.2:Fortran 用户指南

第 2 章 使用 Solaris Studio Fortran

本章介绍如何使用 Fortran 编译器。

所有编译器的主要用途都是将使用过程语言(如 Fortran)编写的程序转换为可由目标计算机硬件执行的数据文件。在此过程中,编译器也可以自动调用系统链接程序来生成可执行文件。

编译器还可以用于:

2.1 快速入门

本节简要介绍如何使用 Fortran 编译器来编译和运行 Fortran 程序。下一章将详细介绍命令行选项。

运行 Fortran 应用程序的基本步骤包括:使用编辑器创建带有文件名后缀 .f.for.f90.f95.F.F90.F95.f03.F03 的 Fortran 源文件(请参见表表 2–1),调用编译器生成可执行文件;最后通过键入文件名来启动该程序的执行:

示例:此程序在屏幕上显示一条消息:


demo% cat greetings.f
      PROGRAM GREETINGS
      PRINT *, ’Real programmers write Fortran!’
      END
demo% f95 greetings.f
demo% a.out
 Real programmers write Fortran!
demo%

在此示例中,f95 编译源文件 greetings.f,并在缺省情况下将可执行程序链接到文件 a.out。要启动该程序,请在命令提示符下键入可执行文件的名称 a.out

传统上,UNIX 编译器将可执行输出写入到名为 a.out 的缺省文件中。每次编译都写入到同一个文件是比较笨拙的方法。再者,如果该文件已存在,则在下次运行编译器时它将被覆盖。因此,请使用 -o 编译器选项来显式指定可执行输出文件的名称:


demo% f95 -o greetings greetings.f
demo% greetings
 Real programmers write Fortran!
demo%

在上面的示例中,-o 选项告知编译器将可执行代码写入到文件 greetings 中。(按照约定,通常会为可执行文件指定与主源文件相同的名称,但可执行文件没有扩展名。)

或者,可在每次编译后通过 mv 命令重命名缺省的 a.out 文件。无论使用哪种方法,都要在 shell 提示符下键入可执行文件的名称来运行程序。

本章的后面几节将讨论 f95 命令使用的约定、编译器源代码行指令,以及有关使用这些编译器的其他问题。下一章将详细介绍命令行语法和所有选项。

2.2 调用编译器

在 shell 提示符调用编译器有一个简单的命令命令,其语法是:

f95 [options] files...

其中,files… 是一个或多个以 .f.F.f90.f95.F90.F95.for 结尾的 Fortran 源文件名称;options 是一个或多个编译器选项标志。(以 .f90.f95 扩展名结尾的文件是只能由 f95 编译器识别的“自由格式”Fortran 95 源文件。)

在下面的示例中,我们在启用运行时调试的情况下,使用 f95 来编译两个源文件以生成名为 growth 的可执行文件:


demo% f95 -g -o growth growth.f fft.f95

注 –

可以使用 f95f90 命令来调用 Fortran 编译器。


新增功能:该编译器还接受扩展名为 .f03.F03 的源文件。这些文件将被视为与 .f95.F95 等效,并且可以作为一种方式来表示源文件包含 Fortran 2003 扩展名。

2.2.2 命令行文件命名约定说明了编译器可以识别的各种源文件扩展名。

2.2.1 编译和链接序列

在上一示例中,编译器自动生成加载器目标文件 growth.offt.o,然后调用系统链接程序以创建可执行程序文件 growth

在编译后,目标文件 growth.offt.o 将保留。此约定使您可以方便地重新链接和重新编译文件。

如果编译失败,您将收到每个错误的对应消息。对于出现错误的源文件,不会生成任何 .o 文件,也不会写入任何可执行程序文件。

2.2.2 命令行文件命名约定

在命令行上出现的文件名后附加的后缀扩展名决定了编译器处理文件的方式。如果文件名的后缀扩展名不是下面列出的任意一个扩展名,或者没有扩展名,则这些文件名将传递给链接程序。

表 2–1 由 Fortran 编译器识别的文件名后缀

后缀  

语言  

操作  

.f

Fortran 77 或 Fortran 95 固定格式 

编译 Fortran 源文件,将目标文件放在当前目录中;目标文件的缺省名称是源文件的名称,但具有 .o 后缀。

.f95.f90

Fortran 95 自由格式 

执行与 .f 相同的操作

.f03

Fortran 2003 自由格式 

执行与 .f 相同的操作

.for

Fortran 77 或 Fortran 95 固定格式 

执行与 .f 相同的操作。

.F

Fortran 77 或 Fortran 95 固定格式 

在编译前,将 Fortran(或 C)预处理程序应用于 Fortran 77 源文件。 

.F95.F90

Fortran 95 自由格式 

在 Fortran 编译 Fortran 95 自由格式源文件前,将 Fortran(或 C)预处理程序应用于该文件。 

.F03

Fortran 2003 自由格式 

.F95 相同

.s

汇编程序 

使用汇编程序汇编源文件。 

.S

汇编程序 

在对汇编程序源文件进行汇编之前,将 C 预处理程序应用于该文件。 

.il

内联扩展 

处理内联扩展的模板文件。编译器将使用模板来扩展选定例程的内联调用。(模板文件是特殊的汇编程序文件;请参见 inline(1) 手册页。)

.o

目标文件 

将目标文件传递到链接程序。 

.a.so.so.n

库 

将库名称传递给链接程序。.a 文件是静态库,.so.so.n 文件是动态库。

Fortran 95 自由格式在4.1 源语言功能中进行说明。

2.2.3 源文件

Fortran 编译器可从命令行接受多个源文件。单个源文件(也称为编译单元)可以包含任意数量的过程(主程序、子例程、函数、块数据、模块等)。可以将应用程序配置为每个文件一个源代码过程,或者将协同工作的过程集中到单个文件中。《Fortran 编程指南》介绍了这些配置的优缺点。

2.2.4 源文件预处理程序

f95 支持两种源文件预处理程序:fppcpp。编译器可以在编译之前调用任一源文件预处理程序来扩展源代码“宏”和符号定义。缺省情况下,编译器将使用 fpp-xpp=cpp 选项可将缺省设置由 fpp 更改为 cpp。(另请参见有关 -Dname 选项的论述。)

fpp 是 Fortran 特定的源文件预处理程序。有关详细信息,请参见 fpp(1) 手册页和 fpp 自述文件。缺省情况下,系统会对具有 .F.F90.F95.F03 扩展名的文件调用该预处理程序。

fpp 的源代码可从 Netlib Web 站点获得:

http://www.netlib.org/fortran/

有关标准 Unix C 语言预处理程序的信息,请参见 cpp(1)。对于 Fortran 源文件,建议使用 fpp 而不是 cpp

2.2.5 分别编译和链接

您可以在不同的步骤中编译和链接。-c 选项编译源文件并生成 .o 目标文件,但不会创建可执行文件。如果不使用 -c 选项,则编译器将调用链接程序。如果通过这种方式将编译和链接步骤分开,那么就不必只为了修复一个文件而重新执行完整的编译,如以下示例所示:

使用单独的步骤来编译一个文件,并将其与其他文件链接在一起:


demo% f95 -c file1.f                          (Make new object file)
demo% f95 -o prgrm file1.o file2.o file3.o         (Make executable file)

请确保链接步骤列出了生成完整程序所需的全部目标文件。如果在此步骤中缺少任何目标文件,则链接将失败,并显示未定义的外部引用错误(缺少例程)。

2.2.6 一致编译和链接

每当分步完成编译和链接时,确保编译和链接选项的一致选择至关重要。在使用选项编译程序的任何部分时,必须使用相同的选项进行链接。另外,许多选项要求使用该选项编译所有源文件,包括链接步骤。

第 3 章中的选项描述指明了此类选项。

示例: 用 -fast 编译 sbr.f,编译 C 例程,然后分步进行链接:


demo% f95 -c -fast sbr.f
demo% cc -c -fast simm.c
demo% f95 -fast sbr.o simm.o        link step; passes  -fast  to the linker

2.2.7 无法识别的命令行参数

编译器无法识别的任何命令行参数都将解释为可能是链接程序选项、目标程序文件名或库名称。

基本区别是:

例如:


demo% f95 -bit move.f           <-  -bit is not a recognized f95 option
f95: Warning: Option -bit passed to ld, if ld is invoked, ignored otherwise
demo% f95 fast move.f           <-   The user meant to type -fast
ld: fatal: file fast: cannot open file; errno=2
ld: fatal: File processing errors.  No output written to a.out

请注意,在第一个示例中,f95 无法识别 -bit,该选项将被传递给链接程序 (ld),后者试图对其进行解释。因为单字母 ld 选项可以串联起来,所以链接程序会将 -bit 视为 -b -i -t,而这些都是合法的 ld 选项!这可能是(也可能不是)用户所希望的结果。

在第二个示例中,用户想键入 f95 选项 -fast,但忽略了前导短线。编译器再次将参数传递给链接程序,而链接程序将参数解释为一个文件名。

这些示例表明在编写编译器命令行时应格外小心!

2.2.8 模块

f95 自动为在源文件中遇到的每个 MODULE 声明创建模块信息文件,并搜索 USE 语句所引用的模块。对于遇到的每个模块 (MODULE module_name),编译器都在当前目录中生成相应的文件 module_name.mod。例如,f95 为文件 mysrc.f95 中出现的 MODULE list 单元生成模块信息文件 list.mod

有关如何设置写入和搜索模块信息文件时所用的缺省路径的信息,请参见 -Mpath-moddir dirlist 选项标志。

有关隐式调用所有编译单元中的 MODULE 声明的信息,另请参见 -use 编译器选项。

使用 fdumpmod(1) 命令可显示与 .mod 模块信息文件内容有关的信息。

有关详细信息,请参见 4.9 模块文件

2.3 指令

可使用源代码指令(一种 Fortran 注释格式)将有关专门的优化或并行化选择的特定信息传递给编译器。编译器指令有时也称为 pragma。编译器可以识别一组通用指令和并行化指令。f95 还可处理 OpenMP 共享内存多处理指令。

特定于 f95 的指令在4.8 指令中进行说明。附录 C中完整总结了 f95 可以识别的所有指令。


注 –

指令并不是 Fortran 标准的一部分。


2.3.1 通用指令

Fortran 通用指令的各种形式包括:

!$PRAGMA keyword ( a [ , a ] ) [ , keyword ( a [ , a ] ) ] ,

!$PRAGMA SUN keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…

变量 keyword 标识特定的指令。此外也可以使用额外的参数或子选项。(某些指令要求使用额外的关键字 SUN,如上所示。)

通用指令使用以下语法:

请遵循以下约束:

Fortran 编译器可识别以下通用指令:

表 2–2 通用 Fortran 指令摘要

C 指令

!$PRAGMA C(list )

将一系列外部函数的名称声明为 C 语言例程。 

IGNORE_TKR 指令

!$PRAGMA IGNORE_TKR {name {, name} ...}

在解析特定调用时,编译器会忽略在通用过程接口中出现的指定哑元参数名称的类型、种类和等级。 

UNROLL 指令

!$PRAGMA SUN UNROLL=n

建议编译器将下面的循环解开为指定的长度 n

WEAK 指令

!$PRAGMA WEAK(name[ =name2])

name 声明为弱符号,或者声明为 name2 的别名。

OPT 指令

!$PRAGMA SUN OPT=n

将子程序的优化级别设置为 n

PIPELOOP 指令

!$PRAGMA SUN PIPELOOP=n

断言下面的循环中在间隔为 n 的迭代之间存在依赖性。

PREFETCH 指令


!$PRAGMA SUN_PREFETCH_READ_ONCE(name)
!$PRAGMA SUN_PREFETCH_READ_MANY(name)
!$PRAGMA SUN_PREFETCH_WRITE_ONCE(name)
!$PRAGMA SUN_PREFETCH_WRITE_MANY(name)

请求编译器为名称引用生成预取指令。(需要使用 -xprefetch 选项,缺省情况下启用该选项。编译时使用 —xprefetch=no 可以禁用预取指令。目标体系结构也必须支持预取指令,而且编译器优化级别必须大于 —xO2。)

ASSUME 指令

!$PRAGMA [BEGIN} ASSUME (expression [ ,probability])

!$PRAGMA END ASSUME

断言编译器可假定程序中某些点处的条件为真。 

2.3.1.1 C 指令

C() 指令指定其参数为外部函数。它与 EXTERNAL 声明等效,但有一点例外,与普通外部名称不同,Fortran 编译器在这些参数名称的后面不附加下划线。有关详细信息,请参见《Fortran 编程指南》中的“C-Fortran 接口”一章。

在每个包含特定函数引用的子程序中,用于该函数的 C() 指令应该出现在对该函数的第一次引用之前。

示例-为 C 编译 ABCXYZ


       EXTERNAL ABC, XYZ
!$PRAGMA C(ABC, XYZ)

2.3.1.2 IGNORE_TKR 指令

此指令导致编译器在解析特定调用时,忽略在通用过程接口中出现的指定哑元参数名称的类型、种类和等级。

例如,在下面的过程接口中,指令指定 SRC 可以是任何数据类型,但 LEN 可以为 KIND=4KIND=8。接口块为通用过程名称定义了两个特定过程。此示例以 Fortran 95 自由格式说明。


INTERFACE BLCKX

SUBROUTINE BLCK_32(LEN,SRC)
  REAL SRC(1)
!$PRAGMA IGNORE_TKR SRC
  INTEGER (KIND=4) LEN
END SUBROUTINE

SUBROUTINE BLCK_64(LEN,SRC)
  REAL SRC(1)
!$PRAGMA IGNORE_TKR SRC
  INTEGER (KIND=8) LEN
END SUBROUTINE

END INTERFACE

The subroutine call:

INTEGER L
REAL S(100)
CALL BLCKX(L,S)

在进行正常编译时,BLCKX 调用将调用 BLCK_32;在使用 -xtypemap=integer:64 进行编译时,将调用 BLCK_64S 的实际类型并不能确定要调用哪个例程。对于基于参数类型、种类或等级来调用特定库例程的包装器来说,这可大大简化为其编写通用接口的工作。

请注意,无法在该指令中指定假定形状数组、Fortran 指针或可分配数组的哑元参数。如果未指定名称,则该指令将应用于过程的所有哑元参数,但假定形状数组、Fortran 指针或可分配数组的哑元参数除外。

2.3.1.3 UNROLL 指令

UNROLL 指令要求您在 !$PRAGMA 后指定 SUN

!$PRAGMA SUN UNROLL=n 指令指示编译器在其优化过程中将以下循环解开 n 次。(只有当编译器分析认为此类解开有必要时,它才会解开循环。)

n 是正整数。选项有:

如果实际解开了任何循环,那么可执行文件会变大。有关详细信息,请参见《Fortran 编程指南》中有关性能与优化的章节。

示例—解开循环两次:


!$PRAGMA SUN UNROLL=2

2.3.1.4 WEAK 指令

WEAK 指令定义一个符号,其优先级比以前定义的相同符号要低。此 pragma 主要用于源文件中以创建库。如果链接程序无法解析弱符号,它并不生成错误消息。


!$PRAGMA WEAK (name1 [=name2])

WEAK (name1) 将 name1 定义为弱符号。如果链接程序没有找到 name1 的定义,它不会生成错误消息。

WEAK (name1=name2) 将 name1 定义为弱符号以及 name2 的别名。

如果程序调用 name1,但没有对其进行定义,那么链接程序将使用库中的定义。但是,如果程序定义了自己的 name1 版本,那么将采用程序的定义,而不是使用库中 name1 的弱全局定义。如果程序直接调用 name2,则将使用库中的定义;重复的 name2 定义将导致错误。有关更多信息,请参见 Solaris《链接程序和库指南》。

2.3.1.5 OPT 指令

OPT 指令要求您在 !$PRAGMA 后面指定 SUN

OPT 指令设置子程序的优化级别,这将覆盖编译命令行中指定的级别。该指令必须紧挨在目标子程序前面出现,并且仅应用于该子程序。例如:


!$PRAGMA SUN OPT=2
        SUBROUTINE smart(a,b,c,d,e)
        ...etc

在使用指定 -O4f95 命令编译以上内容时,该指令将覆盖此级别,并以 -O2 级别编译子例程。 除非该例程后面另有一个指令,否则下一个子程序将以 -O4 级别编译。

还必须使用 -xmaxopt[=n] 选项编译例程以便识别该指令。此编译器选项为 PRAGMA OPT 指令指定最大的优化值:如果 PRAGMA OPT 指定的优化级别大于 -xmaxopt 级别,则使用 -xmaxopt 级别。

2.3.1.6 PIPELOOP[= n] 指令

PIPELOOP=n 指令要求您在 !$PRAGMA 后面指定 SUN

此指令必须紧挨在 DO 循环前面出现。n 是正整数常量或零,它向优化器断言循环迭代之间是否存在依赖性。值零表示循环中没有迭代间的(即循环带有的)依赖性,优化器可以对循环执行任意管道处理。正值 n 表示,循环的第 I 次迭代与第 (I-n) 次迭代之间存在依赖性,每次最多只能对 n 个迭代进行管道处理。(如果未指定 n,则缺省为 0)


C    We know that the value of K is such that there can be no
C    cross-iteration dependencies (E.g. K>N)
!$PRAGMA SUN PIPELOOP=0
      DO I=1,N
       A(I)=A(I+K) + D(I)
       B(I)=B(I) + A(I)
      END DO

有关优化的更多信息,请参见《Fortran 编程指南》。

2.3.1.7 PREFETCH 指令

-xprefetch 选项标志(3.4.161 –xprefetch[= a[,a]])可启用一组 PREFETCH 指令,这些指令指示编译器在支持预取的处理器上为指定的数据元素生成预取指令。


!$PRAGMA SUN_PREFETCH_READ_ONCE(name)
!$PRAGMA SUN_PREFETCH_READ_MANY(name)
!$PRAGMA SUN_PREFETCH_WRITE_ONCE(name)
!$PRAGMA SUN_PREFETCH_WRITE_MANY(name)

有关预取指令的详细信息,另请参见《C 用户指南》或《SPARC Architecture Manual, Version 9》。

2.3.1.8 ASSUME 指令

ASSUME 指令向编译器提供有关程序中某些点的条件的提示。这些断言可以帮助编译器设定其优化策略。程序员也可以在执行过程中使用这些指令检查程序的有效性。ASSUME 有两种格式。

“点断言”ASSUME 的语法是:


!$PRAGMA ASSUME (expression [,probability])

另外,“范围断言”ASSUME 的语法是:


!$PRAGMA BEGIN ASSUME [expression [, probability)
     block of statements
!$PRAGMA END ASSUME

请使用点断言格式来声明编译器可在程序中的该点采用的条件。而使用范围断言格式来声明在语句封闭范围内有效的条件。范围断言中的 BEGINEND 对必须正确嵌套。

必需的 expression 是一个布尔表达式,该表达式可在程序中的该点求值,并且其中不包含用户定义的运算符或函数调用(下面列出的除外)。

可选的 probability 值是一个介于 0.0 和 1.0 之间的实数或者是整数 0 或 1,它给出表达式为真的可能性。probability 的值为 0.0(或 0)意味着永远不会为真;值为 1.0(或 1)则意味着始终为真。如果没有指定,则认为表达式很有可能为真,但并不一定为真。probability 为 0 或 1 以外其他值的断言是非必然断言。类似地,probability 正好为 0 或 1 的断言是必然断言

例如,如果程序员知道 DO 循环的长度始终大于 10,000,则为编译器提供该提示可使之生成更好的代码。通常,以下循环在使用 ASSUME pragma 时比不使用时运行得要快。


!$PRAGMA BEGIN ASSUME(__tripcount().GE.10000,1) !! a big loop
        do i = j, n
           a(i) = a(j) + 1
        end do
!$PRAGMA END ASSUME

有两个内部函数专用于 ASSUME 指令的表达式子句。(请注意,它们的名称前面有两个下划线。)

__branchexp()

用于紧挨在分支转移语句(带有布尔控制表达式)前面的点断言。它与控制分支转移语句的布尔表达式生成相同的结果。 

__tripcount()

生成紧跟在指令后面的或指令所包含的循环的行程计数。在用于点断言时,指令后面的语句必须位于 DO 的第一行。在用于范围断言时,它应用于最外层的封闭循环。

在将来的版本中,特殊内部函数的列表可能会扩展。

可与 -xassume_control 编译器选项结合使用。(请参见3.4.111 –xassume_control[ =keywords])例如,在使用 -xassume_control=check 进行编译时,如果行程计数变为小于 10,000,则上述示例将生成一条警告。

如果使用 -xassume_control=retrospective 进行编译,则在程序终止时会生成一个摘要报告,指出所有断言是真还是假。有关 -xassume_control 的详细信息,请参见 f95 手册页。

另一个示例:


!$PRAGMA ASSUME(__tripcount.GT.0,1)
       do i=n0, nx

如果使用 -xassume_control=check 编译上述示例,则在由于行程计数为零或负数而没有执行循环时,将会发出一条运行时警告。

2.3.2 并行化指令

并行化指令显式地请求编译器尝试并行处理该指令后面的 DO 循环或代码区域。其语法与一般指令不同。只有在使用 -openmp 选项进行编译时才能识别并行化指令。有关 Fortran 并行化的详细信息,请参见《OpenMP API 用户指南》和《Fortran 编程指南》。

Fortran 编译器支持 OpenMP 3.0 共享内存并行化模型。传统的 Sun 和 Cray 并行化指令现已过时,不应再使用它们。

2.3.2.1 OpenMP 并行化指令

Fortran 编译器将 OpenMP Fortran 共享内存多处理 API 识别为首选的并行编程模型。该 API 是由 OpenMP 体系结构审查委员会 (http://www.openmp.org) 指定的。

要启用 OpenMP 指令,您必须使用命令行选项 -xopenmp 进行编译。(请参见3.4.153 –xopenmp[={ parallel|noopt|none}]。)

有关 f95 接受的 OpenMP 指令的更多信息,请参见《OpenMP API 用户指南》。

2.3.2.2 传统的 Sun/Cray 并行化指令


注 –

传统的 Sun 和 Cray 风格的并行化指令现已过时。首选使用 OpenMP 并行化 API。有关如何从传统的 Sun/Cray 指令迁移到 OpenMP 模型的信息,请参见《OpenMP API 用户指南》。


2.3.3 IVDEP 指令

!DIR$ IVDEP 指令指示编译器忽略其在循环中找到的部分或全部对数组引用的循环附带依赖性,使编译器能够在其他循环之间执行各种循环优化,例如微向量化、分布、软件流水化,否则这些优化将无法实现。当用户知道这些依赖性无关紧要或者实际上永远不会发生时,可以使用该指令。

例如:


	 DO I = 1, N 
	   A(V(I)) = A(V(I)) + C(I) 
	 END DO        

在此循环中,存在几处对 A(V(I)) 的循环附带依赖性,因为 V(I) 可能会将重复值传递给索引 A,对循环重新排序可能会产生不同的结果。但如果已知 V 仅包含不同的值,则可以安全地对循环进行重新排序,并且可以使用 IVDEP 指令来实现优化。

可以使用 —xivdep 编译器选项(请参见3.4.133 –xivdep[= p])来禁用或确定 IVDEP 指令的解释。

IVDEP 指令的某些传统解释仅能断言不存在向后循环附带依赖性。Fortran 编译器的缺省值是 —xivdep=loop,表示 IVDEP 指令断言不存在假定的循环依赖性。

下面的示例解释向后依赖性与向前依赖性。


 	 do i = 1, n			! BACKWARD LOOP-CARRIED DEPENDENCE 
		... = a(i-1)		 ! S1 
	    a(i) = ...		 ! S2 
	 end do  

	 do i = 1, n			! FORWARD LOOP-CARRIED DEPENDENCE 
	    a(i) = ...		! S3 
		... = a(i-1)		! S4 
	 end do       

第一个循环有一个从 S2 到 S1 的向后循环附带依赖性,第二个循环中有一个从 S3 到 S4 的向前循环附带依赖性。由于第二个循环只有一个向前依赖性,因此可以安全地进行分布和/或微向量化,而第一个循环则不能。

下面是使用缺省值 -xivdep=loop 的情况下使用 IVDEP 的示例:


integer target a(n)
integer, pointer :: p(:), q(:)
!DIR$ IVDEP
do i = 1, n
	 p(i) = q(i) 
	 a(i) = a(i-1)
end do        

p(i)q(i) 之间以及 p(i)a(*) 之间的假定依赖性将被忽略,而 a(i)a(i-1) 之间的显式依赖性则不被忽略。该循环可分割为两个循环,所生成的 p(i) = q(i) 循环可以实现微向量化。

IVDEP 指令应用于紧随其后的 DO 循环。在指令与循环之间不允许有其他代码。!DIR$ IVDEP 也可以应用于数组赋值语句 FORALLWHERE 结构。如果特定的循环存在多个指令(例如 IVDEP? 和 UNROLL),编译器会尽可能服从所有指令。

2.4 库接口和 system.inc

Fortran 编译器提供一个 include 文件 system.inc,它为大多数非内在库例程定义了接口。请声明此 include 文件以确保所调用函数及其参数的类型得到正确的设置,尤其是在使用 -xtypemap 更改了缺省数据类型时。

例如,以下命令可能会生成一个运算异常,原因是没有显式地设置函数 getpid() 的类型:


        integer(4) mypid
        mypid = getpid()
        print *, mypid

getpid() 例程返回一个整数值,但如果没有为该函数声明显式类型,则编译器认为它返回一个实数值。此值将进一步转换为整数,这很有可能会导致浮点错误。

要纠正这种错误,您应该显式地设置所调用的 getuid() 及类似函数的类型:


        integer(4) mypid, getpid
        mypid = getpid()
        print *, mypid

您可以使用 -Xlist(全局程序检查)选项诊断此类问题。Fortran include 文件 'system.inc' 为这些例程提供了显式接口定义。


        include ’system.inc’
        integer(4) mypid
        mypid = getpid()
        print *, mypid

通过在调用 Fortran 库中例程的程序单元中包含 system.inc,可以自动定义接口,并帮助编译器诊断类型不匹配的问题。(有关更多信息,请参见《Fortran 库参考》。)

2.5 编译器用法提示

下面几节提供了一些高效使用 Fortran 编译器的建议方法。下一章中给出了完整的编译器选项参考。

2.5.1 确定硬件平台

某些编译器标志允许用户使用一组特定的硬件平台选项来调节代码的生成。编译器的 -dryrun 选项可用来确定本机处理程序:


<sparc>%f95 -dryrun -xtarget=native
###     command line files and options (expanded):
### -dryrun -xarch=sparcvis2 -xcache=64/32/4:1024/64/4 -xchip=ultra3i

<x64>%f95 -dryrun -xtarget=native
###     command line files and options (expanded):
### -dryrun -xarch=sse2a -xcache=64/64/2:1024/64/16 -xchip=opteron

2.5.2 使用环境变量

可通过设置 FFLAGSOPTIONS 变量来指定选项。

可以在命令行中显式地使用 FFLAGSOPTIONS。在使用 make 的隐式编译规则时,make 程序会自动使用 FFLAGS

示例: 设置 FFLAGS: (C Shell)


demo% setenv FFLAGS ’-fast -Xlist’

示例: 显式地使用 FFLAGS


demo% f95 $FFLAGS any.f

在使用 make 时,如果按上述方式设置了 FFLAGS 变量,而且 makefile 的编译规则是隐式的(即没有显式的编译器命令行),则调用 make 的编译效果与以下命令相当:

f95 -fast -Xlist files

make 是一个功能非常强大的程序开发工具,可以方便地将其用于所有的 Sun 编译器。请参见 make(1) 手册页以及《Fortran 编程指南》中的“程序开发”一章。


注 –

make 使用的缺省隐式规则可能无法识别具有 .f95.mod(模块文件)扩展名的文件。有关详细信息,请参见《Fortran 编程指南》和 Fortran 自述文件。


2.5.3 内存大小

编译可能需要使用大量内存。这取决于选定的优化级别以及所编译文件的大小和复杂性。如果优化器内存不足,它将尝试通过在较低的优化级别上重试当前过程来进行恢复,并以命令行上 -On 选项指定的原始级别继续执行后续例程。

运行编译器的处理器应该至少具有 64 兆字节内存;建议使用 256 兆字节内存。此外还应该分配足够的交换空间。最低为 200 MB;建议为 300 MB。

内存使用情况取决于每个过程的大小、优化级别、为虚拟内存设置的限制、磁盘交换文件的大小以及各种其他参数。

在编译包含多个例程的单个源文件时,可能会出现编译器内存或交换空间不足的情况。

如果编译器内存不足,请尝试降低优化级别,或者使用 fsplit(1) 将多例程的源文件分成多个文件,使每个文件包含一个例程。

2.5.3.1 交换空间限制

Solaris 操作系统命令 swap -s 显示可用的交换空间。请参见 swap(1M)。

示例: 使用 swap 命令:


demo% swap -s
total: 40236k bytes allocated + 7280k reserved = 47516k used, 1058708k available
To determine the actual real memory:

demo% /usr/sbin/dmesg | grep mem
mem = 655360K (0x28000000)
avail mem = 602476544

2.5.3.2 增加交换空间

使用 mkfile(1M) 和 swap(1M) 可增加工作站上交换空间的大小。您必须成为超级用户才能执行此操作。mkfile 创建一个特定大小的文件,而 swap -a 将该文件添加到系统交换空间中:


demo# mkfile -v 90m /home/swapfile
/home/swapfile 94317840 bytes
demo# /usr/sbin/swap -a  /home/swapfile

2.5.3.3 虚拟内存的控制

-O3 或更高的优化级别编译非常大的例程时,可能需要额外的内存,这可能会降低编译时性能。您可以通过限制单个进程的可用虚拟内存量来控制这种情况。

sh shell 中,请使用 ulimit 命令。请参见 sh(1)。

示例: 将虚拟内存限定为 16 MB:


demo$ ulimit -d 16000

csh shell 中,请使用 limit 命令。请参见 csh(1)。

示例: 将虚拟内存限定在 16 MB 以内:


demo% limit datasize 16M

这些命令行的每一个命令行都会使优化器在数据空间达到 16 MB 时尝试恢复。

此限制值不能大于系统的总可用交换空间,实际上,在进行较大的编译时,此限制值必须足够小才能保证正常地使用系统。请确保没有任何编译占用一半以上的空间。

示例: 对于 32M 的交换空间,请使用以下命令:

sh shell 中:


demo$ ulimit -d 1600

csh shell 中:


demo% limit datasize 16M

最佳设置取决于所请求的优化等级以及可用的实际内存量和虚拟内存量。

在 64 位 Solaris 环境中,应用程序数据段大小的软限制为 2 GB。如果应用程序需要分配更多的空间,请使用 shell 的 limitulimit 命令取消该限制。

对于 csh,请使用:


demo% limit datasize unlimited

对于 shksh,请使用:


demo$ ulimit -d unlimited

有关更多信息,请参见《Solaris(64 位)开发者指南》。