Makefile 简单编写

概述

在 Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个make命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile 文件的编写。

所要完成的Makefile 文件描述了整个工程的编译、连接等规则。其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要的可执行文件。

尽管看起来可能是很复杂的事情,但是为工程编写Makefile 的好处是能够使用一行命令来完成“自动化编译”,一旦提供一个(通常对于一个工程来说会是多个)正确的 Makefile。编译整个工程你所要做的事就是在shell 提示符下输入make命令。整个工程完全自动编译,极大提高了效率。

Makefile的基本格式

<target> : <prerequisites> 
[tab]  <commands>

其中
target :目标文件, 可以是 Object File, 也可以是可执行文件
prerequisites :生成 target 所需要的文件或者目标
command:make需要执行的命令 (任意的shell命令), Makefile中的命令必须以 [tab] 开头

示例解析

CC = gcc
CFLAGS = -g -O  -Wall -I/home/tao/curl-7.71.1/_install/include -I/home/tao/WiringPi/wiringPi
LDFLAGS = -L/home/tao/curl-7.71.1/_install/lib -L/home/tao
LIBS = -lpthread -lwiringPi -lcurl

smartHousePro:bathroomLight.o bedroomLight.o kitchenLight.o livingroomLight.o swimmingpoolLight.o \
	findDeviceByName.o fire.o faceDoor.o faceRecognition.o socket.o voicer.o main.o 
	$(CC) $^ $(LDFLAGS) -o $@ $(LIBS)
%.o:%.c
	$(CC) $(CFLAGS) -c $^
clean:
	rm -f *.o

第1~4行

自定义变量 和 $( )的使用

其中前4行是自定义变量
Makefile 允许使用等号自定义变量
调用时,变量需要放在 $( ) 之中,可以查看第7和第9行

//指定使用的编译器为gcc
CC = gcc

//指定头文件(.h文件)的路径
CFLAGS = -g -O -Wall -I/home/tao/curl-7.71.1/_install/include -I/home/tao/WiringPi/wiringPi

//指定库文件的位置
LDFLAGS = -L/home/tao/curl-7.71.1/_install/lib -L/home/tao

//告诉链接器要链接哪些库文件
LIBS = -lpthread -lwiringPi -lcurl

Makefile一共提供了四个赋值运算符 (=、:=、?=、+=)

VARIABLE = value
在执行时扩展,允许递归扩展。

VARIABLE := value
在定义时扩展。

VARIABLE ?= value
只有在该变量为空时才设置值。

VARIABLE += value
将值追加到变量的尾端。

第5~7行

smartHousePro:bathroomLight.o bedroomLight.o kitchenLight.o livingroomLight.o swimmingpoolLight.o \
	findDeviceByName.o fire.o faceDoor.o faceRecognition.o socket.o voicer.o main.o 
	$(CC) $^ $(LDFLAGS) -o $@ $(LIBS)

注意:第二行必须由【Tab】键起首,不能用空格

反斜杠转义符号

在第5行出现了 \ 符号,使用的原因是第5行的内容太长了,不便于查看所写的内容
其中的作用是将第6行的内容承接在第5行的后面

自动变量 $^ 和 $@

第5~7行

smartHousePro:bathroomLight.o bedroomLight.o kitchenLight.o livingroomLight.o swimmingpoolLight.o \
	findDeviceByName.o fire.o faceDoor.o faceRecognition.o socket.o voicer.o main.o 
	$(CC) $^ $(LDFLAGS) -o $@ $(LIBS)

$^

$^ 指代所有前置条件,之间以空格分隔。
比如,规则为 smartHousePro:bathroomLight.o bedroomLight.o kitchenLight.o,那么 $^ 就指代 bathroomLight.o bedroomLight.o kitchenLight.o

$@

$@指代当前目标,就是Make命令当前构建的那个目标。
比如,make smartHousePro 的 $@ 就指代 smartHousePro

第8、9行

%.o:%.c
	$(CC) $(CFLAGS) -c $^

匹配符%

Make命令允许对文件名,进行类似正则运算的匹配,主要用到的匹配符是%
比如,假定当前目录下有 a.c 和 b.c 两个源码文件,需要将它们编译为对应的对象文件(.o文件)

%.o: %.c

等同于

a.o: a.c
b.o: b.c

使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。

即第8、9行的作用是将所有的.c文件生成.o文件(对象文件)

第10、11行

clean:
	rm -f *.o

上面代码的目标是clean,它不是文件名,而是一个操作的名字,属于"伪目标 ",作用是删除对象文件;其中 * 为通配符,即当执行 make clean 指令时,会将所有尾缀为.o的文件删除

CFLAGS、LDFLAGS和LIBS

CFLAGS

CFLAGS: 指定头文件(.h文件)的路径。如:CFLAGS=-I/usr/include -I/path/include
同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的include目录加入到该变量中来。

选项         说明
-c           用于把源码文件编译成 .o 对象文件,不进行链接过程
-o           用于连接生成可执行文件,在其后可以指定输出文件的名称
-g           用于在生成的目标可执行文件中,添加调试信息,可以使用GDB进行调试
-Idir        用于把新目录添加到include路径上,可以使用相对和绝对路径,“-I.”、“-I./include”、“-I/opt/include”
-Wall        生成常见的所有告警信息,且停止编译,具体是哪些告警信息,请参见GCC手册,一般用这个足矣!
-w           关闭所有告警信息
-O           表示编译优化选项,其后可跟优化等级0\1\2\3,默认是0,不优化
-fPIC        用于生成位置无关的代码
-v           (在标准错误)显示执行编译阶段的命令,同时显示编译器驱动程序,预处理器,编译器的版本号

LDFLAGS

LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。
用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安装一个包都几乎一定的会在安装目录里建立一个lib目录。如果明明安装了某个包,而安装另一个包时,它愣是说找不到,可以抒那个包的lib路径加入的LDFALGS中试一下。

LIBS

LIBS:告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv

简单地说,LDFLAGS是告诉链接器从哪里寻找库文件,而LIBS是告诉链接器要链接哪些库文件。不过使用时链接阶段这两个参数都会加上,所以你即使将这两个的值互换,也没有问题。

有时候LDFLAGS指定-L虽然能让链接器找到库进行链接,但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,那么我们需要增加这两个库给"-Wl,R":
LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

猜你喜欢

转载自blog.csdn.net/weixin_50438937/article/details/114735479