嵌入式Linux 基础知识
Wsl2开发环境
Windows已步入win11时代,wsl已经发展到第二代,使用wsl2做嵌入式linux编译完全可行,且相比于虚拟机,wsl2的文件可在主机中直接访问,网络也可直接ping通,占用空间较小,对电脑性能的利用更加充分,因此本文记录了我使用Wsl2进行Linux驱动开发和应用开发的环境配置方式。
WSL2安装配置
安装wsl2
首先将自己的wsl更新到wsl2
- 设置wsl版本为wsl2
wsl --set-default-version 2
- 更新wsl
wsl --update
使用 WSL Manager
WSL Manager:Releases · bostrot/wsl2-distro-manager (github.com),是一个管理WSL镜像的GUI工具,可以启动、停止、安装、卸载wsl,免除使用命令行来操作
从链接处下载最新版本的压缩版,免安装打开wsl manager
可以看到WSL Manager的界面,点击左边的 + 号添加发行即可
在该工具中选中实例之后可以控制启动和停止
换镜像源
- 将系统源文件复制一份备用
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
- 用 vi 编辑器打开源文件,直接输入
49dd
,就可以清除所有内容了
sudo vi /etc/apt/sources.list
- 替换国内源
注意
下列源链接 适用于 Ubuntu 20.04 的分发版本
将以下内容粘贴进去
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
- 更新
sudo apt-get -y update && sudo apt-get -y upgrade
交叉编译工具配置
ubuntu自带的gcc是针对 X86 架构的,可以使用 gcc -v
查看,在电脑上(X86架构)编译开发板(ARM架构)上使用的二进制代码叫做交叉编译,这个编译器叫做交叉编译器
安装交叉编译器
用于编译Cortex-A7 内核程序的交叉编译器链接如下: https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/
提示
64位系统选择 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
32位系统选择 gcc-linaro-4.9.4-2017.01-x86_32_arm-linux-gnueabihf.tar.xz
在 Ubuntu 中创建目录 /usr/local/arm:
sudo mkdir /usr/local/arm
使用如下命令将交叉编译器复制到/usr/local/arm 中:
sudo cp gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz /usr/local/arm/ -f
拷贝完成以后在/usr/local/arm 目录中对交叉编译工具进行解压
sudo tar -vxf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
等待解压完成,解压完成以后会生成一个名为“gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf”的文件夹,这个文件夹里面就是我们的交叉编译工具链。修改环境变量,使用 VI 打开/etc/profile 文件,命令如下:
sudo vi /etc/profile
打开/etc/profile 以后,在最后面输入如下所示内容:
export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin
修改好以后就保存退出,重启 Ubuntu 系统,交叉编译工具链(编译器)就安装成功了。
测试交叉编译器
在使用交叉编译器之前还需要安装一下其它的库,命令如下:
sudo apt-get install lsb-core lib32stdc++6
首先查看一下交叉编译工具的版本号,输入如下命令:
arm-linux-gnueabihf-gcc -v
如果交叉编译器安装正确的话就会显示版本号
注意
- 使用 Ubuntu 自带的 GCC 编译器,我们用的是命令
gcc
- 用交叉编译器的时候使用的命令是
arm-linux-gnueabihf-gcc
Linux编程知识
gcc 工具
gcc 命令
gcc 命令格式如下:
gcc [选项] [文件名字]
-c:只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o:<输出文件名> 用来指定编译结束以后的输出文件名,如果不使用这个选项的话 GCC 默认编译出来的可执行文件名字为 a.out。
-g:添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编译的时候生成调试所需的符号信息。
-O:对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进行优化,这样产生的可执行文件执行效率就高。
-O2:比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
gcc使用
使用 gcc -v
可查看Ubuntu下自带gcc版本,如果没有可以使用 sudo apt install gcc
来安装
在Ubuntu中使用vim创建文件main.c
,使用以下命令:
vim mian.c
在main.c中写入以下内容,wq退出
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("hello world!\n");
}
使用gcc编译
gcc main.c –o main
在目录下可以看到生成的可执行文件 main
,现在来执行它
./main
可以看到输出结果
hello world!
gcc编译流程
GCC 编译器的编译流程是:预处理、编译、汇编和链接。预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。编译是将经过预编译处理的代码编译成汇编代码,也就是我们常说的程序编译。汇编就是将汇编语言文件编译成二进制目标文件。链接就是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉及到静态库和动态库等问题。
Make与MakeFile
使用 GCC 编译器在 Linux 进行 C 语言编译,通过在终端执行 gcc 命令来完成 C 文件的编译,如果我们的工程只有一两个 C 文件还好,需要输入的命令不多,当文件有几十、上百甚至上万个的时候用终端输入 GCC 命令的方法显然是不现实的。
为了解决大型工程编译的问题,make工具应运而生,Makefile是make工具的描述文件
创建测试文件
在Ubuntu环境下创建5个文件 main.c
、input.c
、input.h
、calcu.c
、calcu.h
。
#include <stdio.h>
#include "input.h"
#include "calcu.h"
int main(int argc, char *argv[])
{
int a, b, num;
input_int(&a, &b);
num = calcu(a, b);
printf("%d + %d = %d\r\n", a, b, num);
}
#include <stdio.h>
#include "input.h"
void input_int(int *a, int *b)
{
printf("input two num:");
scanf("%d %d", a, b);
printf("\r\n");
}
#ifndef _INPUT_H
#define _INPUT_H
void input_int(int *a, int *b);
#endif
#include "calcu.h"
int calcu(int a, int b)
{
return (a + b);
}
#ifndef _CALCU_H
#define _CALCU_H
int calcu(int a, int b);
#endif
使用gcc测试编译,在终端输入如下命令:
gcc main.c calcu.c input.c -o main
上面命令的意思就是使用 gcc 编译器对 main.c
、calcu.c
和 input.c
这三个文件进行编译,编译生成的可执行文件叫做 main
。
引入Makefile
在相同目录下创建新文件Makefile
,并加入以下内容:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm mai
输入make
命令编译,可以看到如下所示的输出
gcc -c main.c
gcc -c input.c
gcc -c calcu.c
gcc -o main main.o input.o calcu.o
修改文件之后只需要再执行make
命令即可编译改动过的文件。
Makefile语法
Makefile 里面是由一系列的规则组成的,这些规则格式如下:
目标…... : 依赖文件集合……
命令 1
命令 2
……
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
make 命令会为 Makefile 中的每个以 TAB 开始的命令创建一个 Shell 进程去执行
对上面创建的Makefile
文件进行分析上述代码中一共有 5 条规则。
make 命令在执行这个 Makefile 的时候其执行步骤如下:
首先更新第一条规则中的 main,第一条规则的目标成为默认目标,只要默认目标更新了那么就认为 Makefile 的工作。在第一次编译的时候由于 main 还不存在,因此第一条规则会执行,第一条规则依赖于文件 main.o、input.o 和 calcu.o 这个三个.o 文件,这三个.o 文件目前还都没有,因此必须先更新这三个文件。make 会查找以这三个.o 文件为目标的规则并执行。以 main.o为例,发现更新 main.o 的是第二条规则,因此会执行第二条规则,第二条规则里面的命令为“gcc–c main.c”,这行命令很熟悉了吧,就是不链接编译 main.c,生成 main.o,其它两个.o 文件同理。最后一个规则目标是 clean,它没有依赖文件,因此会默认为依赖文件都是最新的,所以其对应的命令不会执行,当我们想要执行 clean 的话可以直接使用命令“make clean”,执行以后就会删除当前目录下所有的.o 文件以及 main,因此 clean 的功能就是完成工程的清理。