The order
in which units appear in the uses clause determines the order of their
initialization (see The
initialization section)and affects the way identifiers are located by the
compiler. If two units declare a variable, constant, type, procedure, or
function with the same name, the compiler uses the one from the unit listed
last in the uses clause. (To access the identifier from the other unit,
you would have to add a qualifier: UnitName.Identifier.)
A uses
clause need include only units used directly by the program or unit in which
the clause appears. That is, if unit A references constants, types, variables,
procedures, or functions that are declared in unit B, then A must use B
explicitly. If B in turn references identifiers from unit C, then A is
indirectly dependent on C; in this case, C needn’t be included in a uses
clause in A, but the compiler must still be able to find both B and C in order
to process A.
The example below illustrates indirect dependency.
program
Prog;
uses
Unit2;
const
a = b;
...
unit
Unit2;
interface
uses
Unit1;
const
b = c;
...
unit
Unit1;
interface
const
c = 1;
...
In this example, Prog depends directly on Unit2, which depends directly on Unit1. Hence Prog is indirectly dependent on Unit1. Because Unit1 does not appear in Prog’s uses clause, identifiers declared in Unit1 are not available to Prog.
To compile a client module, the
compiler needs to locate all units that the client depends on, directly or
indirectly. Unless the source code for these units has changed, however, the
compiler needs only their .dcu (Windows) or .dcu/.dpu (Linux) files, not their
source (.pas) files.
When changes are made in the interface section of a unit, other units that depend on it must be recompiled. But when changes are made only in the implementation or other sections of a unit, dependent units don’t have to be recompiled. The compiler tracks these dependencies automatically and recompiles units only when necessary.
Program structure and syntax:
Overview
Unit structure and syntax: Overview
Unit references and
the uses clause
Multiple and indirect
unit references
Unit references and the uses clause
单元在uses子句中出现的位置决定了其初始化节执行的顺序(初始化节)并且对编译器定位该单元中标识符的方式有影响。如果两个单元声明了同名的变量、常量、类型、过程或函数,那么编译器将根据uses子句中的单元列表从后向前查找,也就是说,列于uses子句中靠后位置的单元,其标识符优先被编译器认可。(要访问其他单元的标识符,可以在标识符前加上限定词,例如:UnitName.Identifier。这样就可以消除编译器自动匹配可能带来的影响。)
uses子句中只需要包括其直接使用的单元。对于程序(program),只需要包括其语句块中直接使用的标识符所在的单元。对于单元,在其接口节使用的标识符所在的单元需要列在其接口节的uses子句中,此时其实现节也可以使用被引用的单元中的公共实体;在其实现节使用的标识符所在的单元需要列在其实现节的uses子句中,此时其接口节中不能使用被引用单元的公共实体。例如,如果单元A引用了在单元B中声明的常量、类型、变量、过程或函数,那么单元A必需通过uses子句显式地使用单元B。如果此时单元B又引用了单元C,那么称单元A间接引用了单元C。在此情况下,单元C不必包括在单元A的uses子句中,而为了成功编译单元A,编译器仍必需能找到单元B和单元C。
下面给出的例子说明了单元的间接依赖关系:
program
Prog;
uses
Unit2;
const
a = b;
...
unit
Unit2;
interface
uses
Unit1;
const
b = c;
...
unit
Unit1;
interface
const
c = 1;
...
在本例中,Prog直接依赖Unit2,Unit2直接依赖Unit1。因此Prog间接依赖Unit1。由于Unit1没有出现在Prog的uses子句中,因此Unit1的标识符对于Prog是不可用的。`
要编译一个客户模块,编译器需要定位该客户依赖的所有单元,包括直接依赖和间接依赖。除非这些单元的源代码发生了改变,否则编译器只需要相应的.dcu文件(Windows)或者.dcu/.dpu文件(Linux)文件,而不需要它们的源(.pas)文件。
在单元的接口节发生改变时,依赖该单元的所有单元必需被重编译。而当单元的实现节或其他部分发生改变时,依赖该单元的单元不必被重编译。编译器会自动跟踪这些依赖关系,并在必要时才重编译相应的客户单元。
编者注
编译器根据uses子句自后向前搜索,是为了尽可能优先使用开发者声明的实体,因为Borland提供的单元一般都IDE自动添加到uses子句单元列表中相对靠前的位置。