使用交叉混合编译从源代码编译龙芯上的llvm/clang-3.4
来源:互联网 发布:工作站品牌 知乎 编辑:程序博客网 时间:2024/04/30 12:41
目标:
使用交叉混合编译(hybrid cross-compiling)从源代码编译龙芯上的llvm/clang-3.4。之所以是混合交叉编译而不是交叉编译,是因为编译的过程中,大部分代码是由性能较高的主体(Host)平台编译,而少部分代码是由性能较低的目标(Target)平台编译。混合交叉编译采用了类似 COMET: Code Offload by Migrating Execution Transparently (OSDI’12) 的思想。其原理是,在目标平台上配置,之后开始编译时,将所有文件同步到主体平台上,并使用主体平台的交叉编译器编译。当需要执行目标平台命令(例如llvm-config
)时,将所有文件同步到目标平台、执行命令,再同步回主体平台,并继续编译。
准备工作:
编译环境:
主体平台
- CPU:Intel Xeon(R) E5620 * 16
- OS:Ubuntu 14.04 + Linux 3.13.0
- 编译器:mipsel-linux-gnu-gcc-4.4/mipsel-linux-gnu-g++-4.4
目标平台
- CPU:loongson 3.2.0-4-loongson-2f, mipsel
- OS:Debian 3.2.51
- 编译器: gcc-4.6.3/g++-4.6.3
预先准备
- 搭建编译环境
- 下载 llvm-3.4的源代码 以及clang-3.4的源代码
- 在主体平台和目标平台上同时创建编译目录并拷贝编译文件
$ mkdir <common/path/prefix>/mips3/llvm $ cp *-3.4.src.tar.gz <common/path/prefix>/mips3/llvm $ cd <common/path/prefix>/mips3/llvm $ tar -xvf *-3.4.src.tar.gz $ mv clang-3.4 llvm-3.4/tools/clang $ rm *-3.4.src.tar.gz
以上脚本同时在两个平台上运行。其中<common/path/prefix>
要求两个平台上的路径名称完全相同,这是因为./configure
后的makefile中包含了使用绝对路径的变量,因此如果路径名称不同,会导致编译出错。
3. 创建编译器符号链接
类似的,在两个平台上的编译器名称也需要一致。本文中使用mipsel-common-g++为两者的c++编译器,mipsel-common-gcc为两者的c编译器。在主体平台上:
$ sudo ln -s /usr/bin/mipsel-common-g++ /usr/bin/mipsel-linux-gnu-g++ $ sudo ln -s /usr/bin/mipsel-common-gcc /usr/bin/mipsel-linux-gnu-gcc
在目标平台上
$ sudo ln -s /usr/bin/mipsel-common-g++ /usr/bin/g++-4.6 $ sudo ln -s /usr/bin/mipsel-common-gcc /usr/bin/gcc-4.6
- 同步编译时间
由于不同平台的时间和时区可能都不同,而编译时makefile会依赖文件时间来确定生成文件的新旧,因此需要同步两者的系统时间。- 同步时区
$ sudo dpkg-reconfigure tzdata
之后选择asia
->Shanghai
,以便两者平台的时区一致。
2. 同步时间
只要使得两个平台的时间相同即可,本文中利用ntp协议使得目标平台的时间和主体平台的时间一致。在目标平台运行以下代码:
$ sudo sntp -s <host-ip>
或者在安装ntp之后
$ sudo service ntp stop $ sudo ntpdate -s time.nist.gov $ sudo service ntp start
- 同步编译文件
本文使用rsync同步主体平台和目标平台之间的文件。- 在主体平台创建rsync配置文件(因为主体平台是同步服务器)
address = <host-ip> use chroot = yes read only = no pid file = /var/run/rsyncd.pid log file = /var/log/rsync.log [mips3] uid = <host-user-name> gid = <host-group-name> path = <common/path/prefix>/mips3 hosts allow = <ip-mask> #例如192.168.0.0/8 auth users = mips3 secrets file = /etc/rsyncd.secrets
其中/etc/rsyncd.secrets
中保存用户名为mips3的密码,内容如下
mips3:<host-password>
此外,为了保证rsyncd可以使用,需要将/etc/rsyncd.secrets
的权限设置为600。
2. 启动rsyncd:
rsyncd --daemon
- 创建同步命令
rsync-commit
和rsync-update
分别用于将目标平台上的程序提交到主体平台上,以及从主体平台上更新目标平台上的程序。此外,创建rsync.password
用户存放密码,以避免每次同步时输入密码。
$ cat <common/path/prefix>/mips3/rsync-commit #!/bin/bash rsync --password-file=<common/path/prefix>/mips3/rsync.password -azv <common/path/prefix>/mips3/llvm mips3@<host-ip>::mips3 $ cat <common/path/prefix>/mips3/rsync-update #!/bin/bash rsync --password-file=<common/path/prefix>/mips3/rsync.password -azv mips3@<host-ip>::mips3/llvm <common/path/prefix>/mips3 $ cat <common/path/prefix>/mips3/rsync.password <host-password>
编译
配置
在编译前,需要在目标平台上配置编译环境:
$ cd <common/path/prefix>/mips3/llvm/llvm-3.4$ CC=mipsel-common-gcc CXX=mipsel-common-g++ ./configure --enable-bindings=none --prefix=`pwd`/root --enable-targets=mips
开始编译
配置完,即可开始编译:
$ make
在出现开始编译某个文件时,CTRL+C
终止编译,因为在目标平台上编译太慢了。此时执行<common/path/prefix>/mips3/rsync-commit
,将目标平台上的编译结果同步到主体平台上。之后,在主体平台上
$ make -j<n>
使用主体平台上numa的并行性编译。一旦主体平台上的编译过程中出现错误,立刻切换到目标平台上
$ <common/path/prefix>/mips3/rsync-update$ make... # 开始编译下一个文件CTRL+C$ <common/path/prefix>/mips3/rsync-commit
来回切换50次以内,即可编译完成。
优化编译过程,提高编译效率
由于频繁CRTL+C
、切换、同步非常耗时,而且是在不同平台上的切换(不同的物理机器),因此减少切换次数可以大大提高自动化程度。
- 只配置mips
clang默认会配置所有的目标平台,而在配置每一种目标平台时,都要调用当前目标平台上的编译结果。这也是需要频繁切换的原因之一。因此在配置时加上--enable-targets=mips
,只配置当前的目标平台,减少切换次数。 - 使用主体平台上的编译结果
clang在编译可执行文件和动态共享库时,会调用llvm-config
获得当前应该链接的静态库。这是需要频繁切换的原因之二。因此,将llvm-config
替换成主体平台也可以运行的、具有相同功能的llvm-config
可以显著减少切换次数。
在主体平台上,先使用相同的配置选项配置clang,之后会生成主体平台上的mipsel交叉编译clang。这里我们用的不是交叉编译clang,而是生成的副产品:llvm-config
。在将其重命名为llvm-config-amd64
,将目标平台上的对应文件命名为llvm-config-mips3
。在主体平台上执行以下命令,替换原有的llvm-config
,即可使用主体平台上的编译程序。
$ cp <path/to/llvm-config-amd64>/llvm-config-amd64 <common/path/prefix>/mips3/llvm/llvm-3.4/Release+Asserts/bin/llvm-config
- 删去单元测试和其他测试
删去clang中和test、unittest相关内容,删去llvm中test目录,这些在编译时都不是必要的,并且会大大增加数据的传输量。
安装
$ cd <common/path/prefix>/mips3/llvm/llvm-3.4$ make install$ <common/path/prefix>/mips3/rsync-commit
即可将编译好的llvm/clang安装到<common/path/prefix>/mips3/llvm/llvm-3.4/root
目录下。
编译完成
在目标平台上我们来测试一个helloworld程序:
#include <iostream>using namespace std;int main() { cout << "Hello World!" << endl; return 0;}
保存并将其命名为test.cpp
。使用新安装好的clang++编译:
$ <common/path/prefix>/mips3/llvm/llvm-3.4/root/bin/clang++ test.cpp --target=mipsel-pc-linux$ ./a.outHello World!
这里需要加上--target=mipsel-pc-linux
选项。这是因为目标平台的龙芯属于 mipsel 体系结构,即little endianness。 而系统uname -a
的结果却是mips64。因此,llvm的配置文件会误认为当前平台是mipsel64,从而生成无法运行的代码。
- 使用交叉混合编译从源代码编译龙芯上的llvm/clang-3.4
- LLVM 和Clang源代码编译
- LLVM(Clang)的编译过程
- 从代码开始编译clang/llvm
- Ubuntu16.04 从源码编译LLVM+Clang
- llvm+clang编译安装
- llvm+clang编译安装
- 使用clang进行交叉编译
- Ubuntu编译安装llvm-clang
- clang llvm 源码编译安装
- Ubuntu编译安装llvm+clang
- Ubuntu编译安装llvm-clang
- Ubuntu编译安装llvm-clang
- 交叉编译 llvm
- Ubuntu下Clang和LLVM的编译安装
- SUSE Linux Enterprise 11 SP3 成功编译LLVM + Clang 3.4
- Ubuntu12.04编译llvm+clang失败(3.4/3.5)及成功(3.3)的尝试
- clang的编译和使用
- 常用trait和特殊类
- 设备驱动的艺术之旅 - 无处不在的字符设备<一>
- Openswan在CentOS6.4上的编译安装与配置
- ArrayList、Vector、LinkedList的区别及其优缺点?
- log4j日志输出到控制台
- 使用交叉混合编译从源代码编译龙芯上的llvm/clang-3.4
- Hibernate的catalog导致数据库连接与实际操作的库不一致
- nfs服务检测与自动恢复
- 样本类和模式匹配
- OC - 第八章(二) KVC
- python 与hadoop之pyhdfs的使用
- 10018---HttpClient 基本使用
- 一天一个数据结构之HashMap
- Android studio安装和一些快捷键