Skip to main content

嵌入式Linux 基础知识

Wsl2开发环境

Windows已步入win11时代,wsl已经发展到第二代,使用wsl2做嵌入式linux编译完全可行,且相比于虚拟机,wsl2的文件可在主机中直接访问,网络也可直接ping通,占用空间较小,对电脑性能的利用更加充分,因此本文记录了我使用Wsl2进行Linux驱动开发和应用开发的环境配置方式。

WSL2安装配置

安装wsl2

首先将自己的wsl更新到wsl2

  1. 设置wsl版本为wsl2
wsl --set-default-version 2
  1. 更新wsl
wsl --update

使用 WSL Manager

WSL Manager:Releases · bostrot/wsl2-distro-manager (github.com),是一个管理WSL镜像的GUI工具,可以启动、停止、安装、卸载wsl,免除使用命令行来操作

  1. 从链接处下载最新版本的压缩版,免安装打开wsl manager

  2. 可以看到WSL Manager的界面,点击左边的 + 号添加发行即可

  3. 在该工具中选中实例之后可以控制启动和停止

换镜像源

  1. 将系统源文件复制一份备用
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
  1. 用 vi 编辑器打开源文件,直接输入49dd,就可以清除所有内容了
sudo vi /etc/apt/sources.list
  1. 替换国内源
注意

下列源链接 适用于 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
  1. 更新
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.cinput.cinput.hcalcu.ccalcu.h

main.c
#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);
}
input.c
#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");
}
input.h
#ifndef _INPUT_H
#define _INPUT_H
void input_int(int *a, int *b);
#endif
calcu.c
#include "calcu.h"
int calcu(int a, int b)
{
return (a + b);
}
calcu.h
#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.ccalcu.cinput.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 的功能就是完成工程的清理。