Makefile中主要包含如下5类内容:
- 显式规则(Explicit Rules)
- 隐式规则(Implicit Rules)
- 变量定义(Variable Definitions)
- 指示指令(Directives)
- 注释(Comments)
显式规则(Explicit Rules)
显示规则明确说明了何时以及如何构造规则的目标。它列出了目标及其依赖,并且提供用于创建或更新目标的命令。
例1:
hello:hello.c
gcc -o hello hello.c
例2:
edit: main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
gcc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
隐式规则(Implicit Rules)
隐式规则定义了何时以及如何根据文件名来构造一类目标。隐式规则描述了目标如何依赖于一个与目标名称相似的文件,并给出了创建或更新此类目标的命令。
Make命令中包含了一系列默认的隐式规则,当Makefile中没有指定某些目标的构建方法时,make就用这些固化在数据库中的规则来进行构建,这可以大大简化Makefile的编写和维护,提升了效率。
例如:
CFLAGS = -Iinc/
%.o:src/%.c #隐式规则
$(CC) $(CFLAGS) -c lt; -o $@
main.o: inc/defs.h #隐式规则
kbd.o: inc/defs.h inc/command.h #隐式规则
- 虽然定义了main.o的规则,依赖文件中没有提供源文件,此时会由隐式规则提供依赖条件(源文件)。另外,main.o的规则中没有recipes,所以make也会根据其内建的隐式规则来进行生成。
- %.o:src/%.c和形如 main.o:inc/def.h 在make展开后将合并为如下规则:
main.o: src/main.c inc/def.h
gcc -Iinc/ -c src/main.c -o main.o
变量定义(Variable Definitions)
变量是一种存储数据的容器。它们用于在程序运行期间存储值,以便在程序的不同部分之间共享和使用这些值。通过使用变量,使程序员能够灵活地处理和操作数据,实现各种功能和逻辑。
Makefile中可以使用变量,用于表示一个文本字符串,称为变量的值。Makefile中的变量定义是指定一个变量的文本字符串值的行,该变量稍后可以替换到文本中。Makefile中的变量可以用来存储诸如文件名、目录名和编译选项等。 变量可以使Makefile的编写更加灵活。
例如:
CC = gcc
CFLAGS = -g -Wall -O2
OBJS = server.o server_priv.o server_access.o
指示指令(Directives)
Directive是一种特殊的命令,它为make提供了特定的指令,以便在读取Makefile时执行特定的操作。这些指令包括:
- 包含指令,如包含另一个Makefile文件: include inc.mk
- 条件指令,例如: ifeq … else…endif等
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
- 定义指令,如: 定义一个多行变量
在Makefile中,define指令用于定义一个多行文本变量。define指令允许你在一个地方定义一个文本变量,并在后续的规则或指令中使用它。使用define指令可以使Makefile更易于维护和修改,因为你只需要在一个地方修改文本,就可以在整个Makefile中更新它。
例如:
MAIN := hello
define compile_rule
$(1).o:$(1).c
$(CC) -g -c $< -o $@
endef
define do_compile
$(CC) -g $(1) -o $(2)
endef
hello: hello.o
$(call do_compile, lt;, $@)
$(eval $(call compile_rule, $(MAIN)))
clean:
$(RM) *.o hello
注释(Comments)
注释是用于解释代码含义或提供其他信息的文本,它不会被程序执行。注释可以帮助其他开发者理解代码的工作原理,或者用于记录代码的某些特定功能或限制。注释通常还可以分为单行注释和多行注释。
Makefile中以”#”开始的行是注释行,这和Linux的Shell脚本一样。 Makefile中只有单行注释,也可以使用续行(“\”)来进行多行注释。如果要在Makefile中使用”#”字符,可以用“\”进行转义,如: \#。
命令行中的注释会被传递到shell,就像任何其他文本一样,由shell决定如何解释它,即是否是注释由shell决定。
例如:
# This is a comment
hello: hello.c
gcc -o $@ lt; # This is a comment at \
the end of the line
一个综合的例子
最后,我们利用上面学习的内容来写一个综合的例子。如下的工程要编译server和client可执行程序, 它们的依赖分别是:
server: server.c server_priv.c server_access.c libpriv.so libprotocol.so
client: client.c client_api.c client_mem.c libprotocol.so
整个工程的内容如下:
[root:~/work/v1/makefile/server-client]# ls
client_api.c client_mem.c makefile protocol.c server.c
client.c debug.mk priv.c server_access.c server_priv.c
[root:~/work/v1/makefile/server-client]#
那这个工程的makefile该如何写呢?
我们给出makefile的内容:
# A comprehensive makefile example
include debug.mk
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
server_LIBS_SO = $(server_LIBS:%=lib%.so)
.PHONY: all
all: $(server_LIBS_SO) $(PROGRAMS)
define PROGRAM_template =
$(1): $($(1)_OBJS) $($(1)_LIBS:%=-l%)
ALL_OBJS += $($(1)_OBJS)
endef
define LIBS_template =
lib$(1).so: $(1).c
$(CC) $(CFLAGS) -c -fPIC -shared -o $@ $<
ALL_OBJS += lib$(1).so
endef
# 编译所有的so文件: libpriv.so libprotocol.so
$(foreach lib,$(server_LIBS),$(eval $(call LIBS_template,$(lib))))
# 定义 server and client 的依赖
# server: server.o server_priv.o server_access.o -lpriv -lprotocol
# client: client.o client_api.o client_mem.o -lprotocol
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
# Build server, client executables
$(PROGRAMS):
$(CC) $(CFLAGS) $^ $(LDLIBS) -o $@
clean:
$(RM) $(ALL_OBJS) $(PROGRAMS)
debug.mk的内容如下, 如果定义了DEBUG,则编译debug版本的工程,否则编译release版本的工程。
# debug.mk
ifneq ($(MAKECMDGOALS),clean)
ifdef DEBUG
$(info To build debug version)
CFLAGS += -g
else
$(info To build release version)
endif
endif
编译整个工程:
[root:~/work/v1/makefile/server-client]# make DEBUG=1
To build debug version
cc -g -c -fPIC -shared -o libpriv.so priv.c
cc -g -c -fPIC -shared -o libprotocol.so protocol.c
cc -g -c -o server.o server.c
cc -g -c -o server_priv.o server_priv.c
cc -g -c -o server_access.o server_access.c
cc -g server.o server_priv.o server_access.o libpriv.so libprotocol.so -o server
cc -g -c -o client.o client.c
cc -g -c -o client_api.o client_api.c
cc -g -c -o client_mem.o client_mem.c
cc -g client.o client_api.o client_mem.o libprotocol.so -o client
[root:~/work/v1/makefile/server-client]#
本文暂时没有评论,来添加一个吧(●'◡'●)