### makefile

在类Unix系统中，当我们使用源码编译某个软件的时候，我们会使用confiure,make,make install这三个命令
cofigure生成makefile文件
make和make install编译和安装

#### wildcard
用来明确表示通配符,用法如下
src = $(wildcard *.c /usr/src/linux-2.6.24/drivers/char/ip2/*.c)

#### vpath  定义make的查找路径
多个目录使用空格或者冒号（：）分开
1.vpath 为符合pattern的文件指定directories的搜索路径；
2.vpath 清除符合pattern文件的搜索路径；
3.vpath清除所有已设置好的搜索路径。

vpath pattern path : 符合pattern的文件在path目录搜索。
vpath pattern      : 清除pattern指定的文件搜索路径
vpath              : 清除所有文件搜索路径。

例1：  
vpath %.h include //指定.h类型文件的搜索路径是include

vpath %.cpp src //指定.cpp类型文件的搜索路径是src

*** 注意gcc 指定路径还得-Iinclude ***

#### VPATH 变量
使用空格或者冒号（:）将多个目录分开
当 make 需要去找寻文件的依赖关系时，你可以在文件前加上路径，但最好的方法是把一个路径告诉 make，让 make 在自动去找

VPATH = include：src //指定了makefile的搜索路径


#### 函数
目录
1、  $(dir )取目录函数
2、$(notdir )取文件函数
3、 $(suffix ) 取后缀函数
4、 $(basename )取前缀函数
5、 $(addsuffix ,)加后缀函数
6、$(addprefix ,)加前缀函数
7、 $(join ,)连接函数

字符串
1. subst: 字符串替换函数
2. patsubst: 模式字符串替换函数
3. strip: 去空格函数
4. findstring: 查找字符串函数
5. filter: 过滤函数
6. filter-out: 反过滤
7. sort: 排序函数
8. word: 取单词函数
9. wordlist: 取单词串函数
10. words: 单词个数统计函数
11. firstword: 首单词函数

#### 函数
函数需要在目标时候执行


#### 判断文件目录是否存在  ??
test = $(shell if [ -d $(DIR_TEST) ]; then echo "exist"; else echo "noexist"; fi)
如果是判断文件，修改[ -d $(DIR_TEST) ] 成  [ -f xxx ]

#### 调试
打印变量 

1,使用info/warning/error增加调试信息
方法1: $(info, "here add the debug info")  -- info后面没有逗号
           但是此不能打印出.mk的行号
方法2: $(warning "here add the debug info")

方法3: $(error "error: this will stop the compile")
     这个可以停止当前makefile的编译
方法4: 打印变量的值
      $(info $(TARGET_DEVICE) )

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

例子1：
all: $(BUILD_DIR)/$(TARGET).exe  
	@echo  ".............."
 
例子2：
 $(info haha)
all:
	$(info haha1)
target1:
	$(info $(TARGET))、


#### FAQ
1. 如何编写函数
define func1
    @echo "my name is $(0)"
endef

调用：
test :
    $(call func1)
    $(call func2, value1)

2. PHONY
当前目录下存在clean,和test文件。 
当声明.PHONY:clean后，忽略clean文件的存在，直接执行命令
所以test文件被删除了

3. 数组拼接
   a += b

4. if 语句如何写
   分在目标外，还是目标内
   ***目标外 *** 
   **关键字前边一定要有tab**
   ```makefile
    #这个ifeq else endif，在target 外部，关键字前边一定要有tab
        ifeq ("aaa","bbb")
        ifeq 和括号间有空格
    #内容前可以有空格，如果是tab时，解析为命令
    #变量前可以多个空格
    LIBS= -laaa
        else
    #+echo "test"
    LIBS= -lbbb
        endif
    ```
    ***目标内：***
    可以shell 或非shell
    ifeq else endif，在target 内部，关键字前边一定没有tab，否则当命令处理。可以有多个空格

5. cubemx 如何方案
   cubemx 的makefile, 
   可以添加与外部目录 Code, 将Code的.c  .h链接过去
   对于外部库， 定义 MODBUS ON，FATFS ON这些变量判断
   如果有库的情况下， 添加MODBUS_LIB_ON  还可以增加库文件是否存在的判断，是否构建库

 
6. 编译后，串口输出中文乱码
    -fexec-charset=GBK
    -finput-charset=UTF-8

7. 包含其他 mk文件
    include MyMakefile.mk
    包含的位置就执行吗？

8. 编译平台兼容定义
    #######################################
    # 编译平台相关
    #######################################
    ifeq ($(shell uname),)
    ifeq ($(OS),Windows_NT)
    export HOST_PLATFORM="Windows"
    export RM_DIR := rd /s /q
    export RM_FILE := del
    export MKDIR := mkdir
    export FIND := dir /s /b
    export FIND_FILE := $(FIND) /a:-d
    export FIND_DIR := $(FIND) /a:d
    export LS := dir /b
    export CAT := type
    export DELIMITER := \\
    else
    $(error OS not defined)
    endif
    else
    ifeq ($(shell uname),Darwin)
    export HOST_PLATFORM="MacOS"
    else
    export HOST_PLATFORM="Unix-Like"
    export RM_FILE := rm -rf
    export RM_DIR := rm -f
    export MKDIR := mkdir
    export FIND = find `pwd` -name
    export FIND_FILE = find `pwd` -type f -name
    export FIND_DIR = find `pwd` -type d -name
    export LS := ls
    export CAT := cat
    export DELIMITER := /
    endif
    endif
