跳至正文

Makefile编写方法总结

本文意在整理一个简明的 Makefile编写方法 ,这种东西基本上写完后不写新项目就不会再碰了,所以记录下免得下回自己写的都看不懂了。只介绍了常用的功能,如果需要查看其他的或希望系统地学习,推荐跟我一起写Makefile。顺便吐槽下国内的搜索引擎,现在给CSDN和博客园这种的权重太高,还有很多像这样的教程根本搜不到。经常CSDN里面就几行的文章都能上百度首页,而同样关键词谷歌就能搜到很多优秀的文章。这种泛滥的题材也没法搞排名,我就放飞自我地写啦~\(≧▽≦)/~

Linux Logo

1 Makefile是干什么的

在Linux下使用C语言编程,编写Makefile几乎是无法避免的。如果程序只有一个文件,那么可以直接使用gcc命令进行编译,生成可执行文件。但是使用多个文件项目,需要对每一个源文件进行分别编译,生成一个.o文件。再将他们链接起来生成整个项目的结果。如果每有一个源文件都要用一次gcc来编译一次就很麻烦,所以就有了Makefile这个东西,帮助我们记录所有需要编译的源文件,这样只用运行一次make就可以完成整个项目的编译。此外,Makefile还有功能可以提高编写和编译效率,这个后面再说。先贴出我为了我的小车写的Makefile,也是本文的最终结果。

TARGET = mcar

OPT = -g -Wall -Os
LDLIBS = -lm -lpthread
INCLUDES = -I ./header -I ./solver
CFLAGS = $(OPT) $(INCLUDES)
CC = gcc

$(TARGET): obj/mcar.o $(patsubst src/%.c,obj/%.o, $(wildcard src/*.c)) $(patsubst %.c,%.o, $(wildcard solver/*.c))
	$(CC) $^ -o $(TARGET) $(OPT) $(LDLIBS)
obj/mcar.o: mcar.c
	make -C obj mcar.o
obj/%.o: src/%.c
	make -C obj $(patsubst %.c,%.o, $(notdir $<))
solver/%.o: solver/%.c
	make -C solver $(patsubst %.c,%.o, $(notdir $<))

all:	$(TARGET)
print:  
	@echo $(wildcard solver/*.c) 
clean:
	rm -f $(TARGET) obj/*.o
rebuild:clean all

2 基本规则

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

只要包含这几个元素就可以编写一个简单Makefile。
target是这一部分要生成的对象。在没有特殊声明的情况下,整个文件的第一个target即使项目生成的目标文件。
prerequisites是生成这个target所需求的项目,可能是项目中的一个文件,也可能是一个另一个target。
command是在调用这个target时需要执行的指令。

requisites = out.o
target:$(requisites)
    command
    ...

Makefile中还可以使用变量,类似于C语言中的宏定义,在执行时直接替换进去的。定义是直接用等号连接变量名和内容。用$(variable)形式进行调用。

3 工作方式

执行make命令,就会自动寻找当前路径下的makefile文件按照里面的规则进行编译。默认情况下以第一个target为目标进行编译,当该目标依赖其他target则会先编译他依赖的目标。如果已经产生了目标则会比较源文件和目标产生的时间,目标产生时间早于源文件则会重新生成这个target,否则不会。

4 模式匹配与自动化变量

%.o : %.c
   gcc $<

%是模式匹配,可以自动将当前路径下所有的c文件,生成与之对应的o文件。
$<是一个自动化变量,指的是依赖目标。像例子中依赖是一个文件集,那么他会一个一个的从中提取。
使用模式匹配和自动化变量。在文件多时使用非常方便。例如当前文件夹下包含a.c和b.c两个文件,那么则等同于:

a.o : a.c
    gcc a.c

b.o : b.c
    gcc b.c

5 函数

$(<function> <arguments>)

makefile中也提供了一些函数方便进行字符串的处理。文章开头的示例中使用了patsubst、wildcard和notdir三个函数。

$(patsubst <pattern>,<replacement>,<text>)

patsubst 是一个替换函数。在<text>中所有负责<pattern>的部分替换为<replacement>

$(wildcard <pattern>...) 

wildcard 是展开函数,输出所有符合<pattern>的文件。例如$(woldcard *.c)则会一个一个得输出当前路径下所有.c文件。

$(notdir <names...>)

notdir是取文件函数,会去除<name…>中的所有路径,只留下文件名。

6 参考

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注