Linux ar命令

功能说明:ar命令是Linux下的归档工具,用于创建、修改和提取归档文件。它主要用于创建和管理静态库文件(.a文件),是C/C++程序开发中的重要工具。
主要功能
  • 创建新的归档文件
  • 向归档文件添加/替换文件
  • 从归档文件提取文件
  • 删除归档文件中的成员
  • 列出归档文件内容
  • 移动/重排归档文件成员
相关文件类型
  • .a - Unix/Linux静态库文件
  • .ar - 归档文件(较少使用)
  • .deb - Debian包(内部使用ar格式)
  • .obj - 目标文件(可打包)
  • .o - 目标文件(可打包)

命令语法

语法格式
ar [选项] 归档文件 成员文件...
ar [选项] 归档文件 操作 [位置成员] 成员文件...

主要操作模式

操作 说明
-r, --replace 向归档文件中添加文件,如果文件已存在则替换
-q, --quick 快速向归档文件末尾添加文件(不检查是否已存在)
-a 在指定成员之后添加新文件
-b 在指定成员之前添加新文件
-d, --delete 从归档文件中删除指定文件
-m, --move 移动归档文件中的成员位置
-p, --print 打印归档文件中指定文件的内容到标准输出
-t, --list 列出归档文件中的内容
-x, --extract 从归档文件中提取指定文件

常用选项

选项 说明
-c, --create 创建新的归档文件,不显示警告
-s, --write-index 为归档文件创建或更新符号表索引
-S 不创建符号表索引
-u, --update 只添加比归档文件中更新的文件
-v, --verbose 详细模式,显示详细信息
-V, --version 显示版本信息
--help 显示帮助信息
--target 指定目标格式(bfdname)

使用示例

1. 创建静态库 常用
示例
# 创建目标文件
gcc -c file1.c file2.c file3.c

# 创建静态库 libexample.a
ar rcs libexample.a file1.o file2.o file3.o

# 另一种写法
ar -rcs libexample.a *.o

# 查看创建的库文件
ls -la libexample.a
file libexample.a
2. 列出归档文件内容
示例
# 列出库中的所有文件
ar t libexample.a
# 输出:
# file1.o
# file2.o
# file3.o

# 详细列出(显示文件大小、时间等)
ar tv libexample.a
# 输出示例:
# rw-r--r-- 1000/1000   1240 Jan 10 10:30 2025 file1.o
# rw-r--r-- 1000/1000   2560 Jan 10 10:31 2025 file2.o
# rw-r--r-- 1000/1000   3120 Jan 10 10:32 2025 file3.o

# 查看系统库文件
ar t /usr/lib/libc.a | head -20
3. 向归档文件添加文件
示例
# 添加单个文件
ar r libexample.a file4.o

# 添加多个文件
ar r libexample.a file5.o file6.o

# 添加文件并创建索引
ar rs libexample.a file7.o

# 在指定位置添加(在file2.o之后添加)
ar ra file2.o libexample.a file8.o

# 快速添加(不检查是否已存在)
ar q libexample.a file9.o
4. 从归档文件提取文件
示例
# 提取所有文件
ar x libexample.a

# 提取特定文件
ar x libexample.a file1.o

# 提取多个文件
ar x libexample.a file1.o file2.o

# 提取到指定目录
mkdir extracted
cd extracted
ar x ../libexample.a

# 提取并保留原始时间戳
ar xv libexample.a
5. 从归档文件删除文件
# 删除单个文件
ar d libexample.a file1.o

# 删除多个文件
ar d libexample.a file2.o file3.o

# 删除后验证
ar t libexample.a
6. 移动/重排归档文件成员
# 将file3.o移动到file1.o之后
ar m libexample.a file3.o file1.o

# 将file2.o移动到开头
ar mb file1.o libexample.a file2.o

# 将file3.o移动到file2.o之后
ar ma file2.o libexample.a file3.o

# 查看重排结果
ar t libexample.a
7. 查看归档文件内容
# 打印文件内容到标准输出
ar p libexample.a file1.o | head -20

# 保存特定文件内容
ar p libexample.a file1.o > file1_extracted.o

# 打印多个文件
ar p libexample.a file1.o file2.o | od -c | head -20
8. 更新归档文件(只添加新文件)
# 只添加比归档文件中更新的文件
ar ru libexample.a *.o

# 创建新版本的文件
touch file1.c
gcc -c file1.c
ar ru libexample.a file1.o

# 查看哪些文件被更新
ar ruv libexample.a *.o

归档文件结构

ar归档文件由文件头和多个成员文件组成:

归档文件头 (8字节): "!<arch>\n"
每个成员文件头 (60字节):
文件名 (16字节)
修改时间戳 (12字节)
所有者ID (6字节)
组ID (6字节)
文件模式 (8字节)
文件大小 (10字节)
结束符 (2字节, "`\n")
成员文件数据: 实际文件内容
符号表索引 (可选): 用于快速链接
查看归档文件原始内容
# 以十六进制查看文件头
head -c 100 libexample.a | od -c | head -20

# 查看成员文件头
ar tv libexample.a

# 使用strings查看可读字符串
strings libexample.a | head -20

实际应用场景

场景1:创建和使用静态库
#!/bin/bash
# 创建和使用静态库的完整示例

# 1. 创建源文件
cat > math_utils.c << 'EOF'
#include "math_utils.h"
double add(double a, double b) { return a + b; }
double multiply(double a, double b) { return a * b; }
EOF

cat > math_utils.h << 'EOF'
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
double add(double a, double b);
double multiply(double a, double b);
#endif
EOF

cat > main.c << 'EOF'
#include 
#include "math_utils.h"
int main() {
    printf("5 + 3 = %.2f\n", add(5, 3));
    printf("5 * 3 = %.2f\n", multiply(5, 3));
    return 0;
}
EOF

