当前位置:   article > 正文

Linux进阶-Makefile_makefile多个目录下所有文件编译

makefile多个目录下所有文件编译

目录

Makefile

Makefile格式

例程

Makefile变量:系统变量、自定义变量、自动化变量。

Makefile模式匹配

例程改进

Makefile条件分支

Makefile常用函数

patsubst:模式替换函数。pattern:模式,substitute:替换。

notdir:去目录取文件名函数。

wildcard:获取匹配模式文件名函数。

foreach:循环函数

Makefile解决头文件依赖


Makefile

Linux中使用make工具来编译程序(特别是大程序),而make工具所执行的动作依赖于Makefile文件。

当工程复杂度再上一个高度时,会觉得手写Makefile很麻烦时就需要用CMake、autotools等工具生成Makefile,实际上Windows系统下很多IDE工具内部也是使用类似Makefile的方式组织工程文件的,只不过被封装成图形界面,对用户不可见。

make命令根据文件更新的时间戳来决定哪些文件需要重新编译,这使得可以避免编译已经编译过的、没有变化的程序,可以大大提高编译效率。

注意:要想完整地了解Makefile的规则,请参考《GNU Make使用手册》。

Makefile本质:无论多么复杂的语法,都是为了更好地解决项目文件之间的依赖关系。

Makefile格式

Makefile三要素:目标、依赖、命令。 格式如下:

目标:依赖

<tab>命令

目标通常是要生成的文件名称,可以是可执行文件或OBJ文件,也可以是一个执行的动作名称(伪目标,比如clean)。

依赖是用来产生目标的材料(比如源文件),一个目标经常有几个依赖。

命令是生成目标时所执行的动作。一个规则可以含有几个命令,每个命令占一行。 

注意:每个命令行前面必须是一个Tab字符。

命令被执行的条件依赖文件比目标文件新 或 目标文件还没生成

通常,如果一个依赖发生了变化,就需要规则调用命令以更新或创建目标。但是并非所有的目标都有依赖,例如目标clean的作用只是清除文件,并没有依赖。

  1. targeta:targetb targetc
  2. echo "targeta"
  3. targetb:
  4. echo "targetb"
  5. targetc:
  6. echo "targetc"

例程

main.c

  1. #include <stdio.h>
  2. int main()
  3. {
  4. play();
  5. stop();
  6. return 0;
  7. }

mp3.c

  1. #include <stdio.h>
  2. void play()
  3. {
  4. printf("play music!\r\n");
  5. }
  6. void stop()
  7. {
  8. printf("stop music!\r\n");
  9. }

 

Makefile变量:系统变量、自定义变量、自动化变量。

注意:=延迟赋值是指在调用时才会被赋值。 即图中的echo "$(B)"时才把A的值赋给B。

Makefile模式匹配

%:匹配任意多个非空字符,相当于shell的*通配符。

.o文件默认使用.c文件进行编译。

例程改进

学习了Makefile变量,对先前的mp3进行加深。 

Makefile条件分支

  1. ifeq (var1,var2)
  2. ... //如果var1和var2相等,执行条件
  3. else
  4. ... //如果var1和var2不相等,执行条件
  5. endif
  1. ifneq (var1,var2)
  2. ... //如果var1和var2不相等,执行条件
  3. else
  4. ... //如果var1和var2相等,执行条件
  5. endif

Makefile常用函数

Makefile官方手册:https://www.gnu.org/software/make/manual

patsubst:模式替换函数。pattern:模式,substitute:替换。

格式:$(patsubst PATTERN,REPLACEMENT,TEXT)。PATTERN为模式,REPLACEMENT为新模式,TEXT为文本。

示例:$(patsubst %.c,%.o,x.c.c bar.c)

TEXT中有两个单词,分别为x.c.c和bar.c,将单词去匹配模式,即%.c。

可知,x.c.c和bar.c都是.c结尾,所以能匹配模式。能匹配模式的话,就把单词去匹配新模式,即x.c.o和bar.o。

简单来说,把字符串“x.c.c bar.c”中以.c结尾的单词替换成以.o结尾的字符。函数的返回结果是“x.c.o bar.o”。

notdir:去目录取文件名函数。

格式:$(notdir NAMES...)

示例:$(notdir src/foo.c hacks),返回值为“foo.c hacks”。

wildcard:获取匹配模式文件名函数。

格式:$(wildcard PATTERN)

示例:$(wildcard *.c),返回值为当前目录下所有.c源文件列表。

foreach:循环函数

格式:$(foreach VAR,LIST,TEXT)

示例:

dirs:=a b c d

$(foreach dir,$(dirs),$(wildcard $(dir)/*))

首先dir=a,执行$(wildcard $(dir)/*)),即找a目录下的所有文件。然后dir=b,执行$(wildcard $(dir)/*)),即找b目录下的所有文件。

以此类推,等同于files:=$(wildcard a/* b/* c/* d/*)        

Makefile解决头文件依赖

写一个头文件,并把头文件添加到编译器的头文件路径中。gcc -l +"头文件"。

实时检查头文件的更新情况,一旦头文件发生变化,应该要重新编译所有相关文件。

  1. ARCH?=x86
  2. ifeq ($(ARCH),x86)
  3. CC=gcc
  4. else
  5. CC=arm-linux-guneabihf-gcc
  6. endif
  7. TARGET=shm
  8. BUILD_DIR=build
  9. SRC_DIR=module
  10. INC_DIR=include
  11. CFLAGS=$(patsubst %,-I %,$(INC_DIR))
  12. INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(dir)/*.h))
  13. SOURCE=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
  14. OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCE)))
  15. VPATH=$(SRC_DIR)
  16. $(BUILD_DIR)/$(TARGET):$(OBJS)
  17. $(CC) $(^) -o $(@)
  18. $(BUILD_DIR)/%.o:%.c $(INCLUDE) | create_build
  19. $(CC) -c $< -o $@ $(CFLAGS)
  20. .PHONY:clean create_build
  21. clean:
  22. rm -r $(BUILD_DIR)
  23. create_build:
  24. mkdir -p $(BUILD_DIR)

注意:Makefile的内容OBJS中SOURCES少了个S

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

闽ICP备14008679号