Learning LLVM Part 2

本贴最后更新于 2333 天前,其中的信息可能已经时异事殊

Understanding LLVM Part 2

咕咕咕,接上篇《Learning LLVM Prat 1》。这篇大概梳理一下这两个月摸鱼时候遇到的坑。

一些坑

如果要编译成功 LLVM 树,那么熟练的使用各种方式把代码拖下来,再用合适的环境编译必不可少。

其实编译这个巨大的东西,还需要好一点的硬件设备(一般我们会都卡在硬盘 IO 上,IO 卡住了就会 Cache 在内存里,然后内存爆炸,PC 就什么也动不了了),比如在目前的这个工作站上:

sk in llvm-detectDataPass/skeleton at Lab on  master ➜ screenfetch ./+o+- sk@Lab yyyyy- -yyyyyy+ OS: Ubuntu 16.04 xenial ://+//////-yyyyyyo Kernel: x86_64 Linux 4.15.0-38-generic .++ .:/++++++/-.+sss/` Uptime: 28m .:++o: /++++++++/:--:/- Packages: 2031 o:+o+:++.`..```.-/oo+++++/ Shell: zsh 5.1.1 .:+o:+o/. `+sssoo+/ CPU: Intel Core i7-8700K CPU @ 4.7GHz .++/+:+oo+o:` /sssooo. GPU: GeForce GTX 1080 Ti /+++//+:`oo+o /::--:. RAM: 1280MiB / 64357MiB \+/+o+++`o++o ++////. .++.o+++oo+:` /dddhhh. .+.o+oo:. `oddhhhh+ \+.++o+o``-````.:ohdhhhhh+ `:o+++ `ohhhhhhhhyo++os: .o:`.syhhhhhhh/.oo++o` /osyyyyyyo++ooo+++/ ````` +oo+++o\: `oo++.

