编译源代码#

构建过程的第一步是编译源代码。此步骤的输出通常称为目标代码——一组由人类可读的源代码生成的计算机指令。不同的编译器会从相同的源代码生成不同的目标代码,命名约定也不同。

结果:

  • If you use a particular compiler for one source file, you need to use that same compiler (or a compatible one) for all other pieces. After all, a program may be built from many different source files and the compiled pieces have to cooperate.

  • 每个源文件都将被编译并将结果存储在扩展名为 .o.obj 的文件中。这些目标文件是下一步的输入:链接过程。

Compilers are complex pieces of software: they have to understand the language in much more detail and depth than the average programmer. They also need to understand the inner workings of the computer. And then, over the years they have been extended with numerous options to customise the compilation process and the final program that will be built.

But the basics are simple enough. Take the gfortran compiler, part of the GNU compiler collection. To compile a simple program like the one above, that consists of one source file, you run the following command, assuming the source code is stored in the file “hello.f90”:

$ gfortran -c hello.f90

这会产生一个文件 hello.o(因为 gfortran 编译器使用 .o 作为目标文件的扩展名)。

选项 -c 表示:只编译源文件。如果你不考虑它,那么编译器的默认操作是编译源文件并启动链接器以构建实际的可执行程序。命令:

$ gfortran hello.f90

生成一个可执行文件,Linux 上的 a.out 或 Windows 上的 a.exe

一些备注:

  • 编译器可能会报错源文件的内容,如果它发现有问题 —— 例如错字或未知关键字。在这种情况下,编译过程会中断,你将无法获得目标文件或可执行程序。例如,如果 program 这个词被无意中输入为 prgoram

$ gfortran hello3.f90
hello.f90:1:0:

    1 | prgoram hello
      |
Error: Unclassifiable statement at (1)
hello3.f90:3:17:

    3 | end program hello
      |                 1
Error: Syntax error in END PROGRAM statement at (1)
f951: Error: Unexpected end of file in 'hello.f90'

使用此编译报告,你可以更正源代码并重试。

  • 没有 -c 的步骤只有在源文件包含主程序时才能成功——以 Fortran 中的 program 语句为特征。否则,链接步骤将抱怨缺少 symbol,类似于以下内容:

$ gfortran hello2.f90
/usr/lib/../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

文件hello2.f90 与文件 hello.f90 几乎相同,只是关键字program已被关键字subroutine替换。

编译器的上述输出示例因编译器和运行平台而异。这些示例来自在 Windows 上的 Cygwin 环境中运行的 gfortran 编译器。

编译器支持的选项也不同,但总的来说:

  • 优化代码的选项——导致更快的程序或更小的内存占用;

  • 检查源代码的选项——例如检查变量在被赋予值之前是否未被使用,或者检查是否使用了语言的某些扩展;

  • 包含或模块文件位置的选项,见下文;

  • 调试选项。