从零到一:在Ubuntu上为树莓派搭建交叉编译环境与wiringPi实战
1. 为什么需要交叉编译环境第一次接触树莓派开发的朋友可能会疑惑为什么不能直接在树莓派上写代码编译呢我刚开始也有同样的疑问直到实际开发时才发现问题。树莓派的ARM处理器性能有限编译一个稍复杂的程序可能要等好几分钟。有次我写了个带图形界面的程序在树莓派上编译足足花了8分钟而同样的代码在Ubuntu笔记本上交叉编译只用了15秒。交叉编译的本质就像翻译工作。想象你要把中文书翻译成英文有两种选择要么找个会说中英文的英国人本地编译要么在中国找专业翻译团队交叉编译。显然后者效率更高因为翻译团队有更强大的硬件资源高性能电脑、专业软件等。同理用x86架构的Ubuntu电脑为ARM架构的树莓派交叉编译能充分利用PC的性能优势。实际开发中还会遇到更棘手的情况。比如开发树莓派上的Linux驱动时目标平台连操作系统都还没装好这时候交叉编译就成了唯一选择。我去年参与的一个物联网项目就是这样需要先交叉编译出树莓派的bootloader和内核镜像才能进行后续开发。2. 搭建交叉编译工具链2.1 获取官方工具链树莓派基金会提供了官方工具链这是最可靠的选择。我对比过第三方工具链发现官方版本对树莓派硬件的支持最完善。获取方法很简单git clone https://github.com/raspberrypi/tools如果GitHub访问慢可以试试官方镜像。下载完成后建议将工具链放在/opt目录下sudo mv tools /opt/rpi-tools记得检查工具链版本是否匹配你的树莓派型号。我的树莓派4B使用的是arm-bcm2708目录下的gcc-linaro-arm-linux-gnueabihf-raspbian-x64工具链。有个小技巧用file命令查看树莓派上/usr/bin下的任意可执行文件就能确认架构file /usr/bin/ls2.2 配置环境变量临时设置PATH虽然简单但每次重启都要重新配置。我推荐修改.bashrc实现永久生效echo export PATH$PATH:/opt/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin ~/.bashrc source ~/.bashrc验证是否配置成功arm-linux-gnueabihf-gcc --version如果看到类似gcc version 4.8.3 20140106的输出说明配置正确。这里有个坑要注意不同版本的工具链可能使用不同的前缀有的是arm-linux-gnueabihf-有的是arm-rpi-linux-gnueabihf-一定要确认清楚。3. 第一个交叉编译程序3.1 编写测试程序创建一个简单的LED闪烁程序blink.c#include stdio.h #include wiringPi.h int main(void) { wiringPiSetup(); pinMode(1, OUTPUT); while(1) { digitalWrite(1, HIGH); delay(500); digitalWrite(1, LOW); delay(500); } return 0; }交叉编译时要注意指定正确的库路径arm-linux-gnueabihf-gcc blink.c -o blink -I/usr/local/include -L/usr/local/lib -lwiringPi这个命令中-I指定头文件路径-L指定库文件路径-l链接具体库3.2 部署到树莓派我习惯用scp传输文件比U盘方便多了scp blink pi192.168.1.100:~/projects然后在树莓派上运行./blink如果遇到libwiringPi.so找不到的错误需要检查树莓派上的库路径是否包含该库。可以用ldd命令查看程序依赖ldd blink4. wiringPi库的安装与使用4.1 方法一源码编译安装这是最推荐的方式能确保版本匹配git clone https://github.com/WiringPi/WiringPi cd WiringPi ./build安装后检查版本gpio -v我在树莓派4B上遇到过兼容性问题解决方法是使用特定分支git checkout legacy ./build4.2 方法二直接复制库文件当源码编译失败时可以从另一台树莓派复制scp pi192.168.1.100:/usr/lib/libwiringPi.so.2.50 . ln -s libwiringPi.so.2.50 libwiringPi.so然后编译时需要指定库路径arm-linux-gnueabihf-gcc -L. -lwiringPi ...4.3 常见问题解决遇到undefined reference错误时可能是链接顺序问题。GCC的链接器是从右往左解析依赖的正确的顺序应该是arm-linux-gnueabihf-gcc blink.c -lwiringPi -lpthread -lm -lcrypt -lrt如果使用CMake需要在CMakeLists.txt中设置交叉编译参数set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g)5. 进阶技巧与优化5.1 使用ccache加速编译安装ccache后修改.bashrcexport CCACHE_PREFIXarm-linux-gnueabihf- export PATH/usr/lib/ccache:$PATH这样重复编译时能显著提升速度。我的一个项目编译时间从45秒缩短到了8秒。5.2 静态链接简化部署对于简单程序可以静态链接避免库依赖问题arm-linux-gnueabihf-gcc -static blink.c -lwiringPi但要注意这会使可执行文件变大我的测试程序从15KB增大到了650KB。5.3 交叉调试技巧在Ubuntu上安装gdbserversudo apt install gdb-multiarch在树莓派上运行gdbserver :1234 ./blink在Ubuntu上连接调试gdb-multiarch ./blink target remote 192.168.1.100:12346. 实际项目经验分享去年开发智能家居控制器时我建立了完整的交叉编译工作流。项目结构如下project/ ├── build/ ├── CMakeLists.txt ├── src/ └── toolchain.cmaketoolchain.cmake内容set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g) set(CMAKE_FIND_ROOT_PATH /opt/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)这样就能用CLion等IDE直接开发树莓派项目了。部署时我写了个简单的脚本#!/bin/bash scp build/project pi$1:~/projects ssh pi$1 cd ~/projects ./project使用时只需运行./deploy.sh 192.168.1.100就能完成编译部署全过程。