使用 LLVM 构建大型项目

2023/02/18 LLVM 共 2102 字,约 7 分钟

所需工具

WLLVM https://github.com/travitch/whole-program-llvm

remake https://github.com/rocky/remake

以 ffmpeg 为例

编译项目并获取可执行文件的相关 IR 代码

克隆仓库:

git clone https://git.ffmpeg.org/ffmpeg.git -b n3.2.1

使用 WLLVM 编译大型项目

# 须指定此环境变量, WLLVM 会读取此环境变量选择相应的编译器
export LLVM_COMPILER=clang
# 配置项目编译环境, 需要指定 CC=wllvm, CXX=wllvm++
# wllvm 必须在环境变量中, 使用 `which wllvm` 确认
./configure --prefix=../build --cc=wllvm --cxx=wllvm++ --disable-asm
# 编译
make -j32
# 安装
make install
# 生成可执行文件的 IR 代码
cd <BUILD_DIR>/bin
extract-bc ffmpeg

简而言之, 对于一个可以指定编译器的大型项目而言, 几乎都可以使用 WLLVM 进行编译, 并生成相关文件的 IR 代码, 大体是以下步骤:

  1. 配置环境变量 LLVM_COMPILER
  2. 编译项目时指定 CCCXXWLLVM
  3. 正常编译程序
  4. 使用 extract-bc , 解析文件的编译步骤, 并生成其相关 IR 代码

使用 extract-bc 生成的 IR 代码并不是完全构建二进制的代码!

使用 IR 代码正常生成可执行文件

很遗憾, 上述生成的 IR 代码由于链接问题, 很有可能无法再次生成可执行文件. 这让我非常的不爽!!!

接下来介绍重磅工具: remake

简而言之, remake 是一个可以记录 make 构建项目时执行的所有命令. 我们可以通过删除可执行程序的方式, 重新构建可执行程序, 并且人工分析它是由哪些 .o 文件构建的. 这些 .o 文件由于没有经过链接, 经过测试都是可以重新编译的. 步骤如下:

# 进入 ffmpeg 根目录中, 删除目标可执行文件
rm ffmpeg ffmpeg_g
# 使用 remake 重新编译, 记录构造命令
remake -x > make.trace
# 在生成的 make.trace 文件中, 分析得到如下构造命令:
# wllvm -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -Qunused-arguments   -o ffmpeg_g cmdutils.o ffmpeg_opt.o ffmpeg_filter.o ffmpeg.o  ffmpeg_vaapi.o ffmpeg_vdpau.o -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -lXv -lX11 -lXext -ldl -lvdpau -lva -lva-drm -lva -lva-x11 -lva -lxcb -lxcb-shm -lxcb-xfixes -lxcb-shape -lX11 -lsndio -lasound -lSDL2 -lm -llzma -lbz2 -lz -pthread  
# 简化版:
# wllvm -o ffmpeg_g cmdutils.o ffmpeg_opt.o ffmpeg_filter.o ffmpeg.o ffmpeg_vaapi.o ffmpeg_vdpau.o

明白了程序的链接过程, 即可对上述的 .o 文件分别 extract-bc 再编译, 然后重新链接即可. 以主程序 ffmpeg.o 为例, 导出 IR、重新编译的步骤如下:

# 进入 ffmpeg 根目录中
# 生成 ffmpeg.o 的 IR 代码, 生成 ffmpeg.o.bc
extract-bc ffmpeg.o
# 从 bc 文件生成可读的 ll 文件
llvm-dis ffmpeg.o.bc -o ffmpeg.o.ll
# 修改 ffmpeg.o.ll 文件, 可修改一个字符串查看效果
## ffmpeg 中的使用提示字符串: Use -h to get full help or
## 如果修改字符串长度需要修改 IR 中的声明
# 删除旧的 ffmpeg.o 文件, 并构建新的 ffmpeg.o
rm ffmpeg.o
llc -filetype=obj ffmpeg.o.ll -o ffmpeg.o
# 重新构建可执行文件
make

此时, 可以看到相关功能已被修改.

image-20230214212421043

猜猜看我改了哪里 :)

备注

  1. 使用 strace 指令貌似也可以使用此功能: strace -f -o make.trace -e trace=process make -j
  2. bear 工具好像也有这个功能, 但是个人感觉不好用

文档信息

搜索

    Table of Contents