llvm和clang环境配置(续篇)

文章详细介绍了如何在古老的Linux发行版上配置LLVM和Clang的开发环境,包括安装GCC7.1,设置cmake的rpath,以及编译和链接LLVM项目时的注意事项。特别强调了LLVM_LOCAL_RPATH变量的作用,使得可执行文件无需设置LD_LIBRARY_PATH即可运行。同时提到了使用clang编译时对动态库的依赖问题。
摘要由CSDN通过智能技术生成

关于llvm和clang开发环境的配置之前已经发过一篇,当时是因为llvm官网给的文档省略了很多重要信息,需要额外补充一些信息才能完成环境配置。

时隔许久,重新打开llvm官网,发现他们的文档已经更新了,写的非常详细,专门列举了一节用来解释如何在远古linux发行版上编译安装llvm+clang的方法。内容大体上和我上篇差不多,但是有些细节需要注意,是我上篇内容中遗漏的,并且当时对于cmake的rpath设置也并不完全掌握。

注意:本文是针对有需要在古老的linxu服务器上进行llvm+clang环境开发的指导说明,如果你的发行版在2017年以后,基本不需要参考这篇文档。本文档也是傻瓜式教程,帮助新手快速部署环境,免于折腾。

关于宿主机的环境

根据llvm官网文档的介绍,想要成功编译llvm项目,必须的环境要求:

  • Clang 5.0
  • Apple Clang 10.0
  • GCC 7.1
  • Visual Studio 2019 16.7

以GCC7.1为例,官方给出的步骤为:

% gcc_version=7.1.0
% wget https://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.bz2
% wget https://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.bz2.sig
% wget https://ftp.gnu.org/gnu/gnu-keyring.gpg
% signature_invalid=`gpg --verify --no-default-keyring --keyring ./gnu-keyring.gpg gcc-${gcc_version}.tar.bz2.sig`
% if [ $signature_invalid ]; then echo "Invalid signature" ; exit 1 ; fi
% tar -xvjf gcc-${gcc_version}.tar.bz2
% cd gcc-${gcc_version}
% ./contrib/download_prerequisites
% cd ..
% mkdir gcc-${gcc_version}-build
% cd gcc-${gcc_version}-build
% $PWD/../gcc-${gcc_version}/configure --prefix=$HOME/toolchains --enable-languages=c,c++
% make -j$(nproc)
% make install

以上的步骤中,$HOME变量可以自行替换为想要在宿主机上部署高版本GCC的路径,这个路径可以任选,除了/usr目录下;建议选择/opt/toolchains这个路径。如果用户不具备root权限,安装在自己加目录下也是可以的。

安装好之后,可以执行$HOME/toolchains/bin/g++ --version查看和确认版本。

之后,进入llvm项目源码目录,也就是从github下载的llvm-project-15.0.7.src.tar.xz这种压缩包。

注意,我们需要进入的目录是解压后的目录内的llvm目录,比方说,解压后产生的文件夹叫llvm-project-15.0.7.src,那么我们就需要进入cd llvm-project-15.0.7.src/llvm这个目录下面。

然后,在该目录下执行cmake命令:

CC=/opt/toolchains/bin/gcc \
CXX=/opt/toolchains/bin/g++ \
cmake -H. -Bbuild \
-DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,/opt/toolchains/lib64 -L/opt/toolchains/lib64" \
-DLLVM_LOCAL_RPATH="/opt/toolchains/lib64" \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi"

注意:

  • 此处CCCXX环境变量指定的工具链路径是刚才上面安装高版本GCC的路径,千万不要搞错了。
  • CMAKE_CXX_LINK_FLAGS非常关键,用于指定连接时的libstdc++.so的路径。
  • DLLVM_LOCAL_RPATH这个变量是看了llvm官网更新后的文档才了解到的;因为llvm默认所有的rpath都指向’$ORIGIN/…/lib’,也就是当前可执行文件上一层的lib目录;使用这个变量后,可以添加固定路径的rpath,这样在本机编译出的可执行文件,就无需设置LD_LIBRARY_PATH环境变量就可以直接执行。如果编译后的文件需要在其他机器上运行,则只需要拷贝libstdc++.so到可执行文件上层的lib目录下。
  • LLVM_ENABLE_PROJECTSLLVM_ENABLE_RUNTIMES这两个变量是llvm官方文档忽略的,他给出的cmake命令例子里面没有这两个变量,所以编译出来只有llvm套件,没有clang和其他工具;如果要用clang,建议同时编译出libcxx(也就是libc++.so)。

按照官方说法,将目录设置成如下形式,即可正常运行clang编译出来的可执行文件:

.
├── bin
│   ├── a.out
│   └── hello.cc
└── lib
    ├── libc++abi.so.1 -> /usr/local/lib/x86_64-unknown-linux-gnu/libc++abi.so.1
    └── libc++.so.1 -> /usr/local/lib/x86_64-unknown-linux-gnu/libc++.so.1

测试代码:

# cat hello.cc 
#include <iostream>
#include <string>
#include <functional>
#include <memory>

void foo(std::function<void()> f)
{ f(); }

int main(int argc, char** argv)
{
    auto msg = std::make_unique<std::string>("hello wolrd"); // make_unique
    foo( [n = std::shared_ptr<std::string>(msg.release())]{ std::cout << *n << std::endl;}); // 移动捕获
    return 0;
}

但是其实是有问题的,需要分情况讨论:

  • 当执行clang++ hello.cc的时候,默认搜索的是系统自带的GCC,是不支持make_unique和移动捕获的;
  • 当执行clang++ -stdlib=libc++ hello.cc的时候,默认是不带rpath的,因此会提示找不到libc++.so

想要让可执行文件能够正确执行,在上述目录结构的情况下,使用以下命令编译:
clang++ -stdlib=libc++ -Wl,-rpath,\$ORIGIN\/..\/lib hello.cc
这样手动给a.out增加一个rpath就可以执行了。

因此,总结一下我们的需求,如果想要:

  1. 利用clang帮助解决编译问题,则不需要带-stdlib=libc++使用,仅仅让clang做一个用户友好的编译器前端;
  2. 如果要利用llvm后端,则必须指定rpath,链接到libc++.solibc++abi.so,但是这样编译产出的可执行文件就同时依赖libc++.solibc++abi.solibstdc++.so.6(高版本的);如果要放到其他古董机上执行,需要把这三个动态库都拷过去,并且指定rpath或者LD_LIBRARY_PATH环境变量。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值