[转]使用makefile更新静态库文件

静态库文件也称为“文档文件”,它是一些 .o 文件的集合。在 Linux Unix )中使用工具“ ar ”对它进行维护管理。它所包含的成员( member )就是若干 .o 文件。

1       库成员作为目标

一个静态库通常由多个成员( .o 文件)组成。 静态库文件的成员可独立被作为一个规则的目标,将库成员作为目标时需要按照如下的格式来书写:

 

     ARCHIVE(MEMBER)

 

注意,这种书写方式只能出现在规则的目标和依赖文件中,不能出现在规则的命令行中! 因为,绝大多数命令不能支持这种表示的语法,它们不能直接对库的成员进行操作。 这种表达式在规则的目标或者依赖中,它表示库“ ARCHIVE ”的成员“ MEMBER ”。含有这种表达方式规则的命令行只能是“ ar ”命令或者其它可以对库成员进行操作的命令。 例如:下边规则创建了库“ foolib ”,并将“ hack.o ”成员纳入到库:

 

foolib(hack.o) : hack.o

     ar cr foolib hack.o

 

实际上,这个规则实现对库的所有成员的更新,其过程使用了隐含规则来创建 .o 文件。另外需要注意工具“ ar ”的使用。

如果规则中需要同时指定一个库中的多个成员,可以将多个成员罗列在括号内,下边那样:

 

foolib(hack.o kludge.o)

 

它就等价于:

 

foolib(hack.o) foolib(kludge.o)

 

在描述的多个成员时也可以使用 shell 的通配符。例如:“ foolib(*.o) ”,它代表库文件“ foolib ”的所有 .o 成员。

2       静态库的更新

上一节已经讲述了规则中形如“ A(M) ”目标的含义,它表示规则的目标是静态库“ A ”的成员“ M ”。在 make 为这样一个目标搜索隐含规则时,对于满足“ (M) ”的隐含规则,同样也被认为是满足“ A(M) ”这个目标的隐含规则。

这样就出现了一个特殊的模式规则,它的目标模式是“ (%) ”。这个特殊的规则用来更新目标“ A(M) ”,规则将文件“ M ”拷贝到库“ A ”中,如果静态库文件“ A ”不存在,则会创建这个库文件。例如:如果一个目标为“ foo.a(bar.o) ”,那么规则将完成:首先使用隐含规则生成“ bar.o ”文件,之后将“ bar.o ”加入到库“ foo.a ”中。那么“ bar.o ”就作为库文件“ foo.a ”的一个成员(当然如果“ foo.a ”不存在,就会被创建件。此特殊规则的命令行一般都是“ ar ”命令)。

