Makefile


<Makefile实战>https://github.com/wangbojing/NtyCo

1. 规则格式

缩进要用TAB键,不能用空格

1.1 规则

目标  : 依赖文件集合

	命令1

	命令2

.。。。。。。。。。。。

1.2例子

main : main.o input.o calcu.o

gcc -o main  main.o input.o calcu.o

命令必须以TAP键开始,不能用空格

2. 原理

2.1 依赖原理

一个规则是由目标(targets)、先决条件(prerequisites)以及命令(commands)所组成出的是,目标和先决条件之间表达的就是依赖关系(dependency)

simple:main.o foo.o
gcc -o simple main.o foo.o
main.o:main.c
	gcc -o main.o -c main.c
foo.o:foo.c
	gcc -o foo.o -c foo.c
clean:
	rm simple main.o foo.o

2.2 通过文件时间戳,判断是否需要重新构建

main.c 和 foo.c 呢?答案很简单,通过文件的时间戳!当 make 在运行一个规则时,我们前面已经提到
了目标和先决条件之间的依赖关系,make 在检查一个规则时,采用的方法是:如果先决条件中相关的文 件的时间戳大于目标的时间戳,即先决条件中的文件比目标更新,则知道有变化,那么需要运行规则当中 的命令重新构建目标。这条规则会运用到所有与我们在 make时指定的目标的依赖树中的每一个规则。比
如,对于 simple 项目,其依赖树中包括三个规则(如图1.21),make 会检查所有三个规则当中的目标

3.伪目标

伪目标不是真正的目标名,为了防止执行命令的目标和实际文件目标名字冲突

  1. 例子
  • 之前

        clean:
        	rm *.o
        	rm main
    

    如果在文件夹中touch clean ,执行make clean,Makefile提示:make: “clean”已是最新。

  • 添加伪目标

        .PHONY:clean
        clean:
        	rm *.o
        	rm main
    

    使用.PHONY声明之后的目标,Makefile不会把它当做一个文件来处理,而是当做一个概念上的目标,所以每次make这个佳目标都会执行

  1. 常见伪目标
  • all 是所有目标的伪目标,功能是编译所有目标
  • clean 删除所有被make创建的文件
  • install 安装已经编译好的程序,其实就是把目标执行文件拷贝到指定目标中
  • print 这个伪目标的功能是列出改变过的源文件
  • tar 把源程序打包备份,就是一个tar文件
  • dist 创建一个压缩文件,一般吧tar文件压缩成Z文件或gz文件
  • TAGS 更新所有目标,以备完整的重编译使用
  • check/test 测试makefile流程

4. Makefile变量

4.1 why,how使用变量??

注释要用#,和shell一样

变量使用 $(变量名)也和shell一样

变量定义直接写

.PHONY:clean
CC=gcc
RM=rm
EXE=simple 
OBJS=main.o foo.o
$(EXE):$(OBJS)
	$(CC) -o $(EXE) $(OBJS)
main.o:main.c
	$(CC) -o main.o -c main.c
foo.o:foo.c
	$(CC) -o foo.o -c foo.c
clean:
	$(RM) $(EXE) $(OBJS) 

命令是什么。还有就是引入了 EXE 和 OBJS 两个变量,一个用于存放可执行文件名,可另一个则用于放
置所有的目标文件名。采用变量的话,当我们需要更改编译器时,只需更改变量斌值的地方,非常方便,
如果不采用变量,那我们得更改每一个使用编译器的地方,很是麻烦。显然,变量的引入增加了 Makefil的可维护性。

4.2自动化变量

“$@” ,表示一个规则之中的目标,当一个规则有多个目标时,“$@” 指其中任何造成命令运行的目标
 “$<” ,表示所有依赖的第一个值,如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
	”$^“ , 所有的依赖目标的集合。以空格为分隔,如果依赖目标中存在有多个重复的,那这个变量会去除重复的依赖目标,只保留一份
  • 例子

      .PHONY:clean
      CC=gcc
      RM=rm
      EXE=simple 
      OBJS=main.o foo.o
      $(EXE):$(OBJS)
      	$(CC) -o $@ $^
      main.o:main.c
      	$(CC) -o $@ -c $^
      foo.o:foo.c
      	$(CC) -o $@ -c $^
      clean:
      	$(RM) $(EXE) $(OBJS) 
    

