本章介绍如何使用 Fortran 95 编译器。
所有编译器的主要用途都是将使用过程语言(如 Fortran)编写的程序转换为可由目标计算机硬件执行的数据文件。在此过程中,编译器也可以自动调用系统链接程序来生成可执行文件。
Fortran 95 编译器还可以用于:
生成并行的可执行文件以用于多处理器 (-openmp)。
跨源文件和子例程分析程序的一致性并生成报告 (-Xlist)。
将源文件转换为:
可重定位的二进制 (.o) 文件,可随后将其链接到可执行文件或静态库 (.a) 文件。
动态共享库 (.so) 文件 (-G)。
将文件链接到可执行文件。
在运行时调试处于启用状态的情况下编译可执行文件 (-g)。
使用运行时语句或过程级文件配置进行编译 (-pg)。
检查源代码是否符合 ANSI 标准 (-ansi)。
本节简要介绍如何使用 Fortran 95 编译器来编译和运行 Fortran 程序。下一章将详细介绍命令行选项。
运行 Fortran 应用程序的极为基本的步骤包括:使用编辑器创建带有文件名后缀 .f、.for、.f90、.f95、.F、.F90 或 .F95 的 Fortran 源文件;调用编译器生成可执行文件;最后通过键入文件名来启动并执行该程序:
示例:此程序在屏幕上显示一条消息:
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 命令使用的约定、编译器源代码行指令,以及有关使用这些编译器的其他问题。下一章将详细介绍命令行语法和所有选项。
在 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 |
可以使用 f95 或 f90 命令来调用 Fortran 95 编译器。
新增功能:该编译器还接受扩展名为 .f03 或 .F03 的源文件。这些文件将被视为与 .f95 和 .F95 等效,并且可以作为一种表示源文件包含 Fortran 2003 扩展名的方式。
2.2.2 命令行文件命名约定说明了编译器可以识别的各种源文件扩展名。
在上一示例中,编译器自动生成加载器目标文件 growth.o 和 fft.o,然后调用系统链接程序以创建可执行程序文件 growth。
在编译后,目标文件 growth.o 和 fft.o 将保留。此约定使您可以方便地重新链接和重新编译文件。
如果编译失败,您将收到每个错误的对应消息。对于出现错误的源文件,不会生成任何 .o 文件,也不会写入任何可执行程序文件。
在命令行上出现的文件名后附加的后缀扩展名决定了编译器处理文件的方式。如果文件名的后缀扩展名不是下面列出的任意一个扩展名,或者没有扩展名,则这些文件名将传递给链接程序。
表 2–1 由 Fortran 95 编译器识别的文件名后缀
后缀 |
语言 |
操作 |
---|---|---|
.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,.s.o,.so.n |
库 |
将库名称传递给链接程序。.a 文件是静态库,.so 和 .so.n 文件是动态库。 |
Fortran 95 自由格式在4.1 源语言功能中进行说明。
Fortran 编译器可从命令行接受多个源文件。单个源文件(也称为编译单元)可以包含任意数量的过程(主程序、子例程、函数、块数据、模块等)。可以将应用程序配置为每个文件一个源代码过程,或者将协同工作的过程集中到单个文件中。《Fortran 编程指南》介绍了这些配置的优缺点。
f95 支持两种源文件预处理程序:fpp 和 cpp。编译器可以在编译之前调用任一源文件预处理程序来扩展源代码“宏”和符号定义。缺省情况下,编译器将使用 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。
您可以在不同的步骤中编译和链接。-c 选项编译源文件并生成 .o 目标文件,但不会创建可执行文件。如果不使用 -c 选项,则编译器将调用链接程序。如果通过这种方式将编译和链接步骤分开,那么就不必只为了修复一个文件而重新执行完整的编译,如以下示例所示:
使用单独的步骤来编译一个文件,并将其与其他文件链接在一起:
demo% f95 -c file1.f (生成新的目标文件) demo% f95 -o prgrm file1.o file2.o file3.o (生成可执行文件) |
请确保链接步骤列出了生成完整程序所需的全部目标文件。如果在此步骤中缺少任何目标文件,则链接将失败,并显示未定义的外部引用错误(缺少例程)。
每当分步完成编译和链接时,确保编译和链接选项的一致选择至关重要。在使用选项编译程序的任何部分时,必须使用相同的选项进行链接。另外,许多选项要求使用该选项编译所有源文件,包括链接步骤。
第 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 |
编译器无法识别的命令行参数将被解释为可能是链接程序选项、目标程序文件名或库名称。
基本区别是:
无法识别的选项(带有 -)会生成警告。
无法识别的非选项(不带 -)不生成警告。但是,这些非选项将被传递给链接程序,如果链接程序无法识别它们,它们将生成链接程序错误消息。
例如:
demo% f95 -bit move.f <- -bit 不是可识别的 f95 选项 f95: Warning: Option -bit passed to ld, if ld is invoked, ignored otherwise demo% f95 fast move.f <- 用户本意是要键入 -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,但忽略了前导短线。编译器再次将参数传递给链接程序,而链接程序将参数解释为一个文件名。
这些示例表明在编写编译器命令行时应格外小心!
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 模块文件。
可使用源代码指令(一种 Fortran 注释格式)将有关特殊优化或并行化选择的特定信息传递给编译器。有时,编译器指令也称为 pragma。编译器可识别一组通用指令和并行化指令。Fortran 95 还可处理 OpenMP 共享内存多处理指令。
特定于 f95 的指令在4.8 指令中进行说明。表 C–1 提供了 f95 可识别的所有指令的完整摘要。
指令并不是 Fortran 标准的一部分。
通用 Fortran 95 指令的形式包括:
C$PRAGMA keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…
C$PRAGMA SUN keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…
C$PRAGMA SPARC keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…
变量 keyword 标识特定的指令。此外也可以使用额外的参数或子选项。(某些指令要求使用额外的关键字 SUN 或 SPARC,如上所示。)
通用指令使用以下语法:
在第一列中,使用以下任一注释指示符:c、C、! 或 *
对于 f95 自由格式,! 是唯一可识别的注释指示符 (!$PRAGMA)。本章中的示例假定采用固定格式。
后面七个字符为大写或小写的 $PRAGMA(字符之间没有空格)。
对于自由格式的源程序,使用 ! 注释指示符的指令可以出现在行中的任意位置。
请遵循以下约束:
与 Fortran 文本一样,在前八个字符之后,空格将被忽略,而且大写和小写字母等效。
因为是注释,所以指令不能连续,但您可以根据需要使用多个连续的 C$PRAGMA 行。
如果注释符合以上语法,则它应该包含一个或多个编译器可识别的指令;如果不符合以上语法,系统会发出一条警告。
C 预处理程序 cpp 将扩展注释行或指令行中的宏符号定义;Fortran 预处理程序 fpp 不扩展注释行中的宏。fpp 会识别合法的 f95 指令,并允许在指令关键字外部进行有限的替换。但是,在处理需要关键字 SUN 的指令时要格外小心。cpp 会将小写的 sun 替换为预定义的值。另外,如果您定义了一个 cpp 宏 SUN,则它可能会与 SUN 指令关键字发生冲突。一般规则是,如果源文件将由 cpp 或 fpp 来处理,那么应以混合大小写来拼写这些 pragma,如下所示:
C$PRAGMA Sun UNROLL=3
Fortran 编译器可识别以下通用指令:
表 2–2 通用 Fortran 指令摘要
C 指令 |
C$PRAGMA C(list) 将一系列外部函数的名称声明为 C 语言例程。 |
IGNORE_TKR 指令 |
C$PRAGMA IGNORE_TKR {name {, name} ...} 在解析特定调用时,编译器会忽略在通用过程接口中出现的指定哑元名称的类型、种类和等级。 |
UNROLL 指令 |
C$PRAGMA SUN UNROLL=n 建议编译器将下面的循环解开为指定的长度 n。 |
WEAK 指令 |
C$PRAGMA WEAK(name[=name2]) 将 name 声明为弱符号,或者声明为 name2 的别名。 |
OPT 指令 |
C$PRAGMA SUN OPT=n 将子程序的优化级别设置为 n。 |
PIPELOOP 指令 |
C$PRAGMA SUN PIPELOOP=n 断言下面的循环中在间隔为 n 的迭代之间存在依赖性。 |
NOMEMDEP 指令 |
C$PRAGMA SUN NOMEMDEP 断言下面的循环中没有内存依赖性。 |
PREFETCH 指令 |
C$PRAGMA SUN_PREFETCH_READ_ONCE(name)C$PRAGMA SUN_PREFETCH_READ_MANY(name)C$PRAGMA SUN_PREFETCH_WRITE_ONCE(name)C$PRAGMA SUN_PREFETCH_WRITE_MANY(name) 请求编译器为名称引用生成预取指令。(要求使用 -xprefetch 选项。) |
ASSUME 指令 |
C$PRAGMA [BEGIN} ASSUME (expression [,probability]) C$PRAGMA END ASSUME 断言编译器可假定程序中某些点处的条件为真。 |
C() 指令指定其参数为外部函数。它与 EXTERNAL 声明等效,但有一点例外:与普通的 外部名称不同,Fortran 编译器在这些参数名称的后面不附加下划线。有关更多详细信息,请参见《Fortran 编程指南》中的“C-Fortran 接口”一章。
在每个包含特定函数引用的子程序中,用于该函数的 C() 指令应该出现在对该函数的第一次引用之前。
示例-为 C 编译 ABC 和 XYZ:
EXTERNAL ABC, XYZ C$PRAGMA C(ABC, XYZ) |
此指令导致编译器在解析特定调用时,忽略在通用过程接口中出现的指定哑元名称的类型、种类和等级。
例如,在下面的过程接口中,此指令指定 SRC 可以是任意数据类型,但 LEN 可以是 KIND=4 或 KIND=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_64。S 的实际类型并不能确定要调用哪个例程。对于基于参数类型、种类或等级来调用特定库例程的包装器来说,这可大大简化为其编写通用接口的工作。
请注意,无法在该指令中指定假定形状数组、Fortran 指针或可分配数组的哑元。如果未指定名称,则该指令将应用于过程的所有哑元,但假定形状数组、Fortran 指针或可分配数组的哑元除外。
UNROLL 指令要求您在 C$PRAGMA 后面指定 SUN。
C$PRAGMA SUN UNROLL=n 指令指示编译器在其优化过程中将下面的循环解开 n 次。(只有当编译器分析认为此类解开有必要时,它才会解开循环。)
n 是正整数。选项有:
如果 n=1,则优化器不得解开任何循环。
如果 n>1,则优化器可以解开循环 n 次。
如果实际解开了任何循环,那么可执行文件会变大。有关详细信息,请参见《Fortran 编程指南》中有关性能与优化的章节。
示例—解开循环两次:
C$PRAGMA SUN UNROLL=2 |
WEAK 指令定义一个符号,其优先级比以前定义的相同符号要低。此 pragma 主要用于源文件中以创建库。如果链接程序无法解析弱符号,它并不生成错误消息。
C$PRAGMA WEAK (name1 [=name2]) |
WEAK (name1) 将 name1 定义为弱符号。如果链接程序没有找到 name1 的定义,它不会生成错误消息。
WEAK (name1=name2) 将 name1 定义为弱符号以及 name2 的别名。
如果程序调用 name1,但没有对其进行定义,那么链接程序将使用库中的定义。但是,如果程序定义了自己的 name1 版本,那么将采用程序的定义,而不是使用库中 name1 的弱全局定义。如果程序直接调用 name2,则将使用库中的定义;重复的 name2 定义将导致错误。有关更多信息,请参见 Solaris《链接程序和库指南》。
OPT 指令设置子程序的优化级别,这将覆盖编译命令行中指定的级别。该指令必须紧挨在目标子程序前面出现,并且仅应用于该子程序。例如:
C$PRAGMA SUN OPT=2 SUBROUTINE smart(a,b,c,d,e) ...etc |
在使用指定 -O4 的 f95 命令编译以上内容时,该指令将覆盖此级别,并以 -O2 级别编译子例程。 除非该例程后面另有一个指令,否则下一个子程序将以 -O4 级别编译。
还必须使用 -xmaxopt[=n] 选项编译例程以便识别该指令。此编译器选项为 PRAGMA OPT 指令指定最大的优化值:如果 PRAGMA OPT 指定的优化级别大于 -xmaxopt 级别,则使用 -xmaxopt 级别。
NOMEMDEP 指令要求您在 C$PRAGMA 后面指定 SUN。
此指令必须紧挨在 DO 循环前面出现。它向优化器断言,在循环的迭代中没有用来禁止并行化的基于内存的依赖性。要求使用 -parallel 或 -explicitpar 选项。
PIPELOOP=n 指令要求您在 C$PRAGMA 后面指定 SUN。
此指令必须紧挨在 DO 循环前面出现。n 是正整数常量或零,它向优化器断言循环迭代之间是否存在依赖性。值零表示循环中没有迭代间的(即循环带有的)依赖性,优化器可以对循环执行任意管道处理。正值 n 表示,循环的第 I 次迭代与第 (I-n) 次迭代之间存在依赖性,每次最多只能对 n 个迭代进行管道处理。
C 我们知道在使用 K 值时, C 迭代间不能存在依赖性(例如 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 |
有关优化的更多信息,请参见《Fortran 编程指南》。
-xprefetch 选项标志 (3.4.163 –xprefetch[ =a[,a]]) 可启用一组 PREFETCH 指令,这些指令建议编译器为指定数据元素(支持预取的处理器上)生成预取指令。
C$PRAGMA SUN_PREFETCH_READ_ONCE(name) C$PRAGMA SUN_PREFETCH_READ_MANY(name) C$PRAGMA SUN_PREFETCH_WRITE_ONCE(name) C$PRAGMA SUN_PREFETCH_WRITE_MANY(name) |
有关预取指令的详细信息,另请参见《C 用户指南》或《SPARC Architecture Manual, Version 9》。
ASSUME 指令向编译器提供有关程序中某些点的条件的提示。这些断言可以帮助编译器设定其优化策略。程序员也可以在执行过程中使用这些指令检查程序的有效性。ASSUME 有两种格式。
“点断言”ASSUME 的语法是:
C$PRAGMA ASSUME (expression [,probability]) |
另外,“范围断言”ASSUME 的语法是:
C$PRAGMA BEGIN ASSUME [expression [, probability) 语句块 C$PRAGMA END ASSUME |
请使用点断言格式来声明编译器可在程序中的该点采用的条件。而使用范围断言格式来声明在语句封闭范围内有效的条件。范围断言中的 BEGIN 和 END 对必须正确嵌套。
必需的 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 时比不使用时运行得要快。
C$PRAGMA BEGIN ASSUME(__tripcount().GE.10000,1) !! a big loop do i = j, n a(i) = a(j) + 1 end do C$PRAGMA END ASSUME |
有两个内函数专用于 ASSUME 指令的表达式子句。(请注意,它们的名称前面有两个下划线。)
__branchexp() |
用于紧挨在分支转移语句(带有布尔控制表达式)前面的点断言。它与控制分支转移语句的布尔表达式生成相同的结果。 |
__tripcount() |
生成紧跟在指令后面的或指令所包含的循环的行程计数。在用于点断言时,指令后面的语句必须位于 DO 的第一行。在用于范围断言时,它应用于最外层的封闭循环。 |
在将来的版本中,特殊内函数的列表可能会扩展。
可与 -xassume_control 编译器选项结合使用。(请参见3.4.114 –xassume_control[ =keywords])例如,在使用 -xassume_control=check 进行编译时,如果行程计数变为小于 10,000,则上述示例将生成一条警告。
如果使用 -xassume_control=retrospective 进行编译,则在程序终止时会生成一个摘要报告,指出所有断言是真还是假。有关 -xassume_control 的详细信息,请参见 f95 手册页。
另一个示例:
C$PRAGMA ASSUME(__tripcount.GT.0,1) do i=n0, nx |
如果使用 -xassume_control=check 编译上述示例,则在由于行程计数为零或负数而没有执行循环时,将会发出一条运行时警告。
并行化指令显式地请求编译器尝试并行处理该指令后面的 DO 循环或代码区域。其语法与一般指令不同。只有在使用 -openmp、-parallel 或 -explicitpar 编译选项时,才能识别并行化指令。有关 Fortran 并行化的详细信息,请参见《OpenMP API 用户指南》和《Fortran 编程指南》。
Fortran 编译器支持 OpenMP 2.5 共享内存并行化模型。传统的 Sun 和 Cray 并行化指令现已过时,不应再使用它们。
Fortran 95 编译器将 OpenMP Fortran 共享内存多处理 API 识别为首选的并行编程模型。该 API 是由 OpenMP 体系结构审查委员会 (http://www.openmp.org) 指定的。
要启用 OpenMP 指令,您必须使用命令行选项 -xopenmp 进行编译。(请参见3.4.155 –xopenmp[={ parallel|noopt|none}]。)
有关 f95 接受的 OpenMP 指令的更多信息,请参见《OpenMP API 用户指南》。
传统的 Sun 和 Cray 风格的并行化指令现已过时。编译器仍能识别这些指令,但在以后的 Sun Studio 发行版中可能会有所变化。首选使用 OpenMP 并行化 API。有关如何从传统的 Sun/Cray 指令迁移到 OpenMP 模型的信息,请参见《OpenMP API 用户指南》。
Sun 风格的并行化指令是 -parallel 和 -explicitpar 的缺省设置。Sun 指令具有指令标记 $PAR。
Cray 风格的并行化指令具有标记 MIC$,这些指令可使用 -mp=cray 编译器选项启用。 Sun 风格和 Cray 风格的类似指令,其解释是不同的。有关详细信息,请参见《Fortran 编程指南》中有关并行化的一章。有关将传统的 Sun/Cray 并行化指令转换为 OpenMP 指令的指导原则,另请参见《OpenMP API 用户指南》。
请注意,在 x86 Solaris 和 Linux 平台上只有 OpenMP 指令可用于并行化。
Sun/Cray 并行化指令使用以下语法:
第一个字符必须在第一列中。
第一个字符可以是以下任一字符:c、C、* 或 !。
后四个字符可以是大写或小写的 $PAR(Sun 风格)或 MIC$(Cray 风格),字符之间没有空格。
然后是指令关键字和限定符,它们之间用空格分隔。显式并行化指令关键字有:
TASKCOMMON、DOALL、DOSERIAL 和 DOSERIAL*
每个并行化指令都有自己的一组可选限定符(跟在关键字后面)。
示例:使用共享变量指定一个循环:
C$PAR DOALL SHARED(yvalue) Sun 风格 CMIC$ DOALL SHARED(yvalue) Cray 风格 |
Fortran 95 编译器提供一个 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 95 include 文件 'system.inc' 为这些例程提供了显式接口定义。
include ’system.inc’ integer(4) mypid mypid = getpid() print *, mypid |
通过在调用 Fortran 库中例程的程序单元中包含 system.inc,可以自动定义接口,并帮助编译器诊断类型不匹配的问题。(有关更多信息,请参见《Fortran 库参考》。)
下面几节提供了一些高效使用 Fortran 95 编译器的建议方法。下一章中给出了完整的编译器选项参考。
某些编译器标志允许用户使用一组特定的硬件平台选项来调节代码的生成。编译器的 -dryrun 选项可用来确定本机处理程序:
<sparc>%f95 -dryrun -xtarget=native ### command line files and options (expanded): ### -dryrun -xarch=v8plusb -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 |
可通过设置 FFLAGS 或 OPTIONS 变量来指定选项。
可以在命令行中显式地使用 FFLAGS 或 OPTIONS。在使用 make 的隐式编译规则时,make 程序会自动使用 FFLAGS。
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 95 模块文件)扩展名的文件。有关详细信息,请参见《Fortran 编程指南》和 Fortran 95 自述文件。
编译可能需要使用大量内存。这取决于选定的优化级别以及所编译文件的大小和复杂性。在 SPARC 平台上,如果优化器内存不足,它将尝试通过在较低的优化级别上重试当前过程来进行恢复,并以命令行上 -On 选项指定的原始级别继续执行后续例程。
运行编译器的处理器应该至少具有 64 兆字节内存;建议使用 256 兆字节内存。此外还应该分配足够的交换空间。最低为 200 MB;建议为 300 MB。
内存使用情况取决于每个过程的大小、优化级别、为虚拟内存设置的限制、磁盘交换文件的大小以及各种其他参数。
在编译包含多个例程的单个源文件时,可能会出现编译器内存或交换空间不足的情况。
如果编译器内存不足,请尝试降低优化级别,或者使用 fsplit(1) 将多例程的源文件分成多个文件,使每个文件包含一个例程。
SunOSTM 操作系统命令 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 |
使用 mkfile(1M) 和 swap(1M) 可增加工作站上交换空间的大小。您必须成为超级用户才能执行此操作。mkfile 创建一个特定大小的文件,而 swap -a 将该文件添加到系统交换空间中:
demo# mkfile -v 90m /home/swapfile /home/swapfile 94317840 bytes demo# /usr/sbin/swap -a /home/swapfile |
以 -O3 或更高的优化级别编译非常大的例程时,可能需要额外的内存,这可能会降低编译时性能。您可以通过限制单个进程的可用虚拟内存量来控制这种情况。
在 sh shell 中,请使用 ulimit 命令。请参见 sh(1)。
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 的 limit 或 ulimit 命令取消该限制。
对于 csh,请使用:
demo% limit datasize unlimited |
对于 sh 或 ksh,请使用:
demo$ ulimit -d unlimited |
有关更多信息,请参见《Solaris(64 位)开发者指南》。