交叉编译简介

交叉编译是在一个平台上编译生成另一个平台上的可执行代码,当我们开发目标是一个嵌入式设备时,便需要在PC机上编译出能在该嵌入式设备上运行的可执行文件,这里编译主机与目标运行主机不是同一个设备,该过程就称为交叉编译;
编译是指一个源代码文件,如C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)等步骤才能变成可执行文件,整个过程统称为编译。

常用的交叉编译环境是:在X86架构主机上编译生成可执行文件,放到ARM架构开发板上运行。
为什么需要交叉编译:目的平台上不允许或不能够安装所需的编译器;或目的平台上的资源贫乏,无法运行我们所需要编译器;或目的平台还没有建立,甚至没有操作系统等。

cmake 交叉编译

C/C++项目,可以使用cmake交叉编译。

使用cmake创建嵌入式开发项目,和创建普通的C/C++项目类似,区别在于不使用默认的gcc/g++编译器,而是使用交叉编译器。

cmake创建C/C++项目参考:https://blog.csdn.net/weixin_40355471/article/details/133200612?spm=1001.2014.3001.5502

1、创建普通cmake项目,包含CMakeLists.txt文件

mkdir build	#在CMakeLists.txt所在目录创建build文件夹
cd build	
vim rvgcc.cmake	#在build/目录创建rvgcc.cmake文件,手动指定交叉编译器路径。

set(CMAKE_C_COMPILER /opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER /opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-g++)
set(CMAKE_ASM_COMPILER /opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-gcc)

set(CMAKE_C_COMPILER_FORCED TRUE)
set(CMAKE_CXX_COMPILER_FORCED TRUE)

2、cmake,使用 -DCMAKE_TOOLCHAIN_FILE 选项指定工具链文件的路径
后面也可以带上其他自定义选项 -DUBUSYS=ON

cmake -DCMAKE_TOOLCHAIN_FILE="rvgcc.cmake" -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=debug -DUBUSYS=ON ..

3、交叉编译,生成可执行文件,拷贝到arm上运行

make -j

报错处理
unknown value ‘native’ for ‘-march’
删掉CMakeLists.txt文件中的-march=native
-march=native #march:指定目标架构名;native:允许编译器自动探测目标架构

clion 交叉编译

cmake创建项目后,可以使用传统的 clion 进行远程开发和交叉编译。

clion 可运行在windows系统,编译环境在 ubuntu20.04,交叉编译后在 arm 上运行(clion 远程开发,代码在windows和ubuntu都有,修改后clion会上传或下载进行代码同步)。

使用 clion 远程 linux 嵌入式开发,可以交叉编译,但交叉编译的可执行文件不能在clion运行和调试。

clion 远程开发配置参考https://blog.csdn.net/weixin_40355471/article/details/127833119?spm=1001.2014.3001.5502

clion 加载 CMakeLists.txt 文件后,在 CMakeLists.txt 所在目录生成文件夹 cmake-build-debug ,把上面的 rvgcc.cmake 文件拷贝到该文件夹。

clion 交叉编译设置:
1、clion–Settings–Toolchains–选择创建的远程连接,C Comoiler 手动录入交叉编译器目录:/opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-gcc
C++ Comoiler 手动录入交叉编译器目录:/opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-g++
其他设置不变,CMake和Debugger均是自动检出。

2、clion–Settings–CMake–CMake options: 输入编译选项:

-DCMAKE_TOOLCHAIN_FILE="rvgcc.cmake" -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=debug -DUBUSYS=ON .

完成设置后,在clion编译即可生成可执行文件,拷贝到arm上运行。

vscode 远程嵌入式开发

嵌入式开发使用 clion 只能交叉编译,不能使用 clion 直接运行和调试交叉编译的可执行文件,如果想简单一点可以直接使用 vscode 远程开发编辑,命令行远程进行交叉编译。

Qt交叉编译

