linux下Makefile学习

本文深入讲解Makefile的基础概念、规则及工作原理,介绍如何利用Makefile简化大型项目的编译过程,包括目标文件、依赖关系、命令定义等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 基本概念

关于程序的编译和链接:
编译 链接
源码------中间代码------可执行文件
.c .o
编译过程中,主要检查语法是否正确,函数与变量声明是否正确,若函数未被声明,编译器会给出警告,但可以生成obj文件;
链接时,主要链接函数和全局变量,负责管理中间目标文件,寻找函数的实现,若找不着,报链接错误码。
大多数情况下,由于源文件较多,编译生成的中间目标文件太多,在链接时要指出的中间目标文件太多,这对编译很不方便,
所以可给中间目标文件打个包,window下称为库文件,即.lib文件;UNIX下,是Archive File,即.a文件。

2. Makefile规则

目标target:依赖关系prerequisites
【TAB】命令command(任意的shell命令)
target即目标文件,可以是object file或可执行文件。生成规则见command。
如果依赖关系中有1个以上的文件比target文件要新,command所定义的命令就会被执行。这就是Makefile的核心规则。
三.make如何工作
1、make在当前目录下查找名为"Makefile"或"makefile"的文件;
2、若找到,它会找文件中的第一个目标文件target,并将此文件作为最终目标文件;
3、查找target后的依赖目标.o是否需要更新;
4、若.o不存在或已修改,查找.o的依赖关系,若找到生成.o文件;
5、生成target。
像make clean这样的,未被第一个目标文件直接或间接关联,不会被自动执行。
四、makefile中使用变量
objects = main.o kbd.o ...\
insert.o ...
gcc -o $(objects)
clean:
rm $(objects)
五、自动推导
找到whatever.o后
自动依赖whatever.c
自动执行cc -c whatever.c
六、另类makefile
kbd.o command.o files.o: command.h
*.o:buffer.h
----------------------makefile总述---------------------------
makefile中引用其它makefile文件:
1、指定makefile文件: make -f/-file <name>
2、指定make执行时的目录,默认为当前目录: make -I/--include-dir
若<prefix>/include(一般是/usr/local/bin/或/usr/include)存在,make也会去找。
3、包含其它makefile命令:include<filename>。可以出现空格但不可以是TAB。

makefile的工作方式:
1、读入所有makefile文件;
2、读入被include的其它makefile;
3、初始化文件中的变量;
4、推导隐晦规则,并分析所有规则;
5、为所有目标文件创建依赖关系链;
6、根据依赖关系,决定哪些目标要重新生成;
7、执行生成命令。

makefile规则中使用的通配符:
* ? [...]
文件名中的~用途: ~/test指当前用户目录下test目录;
~zhangb/test指用户zhangb的主目录下test目录。
$?表示自动化变量

文件的搜寻:
在一些大工程中,大量源文件,存放于不同的目录。所以,当make需要寻找依赖关系时,在文件前加上路径,让make自动去找。
Makefile文件中的特殊变量"VPATH"就是完成此功能的。
默认,make在当前目录寻找依赖文件和目标文件;若定义此变量,make会在当前目录找不到的情况下,到所指定的目录中去寻找文件。
VPATH = src: ../headers
上述定义指定两个目录: src和 ../headers,make按此顺序搜索。多个目录之间用:隔开。

设置vpath也可以,只不过它不是变量,是make的关键字【更灵活】,可指定不同的文件在不同的搜索目录中。使用方法有三种:
1. vpath <pattern> <directories>
为符合模式pattern的文件指定搜索目录directories
2. vpath <pattern>
清除符合模式pattern的文件搜索目录
3. vpath
清除所有已被设置好了的文件搜索目录
其中,pattern中需要包含%字符。表示匹配0或若干字符,比如"%.h"表示所有以.h结尾的文件。
比如,vpath %.h ../headers 表示make在../headers中搜索所有以.h结尾的文件。
比如,vpath %.c foo
vpath % blish
vpath %.c bar
表示.c结尾的文件,先在foo目录,然后blish,最后是bar目录。
vpath %.c foo:bar
vpath % blish
表示.c结尾的文件,先在foo目录,然后是bar最后才是blish。

伪目标:
clean:
rm *.o temp
clean并非表示某个文件,只是一个标签,make无法生成它的依赖关系和决定它是否执行。为避免与文件重名,使用.PHONY来显式指明目标为伪目标。
.PHONY:clean
clean:
rm *.o temp
伪目标一般没有依赖关系,但我们可以为伪目标指定依赖关系。比如一口气生成若干可执行文件:
all: prog1 prog2 prog3
.PHONY:all 声明目标为伪目标
prog1:..
prog2...
prog3...
同样,伪目标也可互相依赖
.PHONY:cleanall cleanobj cleandiff
cleanall:cleanobj cleandiff
rm program
cleanobj:
rm *.o
cleandiff:
rm *.diff
通过上述示例,可达到清除不同目录的目的。

多目标:
使多个目标同时产生依赖关系,比如:
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
等价于
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
-$(subst output ,, $@),其中$表示执行一个makefile函数,$@表示目标集合,类似数组,依次取出目标。

静态模式:
可更容易地定义多目标的规则,让我们的规则更加弹性和灵活。
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
targets:定义一系列的目标文件,可以有通配符,表示目标的集合;
target-pattern:指明targets模式,即目标集模式;
prereq-parrterns:目标依赖模式,对target-pattern形成的模式再进行一次依赖目标的定义。
举例:
***************************
objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c //目标从$objects中取,%.o指foo.o,bar.o。依赖模式%.c表示 foo.c bar.c
$(CC) -c $(CFLAGS) $< -o $@ //$< $@表示自动化变量,前者表示所有依赖目标集,即.c,后者表示目标集。
***************************
等价于:
foo.o:foo.c
cc -c $(CFLAGS) foo.c -o foo.o
bar.o:bar.c
cc -c $(CFLAGS) bar.c -o bar.o
再举例:
***************************
files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c //filter是makefile的filter函数,只保留%.o的内容。
$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<
******************************

自动生成依赖性:
如果工程较大,必需清楚包含哪些头文件非常麻烦。可使用C/C++编译器自带选项生成依赖关系。例如:
cc -M main.c其输出是:main.o:main.c defs.h
假设使用的是gcc编译器
gcc -M main.c输出是
main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/sched.h /usr/include/libio.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/include/bits/wchar.h /usr/include/gconv.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
/usr/include/bits/stdio_lim.h
而gcc -MM main.c输出是:
main.o: main.c defs.h
-MM选项过滤标准库中的头文件
.d为系统自动生成的依赖关系,当代码更新后,会自动更新。

书写相关:
UNIX下,make命令默认被/bin/sh,解释执行。
默认make会在屏幕输出要执行的命令,可用@字符在命令行前屏蔽。
若执行make时,带入参数 -n或 --just-print只显示命令,但不执行,有利于调试makefile。
make -s或--slient全面禁止命令的显示

转载于:https://www.cnblogs.com/obstinate-butterfly/p/4231667.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值