编译GCC native编译器的几点启示

启示

  • 编译 GCC native compiler按照官方介绍并不难

步骤见后面实践脚本,以及官方编译指南链接


  • GCC编译器编译其它程序组件时,会优先使用自身携带的库,例如,常用的自带库,libgcc_s.so、libstdc++
  • 如果部署环境与编译要求存在比较大的依赖差异,则会诱发兼容性问题
  • 高度推荐容器化部署,使得编译环境与部署环境高度一致
  • 组件依赖会形成类似maven库中的依赖树,组件依赖关系各种编程语言均存在类似关系,而这与具体编程语言无关

  • 在一个环境中使用不同的GCC编译版本,例如,高版本GCC编译器,尽量选择devtooolset-*系列rpm包;但如果devtoolset-*包中对齐的GCC版本并非最后结项版本,则可以选择自行编译GCC native compiler,而这个过程并不难
  • 自行编译GCC native compiler,可以参考devtoolset-*系列的目录结构,和其enable切换环境脚本
  • devtoolset-*早期版本容易对齐GCC结项版本,后期发行版失去维护后,较新的GCC高版本则一般没有对齐

为什么选择高版本编译器

  • 更多的warning、error自动检查

部分warning可以转化成error项,结合静态代码检查工具形成代码开发工具链,以及自动编码规范

  • 更准确的错误定位能力,和错误提示
  • sanitizer检查能力
  • 更优良的代码生成质量
  • 新的语言特性

追求新语言特性的优先级最低,除非是必要、能够提高开发效率的语言特性,在一定程度上可以定死编译器的编译标准,作为编码规范的一部分

使用高版本编译器的兼容性问题

图解GCC高版本编译后的部署问题

GCC编译时优先使用自身携带库

编译器存在自身要求的依赖库

  • 这些依赖库体现为新的特性,或编译器定制化要求
  • 不一致会形成依赖冲突,甚至程序不能运行

推荐部署结构

推荐部署结构

  • 编译环境高度和部署环境一致
  • 通过携带少量对齐库依赖,定制环境变量,达到与要求环境模拟一致,但并不污染其它应用
  • 忽略差异依赖库的差异,依赖部署环境的向前、向后兼容能力,用覆盖测试进行保证

公之下策,实为上策!

下策看似不推荐,但是其实是大家用的比较多,也比较省事的做法。忽略了差异性可能带来的风险,而由功能覆盖测试保证产品的可用性。

但是,由于Linux社区强大的兼容性保证能力,得以很多跨版本编译、部署能够经得住功能覆盖测试

如何分析程序的依赖

  # 注意LD_LIRBRARY_PATH设定为优先编译器相对于的库目录,也就是是devtoolset-* enable脚本所做的
  ldd /path/to/excutable
  • 由此分析出程序依赖的编译器

困难的三方组件

  • 建议直接源码,或静态库依赖
  • 重新编译三方库,或向能够编译它的第三方获取新的动态库版本

对于,具有第三方依赖的程序,更换编译器的代价会更大点,需要根据实际进行选择。

如果一开始,就可以将编译器标准界定的比较高,相当于从最开始就拥有了良好的开端!

从这里也说明一个问题,获取三方库,如果对方也存在复杂的依赖,三方库编译的编译器版本也是需要进行安全评估的

从使用GCC多版本再议环境变量传参的优劣

根据devtoolset-*组件enable脚本对于环境变量的设定,再次总结环境变量与命令选项在传参上的不同

-环境变量命令选项说明
粒度命令选项仅实施于个体程序
共享共用独用环境变量在有一批程序共享使用时比较便捷
方便自动传递每次传递环境变量一次设置,多次免参传递
  • 尺有所短、寸有所长,在合适的场景使用环境变量传递参数信息非常有利,例如,切换GCC不同的版本

参考


实操编译native compiler脚本

 cd ~
 # 建立下载源码目录
 mkdir gcc
 curl -O https://mirrors.ustc.edu.cn/gnu/gcc/gcc-9.5.0/gcc-9.5.0.tar.xz
 tar xf gcc-9.5.0.tar.xz
 
 # GCC top-level目录
 cd gcc-9.5.0
 # 下载依赖
 ./contrib/download_prerequisites

 # 创建独立编译目录
  cd ~/gcc
  mkdir build
  cd build
  
  # 因为编译native compiler,除了必要定制项,其它直接以来configure自动配置
  # 参考devtoolset-*中的目录结构
 ~/gcc/gcc-9.5.0/configure --prefix=/opt/gcc/9.5.0/root/usr --mandir=/opt/gcc/9.5.0/root/usr/share/man --infodir=/opt/gcc/9.5.0/root/usr/share/info --disable-multilib --enable-language=c,c++

# 并行编译
 make -j8

–disable-multilib 撇开对于32位的支持,如果不需要的话

参考devtoolset-9的enable文件提供编译环境切换能力

# General environment variables
export PATH=/opt/gcc/9.5.0/root/usr/bin${PATH:+:${PATH}}
export MANPATH=/opt/gcc/9.5.0/root/usr/share/man:${MANPATH}
export INFOPATH=/opt/gcc/9.5.0/root/usr/share/info${INFOPATH:+:${INFOPATH}}
export PCP_DIR=/opt/gcc/9.5.0/root

# bz847911 workaround:
# we need to evaluate rpm's installed run-time % { _libdir }, not rpmbuild time
# or else /etc/ld.so.conf.d files?
rpmlibdir=$(rpm --eval "%{_libdir}")
# bz1017604: On 64-bit hosts, we should include also the 32-bit library path.
if [ "$rpmlibdir" != "${rpmlibdir/lib64/}" ]; then
 rpmlibdir32=":/opt/gcc/9.5.0/root${rpmlibdir/lib64/lib}"
fi

# 库的依赖环境变量
export LD_LIBRARY_PATH=/opt/gcc/9.5.0/root$rpmlibdir$rpmlibdir32${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
export LD_LIBRARY_PATH=/opt/gcc/9.5.0/root$rpmlibdir$rpmlibdir32:/opt/gcc/9.5.0/root$rpmlibdir/dyninst$rpmlibdir32/dyninst${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
export PKG_CONFIG_PATH=/opt/gcc/9.5.0/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}
  • 切换编译环境,重要的是设置PATH和LD_LIBRARY_PATH两个环境变量

strip瘦身

strip  /path/to/executable_file
  • 主机上新编译的native compiler占用比较大的磁盘空间,例如,cc1 就200多M,可以用strip程序进行瘦身

环境切换

# 建议打开一个具有新环境变量的新终端
bash -c 'source /opt/gcc/9.5.0/enable; exec bash'

# 使用完毕后退出到原环境中
exit
  • 注意,利用exec命令在执行了切换环境变量后,非常巧妙地重新打开bash,进入shell命令可输入状态
  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值