经常在一个项目中包含多个.c源文件,而且一个.c源文件包含了一堆的头文件,这种情况下如何编写makefile,使得能成功编译整个项目?本博文对这些问题提出自己浅析的理解。涉及到对gcc命令使用与编译流程理解及多文件时makefile的编写。
有些场景下编译的程序是不能依赖OS和标准的C库的,并且需要C和汇编混合编译,如bootloader程序,就需要制定参数-nostdlib,这样的Makefile如下所示:
all:
arm-linux-gcc -O2 -Wall -nostdlib -march=armv4 -Wl,-T,ipl.lds uart.c ipl.c nfc.c nand.c sha1.c arm.s -o ipl.exe
arm-linux-objcopy -Obinary ipl.exe ipl.bin
clean:
rm -rf ipl.exe ipl.bin
很奇怪的是,在《跟我一起学Makefile-陈皓》的文档中,第五部分第八章,有讲到自动生成依赖性的问题。从字面意思,我理解为在.c源文件中每添加一个自己的头文件都需要在makefile的对应目标中添加对该头文件的依赖。
添加对此头文件的依赖是为了确保有此文件?但是在gcc编译时,如果寻找不到该头文件,是会停止编译且报错的。
然后我就直接理解为了:添加头文件依赖是为了gcc编译时让此头文件也作为输入文件
例如:
[objc] view plain copy《abc.c》:
include “abc.h”
include 《stdio.h》
void main()
{
printf(“helloworld”);
}
编译成.o文件时,应该为:
[objc] view plain copygcc -c abc.c abc.h //错误示范
结果却是相当于执行了:
[objc] view plain copygcc -c abc.c
gcc -c abc.h
是因为我的gcc版本较新?总之,折腾了很久后,我就是发现,头文件没必要写到依赖中,而gcc也不需要直接把此头文件作为输入,但是若头文件不在当前目录下,需要用-I指出头文件地址。(纯粹个人阶段性的理解,还希望大牛能指正)
在编程的时候,我们可以把一个完整程序的每个函数分离出来,写成.c文件,最后再一起编译和链接。这样有利于程序功能模块化,也方便检查代码错误。
.h文件:里面编辑该程序需要引用的头文件。
#ifndef /#define / #endif : 防止该头文件被重复引用。
整体用法:
#ifndef A_H //如果没有a.h文件,#define A_H。如果有,结束定义
#define A_H //定义a.h文件
定义a.h需要的头文件
#endif //结束定义部分
例子:
一个.h文件的书写格式。
#ifndef A_H
#define A_H
定义程序所需的一些头文件
#include《stdio.h》
#include《string.h》
#include《stdlib.h》
…
#endif
保存退出。
其实在编写小程序的时候也可以不用#ifndef /#define / #endif,但是用它更安全,不易出错。
c文件的书写格式
在写每个函数之前要加载头文件,如果是.h文件,就需要写#include”a.h”。
例如:引用之前的a.h文件。
add.c
#include”a.h”
int add(int a,intb)
{
return a+b;
}
保存退出。
程序编辑完成之后,需要编译链接。
我们可以用gcc编译每个.c文件。如果有三个.c文件a.c、b.c、c.c,编译方法如下:
gcc a.c –o a.o //将三个.c文件编译成.o文件
gcc b.c -o b.o
gcc c.c -o c.o
gcc a.o b.o c.o –o all //将三个.o文件编译成一个可执行文件
。/all //执行程序
例如:
test.h
add.c
main.c
编译:
执行:
如果我们有很多个.c文件,这个方法就不太好了,这时,我们提出Makefile文件。
Makefile:自动编译。先将每个.c文件的编译过程提前写在Makefile文件中,在运行程序时,系统直接用make命令使文件自动编译,提高效率。
Makefile文件的书写格式:
vim Makefile
文件类型:由哪个文件得到
得到过程
例如:
main:main.o //可执行文件main是由目标文件main.o得到。
gcc main.o –o main //得到过程是将main.o编译成main文件。
main.o:main.c
gcc -c main.c -o main.o
在Makefile文件中一定要将每一个.c文件按执行顺序先编译成.o文件,再按顺序将.o文件编译成可执行文件。
每次编译过后会产生很多的.o文件,对于程序运行没什么太大意义,反而会占内存,所以我们也可以在Makefile文件中添加清除命令(clean),如:
.PHONY:clean
clean: 删除所有文件类型为.o的文件
rm –rf *.o
一些文件也可用下面符号表示:
$@: 代表规则里面的目标文件。
$《:代表规则当中的第一个依赖文件。
%.c:%.o 所有.c文件全部编译成.o文件
.PHONY:clean
如果有.PHONY:clean,外面也有clean文件,执行make clean时,里面的.o文件会被删除而外面的clean文件还在。确保了外面clean文件的安全性。如果没有.PHONY:clean 语句,外面也没有clean文件时,在执行make clean也会删除.o文件,如果外面有clean,则会报错。
PHONY:目标并非实际的文件名,只是显示在请求时执行命令的名字。有两种理由需要使用PHONY目标:避免和文件名冲突,改善性能。
例如:
vim Makefile
编译和执行(make:编译, 。/all:执行):
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)