Linux下的Makefile编写与优化


一、什么是Makefile?

用于工程项目管理的一个文本文件,文件名为Makefile的文本文件
Makefile文件首字母可以大写,也可以小写,一般使用大写的Makefile .
如果Makefile和makefile文件都存在,执行make命令时,默认执行小写的makefile文件.

二、什么是make?

make是一个执行Makefile的工具,是一个解释器,当执行make命令时,
会解析Makefile文件中的依赖关系,通过依赖关系最终执行编译相关的命令,
完成对整个项目代码的编译。
make可执行程序在/usr/bin目录下(默认ubuntu系统都自带make命令)
sudo apt-get install make 

三、Makefile的用途?

描述了整个工程了的编译、链接规则
软件项目自动化编译

四、理论基础

软件构造过程、程序的编译和链接
	面向依赖的思维(思想)
	编译代码的4个阶段:预处理  ---> 编译  ---> 汇编  ---> 链接
	    1.预处理:头文件的展开、注释的删除、宏定义的替换
            gcc  -E  xxx.c  -o  xxx.i
        2.编译:词法分析、语法分析  --查错的 
            如果无误,会生成汇编文件
            gcc  -S  xxx.i   -o  xxx.s
        3.汇编:将汇编文件生成二进制文件
            gcc  -c  xxx.s  -o  xxx.o
        4.链接:链接需要用到的库文件,最终生成可执行文件
            链接库需要加编译选项  -l
            gcc  xxx.o  -o  a.out
	
	面向依赖的思想:
	得到.elf可执行文件-依赖-> ***.o -依赖-> ***.s -依赖-> ***.i -依赖-> ***.c

五、Makefile的工作过程?

源文件 --> 编译 --> 目标文件 --> 链接 --> 可执行文件
hello.c -----> hello.o -----> hello
Makefile编译源文件分成两步?
1》本质上可以通过一步直接生成可执行文件。

通过一步编译完成,最终生成可执行文件:
gcc score.c main.c -o stu_manage
缺点:只要修改一个.c文件,,其他的.c文件都会被重新编译,浪费时间。

2》分成两部目的是。
对于大型工程文件,源文件很多,如果修改某个
源文件,当你再次执行make的时候,如果源文件
没有修改,make是不会重新生成目标文件,
只有修改过的源文件才会重新生成目标文件,
最后进行链接即可,这样可以有效的节约代码的编译时间。

通过两步编译完成,最终生成可执行文件:
第一步:(-c:只编译不链接,将.c文件编译生成.o文件)
	gcc -c score.c -o score.o 
	gcc -c main.c -o main.o
第二步:(链接:将所有的.o文件链接生成可执行文件)
	gcc score.o main.o -o stu_manage
	优点:如果修改了一个.c文件只需要重新编译修改过的.c文件将其生成.o文件,
		最后将所有的.o文件重新链接生成可执行文件即可。
	Makefile文件如何知道源文件是否修改呢?根据文件的时间戳

六、规则的构成

  1. 规则基本构成(由三部分组成)
    目标
    目标依赖
    命令

  2. 语法格式
    目标:目标依赖
    命令

    注意事项:
    命令必须使用tab键开头、一般是shell命令
    一个规则中可以无目标依赖,仅仅实现某种操作
    一个规则中可以没有命令,仅仅描述依赖关系
    一个规则中必须有一个目标

#案例:
# 规则:只有目标和目标只来,用来描述依赖的关系
all:hello

# 规则:有目标,有目标依赖,有命令,即描述了依赖关系,又完成某种操作。
hello:hello.o
    gcc hello.o -o hello
hello.o:hello.c
    gcc -c hello.c -o hello.o

# 规则:有目标,没有依赖,有命令,为了完成某种操作
clean:
    rm hello.o  hello 

七、Makefile实例

1.我们现在有两个文件,score.c和main.c,需要将两个.c文件编译生成一个可执行文件stuManager。
对于我们常规的做法,就是:gcc score.c main.c -o stuManager就可以了。那么怎么用Makefile来实现呢?

#写法1
stuManager:main.o score.o
	gcc main.o score.o -o stuManager
main.o:main.c
	gcc -c main.c -o main.o
score.o:score.c
	gcc -c score.c -o score.o
	
clean:
	rm *.*[^ch] stuManager

2.第一种写法,感觉也不是很方便,有没有更方便一点的写法呢?
当然是有的,不过在这里要先说一下:$@代表目标,$^代表所有依赖,那么第一种方法就可以简化为如下形式。

#写法2
stuManager:main.o score.o
	gcc $^ -o $@
main.o:main.c
	gcc -c $^ -o $@
score.o:score.c
	gcc -c $^ -o $@
	
clean:
	rm *.*[^ch] stuManager

3.我们会发现第2种写法中,执行的命令都一样,那么还有没有办法进行进一步的合并呢?也是有的。其中,% 代表模式匹配。

#写法3
stuManager:main.o score.o
	gcc $^ -o $@
# % :模式匹配,后边一个%号对应的字符串和前边的%代表的是同一个字符串
%.o:%.c
	gcc -c $^ -o $@
	
clean:
	rm *.*[^ch] stuManager

4.上面的写法已经很简单了,但是这时候我们又会发现一个问题:现在目标stuManager的依赖只有main.o score.o两个文件,那么如果此时需要的依赖文件又多了一个呢?这个时候,就要再手动添加一个新的依赖文件,那如果多的是5个,10个呢?每次都手动添加,也显得很麻烦。

那么这个时候,我们就要用到两个函数了wildcard和patsubst。
用法示例:

$(wildcard *.c) 
返回值为当前目录下所有.c 源文件列表。

$(patsubst %.c, %.o, a.c b.c) 
把字串“a.c b.c”中以.c 结尾的单词替换成以.o 结尾的字符。
函数的返回结果是“a.o b.o”
#写法4
#返回值为当前目录下所有.c 源文件列表。
var := $(wildcard *.c)
#将字符串$(var)中以.c 结尾的文件名替换成以.o 结尾的文件名。
obj := $(patsubst %.c, %.o, $(var))

stuManager:$(obj)
	gcc $^ -o $@
# % :模式匹配,后边一个%号对应的字符串和前边的%代表的是同一个字符串
%.o:%.c
	gcc -c $^ -o $@
	
clean:
	rm *.*[^ch] stuManager

总结

以上就是对Linux下Makefile实现的简单讲解与实现,不足之处还望大家指出,谢谢大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值