The next example shows a program that is divided into two files: a project file and a unit file. The project file, which you can save as Greeting.dpr, looks like this:
program
Greeting;
{$APPTYPE
CONSOLE}
uses
Unit1;
begin
PrintMessage('Hello World!');
end.
The first line declares a program called Greeting, which, once again, is a console application. The uses Unit1; clause tells the compiler that Greeting includes a unit called Unit1. Finally, the program calls the PrintMessage procedure, passing to it the string “Hello World!” Where does the PrintMessage procedure come from. It’s defined in Unit1. Here’s the source code for Unit1, which you can save in a file called Unit1.pas:
unit
Unit1;
interface
procedure
PrintMessage(msg: string);
implementation
procedure
PrintMessage(msg: string);
begin
Writeln(msg);
end;
end.
Unit1 defines a procedure called PrintMessage that takes a single string as an argument and sends the string to the standard output. (In Pascal, routines that do not return a value are called procedures. Routines that return a value are called functions.) Notice that PrintMessage is declared twice in Unit1. The first declaration, under the reserved word
interface,
makes PrintMessage available to other modules (such as Greeting)
that use Unit1. The second declaration, under the reserved word implementation,
actually defines PrintMessage.
You can now compile Greeting from the command line by entering
On
Delphi: DCC32 Greeting
On
Kylix: dcc Greeting
There’s no need to include Unit1 as a command-line argument. When the compiler processes Greeting.dpr, it automatically looks for unit files that the Greeting program depends on. The resulting executable does the same thing as our first example: it prints the message “Hello world!”.
Program organization: Overview
Other files used to build applications
下面的范例展示了一个程序分布到两个文件中的情形:一个工程文件和一个单元文件。可以将工程文件保存为Greeting.dpr,源代码如下:
program
Greeting;
{$APPTYPE
CONSOLE}
uses
Unit1;
begin
PrintMessage('Hello World!');
end.
第一行声明了一个名为Greeting的程序,与前一个范例相同,这也是一个控制台应用程序。编译器通过子句“uses Unit1; ”得知Greeting包含了一个名为Unit1的单元。最后,程序调用PrintMessage过程,将字符串“Hello World!”传递给PrintMessage过程的出处,也就是定义该过程的单元Unit1。下面是Unit1的源代码,可以将该单元保存到文件Unit1.pas。
unit
Unit1;
interface
procedure
PrintMessage(msg: string);
implementation
procedure
PrintMessage(msg: string);
begin
Writeln(msg);
end;
end.
单元Unit1定义了一个名为PrintMessage的过程,该过程接受一个作为参数的单独字符串并发送该字符串到标准输出设备。(在Pascal中,不返回值的例程叫做过程,返回值的例程叫做函数。)可以看到,PrintMessage过程在单元Unit1中声明了两次。第一个声明是在保留字interface之后,意义在于使得PrintMessage过程对于那些通过uses子句引用了单元Unit1的模块(如Greeting)是可用的。第二个声明是在保留字implemetation之后,实际上是PrintMessage的定义。
可以以如下的命令行对Greeting进行编译:
对于Delphi,命令行: DCC32
Greeting
对于Kylix,命令行: dcc
Greeting
在编译命的参数中中不需要包括Unit1。当编译Greeting.dpr时,编译器将自动查找Greeting程序必需的单元文件。编译的结果是一个可执行文件,与前一个范例相似,运行时将显示信息“Hello World!”。
编者注
声明和定义
声明(declaration)和定义(definition)在某些情况下是等同的,例如常量,声明也可以看作是定义,因此常量声明和常量定义是没有区别的。而对于过程、函数以及类的方法等,则声明和定义是有区别的。简单地说,声明的意义在于确定了声明内容的可见度,而定义可以理解为具体实现,并且有时也决定其内容的可见度。因此可以认为定义同时具有声明的特性。在当前范例的单元Unit1中,如果没有interface部分(接口节)的声明,那么Greeting将不能被成功编译,但此时单元Unit1完整无误并且可以被成功编译。而如果是没有implemetation部分(实现节)的定义,那么单元Unit1是不完整的,当然也无法成功编译,而此时Greeting也无法成功编译。
综上所述,可以认为声明是在一定范围内公开的,而实现是单元内部的;声明一般出现在接口节(当单元实现节中的过程定义或函数定义在接口节没有相应的声明时,那么实现节中的定义本身也作为对单元内部的过程声明或函数声明),定义一定出现在实现节。
单元间的依赖关系
无论是通过Borland集成开发环境还是命令行,向编译器发送的命令只需要提供主程序文件或工程文的文件名,编译器为每个模块(程序或单元)自动引用标准单元System,在此基础上根据模块中的uses子句查必需的单元并根据需要对其进行编译。以此类推,编译器将会根据需要对程序必需的每个单元进行编译,最后连接并建立目标应用程序。