浅谈如何使⽤clang替换gcc进⾏编译
经过多年的发展,LLVM事实上已经对⼤部分语⾔进⾏了⽀持,其完备的功能和好的模块化和轻耦合的特性得到了很多⼈的认可,但是在很多传统领域,实际上的编译器还是
gcc(基础设施),⼤部分⼈如果想使⽤LLVM对gcc进⾏替换时,会遇到⼀些⿇烦。Clang的官⽹上对这个地⽅有个说明:The 'clang' driver is designed to work as closely to
GCC as possible to maximize portability. The only major difference between the two is that Clang defaults to gnu99 mode while GCC defaults to gnu89 mode. If you see weird
link-time errors relating to inline functions, try passing -std=gnu89 to clang.。本⽂想从⼀个普通开发者的⾓度去解释⼀些传统gcc编译领域使⽤clang来进⾏替换的⼀些实际步
骤。
我想根据project的特点,把LLVM替换gcc的编译过程分为以下三个类型(不完全是,简单分类):
1. 测试型的project,例如⾃⼰写的testcase,基本上以⼀个main函数,调⽤⼏个简单的cpp⽂件为主,使⽤shell脚本进⾏编译
2. 传统的使⽤configure⽣成Makefile⽂件,然后进⾏编译的project
3. ⼤型project,往往使⽤cmake⽣成编译脚本,然后编译的project
1. 测试型的project
对于这种类型,⼀般就是⼏条简单的gcc或者g++编译命令,这种project建议完全复制,粘贴时将gcc替换为clang就能解决问题,⼤部分gcc⽀持option,clang都进⾏了⽀持,
甚⾄⽀持的更好,⼀般⽤户很少能写出gcc⽀持⽽clang不⽀持的命令
2. 传统configure类型的project
对于这种类型的project,是⽬前⼀般⽤户见到的最多的。我这⾥以⼀个开源的bird-2.0.8来进⾏说明。(⾸先说明,⾮⽹络专业⽤户,仅测试使⽤)某度百科上的词条介绍是:
BIRD是⼀个类UNIX系统的动态路由守护进程。它⽀持当代互联⽹中所⽤所有路由协议,如BGP、OSPF、RIP和这些协议的IPv6的变种(除OSPFv3⽬前尚在发展)。其实做什
么的,我们并不关⼼,我们只关⼼如何得到⼀个正确的编译结果。
要想知道如何得到⼀个正确的结果,正常使⽤gcc搞这类project的流程是使⽤configure进⾏配置,然后make,后边make install进⾏安装,其中configure是⽤来⽣成Makefile⽂
件的,也会进⾏很多配置的检测。这⾥我采⽤的思路是⾸先⽤默认配置来⼀遍,然后再换编译器。
./configure
会遇到
的问题,按照提⽰安装libreadline或者直接使⽤
./configure --disable-client
make -j 32
就可以发现编译完成了,⾮常简单。
现在我们开始换编译器。先看下configure⽂件,发现有如下的介绍:
也就是说刚才在配置的时候,通过设置CC,CPP等环境变量就可以实现切换编译器的过程,我这⾥采⽤最暴⼒的⽅法,直接替换(其实也差不了太多)。
到Makefile⽂件,查CC的变量直接替换为CC=clang,然后make,发现问题:
LD -pthread -flto=4 -g -o bird obj/conf/cf-parse.tab.o obj/conf/cf-lex.o obj/conf/conf.o obj/filter/filter.o obj/filter/data.o obj/filter/f-util.o obj/filter/tree.o obj/filter/trie.o obj/filter/inst-gen.o obj/lib/bitmap.o obj/lib/bitops.o obj/lib/checksum.o obj/lib/event.o clang-7: error: unsupported argument '4' to option 'flto='
Makefile:159: recipe for target 'bird' failed
make: *** [bird] Error 1
我这⾥使⽤的LLVM 7.0,所以会提⽰clang-7,后边意思就是clang-7不⽀持gcc的-flto=4的option,man gcc查看该option的⽤法,是⼀个⽤于link级别的选项,再man clang就能
发现clang在这个选项,要求使⽤ -flto -O2这种标准的⽤法,这⾥编译替换就好:
CFLAGS=$(CPPFLAGS) -g -O2 -pthread -fno-strict-aliasing -fno-strict-overflow -flto -Wall -Wextra -Wstrict-prototypes -Wno-parentheses -Wno-pointer-sign -Wno-missing-field-initializers
LDFLAGS= -pthread -flto -O2 -g
既然是LD提⽰的错误,直接给LDFLAG修改就好。
再次编译,会出现/usr/bin/ld: /home/daily_learning/oldLLVM/build/bin/../lib/LLVMgold.so: error loading plugin: /home/daily_learning/oldLLVM/build/bin/../lib/LLVMgold.so:
cannot open shared object file: No such file or directory
也就是LLVMgold.so不到的问题,到那个⽂件下,发现确实没有这个so⽂件,这是因为加了flto选项需要引⼊LLVMgold库,这个库是需要放在源码中进⾏编译的,⽹上的教程
很多,不再赘述,解决掉这⾥后,发现就能得到和gcc⼀样的结果。整个替换过程⽐较简单。
cmake如何使用相对直接⽤于test的project来说,⼀般project的configure和编译过程相对⽐较复杂,整个编译流程也分为了预编译、编译、链接三个过程,预编译⼀般没有问题,编译过程中可
能遇到option的问题,链接过程可能遇到库的兼容性问题,相对来说,有点复杂也需要⼀点经验。但是对于想⼊⼿学习的⼈来说,还是⾮常有必要的。
对于想要进⾏学习交流的来说,很多时候需要获得的不是最终的链接结果,需要的是中间的bc⽂件,这个时候其实完全不需要考虑什么-c的编译过程中添加什么-emit-llvm什么选
项这些复杂的问题,直接在CFLAGS后边添加-save-temps,你就可以获得中间⽂件了,虽然有点多。
3. ⼤型project
这部分其实和上边差不多,不过这种功能⼀般就不能暴⼒修改Makefile⽂件来进⾏了,需要预先配置编译器和环境变量。我这⾥给出⼀个我使⽤的环境变量,其他⼈可以对照修
改(不保证完全够):
export LLVM_HOME=/home/daily_learning/oldLLVM
export PATH=/home/local/bin:$LLVM_HOME/build/bin:$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LLVM_HOME/build/lib
export C_INCLUDE_PATH=$C_INCLUDE_PATH:$LLVM_HOME/build/include
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:$LLVM_HOME/build/include
说实话,⾮常想给出⼀个完整的例⼦。主要问题是,⼀个真实的project,想要全流程的介绍和切换,⼀般是稍微需要⼀点时间和耐⼼的,⽽且在短的篇幅内把遇到的问题都说
明⽩,也⾮常考验project⾃⾝,所以⼀个合适的project⾮常重要,待有机会再进⾏补充这部分内容。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论