# 2. 编译为目标文件
gcc -c math_utils.c -o math_utils.o

# 3. 创建静态库
ar rcs libmathutils.a math_utils.o

# 4. 编译程序并链接静态库
gcc main.c -L. -lmathutils -o calculator

# 5. 运行程序
./calculator

# 6. 查看库信息
echo "=== 库文件信息 ==="
file libmathutils.a
ar t libmathutils.a
nm libmathutils.a
场景2:更新和管理库文件
#!/bin/bash
# 库文件管理脚本

LIBRARY="libproject.a"
SOURCE_FILES="*.c"

# 检查库文件是否存在
if [[ ! -f "$LIBRARY" ]]; then
    echo "创建新库文件: $LIBRARY"
    # 编译所有源文件
    for src in $SOURCE_FILES; do
        if [[ -f "$src" ]]; then
            obj="${src%.c}.o"
            gcc -c "$src" -o "$obj"
            ar rcs "$LIBRARY" "$obj"
            echo "添加: $obj"
        fi
    done
else
    echo "更新现有库文件: $LIBRARY"
    # 只更新修改过的文件
    for src in $SOURCE_FILES; do
        if [[ -f "$src" ]]; then
            obj="${src%.c}.o"
            # 如果源文件比目标文件新,则重新编译
            if [[ "$src" -nt "$obj" ]]; then
                gcc -c "$src" -o "$obj"
                ar rus "$LIBRARY" "$obj"
                echo "更新: $obj"
            fi
        fi
    done
fi

# 显示库内容
echo "=== 库内容 ==="
ar tv "$LIBRARY"

# 生成符号表索引
ranlib "$LIBRARY"
echo "已生成符号表索引"
场景3:从Debian包中提取文件
#!/bin/bash
# 提取.deb包内容的示例

DEB_FILE="package.deb"
EXTRACT_DIR="extracted_package"

# 创建提取目录
mkdir -p "$EXTRACT_DIR"
cd "$EXTRACT_DIR"

# 使用ar提取.deb包
# .deb包实际上是ar归档文件
echo "提取 $DEB_FILE..."
ar x "../$DEB_FILE"

# 查看提取的文件
echo "提取的文件:"
ls -la

# .deb包通常包含三个文件:
# 1. debian-binary - 版本信息
# 2. control.tar.* - 控制信息
# 3. data.tar.* - 实际文件

# 查看debian-binary
echo "=== Debian版本 ==="
cat debian-binary

# 提取控制文件
if [[ -f control.tar.gz ]]; then
    echo "=== 控制文件 ==="
    tar -tzf control.tar.gz
    tar -xzf control.tar.gz
    cat control
fi

# 提取数据文件
if [[ -f data.tar.gz ]]; then
    echo "=== 数据文件 ==="
    tar -xzf data.tar.gz
fi

echo "提取完成"

与其他工具的比较

工具 主要用途 压缩 特点
ar 创建静态库 不支持 Unix标准库工具,适合目标文件
tar 文件归档 支持 通用归档工具,保留权限和时间
zip 跨平台压缩 支持 Windows/Linux兼容,有损压缩
gzip 文件压缩 支持 单个文件压缩,常与tar配合
cpio 文件归档 支持 适合备份,处理特殊文件

注意事项

重要注意事项:
  • 符号表索引:创建静态库后通常需要运行ranlib或使用-s选项创建符号表索引
  • 文件顺序:某些链接器对库中文件的顺序敏感,可能需要特定排列
  • 权限保留:ar会保留文件的权限和时间戳信息
  • 目标文件:通常用于打包.o目标文件,而不是源文件
  • 跨平台:ar格式是Unix标准,但在不同系统间可能有细微差异
  • 文件大小:ar不支持大文件(>8GB),某些实现有文件大小限制

常见问题

A: 主要区别:
  • ar:主要用于创建静态库,打包目标文件,是Unix传统库工具
  • tar:通用归档工具,用于备份和分发文件,保留完整属性
  • 格式:ar是简单的文件串联,tar是流式归档格式
  • 压缩:ar不支持压缩,tar可配合gzip/bzip2压缩
  • 使用场景:ar用于开发,tar用于部署和备份

A: 符号表索引包含库中所有全局符号的位置信息:
  • 作用:加速链接过程,链接器不需要扫描整个库文件
  • 创建:使用ar -sranlib命令
  • 位置:通常是归档文件的第一个成员
  • 查看:使用nm -s libname.a查看符号表
示例:
# 创建符号表索引
ar s libexample.a
# 或
ranlib libexample.a

# 查看符号表
nm -s libexample.a
# 或
ar tv libexample.a  # 第一个文件通常是__.SYMDEF或类似名称

A: 使用nm命令查看归档文件中的符号:
# 查看库中所有目标文件的符号
nm libexample.a

# 只查看全局符号
nm -g libexample.a

# 查看未定义符号
nm -u libexample.a

# 查看特定目标文件的符号
ar x libexample.a file1.o
nm file1.o

# 使用objdump查看更详细信息
objdump -t libexample.a | head -20

# 使用readelf(ELF格式)
readelf -s libexample.a 2>/dev/null | head -20

相关命令

tar

通用归档工具:

tar -cvf archive.tar files/
tar -xvf archive.tar
tar -czvf archive.tar.gz files/
nm

查看目标文件符号:

nm libexample.a
nm -g file.o
nm -D libexample.so
ranlib

为归档文件生成索引:

ranlib libexample.a
# 相当于
ar s libexample.a
objdump

显示目标文件信息:

objdump -t file.o
objdump -d file.o
objdump -x libexample.a