4.3 特殊变量

  1. $(MAKE) = make ,当我们在一个Makefile文件之中打算make另一个文件时需要使用
  2. $(MAKECMDGOALS) ,指的是用户输入的目标

4.4 变量的类别

  1. “=”是递归扩展变量, 不能对自己赋值,会出现死循环
    - 可以将变量的值推到后面去定义

    • 例子:

      name = lak
      curName = $(name)
      name = liankang
      print:
      	@echo currname: $(curName)
      

      #结果为: liankang

  2. “:=”是简单扩展变量,make只对其进行一次扫描和替换

    • 相当于正常的=,不会使用后面定义的值,

    • 例子:

      name = lak
      curName := $(name)
      name = liankang
      print:
      	@echo currname: $(curName)
      

      #结果为:lak

  • ?=
    name = lak

    • name ?= liankang
    • name1 = liankang
      结果:name = lak name1 = liankang
    • 意思是如果name上面被赋值就是之前的值,没有赋值就是赋值为liankang
  • +=

    • 给字符串追加

4.5 变量来源和值

  1. 自动变量,通过上下文自动获取
  2. make bar = x ,make执行时覆盖Makefile之中变量的值
  3. 来自shell环境
    在这里插入图片描述

4.6 override指令

可以使Makefile之中变量不会被输入make 覆盖
在这里插入图片描述

5. 模式

  1. “%”
  • 表示长度任意的字符串,类似shell中的“*”

例子1:

			  %.o : %.c
			  gcc  -c  $<  -o  $@
			
			  把所有的c文件编译生成对应的o文件,$<代表每次取的c文件,$@代表每次c文件对应的目标文件
			
				- “$(@D)”, $@的目录部分
				- “$(@F)"$@的文件部分

			 "$%", 表示函数库文件中
			
			- 用于打包静态库,的.o文件 集合

			”$+“, 所有依赖目标的集合,不去除重复目标
			
			 ”$*“, 表示目标模式 % 及其之前的部分,如果目标是”dir/a.foo.b", 并且目标模式是“a.%.b",那么 ”$*"表示的值就是“dir/a.foo"
			
			”$?“所有比目标新的依赖目标集合,以空格分开

6. 函数

  1. addprefix,添加前缀。$(addprefix prefex, names…)
    在这里插入图片描述

  2. filter , 从字符串之中获取符合格式的字符串,$(filter pattern…, text)
    在这里插入图片描述

  3. filter-out, 从字符串之中过滤掉一部分字符串, $(filter-out pattern… , text)
    在这里插入图片描述

  4. patsubst, 用来做字符串替换,$(patsubst pattern, replacement, text)
    在这里插入图片描述

  5. strip 去除多余的空格,只保留一个空格, $(strip string)

  6. wildcard , 通配符,$(wildcard, pattern)
    在这里插入图片描述

7. 创建目录

.PHONY:all
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIRS=objs exes
all:$(DIRS)
$(DIRS):
	$(MKDIR) $@
clean:
	$(RM) $(RMFLAGS) $(DIRS)

结果:

	mi@mi-OptiPlex-7060:~/test/complicated$ make
	make: 对“all”无需做任何事。
	mi@mi-OptiPlex-7060:~/test/complicated$ make clean
	rm -rf objs exes
	mi@mi-OptiPlex-7060:~/test/complicated$ make all
	mkdir objs
	mkdir exes
	mi@mi-OptiPlex-7060:~/test/complicated$ make
	make: 对“all”无需做任何事。


.PHONY:all
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIRS=objs exes
CC=gcc
EXE=complicated
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
all:$(DIRS) $(EXE)
$(DIRS):
	$(MKDIR) $@
$(EXE):$(OBJS)
	$(CC) -o $@ $^
%.o:%.c
	$(CC) -o $@ -c $^
clean:
	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)

