嵌入式Linux学习第二天

今天学习linuxC编程。首先要熟悉linux下编写c程序的过程。

编写程序Hello World!

首先创建存放程序的文件夹,如下图所示:

接下来在创建一个文件夹来保存这节要编写的代码。指令:mkdir 3.1

接下来我们要设置VIM编辑器的一些配置,比如设置tab的字符数为4、以及设置VIM编辑器的行号。在文件/etc/vim/vimrc 中添加代码:

bash 复制代码
set nu
set ts=4

然后创建main.c文件。

编写程序完事后,使用"gcc main.c --o main"来编译 main.c 文件,使用参数"-o"来指定编译生成的可执行文件名字。

GCC编译器

gcc 命令

在上一小节我们已经使用过 GCC 编译器来编译 C 文件了,我们使用到是 gcc 命令,gcc 命令格式如下:

bash 复制代码
gcc [选项] [文件名字]
主要选项如下:
-c:只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o:<输出文件名>用来指定编译结束以后的输出文件名,如果不使用这个选项的话 GCC 默
认编译出来的可执行文件名字为 a.out。
-g:添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编
译的时候生成调试所需的符号信息。
-O:对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进
行优化,这样产生的可执行文件执行效率就高。
-O2:比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。

编译流程

GCC 编译器的编译流程是:预处理、编译、汇编和链接。预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。编译是将经过预编译处理的代码编译成汇编代码,也就是我们常说的程序编译。汇编就是将汇编语言文件编译成二进制目标文件。链接就是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉及到静态库和动态库等问题。上一小节演示的例程都只有一个文件,而且文件非常简单,因此可以直接使用 gcc 命令生成可执行文件,并没有先将 c 文件编译成.o 文件,然后再链接在一起。

Makefile 基础

当文件有几十、上百甚至上万个的时候用终端输入 GCC 命令的方法显然是不现实的。如果我们能够编写一个文件,这个文件描述了编译哪些源码文件、如何编译那就好了,每次需要编译工程的时只需要使用这个文件就行了。这种问题怎么可能难倒聪明的程序员,为此提出了一个解决大工程编译的工具:make,描述哪些文件需要编译、哪些需要重新编译的文件就叫做 Makefile,Makefile 就跟脚本文件一样,Makefile 里面还可以执行系统命令。使用的时候只需要一个 make命令即可完成整个工程的自动编译,极大的提高了软件开发的效率。如果大家以前一直使用 IDE来编写 C 语言的话肯定没有听说过 Makefile 这个东西,其实这些 IDE 是有的,只不过这些 IDE对其进行了封装,提供给大家的是已经经过封装后的图形界面了,我们在 IDE 中添加要编译的

C 文件,然后点击按钮就完成了编译。在 Linux 下用的最多的是 GCC 编译器,这是个没有 UI的编译器,因此 Makefile 就需要我们自己来编写了。

Makefile 语法

Makefile 规则格式

Makefile 里面是由一系列的规则组成的,这些规则格式如下:

powershell 复制代码
目标...... : 依赖文件集合......
命令 1
命令 2
......
powershell 复制代码
main : main.o input.o calcu.o
 gcc -o main main.o input.o calcu.o

第一行定义了一个规则,它告诉make命令如何构建目标main。在这里,main是一个目标(通常是最终要生成的程序或文件),而main.o、input.o和calcu.o是这个目标的依赖项,意味着在构建main之前,必须首先存在或构建这些依赖项。

目标(target):main是这条规则的目标,也就是这条规则想要构建或更新的文件。

依赖(dependencies):main.o、input.o和calcu.o是目标的依赖项,这意味着在尝试构建main之前,make会确保所有的依赖项都是最新的。

gcc是GNU编译器集合中的C编译器,用于编译C语言程序。-o main选项告诉gcc将链接生成的可执行文件命名为main。main.o、input.o和calcu.o是gcc需要链接的对象文件。这些对象文件之前已经由gcc从相应的源文件编译生成。
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!

make 命令会为 Makefile 中的每个以 TAB 开始的命令创建一个 Shell 进程去执行。了解了 Makefile 的基本运行规则以后我们再来分析一下 3.3 节中"示例代码 3.3.2.6"中的Makefile,代码如下:、

