Linux命令学习手册-ar
ar [-c] [-l] [-g|-o] [-s] [-v] [-C] [-T] [-z] {-h|-p|-t|-x} [-X {32|64|32_64}] ArchiveFile [File ...]
ar [-c] [-l] [-g|-o] [-s] [-v] [-C] [-T] [-z] {-m|-r [-u]} [{-a|-b|-i} PositionName] [-X {32|64|32_64}] ArchiveFile File ...
ar [-c] [-l] [-g|-o] [-s] [-v] [-C] [-T] [-z] {-d|-q} [-X {32|64|32_64}] ArchiveFile File ...
ar [-c] [-l] [-v] [-C] [-T] [-z] {-g|-o|-s|-w} [-X {32|64|32_64}] ArchiveFile
功能
ar
命令可以用来创建、修改库,也可以从库中提出单个模块。库是一单独的文件,里面包含了按照特定的结构组织起来的其它的一些文件(称做此库文件的 member
)。原始文件的内容、模式、时间戳、属主、组等属性都保留在库文件中。
描述
当我们的程序中有经常使用的模块,而且这种模块在其他程序中也会用到,这时按照软件重用的思想,我们应该将它们生成库,使得以后编程可以减少开发代码量。
选项
选项前可以有 -
字符,也可以没有。
-a PositionName
在 PositionName
参数标识的现有文件后安置指定的文件。
-b PositionName
在 PositionName
参数标识的现有文件前安置指定的文件。
-c
禁止在创建库时产生的正常消息。
-C
阻止解压缩的文件替换文件系统中同名的文件。
-d
从库中删除指定的文件。
-g
对压缩文档成员进行排序以确保用最小数量的未用空间获得最大的加载效率。在几乎所有情况下, -g
标志以压缩文档成员的逻辑链接顺序物理地安置它们。最终生成的压缩文档通常写成小格式,这样该标志可用来将大格式压缩文档转换成小格式压缩文档。包含 64 位 XCOFF 对象的压缩文档不能创建成或转换至小格式。
-h
将指定的文件的成员报头中的修改时间设置为当前日期和时间。如果不指定任何文件名称,则 ar
命令设置所有成员报头的时间戳记。此标志不能和 -z
标志一起使用。
-i PositionName
在 PositionName
参数标识的现有文件前安置指定的文件(和 -b
相同)。
-l
将临时文件置于当前(本地)目录中,而非 TMPDIR
目录中(缺省为 /tmp
)。
-m
将指定的文件移动到库中的某个其它位置。缺省情况下,它将指定的文件移动到库的末尾。使用位置标志( abi
)来指定某个其它位置。
-o
对压缩文档成员进行排序以确保用最小数量的未用空间获得最大的加载效率。在几乎所有情况下, -o
标志以压缩文档成员的逻辑链接顺序物理地安置它们。最终生成的压缩文档通常写成大格式,这样该标志可用来将小格式压缩文档转换成大格式压缩文档。
-p
将 Files
参数中指定的文件的内容或在 ArchiveFile
参数中指定的所有文件(如果您不指定任何文件)都写至标准输出。
-q
将指定的文件添加到库的末尾。另外,如果指定同一个文件两次,它可能被放入库中两次。
-r
如果指定的文件已经存在于库中,则替换它。因为指定的文件在库中占据它们替换的文件的同一个位置,位置标志没有任何附加的影响。当和 -u
标志(更新)一起使用时, -r
标志仅替换自从最后一次添加到库中以后修改的文件。 如果指定的文件不存在于库中,则 ar
命令添加它。在这种情况下,位置标志影响放置。如果不指定位置,则将新文件置于库的末尾。如果指定同一个文件两次,它可能被放入库中两次。
-s
无论 ar
命令是否修改了库内容都强制重新生成库符号表。请在库上使用 strip
命令之后,使用此标志来恢复库符号表。
-t
将库的目录写至标准输出。如果指定文件名称,则仅显示指定的那些文件。如果不指定任何文件, -t
标志列出库中的所有文件。
-T
如果压缩文档成员名称比文件系统支持的长,则允许文件名称截短。此选项无效,因为文件系统支持的名称长度等于 255
个字符的最大压缩文档成员名称。
-u
仅复制自它们最后一次复制起更改的文件(请参阅先前讨论过的 -r
标志)。
-v
将建立新库的详细的逐个文件的描述写至标准输出。当和 -t
标志一起使用时,它给出类似于 ls -l
命令给出的长列表。当和 -x
标志一起使用时,它在每个文件前加一个名称。当和 -h
标志一起使用,它列出成员名称和更新的修改时间。
-w
显示压缩文档符号表。每个符号和其中定义此符号的文件的名称一起列出。
-x
通过将指定的文件复制到当前目录来解压缩它们。这些副本和原始文件(保留在库中)具有相同的名称。如果不指定任何文件,=-x= 标志复制库中的所有文件。此过程不会更改库。
-X mode
指定 ar
应检查的目标文件的类型。 mode
必须是以下项之一:
-
32
仅处理32
位目标文件 -
64
仅处理64
位目标文件 -
32_64
处理32
位 和64
位目标文件
缺省值是处理 32
位目标文件(忽略 64
位对象)。 mode
还可以用 OBJECT_MODE
环境变量来设置。例如, OBJECT_MODE=64
使 ar
处理任何 64
位对象并忽略 32
位对象。=-X= 标志覆盖 OBJECT_MODE
变量。
-z
创建压缩文档的临时副本并对副本执行所有要求的修改。当所有操作成功完成时,压缩文档的工作副本覆盖原始副本。此标志不能和 -h
标志一起使用。
ArchiveFile
指定压缩文档文件名称;必需。
MemberName ...
各压缩文档成员的名称。
退出状态
该命令返回以下出口值:
0
成功完成。
>0
发生错误。
举例
查看 ar
的版本号
$ar -V
要创建一个库
$ar -rv libhello.a hello1.o hello2.o hello3.o hello4.o hello5.o hello6.o
输入之后,输出如下:
ar: creating libhello.a
a - hello1.o
a - hello2.o
a - hello3.o
a - hello4.o
a - hello5.o
a - hello6.o
这里,从多个用 ld
命令创建的共享模块( hello*.o
目标文件)中创建一个压缩文档库,编译并链接如何使用这个库文件本文有举例。注意这里的添加顺序。 -v
标志设置详细方式,在此方式中 ar
命令在其进行时显示进程报告,如果没有这个 v
将只显示:
ar: creating libhello.a。
创建一个库的另一个方法
$ar -qv libhello.a hello1.o hello2.o hello3.o hello4.o hello5.o hello6.o
这里,如果 libhello.a
库不存在,则此命令创建它,并将文件 hello1.o-hello6.o
的副本输入其中。如果 libhello.a
库存在,则此命令在不检查相同成员的情况下,将新的成员添加到末尾。
查看库中的所有模块
$ar -t libhello.a
输入之后,输出如下:
hello1.o
hello2.o
hello3.o
hello4.o
hello5.o
hello6.o
这样会依次列出库中所有的模块成员。显示的次序不是根据名字的,而是添加模块时候决定的。加 -v
则类似 ls -l
的长格式。
删除库中的指定模块
$ar -dv libhello.a hello3.o
输入之后输出如下:
d - hello3.o
这样会在库中删除指定的模块成员 hello3.o
,加 -v
是为了显示删除什么文件。下面用详细方式显示删除后的库文件如下:
$ar -tv libhello.a
输入之后输出如下:
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello1.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello2.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello4.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello5.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello6.o
将库中指定的模块提取出来
$ar -xv libhello.a hello1.o
输入之后,输出如下:
x - hello1.o
这样,会将库中的模块 hello1.o
释放到当前的文件夹,不会在库中删除该模块。这里实际是加 -v
选项是为了显示输出删除了那个模块。
打印成员的内容
$ar -pv libhello.a hello1.o
输入之后,输出如下:
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@(^A^@^@^@^@^@^@^@^@^@^@@^@^@^@^@^@@^@^M^@
.....由于篇幅关系,后面省略了......
这里,打印的是 hello1.o
的内容,估计我们也看不懂,如果不加 -v
选项,就不会打印第一行的了。
解压缩并重命名一个成员
$ar -p libhello.a hello1.o >hello1copy.o
此命令将成员 hello.o
复制到一个名为 hello1copy.o
的文件,实际就是一个重定向的操作。
要指定在模块的前面插入新成员
$ar -rb hello1.o libhello.a hello3.o
或
$ar -ri hello1.o libhello.a hello3.o
这样,没用 -v
所以没有输出,但会把 hello3.o
插入 libtest.a
中,并且在 hello1.o
模块前.用 -t
可以看到次序如下:
$ar -tv libhello.a
输入之后,输出如下:
rw-r--r-- 14506/1001 1488 Jul 4 14:24 2009 hello3.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello1.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello2.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello4.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello5.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello6.o
如果要插入的成员已经存在于库中,结果相当于将原来的同名模块删除,之后再插入,如下:
quietheart@ubuntu:~/libTest/hellolib/ver2obj/bak$ar -rb hello4.o libhello.a hello3.o
quietheart@ubuntu:~/libTest/hellolib/ver2obj/bak$ar -tv libhello.a
输入之后,输出如下:
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello1.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello2.o
rw-r--r-- 14506/1001 1488 Jul 4 14:25 2009 hello3.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello4.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello5.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello6.o
在这里,我们用 -v
选项会显示详细的插入信息,这里我修改了 hello3.o
的内容,如果不修改,那么始终时间是 14:23
怎么加都是。
要指定在模块的后面插入新成员
$ar -ra hello2.o libhello.a hello3.o
这里的操作和 rb
或者 ri
选项指定的在前面插入原理一样,不过插入的方向变成了在后面追加插入了。用 -v
会显示详细的插入信息。
要替换或添加新成员到库中
$ar -r libhello.a hello6.o
这样,如果 libhello.a
库中没有 hello6.o
那么就会把模块 hello6.o
添加到库的末尾,如果有的话就会替换之( 位置还是原来的位置)。
要更新一个已经更改过的成员
$ar -ru libhello.a hello3.o
这时候,仅当 hello3.o
比库中的 hello3.o
更新时或者没有在库中时才替代库中的 hello3.o
或者加入 hello3.o
.
更改库成员的顺序
$ar -mav hello4.o libhello.a hello1.o hello3.o
输入之后,输出如下:
m - hello1.o
m - hello3.o
此命令将成员 hello1.o
和 hello3.o
移动到 hello4.o
后面。当库中如果有若干模块有相同的符号定义(如函数定义),则成员的位置顺序很重要。
如果没有指定任选项,任何指定的成员将移到库的最后。也可以使用 a
, b
,或 i
任选项移动到指定的位置。检查结果如下:
$ar -tv libhello.a
输入之后,输出如下:
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello2.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello4.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello3.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello1.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello5.o
rw-r--r-- 14506/1001 1488 Jul 4 14:23 2009 hello6.o
这里,注意,发现参考资料中别人的解释和实践之后的结果不一样,那个参考资料这样说的:
$ar -v -m -a strcmp.o lib.a strcat.o strcpy.o
此命令将成员 strcat.o
和 strcpy.o
移动到紧跟在 strcmp.o
成员之后的位置。保留 strcat.o
和 strcpy.o
成员的相对顺序。换句话说,如果在移动之前 strcpy.o
成员在 strcat.o
成员之前,那么(移动后)它依旧如此。可是我运行了这个命令发现相对次序也变化了??
其它
利用库文件进行编译举例1(后面有简化)
编辑 hello1.c/h hello2.c/h hello3.c/h hello4.c/h hello5.c/h hello6.c/h
内容如下:
//hello1.h
1 int hello1();
//hello2.h-hello6.h的内容类似,不过把hello1替换成相应的hello2-hello6了.
//hello1.c
1 #include
2 #include "hello1.h"
3 int hello1()
4 {
5 printf("hello1\n");
6 }
//hello2.c-hello6.c的内容类似,不过把hello1替换成相应的hello2-hello6了.
编译生成目标文件(模块)
$gcc -c hello*.c
这样会在当前目录下面生成 hello1.o hello2.o hello3.o hello4.o hello5.o hello6.o
打成 libhello.a
库包
$ar -rv libhello.a hello*.o
这样会把所有的 .o
文件做为模块打包进 libhello.a
库中。
编辑 main.c
//main.c
1 #include
2 #include"hello1.h"
3 #include"hello3.h"
4
5 int main(int argc, char *argv[])
6 {
7 hello1();
8 hello3();
9 return 0;
10 }
建立一个子文件夹 program/
,把 hello*.h
和 main.c
移动到 program
里面并且利用刚才的库编译 main.c
:
$mkdir program;mv hello*.h program;mv main.c hello*.h;cd program
$gcc -o main main.c -L ../ -lhello
这样,在 program
中生成了 main
,编译命令的 -L
选项指定库的路径, -l
指定 ld
链接的库的名字,即 libhello.a
中的 hello
。
运行测试
$./main
输入之后,输出如下:
hello1
hello3
利用库进行编译链接举例2(对例1的简化)
过程同上例1,不同的唯一之处是:
hello*.c
中不需要包含 hello*.h
头文件,
其内容如下:
//hello1.c
1 #include
2 //#include "hello1.h"
3 int hello1()
4 {
5 printf("hello1\n");
6 }
//hello2.c-hello6.c的内容类似,不过把hello1替换成相应的hello2-hello6了.
编译运行
$gcc -o main main.c -L ../ -lhello
这样编译之后,照样能运行。
利用库进行编译链接举例3(对例3的进一步简化,这样看不到接口头文件了):
过程同上例2,不同的唯一之处是:
main.c
中不需要包含 hello*.h
头文件了(即所有文件任何地方都不需要头文件了),
其内容如下:
//main.c
1 #include
2 //#include"hello1.h"
3 //#include"hello3.h"
4
5 int main(int argc, char *argv[])
6 {
7 hello1();
8 hello3();
9 return 0;
10 }
编译运行
$gcc -o main main.c -L ../ -lhello
这样编译之后,照样能运行。