本文记录了如何在mojave上构建raspberry pi 3 b+的交叉编译环境。交叉编译的原因最主要的还是速度,当然还有目标平台没有直接的编译工具链等。在构建交叉编译环境之前,最好确认目标平台的相关信息,能直接确认目标平台的工具链是最好的,因为从CPU判断可能并不准确。
比如raspebrry pi 3 b+,自带gcc,相关信息如下
Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/6/lto-wrapper Target: arm-linux-gnueabihf Configured with: ../src/configure -v --with-pkgversion='Raspbian 6.3.0-18+rpi1+deb9u1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-hecking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf Thread model: posix gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
注意其中target为arm-linux-gnueabihf。假如从raspberry pi 3 b+的CPU(Broadcom BCM2837 64bit CPU)判断的话,armv8,aarch64貌似都可以用,但实际用aarch64架构编译出来的程序无法在raspberry pi,准确来说是安装了raspbian上的raspberry pi上执行,这点请注意(假如想在raspberry pi 3 b+上执行aarch64架构的程序的话,个人觉得可能要换raspbian以外的系统,或者修改内核编译选项,这块等自己有空尝试并成功了再发出来)。
macos下交叉编译,首先要安装crosstool-ng
brew install crosstool-ng
个人安装的是版本1.23.0_3
➜ ~ brew info crosstool-ng crosstool-ng: stable 1.23.0 (bottled), HEAD Tool for building toolchains https://crosstool-ng.github.io/ /usr/local/Cellar/crosstool-ng/1.23.0_3 (1,294 files, 7.7MB) * Poured from bottle on 2019-02-08 at 17:07:19 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/crosstool-ng.rb ==> Dependencies Build: help2man ✔ Required: autoconf ✔, automake ✔, binutils ✔, coreutils ✔, flex ✔, gawk ✔, gnu-sed ✔, grep ✔, libtool ✔, m4 ✔, make ✔, ncurses ✔, xz ✔ ==> Options --HEAD Install HEAD version ==> Analytics install: 370 (30 days), 1,283 (90 days), 4,018 (365 days) install_on_request: 342 (30 days), 1,106 (90 days), 3,409 (365 days) build_error: 0 (30 days)
如果你在brew info时,发现help2man没有打勾的话,可以通过brew install安装。个人不确定对构建交叉编译环境是否有影响。
部分介绍交叉编译环境的文章会说再安装一个新版本的bison,个人没有安装,作为参考,本机的bison信息如下
➜ ~ brew info bison bison: stable 3.3.2 (bottled) [keg-only] Parser generator https://www.gnu.org/software/bison/ /usr/local/Cellar/bison/3.0.4 (51 files, 2.1MB) Poured from bottle on 2016-01-25 at 19:23:54 /usr/local/Cellar/bison/3.0.5 (52 files, 2.1MB) Poured from bottle on 2018-06-19 at 11:25:38 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/bison.rb ==> Caveats bison is keg-only, which means it was not symlinked into /usr/local, because some formulae require a newer version of bison. ==> Analytics install: 17,770 (30 days), 52,184 (90 days), 156,520 (365 days) install_on_request: 10,829 (30 days), 31,225 (90 days), 92,262 (365 days) build_error: 0 (30 days)
安装完crosstool-ng之后,macos上需要为交叉编译环境分配一个大约10G的字符大小写敏感的分区。具体要多大,看目标平台。一个平台的话10G够了,两个会超过10G。作为参考构建完arm-linux-gnueabihf之后使用空间8.7G。
打开Disk Utility,工具栏上添加volume,选择一个名字,格式选择APFS(Case-sensitive)。在Size options…中两个都填入10G。
创建完之后在命令行下进入这个新volume
cd /Volumes/xtool-build-env
用crosstool-ng列出可选的一些sample
ct-ng list-samples
其中应该包括arm-linux-gnueabihf。选择arm-linux-gnueabihf
ct-ng arm-linux-gnueabihf
ct-ng会在/Volumes/xtool-build-env下生成一个叫做 .config 的文件,里面包含了很多配置。其中需要关注的几个配置是路径相关的几个配置。把几个路径改成volume内的路径
CT_LOCAL_TARBALLS_DIR="/Volumes/xtool-build-env/src" CT_SAVE_TARBALLS=y CT_WORK_DIR="/Volumes/xtool-build-env/build" CT_BUILD_TOP_DIR="${CT_WORK_DIR}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}" CT_PREFIX_DIR="/Volumes/xtool-build-env/${CT_TARGET}"
改好之后,备份这个 .config
cp .config config-bak
备份的原因是ct-ng build中途失败时处理方法导致的,具体之后会看到。
开始build
ct-ng build
如果一切正常的话,大约1个多小时能完全(不包括下载时间)。问题是,ct-ng build有大几率会碰到乱七八糟的问题而停下来。以下是我碰到的几个
build m4 failed
[INFO ] Installing m4 for build [EXTRA] Configuring m4 [EXTRA] Building m4 [24:09] / /usr/local/Cellar/crosstool-ng/1.23.0_3/lib/crosstool-ng-1.23.0/scripts/functions: line 297: 30256 Segmentation fault: 11 "${@}" 2>&1 30257 Done | CT_DoLog "${level}" [ERROR] [ERROR] >> [ERROR] >> Build failed in step 'Installing m4 for build' [ERROR] >> called in step '(top-level)' [ERROR] >> [ERROR] >> Error happened in: CT_DoExecLog[scripts/functions@297] [ERROR] >> called from: do_m4_backend[scripts/build/companion_tools/100-m4.sh@66] [ERROR] >> called from: do_companion_tools_m4_for_build[scripts/build/companion_tools/100-m4.sh@17] [ERROR] >> called from: do_companion_tools_for_build[scripts/build/companion_tools.sh@35] [ERROR] >> called from: main[scripts/crosstool-NG.sh@653] [ERROR] >> [ERROR] >> For more info on this error, look at the file: 'build.log' [ERROR] >> There is a list of known issues, some with workarounds, in: [ERROR] >> '/usr/local/Cellar/crosstool-ng/1.23.0_3/share/doc/crosstool-ng/crosstool-ng-1.23.0/B - Known issues.txt' [ERROR] >> [ERROR] >> If you feel this is a bug in crosstool-NG, report it at: [ERROR] >> https://github.com/crosstool-ng/crosstool-ng/issues/ [ERROR] >> [ERROR] >> Make sure your report includes all the information pertinent to this issue. [ERROR] >> Read the bug reporting guidelines here: [ERROR] >> http://crosstool-ng.github.io/support/ [ERROR] [ERROR] (elapsed: 24:07.00) [24:09] / gmake: *** [/usr/local/bin/ct-ng:147: build] Error 1
根据这个issue,解决方法如下
brew uninstall --ignore-dependencies binutils brew install binutils
但是此时如果你ct-ng build想继续build的话是不行的,具体原因不清楚,我的解决方法是
ct-ng distclean cp config-bak .config
distclean会把.config删除掉,所以要事先备份。
automake not found
[INFO ] Installing gettext for host [EXTRA] Configuring gettext [EXTRA] Building gettext [ERROR] make[5]: *** [Makefile:2561: /Volumes/xtool-build-env/build/src/gettext-0.19.8.1/gettext-tools/src/Makefile.in] Error 127 [ERROR] make[4]: *** [Makefile:2026: all-recursive] Error 1 [ERROR] make[3]: *** [Makefile:1892: all] Error 2 [ERROR] make[2]: *** [Makefile:414: all-recursive] Error 1 [ERROR] make[1]: *** [Makefile:370: all] Error 2 [ERROR] [ERROR] >> [ERROR] >> Build failed in step 'Installing gettext for host' [ERROR] >> called in step '(top-level)' [ERROR] >> [ERROR] >> Error happened in: CT_DoExecLog[scripts/functions@297] [ERROR] >> called from: do_gettext_backend[scripts/build/companion_libs/330-gettext.sh@136] [ERROR] >> called from: do_gettext_for_host[scripts/build/companion_libs/330-gettext.sh@53] [ERROR] >> called from: do_companion_libs_for_host[scripts/build/companion_libs.sh@36] [ERROR] >> called from: main[scripts/crosstool-NG.sh@653] [ERROR] >> [ERROR] >> For more info on this error, look at the file: 'build.log' [ERROR] >> There is a list of known issues, some with workarounds, in: [ERROR] >> '/usr/local/Cellar/crosstool-ng/1.23.0_3/share/doc/crosstool-ng/crosstool-ng-1.23.0/B - Known issues.txt' [ERROR] >> [ERROR] >> If you feel this is a bug in crosstool-NG, report it at: [ERROR] >> https://github.com/crosstool-ng/crosstool-ng/issues/ [ERROR] >> [ERROR] >> Make sure your report includes all the information pertinent to this issue. [ERROR] >> Read the bug reporting guidelines here: [ERROR] >> http://crosstool-ng.github.io/support/ [ERROR] [ERROR] (elapsed: 14:14.00) [14:16] / gmake: *** [/usr/local/bin/ct-ng:147: build] Error 1
如果你tail一下build.log时,你会看到
[ALL ] /Volumes/xtool-build-env/build/src/gettext-0.19.8.1/build-aux/missing: line 81: automake-1.15: command not found [ALL ] WARNING: 'automake-1.15' is missing on your system. [ALL ] You should only need it if you modified 'Makefile.am' or [ALL ] 'configure.ac' or m4 files included by 'configure.ac'. [ALL ] The 'automake' program is part of the GNU Automake package: [ALL ] <http://www.gnu.org/software/automake> [ALL ] It also requires GNU Autoconf, GNU m4 and Perl in order to run: [ALL ] <http://www.gnu.org/software/autoconf> [ALL ] <http://www.gnu.org/software/m4/> [ALL ] <http://www.perl.org/> [ERROR] make[5]: *** [Makefile:2561: /Volumes/xtool-build-env/build/src/gettext-0.19.8.1/gettext-tools/src/Makefile.in] Error 127 [ALL ] make[5]: Leaving directory '/Volumes/xtool-build-env/build/aarch64-rpi3-linux-gnueabi/build/build-gettext-host-x86_64-build_apple-darwin18.2.0/gettext-tools/src' [ERROR] make[4]: *** [Makefile:2026: all-recursive] Error 1 [ALL ] make[4]: Leaving directory '/Volumes/xtool-build-env/build/aarch64-rpi3-linux-gnueabi/build/build-gettext-host-x86_64-build_apple-darwin18.2.0/gettext-tools' [ERROR] make[3]: *** [Makefile:1892: all] Error 2 [ALL ] make[3]: Leaving directory '/Volumes/xtool-build-env/build/aarch64-rpi3-linux-gnueabi/build/build-gettext-host-x86_64-build_apple-darwin18.2.0/gettext-tools' [ERROR] make[2]: *** [Makefile:414: all-recursive] Error 1 [ALL ] make[2]: Leaving directory '/Volumes/xtool-build-env/build/aarch64-rpi3-linux-gnueabi/build/build-gettext-host-x86_64-build_apple-darwin18.2.0' [ERROR] make[1]: *** [Makefile:370: all] Error 2 [ALL ] make[1]: Leaving directory '/Volumes/xtool-build-env/build/aarch64-rpi3-linux-gnueabi/build/build-gettext-host-x86_64-build_apple-darwin18.2.0'
即没有automake,所以解决方法是
ct-ng menuconfig
在companion tools中勾选automake。记得更新了 .config 之后备份。
在解决了上面两个问题之后,我的ct-ng build就顺利完成了。最后写一个hello world,cross compile之后复制到raspberry pi 3 b+上能执行的话就OK了。
小结
老实说,cross compile一直是个人的心结,因为cross compile的环境构建真得很麻烦。相比之下Write once,run everywhere是开发者的福音,不管是过去还是现在。