Qt交叉编译,在arm板上运行(比如RK3399)。
环境搭建
主机:win10
开发环境:虚拟机,ubuntu 20.04.2
Qt交叉编译库版本:Qt5.12.9
Qt开发版本:Qt5.14.1
arm板:RK3399

大致思路
1、要让程序在arm上运行,需要特殊的编译器,首先在ubuntu上安装这种编译器(交叉编译工具)。
2、ubuntu上,使用交叉编译工具,把QT源码编译成可以在arm上使用的QT依赖库。
3、编译好的QT依赖库拷贝到arm板子上,arm上可以执行QT交叉编译的程序。
4、ubuntu安装普通版本QT,配置构建套件,编译器使用交叉编译工具,QT版本配置交叉编译好的qmake路径。
5、至此可使用ubuntu的QT开发和交叉编译,编译的可执行文件拷贝到arm上运行。

硬件环境
RK3399 arm开发板通过USB转串口与win10主机相连,识别COM口,win10主机通过COM口使用MobaXterm等远程工具连接板子,给板子配置IP和网关后可以通过IP地址远程,使用SCP进行文件传输。

#一些常用命令
vi  /etc/eth0-setting	#改网卡IP

ifconfig eth2 down
ifconfig eth2 192.168.72.167 up
ifconfig eth2  192.168.72.165  netmask 255.255.255.0

1.安装交叉编译工具

下载地址:https://www.linaro.org/downloads/
下载压缩包:gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.gz。

#拷贝到/opt目录下
cd /opt
sudo tar -xvf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.gz
sudo mv gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu gcc-aarch64-linux-gnu
sudo vim /etc/profile
export PATH="/opt/gcc-aarch64-linux-gnu/bin:$PATH"
source  /etc/profile
aarch64-none-linux-gnu-gcc -v

安装完成后获得交叉编译器(/opt/gcc-aarch64-linux-gnu/bin 目录下),配置环境变量后可以使用交叉编译命令,和直接使用gcc类似。

#查询版本,如果查询到版本信息则说明安装成功
aarch64-none-linux-gnu-gcc -v

交叉编译qt库时需要配置这个编译器,后续也要配置到Qt Creator的构建套件里。

2.交叉编译qt库

下载Qt5.12.9源码:https://download.qt.io/archive/qt/5.12/5.12.9/single/
下载版本:qt-everywhere-src-5.12.9.tar.xz
解压缩源码:

tar -xvf qt-everywhere-src-5.12.9.tar.xz
cd qt-everywhere-src-5.12.9/

2.1修改qmake.conf

vim qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf
#
# qmake configuration for building with arm-linux-gnueabi-g++
#

MAKEFILE_GENERATOR      = UNIX
CONFIG                 += incremental
QMAKE_INCREMENTAL_STYLE = sublib

#添加
QT_QPA_DEFAULT_PLATFORM = linuxfb
QMAKE_CFLAGS_RELEASE += -O2 -march=armv8-a -lts
QMAKE_CXXFLAGS_RELEASE += -O2 -march=armv8-a -lts


include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)

# modifications to g++.conf
# 修改交叉编译工具可执行文件
QMAKE_CC                = aarch64-none-linux-gnu-gcc
QMAKE_CXX               = aarch64-none-linux-gnu-g++
QMAKE_LINK              = aarch64-none-linux-gnu-g++
QMAKE_LINK_SHLIB        = aarch64-none-linux-gnu-g++

# modifications to linux.conf
QMAKE_AR                = aarch64-none-linux-gnu-ar cqs
QMAKE_OBJCOPY           = aarch64-none-linux-gnu-objcopy
QMAKE_NM                = aarch64-none-linux-gnu-nm -P
QMAKE_STRIP             = aarch64-none-linux-gnu-strip
load(qt_config)

2.2创建交叉编译自动配置脚本,开始编译
-prefix /opt/qt5.12.9-arm,配置生成的依赖库保存路径。

