当前位置:   article > 正文

学习Makefile从头开始学之超详细知识点+例子及细节总结+附万能makefile_makefile设置头文件路径

makefile设置头文件路径

目录

1.makefile 之语法规则

2.makefile 之变量

3.makefile 之变量赋值

1、"="是最普通的等号,在Makefile中容易搞错赋值等号,使用 “=”进行赋值,变量的值是整个Makefile中最后被指定的值。

2、“:=” 表示直接赋值,赋予当前位置的值。

3、“?=” 表示如果该变量没有被赋值,赋值予等号后面的值。

4、"+="和平时写代码的理解是一样的,表示将符号后面的值添加到前面的变量上

4.makefile 之函数

5.makefile 之伪目标.PHONY

6.makefile 之常用命令

1.@echo:输出指定的文本到终端

2.@mkdir:创建目录

3.@rm:删除文件或目录

4.@cp:复制文件

5.@mv:移动文件

6.@cd:改变当前工作目录

7.@$(shell command):执行shell命令

8.@$(foreach var, list, text):遍历列表,并将每个元素替换为指定的文本

9.@$(if condition, text-if-true, text-if-false):根据条件选择输出指定的文本

10.@$(wildcard pattern):匹配指定模式的文件列表

补充说明:

7.Makefile 之嵌套执行

8.Makefile 之指定路径

1.指定头文件路径:一般都是通过"-I"(大写i)来指定

2.指定库文件路径:上面指定头文件类似只不过使用的是"-L"来指定

9.Makefile 之简单示例

10.细节巩固

1.【字符串处理函数】

2.【规则中的”%”】

3.【自动化变量】

4.【”@” 和 “-” 】

5.【调试】

6.【"-c"和"-o"】

7.【清空目标文件的规则】

11.附录:gcc 命令的常用选项及万能makefile


1.makefile 之语法规则

  1. 目标...:依赖...
  2. TAB + 命令1
  3. 命令2
  4. 命令3
  5. ...

2.makefile 之变量

  1. $^ 表示所有的依赖文件
  2. $@ 表示生成的目标文件
  3. $< 代表第一个依赖文件
  1. //1
  2. SRC = $(wildcard *.c)
  3. OBJ = $(patsubst %.c, %.o, $(SRC))
  4. ALL: hello.out
  5. hello.out: $(OBJ)
  6. gcc $< -o $@
  7. $(OBJ): $(SRC)
  8. gcc -c $< -o $@
  9. //其中$@表示的是生成对应的目标文件
  10. //2
  11. objs = ${main.o fun0.o fun1.o fun2.o fun3.o}
  12. main:${objs}
  13. gcc -o main ${objs}
  14. %.o:%.c
  15. gcc -c $<
  16. clear:
  17. rm *.o
  18. //注意:
  19. //gcc -c $< -o $@ 和 gcc -c $< 是编译源文件为目标文件的两种常用方式,它们之间有以下区别:
  20. //gcc -c $< -o $@
  21. //这个命令将会编译指定的源文件($<)并生成对应的目标文件($@)。
  22. //使用 -o 选项可以指定输出的目标文件名。例如,如果源文件为 example.c,则生成的目标文件为 example.o。
  23. //gcc -c $<
  24. //这个命令将会编译指定的源文件,并使用默认的命名规则生成目标文件。默认情况下,GCC 会根据源文件的名称生成目标文件,将源文件的扩展名 .c 替换为 .o。
  25. //例如,如果源文件为 example.c,则生成的目标文件为 example.o。
  26. //总的来说,前者允许你显式地指定输出的目标文件名,而后者则使用默认的命名规则生成目标文件。
  27. //选择哪种方式取决于你的需求和习惯。如果你想要手动指定目标文件名,可以使用 gcc -c $< -o $@,如果对生成的目标文件名没有特殊要求,可以简化为 gcc -c $<

3.makefile 之变量赋值

1、"="是最普通的等号,在Makefile中容易搞错赋值等号,使用 “=”进行赋值,变量的值是整个Makefile中最后被指定的值。

  1. VIR_A = A
  2. VIR_B = $(VIR_A) B
  3. VIR_A = AA
  4. //经过上面的赋值后,最后VIR_B的值是AA B,而不是A B,在make时,会把整个Makefile展开,来决定变量的值