8.将文件放进目录之中

	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean
			rm -rf exes objs  
	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ ls
			foo.c  foo.h  main.c  Makefile
	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make 
			mkdir exes
			mkdir objs
			gcc -o objs/foo.o -c foo.c
			gcc -o objs/main.o -c main.c
			gcc -o exes/complicated objs/foo.o objs/main.o
	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ cat Makefile 
			.PHONY:all
			MKDIR=mkdir
			RM=rm
			RMFLAGS=-rf
			DIR_OBJS=objs
			DIR_EXES=exes
			DIRS=$(DIR_EXES) $(DIR_OBJS)
			CC=gcc
			EXE=complicated
			EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
			SRCS=$(wildcard *.c)
			OBJS=$(SRCS:.c=.o)
			OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
			all:$(DIRS) $(EXE)
			$(DIRS):
				$(MKDIR) $@
			$(EXE):$(OBJS)
				$(CC) -o $@ $^
			$(DIR_OBJS)/%.o:%.c
				$(CC) -o $@ -c $^
			clean:
				$(RM) $(RMFLAGS) $(DIRS)  

9. 更复杂的依赖

  1. 当不依赖头文件时,头文件修改,make并不会检查头文件的时间戳,认为没有必要重新make

  2. 修改,在 %c后面添加头文件,并且将下面自动变量设为取第一个依赖
    $(DIR_OBJS)/%.o:%.c foo.h
    $(CC) -o $@ -c $<

  3. 采用gcc -MM foo.c 可以查看foo.c所依赖的文件,将所有头文件添加到依赖选项上

     .PHONY:all
     MKDIR=mkdir
     RM=rm
     RMFLAGS=-rf
     DIR_OBJS=objs
     DIR_EXES=exes
     DIR_DEPS=deps
     DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS)
     CC=gcc
     EXE=complicated
     EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
     SRCS=$(wildcard *.c)
     OBJS=$(SRCS:.c=.o)
     OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
     DEPS=$(SRCS:.c=.dep)
     DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS))
     all:$(DIRS) $(DEPS) $(EXE)
     $(DIRS):
     	$(MKDIR) $@
     $(EXE):$(OBJS)
     	$(CC) -o $@ $^
     $(DIR_OBJS)/%.o: %.c 
     	$(CC) -o $@ -c $^
     $(DIR_DEPS)/%.dep: %.c
     	@echo "Making $@ ..."
     	@set -e;\
     	$(RM) $(RMFLAGS) $@.tmp;\
     	$(CC) -E -MM $^ > $@.tmp;\
     	sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' < $@.tmp > $@; \
     	$(RM) $(RMFLAGS) $@.tmp
     
     clean:
     	$(RM) $(RMFLAGS) $(DIRS)  
    

10.包含文件include

	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make
	Makefile:18: deps/foo.dep: 没有那个文件或目录
	Makefile:18: deps/main.dep: 没有那个文件或目录
	Making deps/main.dep ...
	/bin/sh: 3: cannot create deps/main.dep.tmp: Directory nonexistent
	Makefile:26: recipe for target 'deps/main.dep' failed
	make: *** [deps/main.dep] Error 2
  1. 原因:make对于include的处理先于all目标构建
  2. 改进:在include前加上一个‘-'号,如果文件不存在就忽略这一个错误,

Makefile中的死循环问题
https://blog.csdn.net/mantis_1984/article/details/72598848

.PHONY:all clean
MKDIR=mkdir

RM=rm
RMFLAGS=-rf
DIR_OBJS=objs
DIR_EXES=exes
DIR_DEPS=deps
DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS)
CC=gcc
EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS=$(SRCS:.c=.dep)
DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS))
all: $(EXE)

ifeq ("$(wildcard $(DIR_DEPS))", "")
     DEP_DIR_DEPS:=$(DIR_DEPS)
endif

-include $(DEPS)

$(DIRS):
	$(MKDIR) $@
$(EXE):$(DIR_EXES) $(OBJS)
	$(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
	$(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
	@echo "Making $@ ..."
	@set -e;\
	$(RM) $(RMFLAGS) $@.tmp;\
	$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
	sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' < $@.tmp > $@; \
	$(RM) $(RMFLAGS) $@.tmp

clean:
	$(RM) $(RMFLAGS) $(DIRS)  

11. 再复杂点的依赖关系

依赖的头文件foo.h 依赖于 define.h ,define.h再依赖于other.h ,当other.h 改变时,make会提示没有修改。
但是sed ‘s,(.).o[:],objs/\1.o $@:,g’ < $@.tmp > $@;
增加 $ @,就好了。
这里不是很懂???

.PHONY:all clean
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIR_OBJS=objs
DIR_EXES=exes
DIR_DEPS=deps
DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS)
CC=gcc
EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS=$(SRCS:.c=.dep)
DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS))
all: $(EXE)