vim auto.sh
#!/bin/sh
./configure \
-prefix /opt/qt5.12.9-arm \
-confirm-license \
-opensource \
-release \
-make libs \
-xplatform linux-arm-gnueabi-g++ \
-pch \
-qt-libjpeg \
-qt-libpng \
-qt-zlib \
-no-opengl \
-no-sse2 \
-no-openssl \
-no-cups \
-no-glib \
-no-dbus \
-no-xcb \
-no-separate-debug-info \

sudo chmod u+x auto.sh 
./auto.sh
sudo make		#如果找不到 aarch64-none-linux-gnu-gcc 命令,可以切换到root下,不使用sudo
sudo make install
cd /opt/qt5.12.9-arm	#已安装到指定目录,查看(bin  doc  include  lib  mkspecs  plugins  qml  translations)

编译完成后获得交叉编译所依赖的Qt库(/opt/qt5.12.9-arm 目录下),编译好的库要拷贝到arm板子上,后续也要配置到Qt Creator的构建套件里。

错误处理
python: not found

type python python2 python3
#如果没有python,则安装
sudo apt install python3
#如果有 python3 ,没有 python,执行
sudo apt install python-is-python3

3.将交叉编译的Qt库复制到板子上

/opt/qt5.12.9-arm,把该目录拷贝到arm板子上,在arm上配置环境变量。
从ubuntu把QT依赖库拷贝到arm上。

scp -r qt5.12.9-arm root@192.168.72.165:/opt

在arm上执行,配置环境变量。

vi /etc/profile
export QTEDIR=/opt/qt5.12.9-arm
export LD_LIBRARY_PATH=/opt/qt5.9.0-arm/lib:$LD_LIBRARY_PATH
export QT_QPA_PLATFORM_PLUGIN_PATH=$QTEDIR/plugins
export QT_QPA_PLATFORM=linuxfb
export QT_QPA_FONTDIR=/usr/share/fonts/truetype/droid

4.安装和配置 Qt Creator,支持交叉编译

ubuntu上安装普通版本的QT,比如5.14.1,可以只安装Qt Creator,安装完成后运行。

构建套件配置
添加C/C++编译器
菜单栏,Tools,Options,Kits,Compilers,选择添加,ADD,GCC,C/C++。
Manual,C,GCC,Complier path:/opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-gcc
Manual,C++,GCC,Complier path:/opt/gcc-aarch64-linux-gnu/bin/aarch64-none-linux-gnu-g++

添加Qt版本
Qt Versions,Add…,选择交叉编译生成的qmake目录
Manual,Qt5.12.9(qt5.12.9-arm),/opt/qt5.12.9-arm/bin/qmake

添加构建套件
Kits,Add
Manual,生成自定义套件,包括名称、设备类型、编译工具、Qt版本等信息。
Name arm
Device Generic Linux Device
Compiler C: GCC
Compiler C++: GCC
Debugger System GDB at /usr/bin/gdb
Qt Version Qt5.12.9(qt5.12.9-arm)
CMake Tool System CMake at /usr/bin/cmake

5.QT嵌入式开发

新建QT项目,在选择构建套件时,选刚刚新建的arm,正常开发编译,把编译好的二进制可执行文件拷贝到3399板子上。

scp hellowd  root@192.168.72.165:/userdata/qt_pro
./hellowd	#板子上运行

6.QT嵌入式开发报错解决

QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed

在板子上运行时报错,原因是缺少iconv库。
下载源码:http://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz
下载:libiconv-1.14.tar.gz

tar xvf libiconv-1.14.tar.gz
cd libiconv-1.14/

# 创建自动配置脚本
vim autoconfig.sh
./configure \
#替换交叉编译器路径
CC=/opt/gcc-arm-linux-gnueabi/bin/arm-linux-gnueabihf-gcc \
CXX=/opt/gcc-arm-linux-gnueabi/bin/arm-linux-gnueabihf-g++ \
#安装目录
--prefix=/opt/libiconv_install/ \
--host=arm-linux \
--enable-shared \
--enable-static \
#当前解压缩路径
--with-sysroot=/home/chw/arm/libiconv-1.14

