详细内容见 《GNU make》 11 Using make to Update Archive Files 章节。
库文件是包含称为成员的命名子文件的文件;它们与程序ar一起维护,它们的主要用途是作为链接的子例程库。
一、存档成员作为目标
存档文件的单个成员可以在 make 中用作目标或先决条件。您可以在归档文件archive中指定名为member的成员,如下所示:
archive(member)
此构造只在目标和先决条件中可用,在配方中不可用!在配方中可能使用的大多数程序不支持此语法,并且不能直接对归档成员执行操作。只有ar和其他专门设计用于操作档案的程序才能做到这一点。因此,更新存档成员目标的有效配方可能必须使用ar。例如,此规则表示通过复制文件 hack.o 在存档中创建成员 hack.o:
foolib(hack.o) : hack.o
ar cr foolib hack.o
实际上,几乎所有的存档成员目标都以这种方式更新,并且有一个隐式规则可以为您做这件事。请注意:如果归档文件不存在,则需要 ar 的 ‘c’ 标志。
要在同一个归档文件中指定多个成员,可以将所有成员名写在括号之间。例如:
foolib(hack.o kludge.o)
相当于:
foolib(hack.o) foolib(kludge.o)
您还可以在归档成员引用中使用shell风格的通配符。例如,‘foolib(*.o)’ 扩展到名称以 ‘.o’ 结尾的 foolib 存档的所有现有成员;也许是 ‘foolib(hack.o) foolib(kludge.o)’。
二、存档成员目标的隐式规则
回想一下,看起来像 a(m) 的目标代表存档文件 a 中名为 m 的成员。
当 make 为这样的目标寻找隐式规则时,作为一个特殊特性,它考虑匹配 (m) 的隐式规则,以及匹配实际目标 a(m) 的隐式规则。
这导致匹配一个特殊的规则,其目标是 (%)。该规则通过将文件m复制到归档文件中来更新目标 a(m)。例如,它将通过将文件 bar.o 作为名为 bar.o 的成员复制到存档 foo.a 中来更新存档成员目标 foo.a(bar.o)。
当这个规则与其他规则捆绑在一起时,结果是非常强大的。因此,当文件 bar.c 存在时,‘make “foo.a(bar.o)”’(需要引号来保护 ‘(’ 和 ‘)’ 不被shell特别解释)就足以运行下面的配方,即使没有 makefile:
cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -f bar.o
这里 bar.o 将文件 make 想象成一个中间文件。
像这样的隐式规则是使用自动变量 ‘$%’ 编写的。
归档文件中的归档成员名不能包含目录名,但在makefile中假装包含目录名可能很有用。如果编写存档成员目标 foo.a(dir/file.o),则 make 将使用此配方执行自动更新:
ar r foo.a dir/file.o
它的作用是将文件 file dir/file.o 复制到名为 file.o 的成员中。在这种用法中,自动变量 %D 和 %F 可能是有用的。
1、更新档案符号目录
作为库使用的归档文件通常包含一个名为 __.SYMDEF
的特殊成员,该成员包含由所有其他成员定义的外部符号名的目录。在您更新任何其他成员之后,您需要更新 __.SYMDEF
,以便它能够正确地总结其他成员。这是通过运行ranlib程序来完成的:
ranlib archivefile
通常,您将把这个命令放在存档文件的规则中,并使存档文件的所有成员成为该规则的先决条件。例如,
libfoo.a: libfoo.a(x.o) libfoo.a(y.o) …
ranlib libfoo.a
这样做的效果是更新存档成员 x.o、y.o 等,然后通过运行ranlib更新符号目录成员 __.SYMDEF
。这里没有显示更新成员的规则;最可能的情况是,您可以省略它们,并使用隐式规则将文件复制到存档中,如前一节所述。
这在使用 GNU ar 程序时是不必要的,它会自动更新 __.SYMDEF
成员。
三、使用档案的危险
在使用并行执行(-j 开关)和归档时要小心,这是很重要的。如果多个ar命令同时在同一个归档文件上运行,它们将不会知道彼此,并可能破坏文件。
将来的 make 版本可能会提供一种机制,通过序列化在同一存档文件上操作的所有菜谱来避免这个问题。但就目前而言,您必须编写makefile以以其他方式避免这个问题,或者不使用 -j。
四、存档文件的后缀规则
您可以编写一种特殊的后缀规则来处理存档文件。存档后缀规则在 GNU make 中已经过时,因为存档的模式规则是一种更通用的机制。但它们被保留是为了与其他 make 相容。
要为归档文件编写后缀规则,只需使用目标后缀 ‘.a’(存档文件通常使用的后缀)编写后缀规则。例如,下面是从C源文件更新库存档的老式后缀规则:
.c.a:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
这就像您已经编写了模式规则一样:
(%.o): %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
实际上,这正是 make 在看到以 ‘.a’ 为目标后缀的后缀规则时所执行的操作。任何双后缀规则 ‘.x.a’ 都被转换为具有目标模式 ‘(%.o)’ 和先决模式 ‘%.x’ 的模式规则。
由于您可能希望使用 ‘.a’ 作为某种其他类型的文件的后缀,因此 make 也要以正常方式将存档后缀规则转换为模式规则。因此,双后缀规则 ‘.x.a’ 产生两个模式规则:‘(%.o): %.x’ 和 ‘%.a: %.x’。