ifeq ("$(wildcard $(DIR_DEPS))", "")
     DEP_DIR_DEPS:=$(DIR_DEPS)
endif

-include $(DEPS)

$(DIRS):
	$(MKDIR) $@
$(EXE):$(DIR_EXES) $(OBJS)
	$(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
	$(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
	@echo "Making $@ ..."
	@set -e;\
	$(RM) $(RMFLAGS) $@.tmp;\
	$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
	sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
	$(RM) $(RMFLAGS) $@.tmp

clean:
	$(RM) $(RMFLAGS) $(DIRS)  

12. 条件语法

当 make 看到条件语法时将立即对其进行分析,这包括 ifdef、ifeq、ifndef 和 ifneq 四种语句形式。

  1. ifeq、ifneq

     	mi@mi-OptiPlex-7060:~/test/makefile/condition$ cat Makefile 
     					.PHONY: all
     					
     					sharp = square
     					desk = square
     					table = circle
     					ifeq ($(sharp), $(desk))
     					result1 = "desk == sharp"
     						endif
     					
     					ifneq "$(table)" 'square'
     						result2 = "table != square"
     						endif
     					
     					all:
     						@echo $(result1)
     						@echo $(result2)
     
     mi@mi-OptiPlex-7060:~/test/makefile/condition$ make
     						desk == sharp
     						table != square
    
  2. ifdef、ifndef

     mi@mi-OptiPlex-7060:~/test/makefile/condition$ cat Makefile 
     				.PHONY: all
     				foo = define
     				Z
     				ifdef foo
     					result1 = "foo is defined"
     					endif
     				
     				ifndef bar 
     					result2 = "bar is not define"
     					endif
     				
     				all:
     					@echo $(result1)
     					@echo $(result2)
     	mi@mi-OptiPlex-7060:~/test/makefile/condition$ make
     				foo is defined
     				bar is not define
    
  3. make clean 也依赖文件夹生成,添加条件判断,让没文件夹时不再重新生成再clean
    修改前

     	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean
     			rm -rf exes objs deps  
     	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean
     			mkdir deps
     			Making deps/main.dep ...
     			Making deps/foo.dep ...
     			rm -rf exes objs deps  
    

    使用条件语句修改依赖

     	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ cat Makefile 
     			.PHONY:all clean
     			MKDIR=mkdir
     			RM=rm
     			RMFLAGS=-rf
     			DIR_OBJS=objs
     			DIR_EXES=exes
     			DIR_DEPS=deps
     			DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS)
     			CC=gcc
     			EXE=complicated
     			EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
     			SRCS=$(wildcard *.c)
     			OBJS=$(SRCS:.c=.o)
     			OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
     			DEPS=$(SRCS:.c=.dep)
     			DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS))
     			all: $(EXE)
     			
     			ifeq ("$(wildcard $(DIR_DEPS))", "")
     			     DEP_DIR_DEPS:=$(DIR_DEPS)
     			endif
     			
     			ifeq ($(MAKECMDGOALS), clean)
     				DEP_DIR_DEPS:= ""
     			endif
     			
     				-include $(DEPS)
     			-include $(DEPS)
     			
     			$(DIRS):
     				$(MKDIR) $@
     			$(EXE):$(DIR_EXES) $(OBJS)
     				$(CC) -o $@ $(filter %.o, $^)
     			$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
     				$(CC) -o $@ -c $(filter %.c, $^)
     			$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
     				@echo "Making $@ ..."
     				@set -e;\
     				$(RM) $(RMFLAGS) $@.tmp;\
     				$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
     				sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
     				$(RM) $(RMFLAGS) $@.tmp
     			
     			clean:
     				$(RM) $(RMFLAGS) $(DIRS)  
     	mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean
     				rm -rf exes objs deps  
     				mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean
     				rm -rf exes objs deps  
    