2、“:=” 表示直接赋值,赋予当前位置的值。

  1. VIR_A := A
  2. VIR_B := $(VIR_A) B
  3. VIR_A := AA
  4. //最后BIR_B的值是A B,即根据当前位置进行赋值。因此相当于“=”,“:=”才是真正意义上的直接赋值

3、“?=” 表示如果该变量没有被赋值,赋值予等号后面的值。

  1. VIR ?= new_value
  2. //如果VIR在之前没有被赋值,那么VIR的值就为new_value
  3. VIR := old_value
  4. VIR ?= new_value
  5. //这种情况下,VIR的值就是old_value

4、"+="和平时写代码的理解是一样的,表示将符号后面的值添加到前面的变量上

4.makefile 之函数

下面是常用的GNU Make函数的格式、功能和例子:

  1. 下面是常用的GNU Make函数的格式、功能和例子:
  2. wildcard函数:
  3. 格式:$(wildcard pattern)
  4. 功能:匹配文件名模式,返回匹配的文件列表。
  5. 例子:$(wildcard *.c)会返回当前目录下所有以.c为后缀的文件列表。
  6. patsubst函数:
  7. 格式:$(patsubst pattern,replacement,text)
  8. 功能:模式替换函数,根据模式匹配替换文本中的字符串。
  9. 例子:$(patsubst %.c,%.o,$(SRC))将变量$(SRC)中的每个以.c为后缀的文件名替换为以.o为后缀的文件名。
  10. subst函数:
  11. 格式:$(subst from,to,text)
  12. 功能:字符串替换函数,将文本中的字符串进行替换。
  13. 例子:$(subst old,new,$(VAR))将变量$(VAR)中的old替换为new
  14. strip函数:
  15. 格式:$(strip string)
  16. 功能:去除字符串两端的空格。
  17. 例子:$(strip $(VAR))会去除变量$(VAR)两端的空格。
  18. shell函数:
  19. 格式:$(shell command)
  20. 功能:执行Shell命令,并返回其输出结果。
  21. 例子:$(shell echo "Hello, world!")会执行echo "Hello, world!"命令并返回结果。
  22. foreach函数:
  23. 格式:$(foreach var,list,text)
  24. 功能:遍历列表,对每个元素执行一系列操作。
  25. 例子:$(foreach file,$(FILES),$(shell chmod +x $(file)))会将变量$(FILES)中的每个文件赋值给变量file,并将其设置为可执行文件。
  26. if函数:
  27. 格式:$(if condition,true-part,false-part)
  28. 功能:条件判断函数,根据条件的真假返回不同的值。
  29. 例子:$(if $(strip $(VAR)),yes,no)根据变量$(VAR)是否为空格返回yes或no。
  30. notdir函数:
  31. 格式:$(notdir names...)
  32. 功能:获取路径中的文件名部分。
  33. 例子:$(notdir $(SRC))会返回变量$(SRC)中所有文件名的基本部分。
  34. dir函数:
  35. 格式:$(dir names...)
  36. 功能:获取路径中的目录部分。
  37. 例子:$(dir $(SRC))会返回变量$(SRC)中所有文件名所在的目录。
  38. basename函数:
  39. 格式:$(basename names...)
  40. 功能:获取文件名中的基本部分(除去后缀)。
  41. 例子:$(basename $(notdir $(SRC)))会返回变量$(SRC)中所有文件名的基本部分(除去后缀)。

5.makefile 之伪目标.PHONY

  1. 使用示例:
  2. SRC = $(wildcard *.c)
  3. OBJ = $(patsubst %.c, %.o, $(SRC))
  4. ALL: hello.out
  5. hello.out: $(OBJ)
  6. gcc $< -o $@
  7. $(OBJ): $(SRC)
  8. gcc -c $< -o $@
  9. clean:
  10. rm -rf $(OBJ) hello.out
  11. .PHONY: clean ALL
  12. 作用:声明clean和ALL为伪目标,确保它们不与同名文件冲突

6.makefile 之常用命令

1.@echo:输出指定的文本到终端

@echo "Hello, World!"

2.@mkdir:创建目录

@mkdir -p build

3.@rm:删除文件或目录

  1. @rm -f file.txt
  2. @rm -rf build/

