Makefile的那些事

阶段三就要完成了,下面的课程将是我更所期待的

makefile在工程很多时可以用自动编译将效率提高很多

在用makefile之前需要安装make,本人是ubuntu系统所以直接

sudo apt-get install make

Makefile的本质是一个文件,需要配合make命令进行自动化编译。文件名常首字母大写。
在Makefile中的格式为:
<目标> : <依赖>
一个TAB<命令>
Makefile的 = 赋值的话有个易错点,就是变量按照最后一次赋的值而进行,具体的意思就是:

1
2
3
4
5
6
7
OBJ1 = A
OBJ2 = $(OBJ1A) B
OBJ1 = AA
all :
@echo ${OBJ2}
//经过上面的赋值后,OBJ2的值为 AA B


“:=” 表示直接赋值,赋予当前位置的值。
像上面的例子,最终结果就是A B


自动变量

$@ 在我个人定义中这个就是匹配当前的目标

$< 依赖文件集合中的第一个文件.

$^ 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,会去除重复的依赖文件,只保留一份。


例如说

我创建了一个fun.h,fun.c以及main.c我一般编译的话直接gcc *.c就行了,从而创建出可执行的a.out。我如果要用makefile的话:

1
2
3
4
5
6
7
8
9
10
11
cc := gcc
TARGET := main_exec#目标
OBJECT := main.o fun.o#可执行文件依赖
${TARGET} : ${OBJECT}
@${cc} $^ -o $@
%.o : %.c
@$(CC) -c $< -o $@
#特别解释一下%,这里的%是匹配规则,和*是不同的,上面的%.c代表匹配到的.c文件逐一进行命令,*仅仅代表所有的.c文件。
#因为我们的依赖文件有两个,所以相当于执行了两次
clean :
rm -rf *.o main_exec

疑惑点:
为什么OBJECT可以被赋多个值
答: Makefile中的变量赋值类似与c语言中的宏,可以理解为直接替换。


Makefile静态模式

Makefile的静态模式指的是一种自动编译模式,在这种模式下,我们可以很容易的定义”多目标”规则。语法如下:

1
2
3
4
5
<targets ...> : <target-pattern> : <prereq-patterns...>
<command>
// target 定义了一系列目标,也就是多个目标。可以是通配符,也可以是多个目标的集合。
//target-pattern 是targets的模式,也就是目标集模式。浅显点在上文可以理解为%.o
//prereq-patterns 则是目标的“依赖”元素

示例:

1
2
3
$(OBJS) : %.o : %.c
gcc -c $< -o $@
//$(OBJS)是多个.o文件的集合。例如: fun.o glob.o main.o

伪目标.PHONY:

当makefile目录下有一个和目标相同的文件时,例如clean文件。我们在执行make命令的时候会出现错误。伪目标就是用于解决此种错误而产生。伪目标只是一个标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.PHONY : clean
CC := gcc

TARGET : exec_main
OBJECT : main.o fun.o

$(TARGET) : $(OBJECT)
$(CC) -O $@ $^

%.o:%.c
$(CC) -O -C $@ $<

clean:
rm -rf *.o exec_main

指定头文件:

linux中一般通过”-I” (大写i)来指定头文件,形式如下:

1
-I  /home/linux/include

Makefile中常见写法:
1
2
3
4
5
 CFLAGS = -I /home/linux/include

myapp: *.c
gcc $(CFLAGS) -o myapp

指定库文件路径:

linux中一般通过”-L” (大写l)来指定库文件的路径,形式如下:

1
LDFLAGS = -L /usr/lib
Contents
  1. 1. 阶段三就要完成了,下面的课程将是我更所期待的
  2. 2. makefile在工程很多时可以用自动编译将效率提高很多
  3. 3. 在用makefile之前需要安装make,本人是ubuntu系统所以直接
  • 自动变量
  • 例如说
    1. 1. Makefile静态模式
    2. 2. 示例:
    3. 3. 伪目标.PHONY:
    4. 4. 指定头文件:
    5. 5. 指定库文件路径: