目录
- 交叉编译简介
- cmake 交叉编译
- clion 交叉编译
- vscode 远程嵌入式开发
- Qt交叉编译
- 1.安装交叉编译工具
- 2.交叉编译qt库
- 3.将交叉编译的Qt库复制到板子上
- 4.安装和配置 Qt Creator,支持交叉编译
- 5.QT嵌入式开发
- 6.QT嵌入式开发报错解决
- QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed
- cannot execute binary file: Exec format error
- arm上报错找不到槽函数
- 交叉编译gdb调试
- 交叉编译 gdbserver
- gdb远程调试
- gdb调试core文件
交叉编译简介
交叉编译是在一个平台上编译生成另一个平台上的可执行代码,当我们开发目标是一个嵌入式设备时,便需要在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 #改网卡IPifconfig 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 -ltsinclude(../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.14chmod +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 installcd /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 #查询调用栈