上述代码中一共有 5 条规则,1~2 行为第一条规则,3~4 行为第二条规则,5~6 行为第三条规则,7~8 行为第四条规则,10~12 为第五条规则,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 的功能就是完成工程的清理,

总结一下 Make 的执行过程:

1、make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。

2、当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。

3、当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。

原子文档总结的很形象。具体执行的过程就如上图所示:

Makefile 变量

跟 C 语言一样 Makefile 也支持变量的,先看一下前面的例子:

bash 复制代码
 main: main.o input.o calcu.o
 gcc -o main main.o input.o calcu.o

上述 Makefile 语句中,main.o input.o 和 calcue.o 这三个依赖文件,我们输入了两遍,我们这个 Makefile 比较小,如果 Makefile 复杂的时候这种重复输入的工作就会非常费时间,而且非常容易输错,为了解决这个问题,Makefile 加入了变量支持。不像 C 语言中的变量有 int、char等各种类型,Makefile 中的变量都是字符串!类似 C 语言中的宏。使用变量将上面的代码修改,修改以后如下所示:

bash 复制代码
1 #Makefile 变量的使用
2 objects = main.o input.o calcu.o
3 main: $(objects)
4 gcc -o main $(objects)

第 1 行是注释,Makefile 中可以写注释,注释开头要用符号"#",不能用 C 语言中的"//"或者"/**/"!第 2 行我们定义了一个变量 objects,并且给这个变量进行了赋值,其值为字符串"main.o input.o calcu.o",第 3 和 4行使用到了变量 objects,Makefile 中变量的引用方法是" ( 变量名 ) ",比如本例中的" (变量名)",比如本例中的" (变量名)",比如本例中的"(objects)"就是使用变量 objects。在"示例代码 3.4.2.1"中我们在定义变量 objects 的时候使用"="对其进行了赋值,Makefile变量的赋值符还有其它两个":="和"?=",我们来看一下这三种赋值符的区别:

1、赋值符"="

示例代码 3.4.2.1 赋值符"="使用

bash 复制代码
1 name = zzk
2 curname = $(name)
3 name = zuozhongkai
4
5 print:
6 @echo curname: $(curname)

2、赋值符":="

赋值符":="不会使用后面定义的变量,只能使用前面已经定义好的,这就是"="和":="两个的区别。

3、赋值符"?="

"?="是一个很有用的赋值符,比如下面这行代码:

bash 复制代码
curname ?= zuozhongkai

上述代码的意思就是,如果变量 curname 前面没有被赋值,那么此变量就是"zuozhongkai",

如果前面已经赋过值了,那么就使用前面赋的值。

4、变量追加"+="

Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进

去,此时就要使用到符号"+=",比如如下所示代码:

bash 复制代码
objects = main.o input.o
objects += calcu.o

一开始变量 objects 的值为"main.o input.o",后面我们给他追加了一个"calcu.o",因此变量 objects 变成了"main.o input.o calcu.o",这个就是变量的追加。

Makefile 模式规则

模式规则中,至少在规则的目标定定义中要包涵"%",否则就是一般规则,目标中的"%"表示对文件名的匹配,"%"表示长度任意的非空字符串,比如"%.c"就是所有的以.c 结尾的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件。

当"%"出现在目标中的时候,目标中"%"所代表的值决定了依赖中的"%"值,

相关推荐
风尚云网6 分钟前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
C-cat.19 分钟前
Linux|环境变量
linux·运维·服务器
yunfanleo34 分钟前
docker run m3e 配置网络,自动重启,GPU等 配置渠道要点
linux·运维·docker
糖豆豆今天也要努力鸭1 小时前
torch.__version__的torch版本和conda list的torch版本不一致
linux·pytorch·python·深度学习·conda·torch
烦躁的大鼻嘎1 小时前
【Linux】深入理解GCC/G++编译流程及库文件管理
linux·运维·服务器
ac.char1 小时前
在 Ubuntu 上安装 Yarn 环境
linux·运维·服务器·ubuntu
敲上瘾1 小时前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
EterNity_TiMe_2 小时前
【论文复现】(CLIP)文本也能和图像配对
python·学习·算法·性能优化·数据分析·clip
长弓聊编程2 小时前
Linux系统使用valgrind分析C++程序内存资源使用情况
linux·c++
sanguine__2 小时前
java学习-集合
学习