material/program/tool/makefile.md
rangersly 216e47571b FIX: lib makefile
FIX: c-cpp lib
    FIX: makefile delete
2025-05-04 10:16:10 +08:00

8.9 KiB
Raw Blame History

make

目录


参数

  • -n 参数可以打印出make会执行的命令但不真正执行
  • -f <filename> 指定makefile
  • -i 忽略错误
  • -k 在某个目标失败时,尽量构建其他
  • -s 静默
  • -j4 4线程
  • -C /dir 进入指定目录再运行
  • -d debug
  • -w 打印工作目录
  • -B 强制重新构建

makefile

Makefile 是一种用于自动化构建和管理项目的工具,尤其在 C/C++ 项目中广泛使用。除了基本的规则和依赖关系Makefile 还支持一些高级语法和功能,可以帮助你编写更灵活和高效的构建脚本

规则:依赖
	命令
__注意: 命令前面必须要用Tab__
  • 普通变量定义 OPTION = -O3 -Wall

  • 变量使用 g++ $(OPTION) xxx


变量和赋值

  • =:递归展开变量,变量值在使用时展开。
  • :=:简单展开变量,变量值在定义时展开。
  • ?=:条件赋值,只有当变量未定义时才赋值。
  • +=:追加赋值,将值追加到变量末尾。

自动变量

  • $@:目标文件名。
  • $<:第一个依赖文件名。
  • $^:所有依赖文件列表。
  • $?:所有比目标新的依赖文件列表。
  • $*:目标文件的主干名(不包含扩展名)。
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

函数

Makefile 提供了一些内置函数,用于处理字符串、文件名等。

  • $(wildcard pattern):匹配文件名模式。
  • $(patsubst pattern,replacement,text):模式替换。
  • $(shell command):执行 shell 命令并返回结果。
  • $(foreach var,list,text):循环遍历列表。
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))

条件判断

  • Makefile 条件判断,可以根据条件执行不同的操作。
ifeq ($(DEBUG),1)
	CFLAGS += -DDEBUG
else
	CFLAGS += -DNDEBUG
endif
  • if 函数可以用于条件判断。
DEBUG = 1

CFLAGS += $(if $(DEBUG),-g,-O2)
  • orand 函数可以用于逻辑操作。
ifeq ($(DEBUG),1)
	CFLAGS += -g
else ifeq ($(OPTIMIZE),1)
	CFLAGS += -O2
endif
  • not 函数可以用于取反操作。
ifneq ($(DEBUG),1)
	CFLAGS += -O2
endif

include

你可以使用 include 指令将其他 Makefile 包含到当前 Makefile 中。

include config.mk
  • 你可以在 Makefile 中调用另一个 Makefile通常用于构建子目录中的项目。
SUBDIRS = dir1 dir2

$(SUBDIRS):
	$(MAKE) -C $@

all: $(SUBDIRS)

多目标规则

  • 你可以为一个规则定义多个目标,这样它们可以共享相同的命令。
all: target1 target2

target1 target2:
	@echo Building $@

伪目标

伪目标是指那些不对应实际文件的目标,通常用于执行一些操作,如清理、安装等。

.PHONY: clean

clean:
	rm -f *.o

自定义函数

  • 你可以通过 defineendef 定义自定义函数。
define greet
	@echo "Hello, $(1)!"
endef

all:
	$(call greet,World)
  • call 函数可以调用自定义函数,并传递参数。
define greet
	@echo "Hello, $(1)!"
endef

all:
	$(call greet,World)

错误处理

你可以使用 $(error text)$(warning text) 来生成错误或警告信息。

$(error CC is not set)
$(info Building target $(TARGET))
$(warning This is a warning message)

环境变量

Makefile 可以访问环境变量,并且可以通过 export 将变量传递给子 Makefile。

export PATH := $(PATH):/usr/local/bin

多行命令

你可以使用反斜杠 \ 将长命令分成多行。

all:
	@echo "This is a long command that spans \
	multiple lines."

命令前缀

命令前缀可以控制命令的执行方式:

  • @:不显示命令本身,只显示输出。
  • -:忽略命令的错误,继续执行。
all:
	@echo "This command will not be displayed"
	-rm -f non_existent_file

文件搜索路径

你可以使用 VPATHvpath 来指定源文件的搜索路径。

VPATH = src:include