13. 更复杂的项目

  1. 文件目录

     	mi@mi-OptiPlex-7060:~/test/makefile/huge$ tree 
     .
     ├── build
     │   └── libs
     └── source
         ├── foo
         │   ├── inc
         │   └── src
         │       ├── foo.c
         │       └── Makefile
         └── hug
             └── src
    
  2. 修改Makefile

     mi@mi-OptiPlex-7060:~/test/makefile/huge/source/foo/src$ cat Makefile 
     .PHONY:all clean
     
     MKDIR = mkdir
     RM = rm
     RMFLAGS = -rf
     
     # 需要学习ar工具的使用
     AR = ar
     ARFLAGS = crs
     
     DIR_OBJS = objs
     DIR_EXES = ../../../build/exes
     DIR_DEPS = deps
     DIR_LIBS = ../../../build/libs
     DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS)
     RMS = $(DIR_OBJS) $(DIR_DEPS)
     CC = gcc
     
     ifneq ($(EXE), "")
     EXE := $(addprefix $(DIR_EXES)/, $(EXE))
     RMS += $(EXE)
     endif
     
     LIB = libfoo.a
     ifneq ($(LIB), "")
     LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
     RMS += $(LIB)
     endif
     
     
     SRCS = $(wildcard *.c)
     OBJS = $(SRCS:.c=.o)
     OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
     DEPS = $(SRCS:.c=.dep)
     DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
     
     ifneq ($(EXE), "")
     all: $(EXE)
     endif
     
     ifneq ($(LIB), "")
     all: $(LIB)
     endif
     
     
     ifeq ("$(wildcard $(DIR_DEPS))", "")
          DEP_DIR_DEPS := $(DIR_DEPS)
     endif
     
     ifeq ($(MAKECMDGOALS), clean)
     	DEP_DIR_DEPS := ""
     endif
     -include $(DEPS)
     
     $(DIRS):
     	$(MKDIR) $@
     $(EXE):$(DIR_EXES) $(OBJS)
     	$(CC) -o $@ $(filter %.o, $^)
     $(LIB):$(DIR_LIBS) $(OBJS)
     	$(AR) $(ARFLAGS) $@ $(filter %.o, $^)
     $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
     	$(CC) -o $@ -c $(filter %.c, $^)
     $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
     	@echo "Making $@ ..."
     	@set -e;\
     	$(RM) $(RMFLAGS) $@.tmp;\
     	$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
     	sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
     	$(RM) $(RMFLAGS) $@.tmp
     
     clean:
      # 删除生成的文件,不删除文件
     	$(RM) $(RMFLAGS)  $(RMS)
     mi@mi-OptiPlex-7060:~/test/makefile/huge/source/foo/src$ make
     		mkdir deps
     		Making deps/foo.dep ...
     		mkdir objs
     		gcc -o objs/foo.o -c foo.c
     		ar crs ../../../build/libs/libfoo.a objs/foo.o
     mi@mi-OptiPlex-7060:~/test/makefile/huge/source/foo/src$ make clean
     		rm -rf  objs deps  ../../../build/libs/libfoo.a 
    

14. 提高复用性

Makefile

  1. 分离Makefile文件
├── huge
│   ├── build
│   │   ├── exes
│   │   │   └── huge
│   │   ├── libs
│   │   └── make.rule
│   └── source
│       ├── foo
│       │   ├── inc
│       │   └── src
│       │       ├── foo.c
│       │       └── Makefile
│       └── hug
│           └── src
│               ├── deps
│               │   └── main.dep
│               ├── main.c
│               ├── Makefile
│               └── objs
	│                   └── main.o
  1. 分解公共部分到make.rule 放在build文件夹之中,每个src之中只写相关部分,并且引用make.rule
  2. 执行时,cd到makefile/huge/ 目录,export ROOT= pwd
    #/huge/build/make.rule
.PHONY:all clean
	MKDIR = mkdir
	RM = rm
	RMFLAGS = -rf
AR = ar
ARFLAGS = crs

DIR_OBJS = objs
DIR_EXES = $(ROOT)/build/exes
DIR_DEPS = deps
DIR_LIBS = $(ROOT)/build/libs
DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS)
RMS = $(DIR_OBJS) $(DIR_DEPS)
CC = gcc