这个特殊的规则可以和其它的隐含规则一起构成一个隐含规则链。因此我们可以直接在命令行中执行“ make foo.a(bar.o) ’”(注意“ foo.a(bar.o) ”作为命令行选项,需要使用引号,否则 shell 会将“ ( ”作为特殊字符对待),只要当前目录下存在“ bar.c ”这个文件,就会执行如下命令:

 

cc -c bar.c -o bar.o

ar r foo.a bar.o

rm -f bar.o

 

我们注意到了“ bar.o ”时被作为中间过程文件处理的。参考 make 的隐含规则链 一节。需要说明的是,包含上述命令的规则,在规则的命令行中使用自动化变量“ $% ”来代替“ bar.o ”。参考 自动化变量 一小节

一个静态库(文档文件)中,其所有的成员名是不包含目录描述的。就是说对于静态库,当使用“ nm ”命令查看其成员时,能够获得的信息只是静态库所包含的成员(一系列 .o 文件,文件名中并没有包含目录)。不能得知静态库在创建时它的每一个成员所在的目录情况。但我们在 Makefile 中,采用“ A(M) ”格式的目标,书写建立(重建或者更新)静态库的规则时,可以指定它的成员来源于那个目录。就是说我们可以对它的成员使用完整路径的文件名进行说明。 Make 在处理这样一个目标“ foo.a(dir/file.o) ”时,可能会执行如下的命令:

 

ar r foo.a dir/file.o

 

和上边的例子类似,它是将指定目录下的 .o 文件纳入到库文件中,作为静态库的一个成员。 Makefile 中出现类似的目标时,隐含规则的命令行中可能就需要使用自动化变量“ %D ”和“ %F ”。

2.1        更新静态库的符号索引表

本小节的内容相对简单。前边提到过,静态库文件可以使用工具“ ar ”来创建、维护。当需要给静态库增建一个成员时(加入一个 .o 文件到静态库中),“ ar ”可以直接需要增加的 .o 文件拷贝到静态库中。这样直接拷贝可能存在一个问题。在使用这个库进行连接生成可执行文件时。“ ld ”却提示了错误,可能是:主程序使用了之前加入到库中的 .o 文件中定义的一个函数(全局变量),但连接程序却告诉你无法找到这个函数(或者变量)。

这个问题的原因就是:之前我们将编译完成的 .o 文件加入到库中,但是并没有更新库的符号表。连接程序进行连接时,在静态库的符号索引表中无法定位刚才加入的 .o 文件中定义的函数或者变量。如果需要让加入的所有 .o 文件中定义的函数(变量)有效,需要使用另外一个工具“ ranlib ”来对静态库的符号索引表进行更新。

我们所使用到的静态库(文档文件)中,存在这样一个特殊的成员,它的名字是“ __.SYMDEF ”。它包含了静态库中所有成员所定义的有效符号(函数名、变量名)。因此,当为库增加了一个成员时,相应的就需要更新成员“ __.SYMDEF ”,否则所增加的成员中定义的所有的符号将无法被连接程序定位。完成更新的命令是:

 

ranlib ARCHIVEFILE

 

通常在 Makefile 中我们可以这样来实现:

 

libfoo.a: libfoo.a(x.o) libfoo.a(y.o) ...

     ranlib libfoo.a

 

它所实现的是:更新静态库成员“ x.o ”和“ y.o ”之后,同时对静态库的成员“ __.SYMDEF ”进行更新(更新库的符号索引表)。

如果我们使用 GNU ar 工具来维护、管理静态库,我们就不需要考虑这一步。 GNU ar 本身已经提供了在创建库时同时更新符号索引表的功能(这是默认行为,我们也可以通过某些命令行选项来控制。大家可以参考 GNU ar 工具的 man 手册)。

3       make 静态库的注意事项

make 静态库(文档文件)时,特别需要注意的一点是: make 的并行执行 (执行 make 时使用“ -j ”选项)可能会给更新静态库所有影响。 因为,在同一时刻,当多个“ ar ”命令同时维护相同的静态库时,会造成静态库的损坏,甚至导致此静态库不可用。

可能在后期的 make 版本中,会提供一种在并行执行时防止同时多个“ ar ”命令对同一静态库的操作的机制。但是就目前的版本来说,这个问题是存在的。因此要求我们在书写 Makefile 时,加入控制策略,来避免 make 并发执行时多个“ ar ”命令同时操作同一个静态库文件。或者不使用 make 并发执行功能。

4       静态库的后缀规则

静态库的后缀规则属于后缀规则的特殊应用,后缀规则在目前版本的 GNU make 中已经使用模式规则替代。 但目前版本 make 同样支持旧风格的后缀规则,主要是为了兼容老版本的 make 。对于静态库也可以使用它的后缀规则。目标后缀需要是“ .a ”(在 Linux Unix )中、静态库的后缀为 .a )。例如这样一个后缀规则:

.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

 

对于老风格的后缀规则,它的目标是“ .a.c ”,当转换为模式规则时。后缀规则中的“ .a ”被作为模式规则的目标文件的后缀(目标文件就是 N.a );“ .c ”被作为了模式规则依赖文件的后缀(依赖文件就是 N.c )。

存在这样一种情况:可能一个不是静态库的文件使用了后缀 .a 。那么 make 也会按照正常的方式静态库的后缀规则转换成为一个模式规则。因此一个双后缀规则的目标“ .x .a ”, make 转换时将会产生两个模式规则:“ (%.o): %.x 和“ %.a: %.x ”。具体的转换过程可参考 后缀规则 一节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值