赞
踩
目录
1、"="是最普通的等号,在Makefile中容易搞错赋值等号,使用 “=”进行赋值,变量的值是整个Makefile中最后被指定的值。
3、“?=” 表示如果该变量没有被赋值,赋值予等号后面的值。
4、"+="和平时写代码的理解是一样的,表示将符号后面的值添加到前面的变量上
8.@$(foreach var, list, text):遍历列表,并将每个元素替换为指定的文本
9.@$(if condition, text-if-true, text-if-false):根据条件选择输出指定的文本
10.@$(wildcard pattern):匹配指定模式的文件列表
2.指定库文件路径:上面指定头文件类似只不过使用的是"-L"来指定
- 目标...:依赖...
- TAB + 命令1
- 命令2
- 命令3
- ...
- $^ 表示所有的依赖文件
- $@ 表示生成的目标文件
- $< 代表第一个依赖文件
- //例1
- SRC = $(wildcard *.c)
- OBJ = $(patsubst %.c, %.o, $(SRC))
-
- ALL: hello.out
-
- hello.out: $(OBJ)
- gcc $< -o $@
-
- $(OBJ): $(SRC)
- gcc -c $< -o $@
- //其中$@表示的是生成对应的目标文件
-
-
- //例2
- objs = ${main.o fun0.o fun1.o fun2.o fun3.o}
- main:${objs}
- gcc -o main ${objs}
- %.o:%.c
- gcc -c $<
- clear:
- rm *.o
-
- //注意:
- //gcc -c $< -o $@ 和 gcc -c $< 是编译源文件为目标文件的两种常用方式,它们之间有以下区别:
- //gcc -c $< -o $@
- //这个命令将会编译指定的源文件($<)并生成对应的目标文件($@)。
- //使用 -o 选项可以指定输出的目标文件名。例如,如果源文件为 example.c,则生成的目标文件为 example.o。
- //gcc -c $<
- //这个命令将会编译指定的源文件,并使用默认的命名规则生成目标文件。默认情况下,GCC 会根据源文件的名称生成目标文件,将源文件的扩展名 .c 替换为 .o。
- //例如,如果源文件为 example.c,则生成的目标文件为 example.o。
- //总的来说,前者允许你显式地指定输出的目标文件名,而后者则使用默认的命名规则生成目标文件。
- //选择哪种方式取决于你的需求和习惯。如果你想要手动指定目标文件名,可以使用 gcc -c $< -o $@,如果对生成的目标文件名没有特殊要求,可以简化为 gcc -c $<。
- VIR_A = A
- VIR_B = $(VIR_A) B
- VIR_A = AA
- //经过上面的赋值后,最后VIR_B的值是AA B,而不是A B,在make时,会把整个Makefile展开,来决定变量的值
- VIR_A := A
- VIR_B := $(VIR_A) B
- VIR_A := AA
- //最后BIR_B的值是A B,即根据当前位置进行赋值。因此相当于“=”,“:=”才是真正意义上的直接赋值
- VIR ?= new_value
- //如果VIR在之前没有被赋值,那么VIR的值就为new_value。
- VIR := old_value
- VIR ?= new_value
- //这种情况下,VIR的值就是old_value
下面是常用的GNU Make函数的格式、功能和例子:
- 下面是常用的GNU Make函数的格式、功能和例子:
-
- wildcard函数:
- 格式:$(wildcard pattern)
- 功能:匹配文件名模式,返回匹配的文件列表。
- 例子:$(wildcard *.c)会返回当前目录下所有以.c为后缀的文件列表。
-
- patsubst函数:
- 格式:$(patsubst pattern,replacement,text)
- 功能:模式替换函数,根据模式匹配替换文本中的字符串。
- 例子:$(patsubst %.c,%.o,$(SRC))将变量$(SRC)中的每个以.c为后缀的文件名替换为以.o为后缀的文件名。
-
- subst函数:
- 格式:$(subst from,to,text)
- 功能:字符串替换函数,将文本中的字符串进行替换。
- 例子:$(subst old,new,$(VAR))将变量$(VAR)中的old替换为new。
-
- strip函数:
- 格式:$(strip string)
- 功能:去除字符串两端的空格。
- 例子:$(strip $(VAR))会去除变量$(VAR)两端的空格。
-
- shell函数:
- 格式:$(shell command)
- 功能:执行Shell命令,并返回其输出结果。
- 例子:$(shell echo "Hello, world!")会执行echo "Hello, world!"命令并返回结果。
-
- foreach函数:
- 格式:$(foreach var,list,text)
- 功能:遍历列表,对每个元素执行一系列操作。
- 例子:$(foreach file,$(FILES),$(shell chmod +x $(file)))会将变量$(FILES)中的每个文件赋值给变量file,并将其设置为可执行文件。
-
- if函数:
- 格式:$(if condition,true-part,false-part)
- 功能:条件判断函数,根据条件的真假返回不同的值。
- 例子:$(if $(strip $(VAR)),yes,no)根据变量$(VAR)是否为空格返回yes或no。
-
- notdir函数:
- 格式:$(notdir names...)
- 功能:获取路径中的文件名部分。
- 例子:$(notdir $(SRC))会返回变量$(SRC)中所有文件名的基本部分。
-
- dir函数:
- 格式:$(dir names...)
- 功能:获取路径中的目录部分。
- 例子:$(dir $(SRC))会返回变量$(SRC)中所有文件名所在的目录。
-
- basename函数:
- 格式:$(basename names...)
- 功能:获取文件名中的基本部分(除去后缀)。
- 例子:$(basename $(notdir $(SRC)))会返回变量$(SRC)中所有文件名的基本部分(除去后缀)。
- 使用示例:
- SRC = $(wildcard *.c)
- OBJ = $(patsubst %.c, %.o, $(SRC))
-
- ALL: hello.out
-
- hello.out: $(OBJ)
- gcc $< -o $@
-
- $(OBJ): $(SRC)
- gcc -c $< -o $@
-
- clean:
- rm -rf $(OBJ) hello.out
-
- .PHONY: clean ALL
- 作用:声明clean和ALL为伪目标,确保它们不与同名文件冲突
@echo "Hello, World!"
@mkdir -p build
- @rm -f file.txt
- @rm -rf build/
@cp source.txt destination.txt
@mv old.txt new.txt
@cd path/to/directory && make
- DATE := $(shell date +%Y-%m-%d)
- @echo "Today's date is $(DATE)"
- FILES := file1.txt file2.txt file3.txt
- TARGETS := $(foreach file, $(FILES), build/$(file))
-
- $(TARGETS): build/%.txt: %.txt
- @cp $< $@
- DEBUG := true
-
- ifeq ($(DEBUG), true)
- MESSAGE := "Debug mode"
- else
- MESSAGE := "Release mode"
- endif
-
- @echo $(MESSAGE)
- SOURCES := $(wildcard src/*.c)
- OBJS := $(patsubst src/%.c, build/%.o, $(SOURCES))
-
- $(OBJS): build/%.o: src/%.c
- @$(CC) $(CFLAGS) -c $< -o $@
用于编译、链接和执行程序,以及清理生成的目标文件常见的Makefile命令。
- 1.all:默认目标,编译并生成可执行文件。
- 2.clean:清理目标文件和可执行文件。
- 3.$(CC):编译器命令,默认为gcc。
- 4.$(CFLAGS):编译选项。
- 5.$(LDFLAGS):链接选项。
- 6.$(TARGET):生成的可执行文件名称。
- 7.$(OBJS):目标文件列表。
- 8.$(SRCS):源文件列表。
部分简单示例:
- # 编译器设置
- CC = gcc
- CFLAGS = -Wall -g
-
- # 目标文件和源文件列表
- OBJS = main.o foo.o bar.o
- SRCS = main.c foo.c bar.c
-
- # 默认目标
- all: $(OBJS)
- $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS)
-
- # 清理目标文件和可执行文件
- clean:
- rm -f $(OBJS) $(TARGET)
-
- # 生成目标文件
- %.o: %.c
- $(CC) $(CFLAGS) -c $< -o $@
在一些大工程中,会把不同模块或不同功能的源文件放在不同的目录中,我们可以在每个目录中都写一个该目录的Makefile这有利于让我们的Makefile变的更加简洁,不至于把所有东西全部写在一个Makefile中。列如在子目录subdir目录下有个Makefile文件,来指明这个目录下文件的编译规则。外部总Makefile可以这样写:
- subsystem:
- cd subdir && $(MAKE)
- 其等价于:
- subsystem:
- $(MAKE) -C subdir
定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较有利于维护。两个例子意思都是先进入"subdir"目录,然后执行make命令。
我们把这个Makefile叫做总控Makefile,总控Makefile的变量可以传递到下级的Makefile中,但是不会覆盖下层Makefile中所定义的变量,除非指定了 "-e"参数。
如果传递变量到下级Makefile中,那么可以使用这样的声明:export
- export variable = value
- 等价于
- variable = value
- export variable
- 等价于
- export variable := value
- 等价于
- variable := value
- export variable
- //如果需要传递所有变量,那么只要一个export就行了。后面什么也不用跟,表示传递所有变量
- //如果不想让某些变量传递到下级Makefile,可以使用:unexport
- //假设头文件在:
- /home/develop/include
- //则可以通过-I指定:
- -I/home/develop/include
- //将该目录添加到头文件搜索路径中在Makefile中则可以这样写:
- CFLAGS=-I/home/develop/include
- //在编译的时候,引用CFLAGS即可:
- yourapp:*.c
- gcc $(CFLAGS) -o yourapp
- LDFLAGS=-L/usr/lib -L/path/to/your/lib
- //告诉链接器要链接哪些库文件,使用"-l"(小写L)如下:
- LIBS = -lpthread -liconv
目录结构
include
myinclude.h
- #include <stdio.h>
- void print1() ;
- void print2() ;
f1
f1.c
- #include "../include/myinclude.h"
-
- void print1()
- {
- printf("Message f1.c\n");
- return;
- }
Makefile
目标前面的路径,意思是将目标生成到指定的目录下
- ../$(OBJS_DIR)/f1.o:f1.c
- @$(CC) -c $^ -o $@
f2
f2.c
- #include "../include/myinclude.h"
-
- void print2()
- {
- printf("Message f2.c\n");
- return;
- }
Makefile
- ../$(OBJS_DIR)/f2.o:f2.c
- @$(CC) -c $^ -o $@
main
main.c
- #include "../include/myinclude.h"
-
- int main(int argc, char const *argv[])
- {
- print1();
- print2();
- return 0;
- }
Makefile
- ../$(OBJS_DIR)/main.o:main.c
- @$(CC) -c $^ -o $@
obj
此目录用来存放相关生成的目标文件
Makefile
- ../$(BIN_DIR)/$(BIN) : $(OBJS)
- @$(CC) $^ -o $@
主Makefile
- #预定义变量
- CC = gcc
- #预定义编译目录
- SUBDIRS = f1 \
- f2 \
- main \
- obj
- #预定义目标
- OBJS = f1.o f2.o main.o
- BIN = myapp
- OBJS_DIR = obj
- BIN_DIR = bin
- #传递预定义参数
- export CC OBJS BIN OBJS_DIR BIN_DIR
-
- all:CHECK_DIR $(SUBDIRS)
- CHECK_DIR:
- @mkdir -p $(BIN_DIR)
- $(SUBDIRS):ECHO
- @make -C $@
-
- ECHO:
- @echo $(SUBDIRS)
- @echo begin compile
- clean:
- @$(RM) $(OBJS_DIR)/*.o
- @rm -rf $(BIN_DIR)
bin
此文件用来存放生成的二进制文件
- 如 notdir, subst, strip, wildcard(准确地说这个不属于次列)等,
- 需要注意的一点是:makefile中字符串的表示和Shell有很大不同。
- 比如 am := xy abc 相当于shell中的 am="xy abc"。
- 变量的表示也不一样,在Makfile中 "$(am)" 和
- shell中 "$am"或者"${am}"是一个意思!!不要忽略这个。
- 比如 "%.o:%.c",意思是说,xxx.o 需要xxx.c,
- 注意,如果他们不在一个路径下,记得改为"%.o:$(path)%.c",
- 这样才能找到.c代码。
- 换句话说,"%"匹配的是这个文件的名字,并不包括路径!
- $@ : 规则中的目标文件
- $< : 规则中的第一个依赖文件名
- $^ : 规则中的所有依赖文件列表,以空格分隔
-
- 注意:这些自动化变量是和上下文环境相关联的。
- 在依赖对应的命令中,可以用"@"来表示该条命令本身不输出,仅输出结果;
- 用"-"来表示该命令执行如果不成功也继续执行!
- 需要注意的一点是:它们都只能用在一个命令的开头。
- 例如:-rm rf *.o
- 可以在make时加上参数:如 make -n –just-print等。
- 或者在makefile文件中加入 $(warning xxxx) ,
- 这个语句可以加到变量前,make过程中就会输出!
- cc -c main.c 和 cc -o main.c 是两个不同的编译命令,具有不同的作用和效果。
-
- cc -c main.c:这个命令表示将 C 语言源代码文件 main.c 编译为目标文件(Object File),
- 而不进行链接操作。
- 目标文件是二进制形式的机器码,包含了编译后的代码和数据,但没有进行最终的链接操作。
- 目标文件通常用于后续的链接步骤,将多个目标文件合并成一个可执行程序。
-
- cc -o main.c:这个命令表示将 C 语言源代码文件 main.c 编译为可执行程序,并将其命名为 main.c。
- -o 是 cc 命令的一个选项,用于指定输出文件的名称。
- 在这种情况下,main.c 文件不仅进行了编译,还进行了链接操作,
- 最终生成一个名为 main.c 的可执行程序文件。
-
- 因此,两者的区别在于 -c 选项只进行编译操作,生成目标文件;
- 而 -o 选项除了编译操作外,还进行链接操作,生成最终的可执行程序文件。
- 每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,
- 这不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”。
-
- 一般的风格都是:
- clean:
-
- rm edit $(objects)
-
- 更为稳健的做法是:
- .PHONY : clean
-
- clean :
-
- -rm edit $(objects)
-
- 前面说过,.PHONY意思表示clean是一个“伪目标”。
- 而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。
- 当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。
- 不成文的规矩是——“clean从来都是放在文件的最后”。
万能Makefile
- ####################################################
- # Generic makefile - 万能Makefile
- # for compiling and linking C++ projects on Linux
- # Author: George Foot Modified:Jackie Lee
- ####################################################
- ### Customising
- #
- # Adjust the following if necessary; EXECUTABLE is the target
- # executable's filename, and LIBS is a list of libraries to link in
- # (e.g. alleg, stdcx, iostr, etc). You can override these on make's
- # command line of course, if you prefer to do it that way.
- #
- #
- EXECUTABLE := main # 可执行文件名
- LIBDIR:= # 静态库目录
- LIBS := # 静 态 库 文 件 名
- INCLUDES:=. # 头文件目录
- SRCDIR:= # 除了当前目录外,其他的源代码文件目录
- #
- # # Now alter any implicit rules' variables if you like, e.g.:
-
- CC:=g++
- CFLAGS := -g -Wall -O3
- CPPFLAGS := $(CFLAGS)
- CPPFLAGS += $(addprefix -I,$(INCLUDES))
- CPPFLAGS += -MMD
- #
- # # The next bit checks to see whether rm is in your djgpp bin
- # # directory; if not it uses del instead, but this can cause (harmless)
- # # `File not found' error messages. If you are not using DOS at all,
- # # set the variable to something which will unquestioningly remove
- # # files.
- #
-
- RM-F := rm -f
-
- # # You shouldn't need to change anything below this point.
- #
- SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
- OBJS := $(patsubst %.cpp,%.o,$(SRCS))
- DEPS := $(patsubst %.o,%.d,$(OBJS))
- MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
- MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))
-
- .PHONY : all deps objs clean veryclean rebuild info
-
- all: $(EXECUTABLE)
-
- deps : $(DEPS)
-
- objs : $(OBJS)
-
- clean :
- @$(RM-F) *.o
- @$(RM-F) *.d
- veryclean: clean
- @$(RM-F) $(EXECUTABLE)
-
- rebuild: veryclean all
- ifneq ($(MISSING_DEPS),)
- $(MISSING_DEPS) :
- @$(RM-F) $(patsubst %.d,%.o,$@)
- endif
- -include $(DEPS)
- $(EXECUTABLE) : $(OBJS)
- $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))
-
- info:
- @echo $(SRCS)
- @echo $(OBJS)
- @echo $(DEPS)
- @echo $(MISSING_DEPS)
- @echo $(MISSING_DEPS_SOURCES)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。