这篇博客是以树莓派CM4为例子进行阐述,其他的arm架构等开发板也可以采用这样的方式进行交叉编译
近期在交叉编译上踩坑颇多,这里针对近期做好的效果进行记录。
本文是的配置环境是:
树莓派CM4核心板+CM4拓展板
VMware下的Ubuntu18.04.6虚拟机
VSCode linux版本
树莓派烧录系统参考我写的烧录博客
Ubuntu系统如何烧录到vmware参考我写的另一篇博客
VSCode在linux的下载教程参考:linux下载vscode
(1)、C/C++,C 和 C++的编译环境(必须)
(2)、C/C++ Snippets,即 C/C++重用代码块。(必须)
(3)、C/C++ Advanced Lint,即 C/C++静态检测 。(必须)
(4)、Code Runner,即代码运行。(必须)
(5)、Include AutoComplete,即自动头文件包含。(高效)
(6)、Rainbow Brackets,彩虹花括号,有助于阅读代码。
(7)、One Dark Pro,VSCode 的主题。(非必须)
(8)、GBKtoUTF8,将 GBK 转换为 UTF8。
(9)、ARM,即支持 ARM 汇编语法高亮显示(非必须,但方便)
(10)、Chinese(Simplified),即中文环境。(看个人水平)
(11)、vscode-icons,VSCode 图标插件,主要是资源管理器下各个文件夹的图标。(美观)
(12)、compareit,比较插件,可以用于比较两个文件的差异。
(13)、DeviceTree,设备树语法插件。(非必须)
(14)、TabNine, AI 自动补全插件(高效)
树莓派的交叉编译链工具根据个人所下载的树莓派系统有关,我这里下载的是树莓派lite64位版本。
如果忘了自己的树莓派系统是什么版本,可以在树莓派控制端输入指令:uname -a
显示树莓派的系统的一些信息。
比如我的是:
Linux raspberrypi 5.15.84-v8+ #1613SMP PREEMPT Thu Jan 512.03.08 GMT 2023 aarch64 GNU/Linux
这里解释一下个字段含义,顺便给自己做个备忘。
系统名称:Linux
用户名:raspberrypi
操作系统的发行版号:5.15.84-v8+
内核版本:#1613SMP PREEMPT Thu Jan 512.03.08 GMT 2023
机器硬件(CPU名称):aarch64
操作系统名:GNU/Linux
通过上面的信息,我们可以知道我们队树莓派进行交叉编译的交叉编译工具链应该是aarch64-linux-gnu系列的,因此我们官网下载工具链->下载链接
在windows下载后,可以通过共享文件夹/U盘/SSH把交叉编译工具链放到linux的目录中,这里的目录后面会用到。我下面用到的目录是我自己放置交叉编译链的地方,大家可以自行设定。
有的读者可能和我之前一样,不知道各种交叉编译链对应的意思,这里可以参考我转载的记录文章:
交叉编译详解
这个小节开始,开始详细记录整个交叉编译的流程。
首先在虚拟机的主文件夹下创建Hello文件夹
打开VSCode选择打开文件夹
,选择刚才的路径
创建hello.c
文件
这里可能会出现无法输入的情况,因为左下角这里不是insert模式,需要我们按一下a
输入测试代码:
#include
int main()
{
printf("helloWorld");
return 0;
}
选择后,点击1
所在位置,接着看2
,针对我们的2框,下面做详细解释。
VSCode最劝退人的一步大概率就是这个json
文件的配置了,关于json文件的说明如下:
task.json是gcc编译产生可执行文件的配置文件。
launch.json是gdb调试使用的配置文件。
我们分别对两个自动生成的json文件进行阐述。
这里我们着重关注以下三个标识:
label
:任务名称
command
:对应使用gcc的具体路径
args
:gcc对应的参数
我们手动编译的时候,其实类似于gcc -g hello.c -o hello
这样的指令
那么在task.json中,实现这样的指令用到的就是command args
下面的代码中,command指定了树莓派交叉编译工具链中gcc的位置,args则表明了执行的可选项。
其中${fileDirname}
和下面参数cwd
(current work directory)对应,表示当前工作目录。
那么-o
后面紧跟着的参数其实就是生成的可执行文件输出的位置。
其实也可以输出到特定文件夹,通过相对路径和绝对路径进行书写。
这里面detail
标识其实就类似于一个注释,我这里写了gcc路径,其实可以根据自己需求自定义。
{
"tasks": [
{
"type": "cppbuild",
"label": "RaspiGCC",
"command": "/home/fpga/Raspi/RaspiToolChain/bin/aarch64-linux-gnu-gcc",
"args": [
"-g",
"hello.c",
"-o",
"${fileDirname}/Test"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "gccPath:/home/fpga/Raspi/RaspiToolChain/bin/aarch64-linux-gnu-gcc"
}
],
"version": "2.0.0"
}
当然,具体运用的时候可能不止编译一个.c
文件,对于多个文件我们这样写。生成的可执行文件保存到当前路径下的out目录中,
这里${fileBasenameNoExtension}
见文知意,生成的文件名为.c
文件没有后缀的执行性文件。
"args": [
"-g",
"${fileDirname}/*.c",
"-o",
"${fileDirname}/out/${fileBasenameNoExtension}"
],
上面是针对很多.c文件的方式,如果就那么几个,我们还可以单独列出来写。
现在假设hello.c和world.c在同一个文件夹,这里两种写法其实一个意思。如果我们在选择源文件的时候不给路径,默认是从当前路径下进行操作。
如果不同文件夹下的不同源文件进行编译,那其实只需要说明路径即可。
例如:用/home/user/world/world.c
代替world.c
"args": [
"-g",
"${fileDirname}/hello.c",
"world.c"
"-o",
"${fileDirname}/out/${fileBasenameNoExtension}"
],
launch.json是debug用的,我们其实可以通过看type
标签知道。
在debug之前要有可执行文件才能debug,所以就需要前置条件。
我们看到preLaunchTask
,这里说明的是在执行launch.json配置文件之前所要执行的任务。
这里和task.json中的Label
标签的值对应,我这里都设置为RaspiGCC,是我自己为了方便知道这个json是给什么用的。如果图省事其实可以选择默认的C/C++: gcc 生成活动文件
,只要保持两个文件的字段保持一致就可以了。
gcc指定了对应的交叉编译链工具位置,gdb也需要指定。
在miDebuggerPath
中的字段即为自己安装交差编译链中gdb所在的地方。
那调试程序还需要知道调试的是什么程序,我们可以通过program
字段来确定。
字段的值要对应刚才生产的可执行文件的名称。
因为刚才的task.json选择生成的可执行文件是在当前目录下,名为Test的可执行文件,所以我们在设置program
字段的时候,也要进行对应。
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb)start",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/Test",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "RaspiGCC",
"miDebuggerPath": "/home/fpga/Raspi/RaspiToolChain/bin/aarch64-linux-gnu-gdb"
}
]
}
编译成功后,会生成可执行文件,可执行文件的位置是自己定的。但是我自己演示的始发现无法调试。
出现下面情况
后来才意识到我是基于树莓派的交差编译链,这和Ubuntu中的环境不一样。所以调试的话得远程调试,虚拟机的VSCode并不支持调试这个交差编译链生成的可执行文件。
至于VSCode远程调试树莓派的话,参考VScode远程linux,这篇博客里面也有各个字段的详细解释。
总结:这篇博客写的时间比较长,也是近期踩坑以及探索过程的一个总结。
详细记录了自己交叉编译过程,为后面嵌入式等交叉编译都打了个基础。
对VSCode的json文件有了更深的理解,感觉自己功力又大进了一步哈哈哈哈。
澄澈i
用简单的语言记录自己走过的技术路