chmod +x autoconfig.sh
./autoconfig.sh
make -j	#编译
make install

‘gets’ undeclared here (not in a function); did you mean ‘fgets’? 报错解决

vim srclib/stdio.in.h

_GL_WARN_ON_USE (gets, “gets is a security hole-use fgets instead”)
# 修改为:
#if defined(GLIBC) && !defined(UCLIBC) && !__GLIBC_PREREQ(2, 16)
_GL_WARN_ON_USE (gets, “gets is a security hole - use fgets instead”);
#endif

安装完成后,生成的库文件路径:/opt/libiconv_install。

# 拷贝到板子上
sudo scp -r libiconv_install/ root@192.168.72.111:/opt	
# 在板子上执行后,运行qt交叉编译的可执行文件即可
export LD_PRELOAD=/opt/libiconv_install/lib/preloadable_libiconv.so	

cannot execute binary file: Exec format error

在板子上运行时报错。
可能的原因:使用64位交叉编译器编译的可执行文件,放在32位arm上运行。
解决方法:更换交叉编译器。

arm上报错找不到槽函数

不使用SIGNAL(readyRead())写法,改为&QSerialPort::readyRead这种写法。

交叉编译gdb调试

本章介绍远程gdb调试方法:交叉编译调试时,主机ubuntu使用gdb,arm使用gdbserver。

交叉编译器自带gdb,一般不需要编译,例如:arm-linux-gnueabihf-gdb

arm-linux-gnueabihf-gdb --version	#查询gdb版本

交叉编译 gdbserver

下载gdb源码:https://www.sourceware.org/gdb/download/
gdb-8.3.tar.gz,拷贝到ubuntu目录

tar zxvf gdb-8.3.tar.gz
cd gdb-8.3/gdb/gdbserver/
./configure --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf  --prefix=/opt/gdb/gdbserver-lib
# --host:该软件将运行的平台,填你的交叉编译器
# --target:该软件所处理的目标平台,填你的交叉编译器
# --prefix:目标文件生成路径
make
sudo make install

cd /opt/gdb/gdbserver-lib/bin/	#生成的gdbserver目录:arm-linux-gnueabihf-gdbserver
#把gdbserver拷贝到arm上
sudo scp arm-linux-gnueabihf-gdbserver root@192.168.72.111:/home/chw

gdb远程调试

arm上执行

#1234是指定的端口号,qt_at3399是可执行程序,此时程序并未运行
./arm-linux-gnueabihf-gdbserver :1234 qt_at3399		
Process /home/chw/qt_at3399 created; pid = 2652
Listening on port 1234

ubuntu上执行

arm-linux-gnueabihf-gdb qt_at3399
#进入gdb
target remote 192.168.72.111:1234	#arm :Remote debugging from host ::ffff:192.168.72.55, port 56972
b 50	#在main.cpp的50行打断点
c		#运行
#Thread 1 "qt_at3399" hit Breakpoint 1,命中第一个断点
q		#退出gdb

在gdb远程调试时,arm只负责 gdbserver 启动远程端口,指定可执行程序;程序的运行由 ubuntu 的gdb负责启动、打断点、调试、关闭等。

error while loading shared libraries: libncursesw.so.5

sudo apt install libncursesw5-dev
ln -s /usr/lib/libncursesw.so.6 /usr/lib/libncursesw.so.5
#不行再运行
sudo apt install apt-file
sudo apt-file update
sudo apt-file find libncursesw.so.5
sudo apt install libncursesw5

gdb调试core文件

ulimit -c unlimited	#arm上执行
#运行程序生成core文件
#把core文件拷贝到ubuntu主机
arm-linux-gnueabihf-gdb qt_at3399 core
bt	#查询调用栈
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