4、卸载命令 umount
三、Linux C 编程入门
Ubuntu 下也有一些可以进行编程的工具,但是大多都只是编辑器,也就是只能进行代码编辑。
Ubuntu 下要编译的话就需要用到 GCC 编译器,使用 GCC 编译器肯定就要接触到Makefile。
3.1 Hello World!
编写代码包括两部分:代码编写和编译。
代码编写用 notepad++ (Windows)和 VIM(Ubuntu)。
编译:GCC 编译器。
3.1.1编写代码
cd ~
mkdir C_Program
cd C_Program
mkdir 3.1
使用 VI 编辑器之前我们先做如下设置:
1、设置 TAB 键为 4 字节
VI 编辑器默认 TAB 键为 8 空格,我们改成 4 空格,用 vi 打开文件/etc/vim/vimrc,在此文件最后面输入如下代码:
set ts=4
修改完成以后保存并关闭文件。
2、VIM 编辑器显示行号
VIM 编辑器默认是不显示行号的,不显示行号不利于代码查看,我们设置 VIM 编辑器显示行号,同样是通过在文件/etc/vim/vimrc 中添加代码来实现,在文件最后面加入下面一行代码即可:
set nu
VIM 编辑器可以自行定制,网上有很多的博客讲解如何设置 VIM。
进入前面创建的“3.1”这个工程文 件夹里面,使用 vi 指令创建一个名为“main.c”的文件:
cd 3.1
vi main.c
然后在里面输入如下代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello World!\n");
}
编写完成以后保存退出 vi 编辑器,可以使用“cat”命令查看代码是否编写成功:
cat main.c
3.1.2 编译代码
Ubuntu 下的 C 语言编译器是 GCC,GCC 编译器在我们安装 Ubuntu 的时候就已经默认安装好了,可以通过如下命令查看 GCC 编译器的版本号:
gcc -v
如果想要 编译在 ARM 上运行的程序就需要针对 ARM 架构的 GCC 编译器,也就是
交叉编译器。我们进行 ARM 开发,因此肯定要安装针对 ARM 架构的 GCC 交叉编译器(在后面会用)。
如何使用 GCC 编译器来编译 main.c 文件呢?
GCC 编译器是
命令模式的,因此需要输入命令来使用 gcc 编译器来编译文件,输入如下命令:
gcc main.c
当编译完成以后会生成一个 a.out 文件,这个 a.out 就是编译生成的
可执行文件。
执行的方法很简单,使用命令: “
./可执行文件”
a.out 这个文件名是 GCC 编译器自动命名的,自己能决定编译完生成的可执行文件名字:
gcc main.c –o main
3.2 GCC编译器
3.2.1 gcc 命令
gcc 命 令格式如下:
主要选项如下:
-c 只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o<输出文件名> 用来指定编译结束以后的输出文件名,如果不使用这个选项的话 GCC 默认编译出来的可执行文件名字为 a.out。
-g 添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编译的时候生成调试所需的符号信息。
-O 对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进行优化,这样产生的可执行文件执行效率就高。
-O2 比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
3.2.2 编译错误警告
GCC 编译器和其它编译器一样,不仅能够检测出错误类型,而且标记除了错误发生在哪个文件、哪一行,方便我们去修改代码。
3.2.3 编译流程
GCC 编译器的编译流程是:预处理、汇编、编译和链接。预处理就是对程序中的宏定义等相关的内容先进行前期的处理。汇编是先将 C 文件转换为汇编文件。当 C 文件转换为汇编文件以后就是文件编译了,编译过程就是将 C 源文件编译成.o 结尾的目标文件。编译生成的.o 文 件不能直接执行,而是需要最后的链接,如果你的工程有很多个 c 源文件的话最终就会有很 多.o 文件,将这些.o 文件链接在一起形成完整的一个可执行文件。
上一小节演示的例程都只有一个文件,而且文件非常简单,因此可以直接使用 gcc 命令生成可执行文件,并没有先将 c 文件编译成.o 文件,然后在链接在一起。
3.3 Makefile 基础
3.3.1 何为Makefile
通过在终端执行 gcc 命令来完成 C 文件的编译,如果我们的工程只有一两个 C 文件还好,需要输入的命令不多,当文件有几十、上百甚至上万个的时候用终端输入 GCC 命令的方法显然是不现实的。
如果我们能够 编写一个文件,这个文件描述了编译哪些源码文件、如何编译那就好了,每次需要编译工程的时侯只需要使用这个文件就行了。
为此提出了一个解决大 工程编译的工具:Make,描述哪些文件需要编译、哪些需要重新编译的文件就叫做 Makefile。
Makefile 就跟脚本文件一样,Makefile 里面还可以执行系统命令。使用的时候只需要一 个 make 命令即可完成整个工程的自动编译,极大的提高了软件开发的效率。
如果大家以前一 直使用 IDE 来编写 C 语言的话肯定没有听说过 Makefile 这个东西,其实这些 IDE 是有的,只 不过这些 IDE 对其进行了封装,提供给大家的是已经经过封装后的图形界面了,我们在 IDE 中添加要编译的 C 文件,然后点击按钮就完成了编译。
作为一个专业的程序员,是 一定要懂得 Makefile 的,一是因为在 Linux 下你不得不懂 Makefile,再就是通过 Makefile 你就能了解整个工程的处理过程。
由于 Makefile 的知识比较多,完全可以单独写本书,因此本章我们只讲解 Makefile 基础 入门,如果想详细的研究 Makefile,推荐大家阅读《跟我一起写 Makefile》这份文档。
3.3.2 Makefile 的引入
完成一个小工程:通过键盘输入两个整形数字,然后计算他们的和并将结果显示在屏幕上。
包括以下文件:main.c,input.c , calcu.c,input.h,calcu.h
main.c 是主体
input.c 负责接收从键盘输入的数值
calcu.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");
}
calcu.c :
#include "calcu.h"
int calcu(int a, int b)
{
return (a + b);
}
input.h :
#ifndef _INPUT_H
#define _INPUT_H
void input_int(int *a, int *b);
#endif
calcu.h :
#ifndef _CALCU_H
#define _CALCU_H
int calcu(int a, int b);
#endif
接下来使用 3.1 节讲的方法来对其进行编 译,在终端输入如下命令:
gcc main.c calcu.c input.c -o main
上面命令的意思就是使用 gcc 编译器对 main.c、calcu.c 和 input.c 这三个文件进行编 译,编译生成的可执行文件叫做 main。
使用命令“gcc main.c calcu.c input.c -o main”看起来很简单,只需要一行就可以完成编译,但是我们这个工程只有三个文件!如果几千个文件呢?再就是如果有一个文件被修改了呢,使用上面的命令编译的时候所有的文件都会重新编译,如果工程有几万个文件(Linux 源码就有这么多文件),想想这几万个文件编译一次所需要的时间就可怕。最好的办法肯定是哪个文件被修改了,只编译这个修改的文件即可,其它没有修改的文件就不需要再次重新编译了,为此我们改变我们的编译方法,如果第一次编译工程,我们先将工程中的文件都编译一遍,然后后面修改了哪个文件就编译哪个文件,命令如下:
gcc -c main.c
gcc -c input.c
gcc -c calcu.c
gcc main.o input.o calcu.o -o main
上述命令前三行分别是将 main.c、input.c 和 calcu.c 编译成对应的.o 文件,所以使用了“-c”选项,“-c”选项我们上面说了,是只编译不链接。最后一行命令是将编译出来的所有.o 文件链接成可执行文件 main。假如我们现在修改了 calcu.c 这个文件,只需要将 caclue.c这一个文件重新编译成.o 文件,然后再将所有的.o 文件链接成可执行文件,只需要下面两条命令即可:
gcc -c calcu.c
gcc main.o input.o calcu.o -o main
但是这样就又有一个问题,如果修改的文件一多,我自己可能都不记得哪个文件修改过了, 然后忘记编译,然后……,为此我们需要这样一个工具:
1、如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。
2、如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可。
3、如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且链接成可执行文件。
很明显,能够完成这个功能的就是 Makefile 了,在工程目录下创建名为“Makefile”的文件,文件名一定要叫做“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 main
上述代码中所有行首需要空出来的地方一定要使用“TAB”键!不要使用空格键!这是 Makefile 的语法要求。
Makefile 编写好以后我们就可以使用 Make 命令来编译我们的工程了,直接在命令行中输入“make”即可,Make 命令会在当前目录下查找是否存在“Makefile”这个文件,如果存在的话就会按照 Makefile 里面定义的编译方式进行编译。
3.4 Makefile 语法
3.4.1 Makefile 规则格式
目标… … : 依赖文件集合… …
命令 1
命令 2
… …
比如下面这条规则:
main : main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
这条规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,如果要更新目标 main,就必须要先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目标也必须更新,“更新”就是执行一遍规则中的命令列表。
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
make 命令会为 Makefile 中的每个以 TAB 开始的命令创建一个 Shell 进程去执行。
了解了 Makefile 的基本运行规则以后我们再来分析一下 3.3 中的 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 main
上述代码中一共有 5 条规则,1~2 行为第一条规则,3~4 行为第二条规则,5~6 行为第三条规则,7~8 行为第四条规则,10~12 为第五条规则,make 命令在执行这个 Makefile 的时候其执行步骤如下:
首先更新第一条规则中的 main,第一条规则的目标成为默认目标,只要默认目标更新了那么就完成了 Makefile 的工作,完成了整个 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) 当发现目标文件
不存在,或者目标所依赖的文件比目标文件
新(也就是最后修改时间比目标文件晚) 的话就会执行后面的命令来
更新目标。
这就是 make 的执行过程,make 工具就是在 Makefile 中一层一层的查找依赖关系,并执行相应的命令。编译出最终的可执行文件。Makefile 的好处就是“自动化编译”,一旦写好了Makefile 文件,以后只需要一个 make 命令即可完成整个工程的编译,
极大的提高了开发效率。
总结一下,Makefile 中规则用来描述在什么情况下使用什么命令来构建一个特定的文件,这个文件就是规则的“目标”,为了生成这个“目标”而作为材料的其它文件称为“目标”的依赖,规则的命令是用来创建或者更新目标的。
除了 Makefile 的“终极目标”所在的规则以外,其它规则的顺序在 Makefile 中是没有意义的,“终极目标”就是指在使用 make 命令的时候没有指定具体的目标时,make 默认的那个目标,它是 Makefile 文件中第一个规则的目标,如果 Makefile 中的
第一个规则有多个目标,那么这些目标中的
第一个目标就是 make 的“
终极目标”。
3.4.2 Makefile 变量
跟 C 语言一样 Makefile 也支持变量的,先看一下前面的例子:
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 语言中的宏。使用变量将上面的代码修改,修改以后如下所示:
#Makefile 变量的使用
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
分析一下,第 1 行是注释,Makefile 中可以写注释,注释开头要用符号“#”。第 2 行我们定义了一个变量 objects,并且给这个变量进行了赋值,其值为字符串“main.o input.o calcu.o”,第 3 和 4 行使用到了变量 objects,Makefile 中变量的引用方法是“$(变量名)”,比如本例中的“$(objects)” 就是使用变量 objects。
Makefile 变量的赋值符有“=”,“:=”和“?=”,三种赋值符的区别:
1、赋值符“=”
使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值,比如如下代码:
name = zzk
curname = $(name)
name = wurao
print:
@echo curname: $(curname)
我们来分析一下上述代码,第 1 行定义了一个变量 name,变量值为“zzk”,第 2 行也定义了一个变量 curname,curname 的变量值引用了变量 name,按照我们写 C 语言的经验此curname 的值就是“zzk”。第 3 行将变量 name 的值改为了“wurao”,第 5、6 行是输出变量 curname 的值。在 Makefile 要输出一串字符的话使用“echo”,就和 C 语言中的“printf”一样,第 6 行中的“echo”前面加了个“@”符号,因为 Make 在执行的过程中会自动输出命令执行过程,在命令前面加上“@”的话就不会输出命令执行过程,也可以测试一下不加“@” 的效果。
使用“make”执行上述代码:
可以看到 curname 的值不是“zzk”,
竟然是“wurao”,也就是变量“name”最后一次赋值的结果,这就是赋值符“=”的神奇之处。借助另外一个变量,可以将变量的真实值推到后面去定义。也就是
变量的真实值取决于它所引用的变量的最后一次有效值。
2、赋值符“:=”
修改代码如下:
name = zzk
curname := $(name)
name = zuozhongkai
print:
@echo curname: $(curname)
修改完成以后重新执行一下 Makefile,结果如下:
可以看到此时的 curname 是 zzk,不是 wurao了。这是因为
赋值符“:=”不会使用后面定义的变量,只能使用前面已经定义好的,这就是“=”和“:=”两个的区别。
3、赋值符“?=”
“?=”是一个很有用的赋值符,比如下面这行代码:
curname ?= wurao
上述代码的意思就是,如果变量 curname 前面没有被赋值,那么此变量就是“wurao”,如果前面已经赋过值了,那么就使用前面赋的值。
4、变量追加“+=”
Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进去,此时就要使用到符号“+=”,比如如下所示代码:
objects = main.o inpiut.o
objects += calcu.o
一开始变量 objects 的值为“main.o input.o”,后面我们给他追加了一个“calcu.o”,因此变量 objects 变成了“main.o input.o calcu.o”,这个就是变量的追加。
3.4.3 Makefile 模式规则
在 3.3.2 小节中我们编写了一个 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 main
上述 Makefile 中第 3~8 行是将对应的.c 源文件编译为.o 文件,每一个 C 文件都要写一个对应的规则,
如果工程中 C 文件很多的话显然
不能这么做。为此,我们可以使用 Makefile 中的
模式规则,通过模式规则我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件。
模式规则中,
至少在规则的目标定定义中要包涵“%”,否则就是一般规则,目标中的“%”表示对文件名的匹配,
“%”表示长度任意的非空字符串,比如“%.c”就是
所有的以.c 结尾的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件。
当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值,使用方法如下:
%.o : %.c
命令
因此上面的 Makefile 可以改为如下形式:
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
%.o : %.c
#命令
clean:
rm *.o
rm main
修改以后的 Makefile 还不能运行,因为第 6 行的命令我们还没写呢,第 6 行的命令我们需要借助另外一种强大的变量—自动化变量。
3.4.4 Makefile 自动化变量
上面讲的模式规则中,目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,如何通过一行命令来从不同的依赖文件中生成对应的目标呢?自动化变量就是完成这个功能的。所谓自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完,自动化变量只应该出现在规则的命令中,常用的自动化变量如下表:
7 个自动化变量中,常用的三种:$@、$< 和 $^ ,我们使用自动化变量来完成上面的 Makefile,最终的完整代码如下所示:
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
%.o : %.c
gcc -c $<
clean:
rm *.o
rm main
上述代码代码就是修改后的完成的 Makefile,可以看出精简了很 多,核心就在于第 5、6 这两行,第 5 行使用了模式规则,第 6 行使用了自动化变量。
3.4.5 Makefile 伪目标
Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,而伪目标不代表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。
使用伪目标的
主要是为了避免 Makefile 中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的,比如在前面小节有如下代码用来完成清理工程的功能:
clean:
rm *.o
rm main
上述
规则中并没有创建文件 clean 的命令,因此工作目录下
永远都不会存在文件 clean,当我们输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行。可是如果我们
“手残”,在工作目录下创建一个名为“clean”的文件,那就不一样了,当执行“make clean”的时候,规则因为没有依赖文件,所以
目标被认为是最新的,因此后面的 rm 命令也就不会执行,我们预先设想的清理工程的功能也就无法完成。
为了避免这个问题,我们可以将 clean 声明为伪目标,声明方式如下:
.PHONY : clean
我们使用伪目标来更改Makefile,修改完成以后如下:
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
.PHONY : clean
%.o : %.c
gcc -c $<
clean:
rm *.o
rm main
上述代码第 5 行声明 clean 为伪目标,声明 clean 为伪目标以后不管当前目录下是否存在名为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行。
3.4.6 Makefile 条件判断
在 C 语言中我们通过条件判断语句来根据不同的情况来执行不同的分支,Makefile 也支持条件判断,语法有两种如下:
<条件关键字>
<条件为真时执行的语句>
endif
以及:
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
其中条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,这四个关键字其实分为两对、 ifeq 与 ifneq、ifdef 与 ifndef,先来看一下 ifeq 和 ifneq,ifeq 用来判断是否相等,ifneq 就是判断是否不相等,ifeq 用法如下:
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”
上述用法中都是用来比较“参数 1”和“参数 2”是否相同,如果相同则为真,“参数 1”和“参数 2”
可以为函数返回值。ifneq 的用法类似,只不过
ifneq 是用来比较“参数 1”和“参数 2”
是否不相等,如果不相等的话就为真。
ifdef 和 ifndef 的用法如下:
ifndef <变量名>
如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是一个函数的返回值。ifndef 用法类似,但是含义与 ifdef 相反。
3.4.7 Makefile 函数使用
Makefile 支持函数,类似 C 语言一样,Makefile 中的函数
是已经定义好的,我们直接使用,
不支持我们自定义函数。make 所支持的函数不多,但是绝对够我们使用了,函数的用法如下:
$(函数名 参数集合)
或者
${函数名 参数集合}
可以看出,调用函数和调用普通变量一样,使用符号“$”来标识。
参数集合是函数的多个参数,参数之间以逗号“
,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“$”开头。接下来我们介绍几个常用的函数,其它的函数大家可以参考《跟我一起写 Makefile》这份文档。
函数 subst 用来完成字符串替换,调用形式如下:
$(subst <from>,<to>,<text>)
此函数的功能是
将字符串<text>中的<from>内容替换为<to>,函数返回被替换以后的字符串,比如如下示例:
$(subst wurao,man,my name is wurao)
把字符串“my name is wurao”中的“wurao”替换为“man”,替换完成以后的字符串为“my name is man”。
2、函数 patsubst
函数 patsubst 用来完成模式字符串替换,使用方法如下:
$(patsubst <pattern>,<replacement>,<text>)
此函数
查找字符串<text>中的单词是否符合模式<pattern>,如果匹配就用<replacement>来替换掉,<pattern>可以使用包括通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串。如果<replacement>中也包涵“%”,那么<replacement>中的“%”将是<pattern>中的那个“%”所代表的字符串,比如:
$(patsubst %.c,%.o,a.c b.c c.c)
将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字符串为“a.o b.o c.o”。
3、函数 dir
函数 dir 用来获取目录,使用方法如下:
$(dir <names…>)
此函数用来
从文件名序列<names>中提取出目录部分,返回值是文件名序列<names>的目录部分,比如:
$(dir </src/a.c>)
提取文件“/src/a.c”的目录部分,也就是“/src”。
4、函数 notdir
函数 notdir 看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:
此函数用于
从文件名序列<names>中提取出文件名非目录部分,比如:
提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。
5、函数 foreach
foreach 函数用来完成循环,用法如下:
$(foreach <var>, <list>,<text>)
此函数的意思就是
把参数<list>中的单词逐一取出来放到参数<var>中,然后再执行<text> 所包含的表达式。每次<text>都会返回一个字符串,循环的过程中,<text>中所包含的每个字符串会以空格隔开,最后当整个循环结束时,<text>所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。
6、函数 wildcard
通配符“%”只能用在规则中,只有在规则中它才会展开,
如果在变量定义和函数使用时,通配符不会自动展开,这个时候就要用到函数 wildcard,使用方法如下:
$(wildcard PATTERN…)
比如:
$(wildcard *.c)
上面的代码是用来获取当前目录下所有的.c 文件,类似“%”。
本节只是对 Makefile 做了最基本的讲解,确保能够完成后续的学习,Makefile 还有大量的知识没有提到,有兴趣的可以自行参考《跟我一起写 Makefile》这份文档来深入学习 Makefile。
本篇总结
重点是各种shell命令的使用和Makefile。
shell多敲就会了,Makefile多学习几个例子便熟悉了。