硬盘是 Intel 760P 512G 的,Ninja 编译完成 Release 版本的 LLVM+clang-6.0.1 十来分钟就搞定了(逃

gcc 版本问题

以我现在正在使用的 LLVM 6.0.1 为例,首先要把代码下载到本地,解压,这部分就不细说了,上篇提到了。

然后就是配置合适的 gcc 和 g++ 版本,在文档 http://releases.llvm.org/6.0.1/docs/GettingStarted.html#software 中可以看到 gcc/g++ 的版本是 >= 4.8.0,而我们一般 Ubuntu 自带的版本是 5.4.0,如果强行使用不恰当的版本编译,会被恶心的 C++ 标准实现报错导致编译不成功,因此在 Ubuntu 16.04 x64 Desktop LTS 上,我们要使用恰当的 gcc/g++ 版本。首先安装 gcc-4.8g++-4.8:

sudo apt install gcc-4.8 g++-4.8

先安装版本:

$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60 $ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 60

切换版本:

sk in ~ at Lab took 7s ➜ sudo update-alternatives --config gcc There are 2 choices for the alternative gcc (providing /usr/bin/gcc). Selection Path Priority Status ------------------------------------------------------------ 0 /usr/bin/gcc-4.8 60 auto mode * 1 /usr/bin/gcc-4.8 60 manual mode 2 /usr/bin/gcc-5 60 manual mode Press <enter> to keep the current choice[*], or type selection number: 1 # g++ 也是一样 sk in ~ at Lab took 3s ➜ sudo update-alternatives --config g++ update-alternatives: warning: alternative /usr/bin/g++-4.7 (part of link group g++) doesn't exist; removing from list of alternatives There are 2 choices for the alternative g++ (providing /usr/bin/g++). Selection Path Priority Status ------------------------------------------------------------ 0 /usr/bin/g++-5 80 auto mode * 1 /usr/bin/g++-4.8 60 manual mode 2 /usr/bin/g++-5 80 manual mode Press <enter> to keep the current choice[*], or type selection number: 1

查看 g++/gcc 版本,如果是文档要求的版本就可以开始下一步了:

sk in ~ at Lab took 3s ➜ g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.5-4ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.8.5 (Ubuntu 4.8.5-4ubuntu2)

debug 版本文件夹过大的问题

这个问题需要在 cmake 生成编译文件的时候添加 Release 版本的参数:

(~/Work/llvm-6.0.1.build)$ cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Release ../llvm-6.0.1.src

这样,编译生成的 LLVM 树就很小了:

sk in ~/Work/llvm-6.0.1.build at Lab ➜ du -sh 2.1G .

看到没,只有 2.1G,如果是 debug 版本的 LLVM,需要 45G。

使用 CLion 编译 Pass

我们编写一 Pass,还要把源码复制到 LLVM 源代码树里,和整个 LLVM 一起编译,这样也太不优雅了,所以我们稍加配置,在 CLion 里编译(你电 edu 邮箱有 CLion 授权,我可是用正版的乖孩子)。

首先,我们需要在 /etc/profile 配置一个名为 LLVM_HOME 的环境变量,就是我们编译生成的 LLVM 树的目录:

# /etc/profile添加一行 export LLVM_HOME=/home/sk/Work/llvm-6.0.1.build

然后我们需要配置 cmake 工程如下:

sk in llvm-detectDataPass/skeleton at Lab on  master ➜ tree . ├── CMakeLists.txt ├── README.md └── skeleton ├── CMakeLists.txt └── Skeleton.cpp

在根目录下的 CMakeLists.txt 内容如下:

sk in llvm-detectDataPass/skeleton at Lab on  master ➜ cat CMakeLists.txt cmake_minimum_required(VERSION 3.4) if(NOT DEFINED ENV{LLVM_HOME}) message(FATAL_ERROR "$LLVM_HOME is not defined") endif() if(NOT DEFINED ENV{LLVM_DIR}) set(ENV{LLVM_DIR} $ENV{LLVM_HOME}/lib/cmake/llvm) endif() find_package(LLVM REQUIRED CONFIG) add_definitions(${LLVM_DEFINITIONS}) include_directories(${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) add_subdirectory(skeleton) # Use your pass name here.

其中主要内容是设置编译环境使用的,不同版本的 LLVM 可能 set(ENV{LLVM_DIR} $ENV{LLVM_HOME}/lib/cmake/llvm) 的位置有所差别,这个需要视版本更改。最后一行是我们 Pass 的目录,这个也很简单。

在 Pass 目录的 CMakeLists.txt 的内容如下所示:

sk in llvm-detectDataPass/skeleton at Lab on  master ➜ cat skeleton/CMakeLists.txt add_library(SkeletonPass MODULE # List your source files here. Skeleton.cpp ) ## Use C++11 to compile your pass (i.e., supply -std=c++11). target_compile_features(SkeletonPass PRIVATE cxx_range_for cxx_auto_type) # LLVM is (typically) built with no C++ RTTI. We need to match that; # otherwise, we'll get linker errors about missing RTTI data. set_target_properties(SkeletonPass PROPERTIES COMPILE_FLAGS "-D__GLIBCXX_USE_CXX11_ABI=0 -fno-rtti" )

第一行 add_library() 中添加的是我们 Pass 的源代码,最后一行注意添加编译选项 COMPILE_FLAGS "-D__GLIBCXX_USE_CXX11_ABI=0 -fno-rtti",否则会出现下面这种找不到符号的问题(https://stackoverflow.com/questions/37366291/undefined-symbol-for-self-built-llvm-opt):

$ clang -Xclang -load -Xclang build/skeleton/libSkeletonPass.so program/test.c error: unable to load plugin 'build/skeleton/libSkeletonPass.so': 'build/skeleton/libSkeletonPass.so: undefined symbol: _ZN4llvm23EnableABIBreakingChecksE'

如果一切正常,那么在 CLion 中导入这个工程,点击右上角的编译按钮,就会在 cmake-build-debug/skeleton 下生成我们想要的 Pass 了,加载试一下:

~/Work/llvm-6.0.1.build ➜ $LLVM_HOME/bin/clang -Xclang -load -Xclang ~/Desktop/llvm-detectDataPass/skeleton/cmake-build-debug/skeleton/libSkeletonPass.so /tmp/tmp.c I saw a function called add! I saw a function called main!

优雅。

开始写 Pass

咕咕咕

参考资料

  • LLVM
    20 引用 • 3 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...