ifneq ($(EXE), "")
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
RMS += $(EXE)
endif

ifneq ($(LIB), "")
LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
RMS += $(LIB)
endif


SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

ifneq ($(EXE), "")
all: $(EXE)
endif

ifneq ($(LIB), "")
all: $(LIB)
endif


ifeq ("$(wildcard $(DIR_DEPS))", "")
     DEP_DIR_DEPS := $(DIR_DEPS)
endif

ifeq ($(MAKECMDGOALS), clean)
        DEP_DIR_DEPS := ""
endif
-include $(DEPS)

$(DIRS):
        $(MKDIR) $@
$(EXE):$(DIR_EXES) $(OBJS)
        $(CC) -o $@ $(filter %.o, $^)
$(LIB):$(DIR_LIBS) $(OBJS)
        $(AR) $(ARFLAGS) $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
        $(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
        @echo "Making $@ ..."
        @set -e;\
        $(RM) $(RMFLAGS) $@.tmp;\
        $(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
        sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
        $(RM) $(RMFLAGS) $@.tmp

clean:
        $(RM) $(RMFLAGS)  $(RMS) 
  1. 加入源程序

  2. 增加头文件目录变量–INC_DIRS,在make.rule中增加一个条件语句模块,去掉多余空格,然后加上-I(i大写)参数

  3. 然后在编译中加上头文件依赖

       .PHONY:all clean
       MKDIR = mkdir
       RM = rm
       RMFLAGS = -rf
       
       AR = ar
       ARFLAGS = crs
       
       DIR_OBJS = objs
       DIR_EXES = $(ROOT)/build/exes
       DIR_DEPS = deps
       DIR_LIBS = $(ROOT)/build/libs
       DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS)
       RMS = $(DIR_OBJS) $(DIR_DEPS)
       CC = gcc
       
       ifneq ($(EXE), "")
       EXE := $(addprefix $(DIR_EXES)/, $(EXE))
       RMS += $(EXE)
       endif
       
       ifneq ($(LIB), "")
       LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
       RMS += $(LIB)
       endif
       
       
       SRCS = $(wildcard *.c)
       OBJS = $(SRCS:.c=.o)
       OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
       DEPS = $(SRCS:.c=.dep)
       DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
       
       ifneq ($(EXE), "")
       all: $(EXE)
       endif
       
       ifneq ($(LIB), "")
       all: $(LIB)
       endif
       
       
       ifeq ("$(wildcard $(DIR_DEPS))", "")
            DEP_DIR_DEPS := $(DIR_DEPS)
       endif
       
       ifeq ($(MAKECMDGOALS), clean)
               DEP_DIR_DEPS := ""
       endif
       include $(DEPS)
       
       ifneq ($(INC_DIRS), "")
           INC_DIRS := $(strip $(INC_DIRS))
           INC_DIRS := $(addprefix -I, $(INC_DIRS))
       endif
       
       
       $(DIRS):
               $(MKDIR) $@
       $(EXE):$(DIR_EXES) $(OBJS)
               $(CC) -o $@ $(filter %.o, $^)
       $(LIB):$(DIR_LIBS) $(OBJS)
               $(AR) $(ARFLAGS) $@ $(filter %.o, $^)
       $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
               $(CC) $(INC_DIRS)  -o $@ -c $(filter %.c, $^)
       $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
               @echo "Making $@ ..."
               @set -e;\
               $(RM) $(RMFLAGS) $@.tmp;\
               $(CC) $(INC_DIRS)  -E -MM $(filter %.c, $^) > $@.tmp;\
               sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
               $(RM) $(RMFLAGS) $@.tmp
       
       clean:
               $(RM) $(RMFLAGS)  $(RMS) 
       
       
       EXE = huge
       LIB = 
       INC_DIRS = $(ROOT)/source/foo/inc
       include $(ROOT)/build/make.rule
       
       
       .PHONY:all clean
       EXE =
       LIB = libfoo.a
       INC_DIRS = $(ROOT)/source/foo/inc
       include $(ROOT)/build/make.rule
    
  4. Makefile 调试

  5. 使用info/warning/error增加调试信息
    1. 方法1: $(info “here add the debug info”)但是此不能打印出.mk的行号
    2. 方法2: $(warning “here add the debug info”)
    3. 方法3: ( e r r o r " e r r o r : t h i s w i l l s t o p t h e c o m p i l e " ) 这个可以停止当前 m a k e f i l e 的编译 4. 方法 4 : 打印变量的值 (error "error: this will stop the compile")这个可以停止当前makefile的编译 4. 方法4: 打印变量的值 (error"error:thiswillstopthecompile")这个可以停止当前makefile的编译4.方法4:打印变量的值(info $(TARGET_DEVICE) )

  6. 使用echo增加调试信息(echo只能在target:后面的语句中使用,且前面是个TAB)
    1. 方法1: @echo “start the compilexxxxxxxxxxxxxxxxxxxxxxx”
    2. 方法2: @echo $(files)

  7. 增加链接库

  8. 修改make.rule ,使用LINK_LIBS, 通过gcc 的-L 搜索

  9. 在src中添加LINK_LIBS = foo ,库名为libfoo.a

       .PHONY: all clean
       
       DIRS = $(ROOT)/source/foo/src \
                  $(ROOT)/source/bar/src \
                  $(ROOT)/source/hug/src 
       RM = rm
       RMFLAGS = -rf
       RMS = $(ROOT)/build/exes $(ROOT)/build/libs
       
       all:
               @set -e; \
               for dir in $(DIRS); \
                       do \
                       cd $$dir && $(MAKE); \
               done
               @echo ""
               @echo ":-) Completed"
               @echo ""
       
       clean:
               @set -e; \
               for dir in $(DIRS); \
                       do \
                       cd $$dir && $(MAKE) clean; \
               done
               @echo ""
               @echo ":-) Completed"
               @echo "".PHONY: all clean
       
       DIRS = $(ROOT)/source/foo/src \
                  $(ROOT)/source/bar/src \
                  $(ROOT)/source/hug/src 
       RM = rm
       RMFLAGS = -rf
       RMS = $(ROOT)/build/exes $(ROOT)/build/libs
       
       all:
               @set -e; \
               for dir in $(DIRS); \
                       do \
                       cd $$dir && $(MAKE); \
               done
               @echo ""
               @echo ":-) Completed"
               @echo ""
       
       clean:
               @set -e; \
               for dir in $(DIRS); \
                       do \
                       cd $$dir && $(MAKE) clean; \
               done
               @echo ""
               @echo ":-) Completed"
               @echo ""
       
       .PHONY:all clean
       MKDIR = mkdir
       RM = rm
       RMFLAGS = -rf
       
       AR = ar
       ARFLAGS = crs
       
       DIR_OBJS = objs
       DIR_EXES = $(ROOT)/build/exes
       DIR_DEPS = deps
       DIR_LIBS = $(ROOT)/build/libs
       DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS)
       RMS = $(DIR_OBJS) $(DIR_DEPS)
       CC = gcc
       
       ifneq ($(EXE), "")
       EXE := $(addprefix $(DIR_EXES)/, $(EXE))
       RMS += $(EXE)
       endif
       
       ifneq ($(LIB), "")
       LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
       RMS += $(LIB)
       endif
       
       
       SRCS = $(wildcard *.c)
       OBJS = $(SRCS:.c=.o)
       OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
       DEPS = $(SRCS:.c=.dep)
       DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
       
       ifneq ($(EXE), "")
       all: $(EXE)
       endif
       
       ifneq ($(LIB), "")
       all: $(LIB)
       endif
       
       
       ifeq ("$(wildcard $(DIR_DEPS))", "")
            DEP_DIR_DEPS := $(DIR_DEPS)
       endif
       
       ifeq ($(MAKECMDGOALS), clean)
               DEP_DIR_DEPS := ""
       endif
       include $(DEPS)
       
       ifneq ($(INC_DIRS), "")
           INC_DIRS := $(strip $(INC_DIRS))
           INC_DIRS := $(addprefix -I, $(INC_DIRS))
       endif
       
       ifneq ($(LINK_LIBS), "")
       #    $(info $(LINK_LIBS))
           LINK_LIBS := $(strip $(LINK_LIBS))
       #    $(info $(LINK_LIBS))
           LINK_LIBS := $(addprefix -l, $(LINK_LIBS))
       #    $(info $(LINK_LIBS))
       endif
       
       $(DIRS):
               $(MKDIR) $@
       $(EXE):$(DIR_EXES) $(OBJS)
               $(CC) -L$(DIR_LIBS) -o $@ $(filter %.o, $^) $(LINK_LIBS)
       $(LIB):$(DIR_LIBS) $(OBJS)
               $(AR) $(ARFLAGS) $@ $(filter %.o, $^)
       $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c 
               $(CC) $(INC_DIRS)  -o $@ -c $(filter %.c, $^)
       $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
               @echo "Making $@ ..."
               @set -e;\
               $(RM) $(RMFLAGS) $@.tmp;\
               $(CC) $(INC_DIRS)  -E -MM $(filter %.c, $^) > $@.tmp;\
               sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
               $(RM) $(RMFLAGS) $@.tmp
       
       clean:
               $(RM) $(RMFLAGS)  $(RMS) 
    

