跳转至

编译器与目标

支持矩阵

compiler 编译命令 静态库 共享库 可执行程序
gxx gcc(.c)/ g++(其余) ar g++ -shared g++ -s
llvm clang ar clang++ -shared(未验证) clang++ -s(未验证)
msvc cl ar 未实现,直接报错退出 未实现,直接报错退出

编译命令按源文件后缀选择:.c 走 C 编译器,.cc / .cpp 走 C++ 编译器。

为什么共享库与可执行程序要经编译器驱动链接

早期版本直接调用 ld -shared,这样生成的共享库不会带上 libstdc++ 等运行时依赖,用 dlopen 或纯 C 宿主加载时会因为未定义的 C++ 符号失败。现在统一走编译器驱动,由它带上 crt 与调用方的运行库。

目标类型

target_type 生成物 链接命令要点
static lib<项目名>.a ar csr,构建后自动 strip --strip-unneeded
shared lib<项目名>.so -shared -o,并显式链 -lm
exe <项目名> -s,并带上 compile_args 与你配置的链接参数

共享库注意事项

编译参数里需要 -fPIC,否则目标文件不能进共享库。antel init 生成的模板已经包含这一项,工具不会再自动追加:

{
  "target_type": "shared",
  "compile_args": ["-std=c++17", "-Os", "-fPIC"]
}

链接参数里以 -l 开头的项(如 -lpthread)会被识别为系统库:

{
  "link_args": ["-lpthread", "-ldl"]
}

版本化共享库

给共享库一个版本号,antel 会产出 libX.so.<版本>(如 libX.so.1.0.0)并自动生成软链 libX.so.1 与 libX.so,链接命令带上 -Wl,-soname:

{
  "target_type": "shared",
  "version": "1.0.0",
  "soname": "libX.so.1",   // 可选,缺省由 version 主版本推导
  "rpath": ["$ORIGIN/lib"] // 可选,消费端运行期到哪找库
}

消费端按 SONAME 链接与加载(rpath 的 $ORIGIN 运行期展开为可执行文件目录,拷走整个输出目录树也能跑):

{
  "link_args": ["-L<库输出目录>", "-lX"],
  "rpath": ["$ORIGIN/../<库输出目录>"]
}

验证:readelf -d 显示 SONAME、ldd 按 SONAME 而非文件名解析即可。完整示例见示例与效果图的 antelstats。

换编译器

同一个项目想用不同编译器构建,用不同的配置文件即可,两者输出目录互不干扰:

antel rebuild -f gcc      # 读取 gcc.json,输出到 <项目名>_gcc/
antel rebuild -f clang    # 读取 clang.json,输出到 <项目名>_clang/

常见问题

报错 命令执行失败(退出码 127) ... 命令不存在或不可执行:cl

说明用到了 msvc,但当前环境没有 cl(或该编译器的链接路径尚未实现)。在 Linux 上用 gxx 或 llvm。

链接时报未定义符号

先看 log/linkInfor,那里有链接器的完整输出。C++ 项目常见原因是源文件被当成 C 编译(后缀写成了 .c),或者缺少 -l 形式的链接参数。

生成的可执行程序体积不对

exe 目标链接时带 -s,会去掉符号表;静态库构建后会 strip --strip-unneeded。需要保留调试符号时,把 -g 加进 compile_args 并自行去掉这些裁剪手段。