C程序的编译:gcc、Makefile用法

文章目录

  • 1 什么是gcc
  • 2 gcc编译C程序的过程
  • 3 使用gcc编译只有一个源文件的C程序
  • 4 使用Makefile编译多个源文件的C程序

1 什么是gcc

原名为GNU C语言编译器(GNU C Compiler),因为它原本只能处理C语言。GCC在发布后很快地得到扩展,变得可处理C++。之后也变得可处理Fortran、Pascal、Objective-C、Java、Ada,Go与其他语言。

后更名为GNU编译器套装(GNU Compiler Collection),指一套编程语言编译器,以GPL及LGPL许可证所发行的自由软件,也是GNU计划的关键部分,是GNU工具链的主要组成部分之一。

2 gcc编译C程序的过程

总共分为四个阶段:预处理、编译、汇编、链接
C程序的编译:gcc、Makefile用法_第1张图片

  • 预处理:展开以#起始的行,如处理宏定义#define、源文件包含#include、条件编译#if/#ifdef/#ifndef/#else/#elif/#endif……
  • 编译:进行词法、语法分析等
  • 汇编:将编译生成的汇编代码转变成目标代码
  • 链接:链接所有目标代码生成可执行文件

3 使用gcc编译只有一个源文件的C程序

选项 作用
-E 仅执行预编译
-S 仅执行汇编
-c 仅执行编译,不进行链接
-o filename 生成名为 filename 的文件

用法示例


语法格式:gcc (选项)(参数)

#include 

int main(void)
{
	for (int i = 0; i < 3; i++)
		puts("Hello World!");
		
	return 0;
}

一次编译

PS C:\users\frey\desktop> gcc hello.c -o hello
PS C:\users\frey\desktop> ./hello
Hello World!
Hello World!
Hello World!

分步编译。执行以下各命令后会在相应目录下生成对应的文件
C程序的编译:gcc、Makefile用法_第2张图片
编译时开启警告功能


当GCC在编译过程中检查出错误的话,它就会中止编译;但检测到警告时却能继续编译生成可执行程序。

用法示例:gcc -Wall hello.c -o hello

该选项相当于同时使用了下列选项:

  • unused-function:遇到仅声明过但尚未定义的静态函数时发出警告。
  • unused-label:遇到声明过但不使用的标号的警告。
  • unused-parameter:从未用过的函数参数的警告。
  • Padded:如果结构体通过充填进行对齐则给出警告。
  • unreachable-code:如果发现从未执行的代码时给出警告。Inline:如果某函数不能内嵌(inline),无论是声明为inline或者是指定了finline-functions 选项,编译器都将发出警告。
  • ……

各警告选项既能使之生效,也能使之关闭。假设想用-Wall来启用个选项,同时又要关闭unused警告,可以使用下面的命令:

gcc -Wall -Wno-unused hello.c -o hello

4 使用Makefile编译多个源文件的C程序

使用Makefile可以较为方便的编译有多个源文件的程序,不使用Makefile的话,需要先将每个源文件分别编译,最后再链接到一起,这样比较麻烦。
C程序的编译:gcc、Makefile用法_第3张图片
不使用Makefile


一次编译所有源文件
C程序的编译:gcc、Makefile用法_第4张图片
单独编译每个源文件
C程序的编译:gcc、Makefile用法_第5张图片
使用Makefile


1 Makefile语法规则

target ... : prerequisites ...
	command
	...
	...

注意:在Makefile中的命令,缩进必须要以 Tab 键开始;而注释以#开始;文件名应为MakefilemakefileMakefile是更为标准的写法

  • target可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。
  • prerequisites是要生成那个target所需要的文件或是目标。
  • command也就是make需要执行的命令。

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在 command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是makefile的规则。也就是makefile中最核心的内容。

2 根据上述规则,我们就可以写出Makefile了

# 普通版Makefile
hiii : main.o hello.o
	gcc main.o hello.o -o hiii

main.o : main.c hello.h
	gcc -c main.c
hello.o : hello.c hello.h
	gcc -c hello.c

clean :				
	del *.o hiii.exe # windows下可用 del,linux 下用 rm

生成 hiii.exe 要依赖 main.o hello;生成 hiii.exe 的规则是 gcc main.o hello.o -o hiii
生成 main.o 要依赖 hello.h main.c;生成 main.o 的规则是 gcc -c main.c
生成 hello.o 要依赖 hello.h hello.c;生成 hello.o 的规则是 gcc -c hello.c
(根据源文件数量的多少,只需要重复使用这个规则就行了)

clean : 删除中间文件 *.o 和执行文件
每个Makefile中都应该写一个清空目标文件( .o 和执行文件)的规则,在不需要这些文件的时候,只需要执行make clean就行了。这不仅便于重编译,也很利于保持文件的清洁。

C程序的编译:gcc、Makefile用法_第6张图片
由于 make 具有自动推导命令的能力,看到一个filename.o,就能推导出filename.c,也能推导出gcc -c filename.c。所以在普通版本的基础上可以省略一些命令。

# 改进版Makefile
object = main.o hello.o

hiii : $(object)
	gcc $(object) -o hiii

main.o : hello.h
hello.o : hello.h

clean :
	del $(object) hiii.exe

# 高级版Makefile
object = main.o hello.o

hiii : $(object)
	gcc $(object) -o hiii

main.o hello.o : hello.h
# one.o two.o : three.h # 如果有的话

clean :
	del $(object) hiii.exe

由于编译器版本的不同,较为简略的写法编译器可能识别不出来,普通版本是最稳妥的写法。如果你用简略写法出错的话,建议使用普通版本的写法。另外,中文注释也可能会引起错误。我用的是下面的综合版:

object = main.o hello.o

hiii : $(object)
	gcc $(object) -o hiii

main.o hello.o : hello.h
	gcc -c main.c hello.c

clean :
	del $(object) hiii.exe

你可能感兴趣的:(数据结构)