#mi@mi-OptiPlex-7060:~/test/makefile/huge/source/hug/src$ cat Makefile

	EXE = huge
	LIB = 
	INC_DIRS = $(ROOT)/source/foo/inc
	LINK_LIBS = foo
	include $(ROOT)/build/make.rule
  1. 添加一个bar模块,添加一个libbar.a的库
  2. mi@mi-OptiPlex-7060:~/test/makefile/huge/source$ mkdir bar
  3. mi@mi-OptiPlex-7060:~/test/makefile/huge/source$ cd bar/
  4. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar$ mkdir src
  5. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar$ mkdir inc
  6. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar$ cd inc/
  7. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/inc$ vim bar.h
  8. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/inc$ cd …/src/
  9. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/src$ vim bar.c
  10. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/src$ vim Makefile
  11. mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/src$ make
  12. 在hug/src/main.c 中引用bar()函数,include “bar.h”
  13. 在hug/src/Makefile中修改INC_DIRS 和LINK_LIBS,如下

├── build
│ ├── exes
│ │ └── huge
│ ├── libs
│ │ ├── foo.a
│ │ ├── libbar.a
│ │ └── libfoo.a
│ └── make.rule
└── source
├── bar
│ ├── inc
│ │ └── bar.h
│ └── src
│ ├── bar.c
│ ├── deps
│ │ └── bar.dep
│ ├── Makefile
│ └── objs
│ └── bar.o
├── foo
│ ├── inc
│ │ ├── define.h
│ │ ├── foo.h
│ │ └── other.h
│ └── src
│ ├── deps
│ │ └── foo.dep
│ ├── foo.c
│ ├── Makefile
│ └── objs
│ └── foo.o
└── hug
└── src
├── deps
│ └── main.dep
├── main.c
├── Makefile
└── objs
└── main.o

