Linux下C语言的makefile

0.定义


工程管理器,顾名思义,是指管理较多的文件,Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件文件的内容来执行大量的编译工作,Make将只编译改动的代码文件,而不用完全编译。

Makefile文件一般和项目的其他源文件放在同一个目录下。在机器上可以同时存在许多不同的makefile文件,如果一个大项目,可以用多个不同的makefile文件来分别管理项目的不同部分。

Make命令和makefile文件的结合提供了有一个在项目管理领域十分强大的工具,不仅可以用于控制源代码的编译,而且还可以用于手册也的编写以及将应用程序安装到目标目录。

1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。


1.实例

a.实例1

main:main.o
gcc main.o -o main
main.o:main.c
gcc -c main.c
clean:
rm -rf main.o main

Linux下C语言的makefile_宏定义

会经过编译(-c) 和 生成(-o)out文件(默认生成a.out)

b.实例2

all:ser
ser:ser.o thread.o
gcc -o ser ser.o thread.o -lpthread
ser.o:ser.c
gcc -c ser.c
thread.o:thread.c
gcc -c thread.c -g
clean:
rm -rf *.o ser

说明:

语句

含义

all:ser

表示最终生成的文件是ser

ser:ser.o thread.o

ser的依赖文件是ser.o和thread.o

gcc -o ser ser.o thread.o -lpthread

接的过程(thread.o是一个多线程文件所以加上了-lpthread)

ser.o:ser.c

ser.o的依赖文件是ser.c

gcc -c ser.c

编译ser.c 为 ser.o

thread.o:thread.c

thread.o的依赖文件是thread.c

gcc -c thread.c -g

编译thread.c 为 thread.o

clean: rm -rf *.o ser

执行clean命令后删除所有的.o文件和ser目标文件

2.make的参数


  • ​-k​​:作用是在让make命令在发现错误时仍然就执行,而不是在检测到第一个错误时就停止,所以可是使用这个选项在一次操作中发下所有未编译成功的源文件
  • ​n​​:作用是让make命令输出将要执行的操作步骤,而不是真正执行这些操作
  • ​-f <filename>​​:作用是告诉make将文件名为filename的我文件作为makefile文件。如果未使用这个选项,标准版的make命令将优先在当前命令下查找名称为makefile的文件,如果不存在名称makefile的文件,则开始查找名为Makefile的文件。

比如新建文件​makefile​:

all:
@echo ""
@echo "This is a makefile test "
@echo "End test"
@echo ""

然后在终端运行:

Linux下C语言的makefile_算法_02

然后再新建​Makefile​(注意这里是大写)

all:
@echo ""
@echo "This is a Makefile test "
@echo "End test"
@echo ""

运行后

Linux下C语言的makefile_leetcode_03

然后使用**-f**选项,

all:
@echo ""
@echo "This is a make command test"
@echo "End test"
@echo ""

可以看出已经不识别​makefile​的语法高亮,那使用**-f​选项指定运行​maketest**文件,效果如下。Linux下C语言的makefile_算法_04

因此默认会生成makefile 若找不到则会找Makefile ,若要在多个makefile指定一个,则可使用​​-f​​ 唯一指定filename。

3.make的工作原则

make会一层一层的找文件的依赖关系,直到最终编译出第一个目标文件。在过程中如果出现错误则直接退出,并报错。

4.makefile 的宏定义

a.预定义变量

CC:C编译器的名称,默认cc;

CFLAGS :C编译器的选项,无默认值;

CXXFLAGS:C++编译器的选项,无默认值;

OBJS=talent.o hardwork.o
CC=gcc
CFLAGS=-Wall -O -g
success:$(OBJS)
$(CC) $(CFLAGS) $^ -o success
talent.o:talent.c talent.h
$(CC) $(CFLAGS) $^ -o talent.o
hardwork.o:hardwork.c hardwork.h
$(CC) $(CFLAGS) $^ -o hardwork.o

Makefile中的特殊宏定义:

可以通过​KEY=value​在makefile中定义宏。可以使用** ( K E Y ) 或 者 (KEY)或者 (KEY)或者{KEY}引用宏**

makefile1:

main:main.o
gcc main.o -o main
main.o:main.c
gcc -c main.c
clean:
rm -rf main.o main

可以将上述的文件makefile1修改成makefile2:

-Wall :表示允许发出gcc所有有用的报警信息。

-g 只是编译器,在编译的时候,产生调试信息。

makefile2:

CC = gcc
CFLAGS = -g -Wall -O

main:main.o
$(CC) main.o -o main
main.o:main.c
$(CC) $(CFLAGS) -c main.c
clean:
rm -rf main.o main

终端执行命令​make -f makefile2​,可以看到:

Linux下C语言的makefile_编译器_05

b.宏定义符号

宏定义符号

含义

$*

不包括后缀名的当前依赖文件的名称

$+

所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件

$<

第一个依赖文件的名称

$?

所有时间戳比目标文件晚的依赖文件,并以空格分开

$@

目标文件的完整名称

$^

所有不重复的目标依赖文件,以空格分开

-:

告诉make命令忽略所有的错误

@:

告诉make在执行命令前不要该改命令显示在标准输出上

那么,上面的makefile2可以修改为:

CC = gcc
CFLAGS = -g -Wall -O
main:main.o
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGS) -c $^
clean:
rm -rf main.o main

5.多个依赖文件的编写

main.c,add.c,add.h,sub.c,aub.h

main.c的内容为:

#include <stdio.h>
#include "add.h"
#include "sub.h"

int main()
{
int a = 10, b = 5;
printf("a + b = %d\r\n", add(a, b));
printf("a - b = %d\r\n", sub(a, b));
return 0;
}

那么makefile可以这样写:

CC = gcc
CFLAGS = -g -O -Wall

main:add.o sub.o main.o
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGS) -c $^
clean:
rm -rf main main.o add.o sub.o

在终端运行make命令后:

Linux下C语言的makefile_算法_06


6.参考文章

​​