专业的编程技术博客社区

网站首页 > 博客文章 正文

[工具]Makefile文件里面都有什么?

baijin 2024-08-08 23:01:02 博客文章 17 ℃ 0 评论

Makefile中主要包含如下5类内容:

  1. 显式规则(Explicit Rules)
  2. 隐式规则(Implicit Rules)
  3. 变量定义(Variable Definitions)
  4. 指示指令(Directives)
  5. 注释(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]#

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表