#mi@mi-OptiPlex-7060:~/test/makefile/huge/source/hug/src$ cat Makefile

EXE = huge
LIB = 
INC_DIRS = $(ROOT)/source/foo/inc \
        $(ROOT)/source/bar/inc 
LINK_LIBS = foo bar
include $(ROOT)/build/make.rule
  1. 简化Make操作
  2. 新建一个文件huge/source/build/Makefile
  3. 文件夹要分先后,先写lib库的路径,再写可执行程序路径,因为Makefile要分先后
    .PHONY: all clean
DIRS = $(ROOT)/source/foo/src \
           $(ROOT)/source/bar/src \
           $(ROOT)/source/hug/src 
RM = rm
RMFLAGS = -rf
RMS = $(ROOT)/build/exes $(ROOT)/build/libs

all:
        @set -e; \
        for dir in $(DIRS); \
                do \
                cd $$dir && $(MAKE); \
        done
        @echo ""
        @echo ":-) Completed"
        @echo ""

clean:
        @set -e; \
        for dir in $(DIRS); \
                do \
                cd $$dir && $(MAKE) clean; \
        done
        @echo ""
        @echo ":-) Completed"
        @echo ""
  1. 完整编译

     cd makefile/huge
     export ROOT=`pwd`
     cd build
     make
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值