4.@cp:复制文件

@cp source.txt destination.txt

5.@mv:移动文件

@mv old.txt new.txt

6.@cd:改变当前工作目录

@cd path/to/directory && make

7.@$(shell command):执行shell命令

  1. DATE := $(shell date +%Y-%m-%d)
  2. @echo "Today's date is $(DATE)"

8.@$(foreach var, list, text):遍历列表,并将每个元素替换为指定的文本

  1. FILES := file1.txt file2.txt file3.txt
  2. TARGETS := $(foreach file, $(FILES), build/$(file))
  3. $(TARGETS): build/%.txt: %.txt
  4. @cp $< $@

9.@$(if condition, text-if-true, text-if-false):根据条件选择输出指定的文本

  1. DEBUG := true
  2. ifeq ($(DEBUG), true)
  3. MESSAGE := "Debug mode"
  4. else
  5. MESSAGE := "Release mode"
  6. endif
  7. @echo $(MESSAGE)

10.@$(wildcard pattern):匹配指定模式的文件列表

  1. SOURCES := $(wildcard src/*.c)
  2. OBJS := $(patsubst src/%.c, build/%.o, $(SOURCES))
  3. $(OBJS): build/%.o: src/%.c
  4. @$(CC) $(CFLAGS) -c $< -o $@

补充说明:

用于编译、链接和执行程序,以及清理生成的目标文件常见的Makefile命令。

  1. 1.all:默认目标,编译并生成可执行文件。
  2. 2.clean:清理目标文件和可执行文件。
  3. 3.$(CC):编译器命令,默认为gcc。
  4. 4.$(CFLAGS):编译选项。
  5. 5.$(LDFLAGS):链接选项。
  6. 6.$(TARGET):生成的可执行文件名称。
  7. 7.$(OBJS):目标文件列表。
  8. 8.$(SRCS):源文件列表。

部分简单示例:

  1. # 编译器设置
  2. CC = gcc
  3. CFLAGS = -Wall -g
  4. # 目标文件和源文件列表
  5. OBJS = main.o foo.o bar.o
  6. SRCS = main.c foo.c bar.c
  7. # 默认目标
  8. all: $(OBJS)
  9. $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS)
  10. # 清理目标文件和可执行文件
  11. clean:
  12. rm -f $(OBJS) $(TARGET)
  13. # 生成目标文件
  14. %.o: %.c
  15. $(CC) $(CFLAGS) -c $< -o $@

7.Makefile 之嵌套执行

  在一些大工程中,会把不同模块或不同功能的源文件放在不同的目录中,我们可以在每个目录中都写一个该目录的Makefile这有利于让我们的Makefile变的更加简洁,不至于把所有东西全部写在一个Makefile中。列如在子目录subdir目录下有个Makefile文件,来指明这个目录下文件的编译规则。外部总Makefile可以这样写:

  1. subsystem:
  2. cd subdir && $(MAKE)
  3. 其等价于:
  4. subsystem:
  5. $(MAKE) -C subdir

  定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较有利于维护。两个例子意思都是先进入"subdir"目录,然后执行make命令。

我们把这个Makefile叫做总控Makefile,总控Makefile的变量可以传递到下级的Makefile中,但是不会覆盖下层Makefile中所定义的变量,除非指定了 "-e"参数。

如果传递变量到下级Makefile中,那么可以使用这样的声明:export

  1. export variable = value
  2. 等价于
  3. variable = value
  4. export variable
  5. 等价于
  6. export variable := value
  7. 等价于
  8. variable := value
  9. export variable
  10. //如果需要传递所有变量,那么只要一个export就行了。后面什么也不用跟,表示传递所有变量
  11. //如果不想让某些变量传递到下级Makefile,可以使用:unexport

8.Makefile 之指定路径

1.指定头文件路径:一般都是通过"-I"(大写i)来指定

  1. //假设头文件在:
  2. /home/develop/include
  3. //则可以通过-I指定:
  4. -I/home/develop/include
  5. //将该目录添加到头文件搜索路径中在Makefile中则可以这样写:
  6. CFLAGS=-I/home/develop/include
  7. //在编译的时候,引用CFLAGS即可:
  8. yourapp:*.c
  9. gcc $(CFLAGS) -o yourapp

2.指定库文件路径:上面指定头文件类似只不过使用的是"-L"来指定

  1. LDFLAGS=-L/usr/lib -L/path/to/your/lib
  2. //告诉链接器要链接哪些库文件,使用"-l"(小写L)如下:
  3. LIBS = -lpthread -liconv

9.Makefile 之简单示例

目录结构

include

myinclude.h

  1. #include <stdio.h>
  2. void print1() ;
  3. void print2() ;

f1

f1.c

  1. #include "../include/myinclude.h"
  2. void print1()
  3. {
  4. printf("Message f1.c\n");
  5. return;
  6. }

Makefile

目标前面的路径,意思是将目标生成到指定的目录下

  1. ../$(OBJS_DIR)/f1.o:f1.c
  2. @$(CC) -c $^ -o $@

f2

f2.c

  1. #include "../include/myinclude.h"
  2. void print2()
  3. {
  4. printf("Message f2.c\n");
  5. return;
  6. }

Makefile

  1. ../$(OBJS_DIR)/f2.o:f2.c
  2. @$(CC) -c $^ -o $@

main

main.c

  1. #include "../include/myinclude.h"
  2. int main(int argc, char const *argv[])
  3. {
  4. print1();
  5. print2();
  6. return 0;
  7. }

Makefile

  1. ../$(OBJS_DIR)/main.o:main.c
  2. @$(CC) -c $^ -o $@

obj

此目录用来存放相关生成的目标文件

Makefile

  1. ../$(BIN_DIR)/$(BIN) : $(OBJS)
  2. @$(CC) $^ -o $@

主Makefile

  1. #预定义变量
  2. CC = gcc
  3. #预定义编译目录
  4. SUBDIRS = f1 \
  5. f2 \
  6. main \
  7. obj
  8. #预定义目标
  9. OBJS = f1.o f2.o main.o
  10. BIN = myapp
  11. OBJS_DIR = obj
  12. BIN_DIR = bin
  13. #传递预定义参数
  14. export CC OBJS BIN OBJS_DIR BIN_DIR
  15. all:CHECK_DIR $(SUBDIRS)
  16. CHECK_DIR:
  17. @mkdir -p $(BIN_DIR)
  18. $(SUBDIRS):ECHO
  19. @make -C $@
  20. ECHO:
  21. @echo $(SUBDIRS)
  22. @echo begin compile
  23. clean:
  24. @$(RM) $(OBJS_DIR)/*.o
  25. @rm -rf $(BIN_DIR)

bin

此文件用来存放生成的二进制文件

10.细节巩固

1.【字符串处理函数】

  1. 如 notdir, subst, strip, wildcard(准确地说这个不属于次列)等,
  2. 需要注意的一点是:makefile中字符串的表示和Shell有很大不同。
  3. 比如 am := xy abc 相当于shell中的 am="xy abc"
  4. 变量的表示也不一样,在Makfile中 "$(am)"
  5. shell中 "$am"或者"${am}"是一个意思!!不要忽略这个。

2.【规则中的”%”】

  1. 比如 "%.o:%.c",意思是说,xxx.o 需要xxx.c,
  2. 注意,如果他们不在一个路径下,记得改为"%.o:$(path)%.c"
  3. 这样才能找到.c代码。
  4. 换句话说,"%"匹配的是这个文件的名字,并不包括路径!

3.【自动化变量】

  1. $@ : 规则中的目标文件
  2. $< : 规则中的第一个依赖文件名
  3. $^ : 规则中的所有依赖文件列表,以空格分隔
  4. 注意:这些自动化变量是和上下文环境相关联的。

4.【”@” 和 “-” 】

  1. 在依赖对应的命令中,可以用"@"来表示该条命令本身不输出,仅输出结果;
  2. "-"来表示该命令执行如果不成功也继续执行!
  3. 需要注意的一点是:它们都只能用在一个命令的开头。
  4. 例如:-rm rf *.o

5.【调试】

  1. 可以在make时加上参数:如 make -n –just-print等。
  2. 或者在makefile文件中加入 $(warning xxxx) ,
  3. 这个语句可以加到变量前,make过程中就会输出!

6.【"-c"和"-o"】

  1. cc -c main.ccc -o main.c 是两个不同的编译命令,具有不同的作用和效果。
  2. cc -c main.c:这个命令表示将 C 语言源代码文件 main.c 编译为目标文件(Object File),
  3. 而不进行链接操作。
  4. 目标文件是二进制形式的机器码,包含了编译后的代码和数据,但没有进行最终的链接操作。
  5. 目标文件通常用于后续的链接步骤,将多个目标文件合并成一个可执行程序。
  6. cc -o main.c:这个命令表示将 C 语言源代码文件 main.c 编译为可执行程序,并将其命名为 main.c
  7. -occ 命令的一个选项,用于指定输出文件的名称。
  8. 在这种情况下,main.c 文件不仅进行了编译,还进行了链接操作,
  9. 最终生成一个名为 main.c 的可执行程序文件。
  10. 因此,两者的区别在于 -c 选项只进行编译操作,生成目标文件;
  11. -o 选项除了编译操作外,还进行链接操作,生成最终的可执行程序文件。

7.【清空目标文件的规则】

  1. 每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,
  2. 这不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”。
  3. 一般的风格都是:
  4. clean:
  5. rm edit $(objects)
  6. 更为稳健的做法是:
  7. .PHONY : clean
  8. clean :
  9. -rm edit $(objects)
  10. 前面说过,.PHONY意思表示clean是一个“伪目标”。
  11. 而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。
  12. 当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。
  13. 不成文的规矩是——“clean从来都是放在文件的最后”。

11.附录:gcc 命令的常用选项及万能makefile

万能Makefile

  1. ####################################################
  2. # Generic makefile - 万能Makefile
  3. # for compiling and linking C++ projects on Linux
  4. # Author: George Foot Modified:Jackie Lee
  5. ####################################################
  6. ### Customising
  7. #
  8. # Adjust the following if necessary; EXECUTABLE is the target
  9. # executable's filename, and LIBS is a list of libraries to link in
  10. # (e.g. alleg, stdcx, iostr, etc). You can override these on make's
  11. # command line of course, if you prefer to do it that way.
  12. #
  13. #
  14. EXECUTABLE := main # 可执行文件名
  15. LIBDIR:= # 静态库目录
  16. LIBS := # 静 态 库 文 件 名
  17. INCLUDES:=. # 头文件目录
  18. SRCDIR:= # 除了当前目录外,其他的源代码文件目录
  19. #
  20. # # Now alter any implicit rules' variables if you like, e.g.:
  21. CC:=g++
  22. CFLAGS := -g -Wall -O3
  23. CPPFLAGS := $(CFLAGS)
  24. CPPFLAGS += $(addprefix -I,$(INCLUDES))
  25. CPPFLAGS += -MMD
  26. #
  27. # # The next bit checks to see whether rm is in your djgpp bin
  28. # # directory; if not it uses del instead, but this can cause (harmless)
  29. # # `File not found' error messages. If you are not using DOS at all,
  30. # # set the variable to something which will unquestioningly remove
  31. # # files.
  32. #
  33. RM-F := rm -f
  34. # # You shouldn't need to change anything below this point.
  35. #
  36. SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
  37. OBJS := $(patsubst %.cpp,%.o,$(SRCS))
  38. DEPS := $(patsubst %.o,%.d,$(OBJS))
  39. MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
  40. MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))
  41. .PHONY : all deps objs clean veryclean rebuild info
  42. all: $(EXECUTABLE)
  43. deps : $(DEPS)
  44. objs : $(OBJS)
  45. clean :
  46. @$(RM-F) *.o
  47. @$(RM-F) *.d
  48. veryclean: clean
  49. @$(RM-F) $(EXECUTABLE)
  50. rebuild: veryclean all
  51. ifneq ($(MISSING_DEPS),)
  52. $(MISSING_DEPS) :
  53. @$(RM-F) $(patsubst %.d,%.o,$@)
  54. endif
  55. -include $(DEPS)
  56. $(EXECUTABLE) : $(OBJS)
  57. $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))
  58. info:
  59. @echo $(SRCS)
  60. @echo $(OBJS)
  61. @echo $(DEPS)
  62. @echo $(MISSING_DEPS)
  63. @echo $(MISSING_DEPS_SOURCES)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/640972
推荐阅读
相关标签
  

闽ICP备14008679号