C语言makefile文件

本文通过制作C语言扫雷游戏,介绍了GCC编译命令及Makefile的基础知识,详细解析了源文件如何编译成中间代码文件,再链接成执行文件的过程,以及Makefile如何智能管理编译流程。

       最近,闲的没事干,想写一个C语言扫雷。看了一篇博客,用到了多文件编程。我之前也没有了解过makefile文件,就打算深入了解一下。结果一学习,就学习了一天。到现在,都还没有开始写扫雷。(逃

       网上关于makefile文件的介绍都很长,我这里主要是把一些大佬的博客整合一下,我感觉这样才能让我更好的理解。

=============================================================================

一.GCC相关命令介绍

       一般来说,无论是C、C++,首先要把源文件编译成中间代码文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link).
       也就是源文件(.c 文件或者.cpp文件)首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error)。
Gcc编译器在编译一个C语言程序时可以继续细分,细分成4个步骤
1.将C语言源程序预处理,生成.i文件。
2.预处理后的.i文件编译成为汇编语言,生成.s文件。
3.将汇编语言文件经过汇编,生成目标文件.o文件。
4.将各个模块的.o文件链接起来生成一个可执行程序文件。
在这里插入图片描述
在写makefile文件之前,我们一定要了解一下gcc相关命令格式
(1).gcc -c
c选项表示编译、汇编指定的源文件(也就是编译源文件),但是不进行链接。使用-c选项可以将每一个源文件编译成对应的目标文件。

gcc -c main.c

编译器编译main.c生成中间文件main.o

(2)gcc -o

gcc [infile] -o [outfile]

[infile] 表示输入文件(也即要处理的文件),它可以是源文件,也可以是汇编文件或者是目标文件;
[outfile] 表示输出文件(也即处理的结果),它可以是预处理文件、目标文件、可执行文件等
-o主要是用于指定输出(out)文件名.

gcc -c main.c -o a.o

将源文件 main.c 编译为目标文件 a.o。如果不使用 -o 选项,那么将生成名为 main.o 的目标文件。

gcc -E main.c -o demo.i   
//gcc -E是进行文件的预处理,主要加载头文件,宏替换,处理带”#”的句子

对源文件 main.c 进行预处理操作,并将结果放在 demo.i 文件中。如果不使用 -o 选项,那么将生成名为 main.i 的预处理文件。

(3)gcc
gcc 不带任何参数,可以把文件直接编译成可执行文件

gcc main.c -o main.exe

直接把main.c源文件编译成main.exe可执行文件(-o只是规定输出文件的名称)

gcc main.o -o main.exe

直接把main.o中间文件编译成main.exe可执行文件

其实,我觉得只要了解过了这三个命令就行了。其他的比如说预编译命令或者变成汇编语言的命令,我感觉用不到。如果你想要继续深入了解,可以访问这个GCC常用选项

二.编写一个makefile文件

       make命令执行时,需要一个 Makefile文件,以告诉make命令需要怎么样的去编译和链接程序。首先,我们用一个示例来说明Makefile的书写规则。我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
1.如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2.如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3.如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。

edit : main.o AAA.o BBB.o CCC.o 
   gcc -o edit main.o AAA.o BBB.o CCC.o 
main.o : main.c  
   gcc -c main.c
AAA.o : AAA.c   AAA.h
   gcc -c AAA.c
BBB.o : BBB.c   BBB.h
   gcc -c BBB.c
CCC.o : CCC.c   CCC.h
   gcc -c CCC.c
clean :
   rm edit main.o AAA.o BBB.o CCC.o

我们把上面的代码保存在一个文件中,文件名可以叫makefile或Makefile。
从上面的实例中,我们可以看出,代码的主要结构为

target:prerequisites …
   command(指令)

target也就是一个目标文件,可以是Object File,也可以是执行文件
prerequisites就是,要生成那个target所需要的文件。
command也就是make需要执行的命令。
       这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件.
