分类:Linux| 发布时间:2021-03-24 15:37:00
最近需要将原本运行于 x86_64 Linux 下的软件移植到 ARM 架构下,由于开发和自测主要还是在 x86_64 下进行, 因此决定使用交叉编译的方式生成 ARM 架构下的可执行文件。
本文主要记录了在 x86_64 Linux 下进行交叉编译所需的环境和要点。
环境如下:
软件需要依赖的开源库有:
项目中需要进行移植的代码主要为 C/C++ 代码,另外还有部分组件是使用 golang 编写而成,也需要针对 ARM 架构进行重新编译
假设系统已经搭建好的 x86_64 的编译环境,在此基础上需要进行 aarch64 架构的编译只需要安装如下软件:
$ sudo apt install g++-aarch64-linux-gnu
protobuf 官方提供了 CMakeLists.txt 进行项目构建,这里主要介绍如何通过 CMakeLists.txt 进行 protobuf 的交叉编译。
假设我们使用如下命令编译 x86_64 版本的 protobuf
$ cmake -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_WITH_ZLIB=OFF -DBUILD_SHARED_LIBS=ON protobuf/cmake
为了进行交叉编译需要通过变量 CMAKE_TOOLCHAIN_FILE 指定工具链的位置:
$ cmake -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_WITH_ZLIB=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_TOOLCHAIN_FILE=aarch64.cmake protobuf/cmake
aarch64.cmake 的内容为:
SET (CMAKE_SYSTEM_PROCESSOR aarch64)
SET (CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
SET (CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
CMAKE_C_COMPILER 和 CMAKE_CXX_COMPILER 的值可以根据实际情况进行修改
我们用如下命令编译 x86_64 版本的 OpenSSL:
$ perl openssl/Configure linux-x86_64
$ make -j8
交叉编译 OpenSSL 需要修改为:
$ CC=/usr/bin/aarch64-linux-gnu-gcc MACHINE=aarch64 perl openssl/Configure linux-aarch64
$ make -j8
我们用如下命令编译 x86_64 版本的 Boost:
./bootstrap.sh
./b2 --with-chrono --with-date_time --with-filesystem --with-locale --with-regex --with-serialization --with-system variant=release
交叉编译 Boost 需要修改为:
./bootstrap.sh
echo "using gcc : $ARCH : /usr/bin/aarch64-linux-gnu-g++ ;" > user-config.jam
BOOST_BUILD_PATH=`pwd` ./b2 --with-chrono --with-date_time --with-filesystem --with-locale --with-regex --with-serialization --with-system variant=release install
为了能让 Boost 的编译系统识别到我们需要使用自定义的编译器,我们需要生成 user-config.jam 文件,在这个文件指定 g++ 的位置。
同时还要通过环境变量 BOOST_BUILD_PATH 让 Boost 的编译系统找到我们的 user-config.jam 文件。
我们用如下命令编译 x86_64 版本的 xxHash:
$ make -j8
交叉编译 Boost 需要修改为:
CC=/usr/bin/aarch64-linux-gnu-gcc CXX=/usr/bin/aarch64-linux-gnu-g++ make -j8
简单来说就是通过 CC 和 CXX 环境变量指定交叉编译其的路径即可。
lz4 和 zstd 的交叉编译都是类似的,这里不再赘述。
我们用如下命令编译 x86_64 版本的 rsync
./configure CPPFLAGS="-I$XXHASH_ROOT/include -DXXH_STATIC_LINKING_ONLY -I$LZ4_ROOT/include -I$ZSTD_ROOT/include -I$OPENSSL_ROOT/include" LIBS="$XXHASH_LIBRARIES $LZ4_LIBRARIES $ZSTD_LIBRARIES $OPENSSL_CRYPTO_LIBRARIES"
交叉编译的 rsync 需要修改为:
./configure --host=aarch64-pc-linux-gnu CPPFLAGS="-I$XXHASH_ROOT/include -DXXH_STATIC_LINKING_ONLY -I$LZ4_ROOT/include -I$ZSTD_ROOT/include -I$OPENSSL_ROOT/include" LIBS="$XXHASH_LIBRARIES $LZ4_LIBRARIES $ZSTD_LIBRARIES $OPENSSL_CRYPTO_LIBRARIES" --disable-simd
交叉编译 rsync 主要通过 --host 参数指定要编译出来的 rsync 的架构,如果你的交叉编译器不在 $PATH 目录下, 需要使用 CC 环境变量指定。
由于 v3.2.3 的编译脚本在进行交叉编译的情况下有 BUG 因此需要显式指定 --disable-simd 参数,目录官方最新的 master 分支是已经修复这个问题了。
有兴趣的可以 点击 查看详情。
我们的 C++ 代码部分是通过 CMakeList.txt 进行构建的,交叉编译自有 C++ 代码与 protobuf 类似,这里不再赘述。
golang 进行交叉编译非常简单,只需要通过环境变量 GOARCH 和 GOOS 指定要编译的环境和架构即可。 在这里我们只需要指定 GOARCH 为 arm64 即可。
另外可以通过命令:
$ go tool dist list
查看所有合法的 GOOS 和 GOARCH 组合。
本文主要描述了如何在 x86_64 的 Linux 系统交叉编译出 arm64 Linux 运行的 C++/C 和 golang 程序。
根据构建系统主要分为如下几类:
另外还有像 OpenSSL 这类比较特殊的构建系统,需要查看官方提供的文档和源码来确定交叉编译的方法。