GCC编译器是由GNU开发的多个编程语言的编译器,包含C,C++,Fortran,Objective-C等,也包含了这些语言的库。
我们可以在命令行中查看Ubuntu系统中的GCC版本号,使用gcc -v
命令即可。
gcc命令的格式是:gcc [源文件名] [选项] [文件名]
常用的[选项]有:
-c:只编译不链接为可执行文件,编译器将源文件编译为.o中间文件
-o:可以在o后指定输出的文件名,编译加链接。例如gcc main.c -o main
,就会链接出一个main
的文件,直接在命令行中输入./main
即可执行这个文件。(这里的指定输出文件名可以是任意的字节,123.45
啥的都行,可以无视扩展名)
-空白:即直接gcc main.c
,则默认编译链接出来的可执行文件名字为a.out
-g:添加调试信息,如果要使用GDB调试工具,则需要用这个选项。比如先gcc main.c -o main -g
,则可以对main文件做调试了。接下来命令行中输入gdb main
则进入gdb调试页面,使用非常多的调试语句,例如断点、逐行执行、打印某个变量的值,说白了就是IDE中提供的那些调试功能在命令行中实现,讲真还真不方便,对于我这种习惯IDE的人来说还是用VSCode提供的调试功能更现实。
gcc main.c input.c output.c -o main
即一次性编译3个源文件之后输出一个可执行文件main
。所以如果源文件和头文件较少,使用gcc命令编译是没有问题的。但如果工程文件太多(成千上万),或者编译完之后有少数几个源文件修改了,要重新编译的时候是不是得把没有修改的文件包括在一起再来一次呢?这时候就轮到Makefile出场了。
它可以满足我们以下的要求:
- 如果工程没有编译过,那么工程中的所有.c文件都要被编译并且链接成可执行程序。
- 如果工程中只有个别.c文件被修改了,那么只编译这些被修改的.c文件即可。
- 如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的.c文件,并且链接成可执行文件。
目标...: 依赖文件集合...
命令1 #注释(命令前的空格键一定要用TAB)
命令2
...
...
来看上面说的这个工程,根据语法规则,可以这样写Makefile
main: main.o input.o output.o #main文件的依赖文件是3个
gcc -o main main.o input.o output.o #这句是命令,即告知main执行文件是怎么来的
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: output.c
gcc -c output.c
clean:
rm *.o #删掉所有.o文件
rm main #删掉main文件
在命令行中直接输入make
(必须要在工程同一个文件夹下)后即自动进行处理(有点像windows的批处理文件啊),生成了main
文件。
输入./main
即可执行该文件。输入make clean
则进行删除工作。
试着更改一个源文件再make
一下,可以发现只会重新编译更改的源文件,节省了时间。
objects = main.o input.o output.o #objects就是变量,"="是赋值
main: $(objects) #Makefile中变量的引用方法是“$(变量名)”
gcc -o main $(objects)
其次,模式规则,也就是“%”的使用。例如%.c就代表所有的.c文件,%.o同理。所以,目标...: 依赖文件集合...
可以直接写成%.o: %.c
。有了这个还不够,命令还没有完成
自动化变量可以通过一行命令来从不同的依赖文件中生成对应的目标,有3种常见的自动化变量:
$@
:规则中的目标集合,如果有多个目标,则标识匹配模式中定义的目标集合$<
:依赖文件集合中的第一个文件,如果依赖文件是以%
定义的,则$<
就是符合模式的一系列文件的集合$^
:所有依赖文件的集合,使用空格分开objects = main.o input.o output.o
main: $(objects)
gcc -o main $(objects)
%.o: %.c
gcc -c $<
8行缩短到了5行,而且就算源文件再多,就可以从N行缩短到5行。实际测试,结果ok。
<条件关键字> #条件关键字包括ifeq, ifnef, ifdef, ifndef
<条件为真时执行语句>
else
<条件为假时执行语句> #其中else分支可以省略,即只考虑条件为真
endif
其实只要记住ifeq
和ifdef
两个关键字即可,ifeq
有两个参数,是比较后面两个参数是否相等,ifdef
只有一个参数为变量名,看这个变量是否为空,如果为空则返回0,否则返回1。
看下面这个例子,就是通过判断ver是release还是debug,来选择不同的编译器选项。
ifeq ($(ver),debug)
CFLAGS =-D__DEBUG__ -g -I. -I./include/ -L./lib/ -lm -ldl -lrt -lpthread -Wall
else
CFLAGS =-g -I. -I./include/ -L./lib/ -Wall -lm -ldl -lrt -lpthread -Wall
endif
基本项目中常用的Makefile应该就是这些了,如果后续有新的东西,再补记录。
接下来要进入Linux的学习了。(未完待续)