vpath %.c src
vpath %.h include

静态模式规则

静态模式规则允许你为特定目标定义规则。

objects = foo.o bar.o

$(objects): %.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

自定义后缀规则

你可以定义自定义的后缀规则来处理特定类型的文件。

.SUFFIXES: .cpp .o

.cpp.o:
	$(CXX) $(CXXFLAGS) -c $< -o $@

动态生成规则

eval 函数可以动态生成 Makefile 规则。

define MAKE_RULE
$(1): $(2)
	$(CC) $(CFLAGS) -c $$< -o $$@
endef

$(eval $(call MAKE_RULE,foo.o,foo.c))

使用循环

foreach 函数可以用于循环处理列表中的每个元素。

DIRS = dir1 dir2 dir3

all:
	$(foreach dir,$(DIRS),$(MAKE) -C $(dir);)

执行外部命令

shell 函数可以执行外部命令并返回结果。

DATE := $(shell date)

32. 使用 filterfilter-out 过滤列表

filterfilter-out 函数可以用于过滤列表。

SRCS = foo.c bar.c baz.c

C_SRCS = $(filter %.c,$(SRCS))
NON_C_SRCS = $(filter-out %.c,$(SRCS))

33. 使用 sort 排序列表

sort 函数可以用于排序列表。

SRCS = foo.c bar.c baz.c

SORTED_SRCS = $(sort $(SRCS))

34. 使用 strip 去除空格

strip 函数可以用于去除字符串中的空格。

STR =   foo bar

STRIPED_STR = $(strip $(STR))

35. 使用 findstring 查找子字符串

findstring 函数可以用于查找子字符串。

ifeq ($(findstring foo,$(STR)),foo)
	@echo "Found foo"
endif

36. 使用 subst 替换字符串

subst 函数可以用于替换字符串。

STR = foo bar baz

NEW_STR = $(subst foo,FOO,$(STR))

37. 使用 patsubst 模式替换

patsubst 函数可以用于模式替换。

SRCS = foo.c bar.c baz.c

OBJS = $(patsubst %.c,%.o,$(SRCS))

38. 使用 wildcard 匹配文件名

wildcard 函数可以用于匹配文件名。

SRCS = $(wildcard *.c)

39. 使用 dirnotdir 获取目录和文件名

dirnotdir 函数可以用于获取目录和文件名。

FILE = /path/to/file.c

DIR = $(dir $(FILE))
NAME = $(notdir $(FILE))

40. 使用 suffixbasename 获取后缀和主干名

suffixbasename 函数可以用于获取文件的后缀和主干名。

FILE = file.c

SUFFIX = $(suffix $(FILE))
BASENAME = $(basename $(FILE))

41. 使用 addsuffixaddprefix 添加后缀和前缀

addsuffixaddprefix 函数可以用于添加后缀和前缀。

FILES = foo bar baz

FILES_WITH_SUFFIX = $(addsuffix .c,$(FILES))
FILES_WITH_PREFIX = $(addprefix src/,$(FILES))

42. 使用 join 连接列表

join 函数可以用于连接两个列表。

LIST1 = foo bar
LIST2 = baz qux

JOINED_LIST = $(join $(LIST1),$(LIST2))

43. 使用 wordwordlist 获取列表中的元素

wordwordlist 函数可以用于获取列表中的元素。

LIST = foo bar baz

FIRST = $(word 1,$(LIST))
SUBLIST = $(wordlist 2,3,$(LIST))

44. 使用 words 获取列表长度

words 函数可以用于获取列表的长度。

LIST = foo bar baz

LENGTH = $(words $(LIST))

45. 使用 firstword 获取列表的第一个元素

firstword 函数可以用于获取列表的第一个元素。

LIST = foo bar baz

FIRST = $(firstword $(LIST))

46. 使用 lastword 获取列表的最后一个元素

lastword 函数可以用于获取列表的最后一个元素。

LIST = foo bar baz

LAST = $(lastword $(LIST))

47. 使用 abspath 获取绝对路径

abspath 函数可以用于获取绝对路径。

FILE = file.c

ABS_PATH = $(abspath $(FILE))

48. 使用 realpath 获取规范化的绝对路径

realpath 函数可以用于获取规范化的绝对路径。

FILE = ../file.c

REAL_PATH = $(realpath $(FILE))