上面的文件中,main.o依赖于main.c,AAA.o依赖于AAA.c和AAA.h,以此类推。依赖的关系实质就是目标文件是由哪些文件生成的,main.o是由main.c生成的,AAA.o是由AAA.c和AAA.h生成的。

       Makefile文件中,命令的执行是看prerequisites中的文件是否比target更新,prerequisites中如果有一个的文件比target文件要新的话,command所定义的命令就会被执行。程序会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,那么,命令就会执行
       比如我在AAA.h中添加了一个函数申明,AAA.c不动,这是只有AAA.h是变了的,AAA.c没变。我们首先比较AAA.o和AAA.c的更新日期,发现是一样的,没有问题。接着比较AAA.o和AAA.h的更新日期,发现AAA.h更新时间更晚。此时,满足命令的执行条件。我们就会执行gcc -c AAA.c这个命令。其实,这也很好理解,你头文件都变了,中间文件肯定要重新编译一下的。

       我们执行make命令(不跟参数,就光光输入一个make),makefile文件默认执行第一行的语句,这里是

edit : main.o AAA.o BBB.o CCC.o

       接下来程序会检查main.o AAA.o BBB.o CCC.o这四个文件是否更新过,如果有一个文件被更新过的话,edit下的程序段就会执行

gcc -o edit main.o AAA.o BBB.o CCC.o

       我们如果只执行make命令(不跟参数,就光光输入一个make),那么就永远无法执行到clean那行代码。我们输入make clean,就可以执行clean的代码.这行代码是把生成的中间文件全部清除掉。

==============================================================================
我这个博客复制了好多别人博客上的段落,如果看不懂,可以去看看原博客
参考链接:https://www.cnblogs.com/aiguona/p/9162500.html
参考链接:http://c.biancheng.net/view/666.html

### C语言Makefile文件的用法及示例 #### 什么是MakefileMakefile是一种用于自动化构建软件项目的工具配置文件。通过定义目标、依赖项和命令,它可以简化大型项目中的编译过程[^1]。 #### 基本结构 一个典型的Makefile由以下几个部分组成: - **目标 (Target)**:表示需要生成的文件或执行的操作。 - **依赖 (Prerequisites)**:目标所依赖的其他文件或目标。 - **命令 (Commands)**:当任何依赖发生变化时,用来更新目标的一系列Shell命令。 #### 示例一:简单的Makefile 假设有一个名为`hello.c`的源程序,我们希望将其编译成可执行文件`hello`: ```makefile # 定义变量 CC = gcc CFLAGS = -Wall # 目标规则 hello: hello.o $(CC) $(CFLAGS) -o hello hello.o hello.o: hello.c $(CC) $(CFLAGS) -c hello.c clean: rm -f *.o hello ``` 在这个例子中, - `CC` 和 `CFLAGS` 是两个常用的变量分别代表使用的编译器及其标志。 - `.o` 文件是从对应的`.c`文件生成而来,利用的是隐含规则[^2]。 #### 示例二:使用通配符和自动变量 对于多个源文件的情况,我们可以更灵活地处理它们: ```makefile SRCS := main.c util.c helper.c OBJS := $(SRCS:.c=.o) all: program program: $(OBJS) gcc -o program $(OBJS) %.o: %.c gcc -c -o $@ $< clean: rm -f $(OBJS) program ``` 这里展示了如何使用通配符来动态生成对象列表,并且应用了模式规则 `%` 来匹配任意单个文件的目标与依赖关系。 #### 关于隐含规则的应用 如果不想手动指定每一个`.c`到`.o`转换的过程,则可以让GNU Make自己去完成这些工作。例如,默认情况下,它知道怎样从`.c`文件创建相应的`.o`文件。 #### Include指令的作用 有时我们需要将一些公共设置放在单独的小型Makefiles里以便重用。这可以通过`include`语句实现。比如下面的例子显示了一个包含其它Makefile片段的方式[^5]: ```makefile include common.mk include more_rules.mk ``` 以上方法允许开发者拆分复杂的Makefile逻辑至不同文件之中,从而提高维护性和清晰度。 #### 总结 尽管有人认为过于繁琐的Makefile没有必要[^3],但在实际工程实践中合理运用它的特性确实能够极大地提升效率并减少重复劳动。上述内容涵盖了基本概念以及若干具体实例供参考学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值