一个有惊喜的makefile
1. 简介
这里我将介绍一个我日常使用的makefile框架,我本人开发单片机裸机程序较多,故这里分享给大家的makefile主要偏向于裸机开发,适合新人上手,但其中有一些技巧我个人觉得有一定的参考价值。mkefile相关文件:GitHub或优快云(后续还有更新,小改动优先更新GitHub),文章更新:一个有惊喜的makefile。
1.1 功能
目前该makefile具备了以下功能:
- 支持在Linux和Windows(git-bash)上运行(git-bash需要额外下载make.exe和ctags.exe)
- 支持通过BASH脚本创建工程
- 支持编译同名文件
- 支持编译工程目录之外的文件(绝对路径或相对路径)
- 支持单独编译静态库
- 支持编译静态库,并使用静态库链接成可执行文件
- 支持单独指定编译静态库的参数
- 支持生成多种类型文件:反汇编文件、二进制文件、HEX文件、MAP文件等
- 支持在执行编译前和编译后调用用户命令
- 支持打印链接完成后存储器使用情况(需链接脚本配合)
- 支持打印参与编译的文件列表
- 支持对所有参与编译的文件执行ctags
- 支持工程拷贝,工程拷贝时会创建一个新的工程,并将目录外的文件拷贝到目录内,删除不参与编译的头文件
- 支持工程瘦身,即移除参与编译但不会被使用到的C文件
- 支持生成Qtcreator的工程文件,可以使用Qt进行源码的编辑
1.2 约束
目前该makefile仅支持.c
.S
.a
.h
四种后缀的文件,.C
.s
.H
文件并不支持。
1.3 文件列表
目前该makefile共有四类文件,其中辅助文件
可以删除而不影响编译功能:
类型 | 名称 | 说明 |
---|---|---|
列表文件 | file.mk | 分为根目录下的file.mk 和各个子目录下的*/file.mk ,用于记录哪些源码文件参与编译,该文件首次可由create.sh 自动生成,后续开发中可手动修改 |
配置文件 | Makefile | 配置编译工具链、链接脚本、CPU等信息 |
规则文件 | make.mk | makefile的主体文件,会根据Makefile 的配置信息补充一些参数,并负责编译.c .S 文件 |
lib.mk | 该文件由各个子目录下的*/file.mk 调用,用于配合编译静态库 | |
辅助文件 | clone.mk | 使用make clone 调用,用于工程拷贝 |
files.mk | 使用make files 调用,用于打印参与编译的文件列表 | |
help.mk | 使用make help 调用,用于打印使用说明 | |
makefile | 当编译静态库需要指定特殊参数时,需要使用该模板 | |
qt.mk | 使用make qt 调用,用于生成Qtcreator工程文件 | |
slim.mk | 使用make slim 调用,用于移除参与编译但未使用的C文件 | |
tags.mk | 使用make tags 调用,用于执行ctags | |
create.sh | 使用./tools/make/create.sh 调用,用于辅助生成file.mk |
2. 创建工程
2.1 小小工程
现有一stm32f072工程目录如下:
$ tree
.
├── arch
│ ├── crt0.S
│ └── ram.lds
└── main.c
我们将makefile的相关文件拷贝进来:
$ tree
.
├── arch
│ ├── crt0.S
│ └── ram.lds
├── main.c
├── Makefile
└── tools
└── make
├── clone.mk
├── create.sh
├── files.mk
├── help.mk
├── lib.mk
├── makefile
├── make.mk
├── qt.mk
├── slim.mk
└── tags.mk
修改Makefile
文件内容如下:
Makefile
###############################################################################
# Version: v2.0.0
# Author: xflm
# Date: Sat Dec 19 09:11:46 CST 2020
###############################################################################
# Define toolchain path
TOOLCHAIN = arm-none-eabi-
# Define target name
TARGET = stm32f072
# Define target type: elf exe lib
TARGET_TYPE = elf
#TARGET_TYPE = exe
#TARGET_TYPE = lib
# Define run type: rom ram
#RUN_TYPE = rom
RUN_TYPE = ram
# Define build type: (null) debug profile release
#BUILD_TYPE =
#BUILD_TYPE = debug
BUILD_TYPE = profile
#BUILD_TYPE = release
# Define link file
LINK_FILE = arch/$(RUN_TYPE).lds
# Append global macro
DEFINES =
# Append cpu infomation
CPU = -mcpu=cortex-m0
CPU += -mfloat-abi=softfp
CPU += -mthumb
CPU +=
# Append standard library
STDLIB =
# Append GCC flags
CFLAGS =
# Append LD flags
LDFLAGS =
# Use vpath mode, y is enable, default is disable
VPATH_MODE =
# Use grabage collection mode, y is enable, default is disable
GARBAGE_COLLECTION = y
# Create files, y is create, default is not create
CREATE_DIS =
CREATE_ASM = y
CREATE_BIN = y
CREATE_HEX =
CREATE_MAP =
CREATE_GC =
# Define shell cmd, run before and after compile
# like: CMD_BEFORE = echo -n ===; echo ===
CMD_BEFORE =
CMD_AFTER =
include tools/make/make.mk
创建空文件file.mk,调用create.sh
,构造工程。构造完毕后会多出make_create_bak
目录,这是对老的file.mk
的备份,可以执行./make_create_bak/recover.sh
恢复之前的file.mk
,确认不需要恢复时可以手动删除该目录:
$ touch file.mk $ ./tools/make/create.sh
file.mk内容如下:
file.mk
###############################################################################
# Verison: v2.0.0
# Author: xflm
# Date: Tue Feb 16 12:15:03 CST 2021
###############################################################################
# Define asm file
ASM_FILE += arch/crt0.S
ASM_FILE +=
# Define source file
SRC_FILE += main.c
SRC_FILE +=
# Define header path
INC_PATH +=
# Define library file
LIB_FILE +=
# Define library file
OTHER_FILE +=
# Include sub file.mk
编译程序,编译过程的打印如下所示,其中->
和Complete !!!
会加粗显示,这个是通过\033[1m
实现的在tools/make/make.mk中可以看到,这个加粗显示目前在git-bash中不兼容:
$ make
-> main.c
-> arch/crt0.S
Complete !!!
type sram file
used 4180 ram profile - - - 打印存储器使用情况,参考ram.lds
和make.mk
unused 16300 build/stm32f072.elf
2.2 两种编译模型
此处介绍两个编译模型,其具体指的是make如何搜索源文件进行编译。
- VPATH模式
该模式和make的
vpath
命令有关,其原理是:我们把.S
.c
的路径都告诉vpath
,main.c
apps/mboard/mboard.c
arch/crt0.S
等所有源码编译后的文件都保存到build/.obj
目录下build/.obj/main.o
build/.obj/mboard.o
build/.obj/crt0.o
。
优点: 目标文件的路径与源码文件路径无关。
缺点: 不支持同名文件,也即若同时存在drivers/mboard.c
源码,最后的链接将会出错,因为有一个build/.obj/mboard.o
被覆盖了。
- 路径模式
该模式不使用
vpath
命令,通过file.mk
make知道所有参与编译的源码的路径,因此可以将.o
的路径和.c
关联起来,这样的话apps/mboard/mboard.c
drivers/mboard.c
编译后目标文件分别为:build/.obj/apps/mboard/mboard.c.o
buils/.obj/drivers/mboard.c.o
不再冲突。
优点: 支持同名文件 。
缺点: 对工程目录以外的文件不友好,也即若存在../drivers/rtc.c
,编译后为build/.obj/../drivers/rtc.c.o
=>build/rtc.c.o
这样就比较乱了。
综上,该makefile提供了VPATH_MODE
(位于Makefile
文件中)变量用于切换两种模式,默认(空)为第二种。
2.3 给工程添加外部文件
现有外部目录文件如下:
$ tree …/drivers/
…/drivers/
├── include
│ └── rtc.h
└── rtc.c
为便于以后通过make clone
拷贝工程,此处引入以下方案:
在当前目录下建立和外部目录同名的目录,在同名目录里建立空
file.mk
,使用./tools/make/create.sh
生成工程,也可以手动从其他子目录下(注意: 子目录的file.mk
和根目录的模板不同)拷贝file.mk
然后手动修改。$ mkdir drivers $ touch drivers/file.mk $ ./tools/make/create.sh ../drivers - - - 也可以试试./tools/make/create.sh "drivers的绝对路径"
drivers/file.mk
内容如下:
drivers/file.mk
###############################################################################
# Verison: v2.0.0
# Author: xflm
# Date: Tue Feb 16 19:10:43 CST 2021
###############################################################################
# Define create lib name
LIB_NAME :=
# Define asm file
FILE_ASM +=
# Define source file
FILE_SRC += $(FILE_PWD)/…/…/drivers/rtc.c - - - 使用绝对路径和相对路径这里生成的不一样
FILE_SRC +=
# Define header path
PATH_INC += $(FILE_PWD)/…/…/drivers/include
PATH_INC +=
# Define library file
FILE_LIB +=
# Define library file
FILE_OTHER +=
# Include lib.mk
include tools/make/lib.mk
file.mk
尾部增加了两行:
file.mk
FILE_PWD = drivers
include $(FILE_PWD)/file.mk
修改Makefile
中VPATH_MODE = y
因为只有vpath
支持外部文件,否则编译的中间文件会出现在build/rtc.c.o
build/rtc.c.d
(虽不影响最终编译成功,但是不推荐)。执行make进行编译:
$ make
-> main.c
-> drivers/…/…/drivers/rtc.c - - - 使用绝对路径和相对路径这里打印的不一样
-> arch/crt0.S
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
可以发现编译的中间文件*.o
*.d
都在build/.obj
下,而之前那个小小工程,在build/.obj
目录下还有一些目录。
2.4 把drivers编译成一个静态库
修改drivers/file.mk
,使得LIB_NAME := rtc
,然后执行编译,你可能发现make打印的信息仅仅是重新链接了一下:
$ make
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
但此时,你查看build
目录结构会发现多了build/drivers/librtc.a
,也即make完成了把rtc打包的任务。需注意该makefile以一个子目录的file.mk
为一个编库的基本单位,库名字定义在file.mk
中,无论该file.mk
中有几个C文件,最后都仅只打包成一个库。
2.5 使用O0编译librtc.a
已知目标程序编译使用的是
O2
优化等级,现在librtc.a
要使用O0
优化等级,也即编译静态库和编译目标程序使用不同的编译参数。通常在一个make环境中只允许一套编译参数,在此场景下我们就需要执行两次make来完成最终的编译。
拷贝tools/make/makefile
到drivers/
目录下(需注意tools/make/makefile
已默认VPATH_MODE = y
,否则此处应当修改文件中的该变量的值),执行编译:
$ make
-> drivers/…/…/drivers/rtc.c
Complete !!!
text data bss dec hex filename
0 0 0 0 0 rtc.c.o (ex build/drivers/librtc.a)
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
可以看到执行了两次make,第一次生成librtc.a
,第二次生成build/stm32f072.elf
。此处我是用的rtc.c
是个空文件,因而size全部为0。
打开
drivers/makefile
可以看到它和Makefile
很相像,不过TOOLCHAIN
BUILD_TYPE
CFLAGS
等变量都等于一个变量,而不是具体的值。这些G_
开头的变量定义在tools/make/make.mk
中是顶层make定义并传递给子make的。
修改drivers/makefile
,使得BUILD_TYPE =
CFLAGS += -O0 -g3
,然后执行编译,你会发现并没有触发编译,不要紧,你可以touch ../drivers/rtc.c;make
或make clean;make
即可触发编译。通常使用的时候我们若更改了makefile应当选择性执行make clean;make
,当然make本身也能够发现makefile被改变了(比如给%.o增加个依赖$(MAKEFILE_LIST)
,MAKEFILE_LIST
是make内置变量,保存了make会读取的所有文件列表),只是这种情况比较少,就手动执行一下吧。可以将修改tools/make/make.mk
,将$(OBJ_DIR)/%.c.o:%.c
下面的@
删除,使得make输出编译过程的参数,如下:
$ make clean; make
-> main.c
arm-none-eabi-gcc -c -MMD -W -Wall -std=gnu99 -fno-builtin -DBUILD_NAME="“stm32f072"” -DBUILD_DATE="“Tue Feb 16 20:48:29 CST 2021"” -DBUILD_AUTH="“xflm”" -ffunction-sections -fdata-sections -O2 -g3 -mcpu=cortex-m3 -mfloat-abi=softfp -mthumb -Idrivers/…/…/…/drivers/include -o build/.obj/main.c.o main.c
-> arch/crt0.S
-> drivers/…/…/…/drivers/rtc.c
arm-none-eabi-gcc -Idrivers/…/…/…/drivers/include -O0 -g3 -c -MMD -W -Wall -std=gnu99 -fno-builtin -DBUILD_NAME="“rtc”" -DBUILD_DATE="“Tue Feb 16 20:48:29 CST 2021"” -DBUILD_AUTH="“xflm”" -mcpu=cortex-m3 -mfloat-abi=softfp -mthumb -o build/drivers/.obj/rtc.c.o drivers/…/…/…/drivers/rtc.c
Complete !!!
text data bss dec hex filename
0 0 0 0 0 rtc.c.o (ex build/drivers/librtc.a)
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
可以看出rtc.c
是使用O0
优化编译的。另外,你会发现build/.obj/
下面并没有rtc.c.o
,这个文件现在的位置是build/drivers/.obj/ret.c.o
,也即使用这种方式编译静态库,该静态库所依赖的.o
文件会与顶层make的.o
文件隔离开来,那么我们又可以把顶层make设置为VPATH_MODE =
以支持同名文件了。
2.6 两种编译模型共存
修改使用O0编译librtc.a的Makefile
,使得VPATH_MODE =
,重新编译,查看build
文件夹:
$ find build/ -type f
build/stm32f072.asm
build/stm32f072.bin
build/stm32f072.elf
build/drivers/librtc.a
build/drivers/.obj/rtc.c.d - - - 在build/drivers/.obj下面
build/drivers/.obj/rtc.c.o
build/.obj/crt0.S.d - - - 都在build/.obj下面
build/.obj/main.c.d
build/.obj/main.c.o
build/.obj/crt0.S.o
$ make clean; make
$ find build/ -type f
build/stm32f072.asm
build/stm32f072.bin
build/stm32f072.elf
build/drivers/librtc.a
build/drivers/.obj/rtc.c.d - - - 在build/drivers/.obj下面
build/drivers/.obj/rtc.c.o
build/.obj/arch/crt0.S.d - - - 在/build/.obj/arch下面
build/.obj/arch/crt0.S.o
build/.obj/main.c.d
build/.obj/main.c.o
2.7 新增一个目录
新现增加apps/mboard
目录如下:
apps/mboard
tree apps
apps/
└── mboard
├── include
│ └── mboard.h
└── mboard.c
老规矩,使用create.sh
创建工程(需注意,执行create.sh
前需要清空build目录,否者create.sh会把build下面的.a文件写到file.mk中),然后编译:
$ touch apps/mboard/file.mk
$ make clean - - - 需要清空build目录,否者create.sh会把build下面的.a文件写到file.mk中的
$ ./tools/make/create.sh …/drivers
$ make clean; make
-> main.c
-> drivers/…/…/drivers/rtc.c
-> apps/mboard/mboard.c
-> arch/crt0.S
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
只编译了一次,原因是./tools/make/create.sh
重构工程时drivers/file.mk
会被重写,LIB_NAME :=
为空,即不编译静态库,此处我们应该手动修改drivers/file.mk
,使得LIB_NAME := rtc
,再次执行make又会编译两次了。此时根目录下file.mk
又多了两行:
file.mk
FILE_PWD = apps/mboard
include $(FILE_PWD)/file.mk
可以尝试使用#
注释掉这两行,再进行编译,由于mboard.c
并没有被引用,故而依旧可以编译通过,如果目录结构清晰,这个方法可以相当于你有种选择性编译模块的感觉有木有。
2.8 新增一个文件
现在新增一个文件apps/mboard/rtc.c
,需要把它添加进来,就一个文件,我们就不使用create.sh
了,手动修改一下吧:
apps/mboard/file.mk
FILE_SRC += $(FILE_PWD)/mboard.c - - - 拷贝这个模板
FILE_SRC += $(FILE_PWD)/rtc.c - - - 新添加一行
执行make编译,可以看到apps/mboard/rtc.c
已经参与编译了,它和../drivers/rtc.c
是同名文件哦。
3. 工程模型
3.1 工程结构
此处简述一下我使用的工程结构:
$ tree
.
├── apps - - - 具体的应用
│ ├── led - - - 比如LED应用
│ │ ├── file.mk - - - 每个应用单独一个file.mk,是一个编库的基本单位
│ │ ├── include - - - include中的头文件可以全局使用
│ │ │ └── led.h - - - 需导出的函数接口
│ │ └── led.c - - - 具体的应用代码
│ └── mboard - - - 板子初始化
│ ├── file.mk - - - 独立的file.mk
│ ├── include
│ │ └── mboard.h
│ ├── mboard.c - - - 初始化单片机时钟等
│ ├── mgpio.c - - - 例如初始化GPIO
│ └── mgpio.h - - - 非include目录下的头文件仅该目录下的C文件使用,不导出给其他目录的C文件使用
├── arch - - - 芯片相关文件
│ ├── crt0.S - - -启动汇编
│ ├── ram.lds - - - ram类(SRAM/DDR)运行时的链接脚本
│ └── rom.lds - - - rom类(FLASH)运行时的链接脚本
├── build - - - 编译时中间文件的存放目录
├── components - - - 完善的可重复使用的源码
│ └── mtools - - - 例如一套用于调试的源码
│ ├── file.mk - - - 单独一个file.mk,是一个编库的基本单位
│ └── include
├── drivers - - - 外设驱动
│ ├── file.mk - - - 单独一个file.mk,是一个编库的基本单位
│ └── include
├── file.mk - - - 根目录file.mk,必备文件,由它引用各个子目录的file.mk
├── main.c - - - C程序入口
├── Makefile - - - 必备文件,配置目标芯片的信息
└── tools - - - 编译的辅助工具,包括除make以外的其他工具
└── make - - - make辅助工具
├── clone.mk
├── create.sh
├── files.mk
├── help.mk
├── lib.mk
├── makefile
├── make.mk
├── qt.mk
├── slim.mk
└── tags.mk
3.2 预定义版本(BUILD_TYPE)
Makefile
和tools/make/makefile
中都有BUILD_TYPE
变量,该变量取值有四种,分别预置了一些参数,具体可以查看tools/make/make.mk
文件。
版本 | 预定义参数 | ||
---|---|---|---|
优化等级(-O) | 段回收(-gc) | 可调式(-g) | |
空 | 未定义 | 未定义 | 未定义 |
debug | O2 | 关闭 | g3 |
profile | O2 | GARBAGE_COLLECTION | g3 |
release | O2 | GARBAGE_COLLECTION | --strip-unneeded |
3.3 目标文件类型(TARGET_TYPE)
Makefile
中有TARGET_TYPE
变量,该变量取值有三种,在tools/make/makefile
中,该变量值固定为lib
。
类型 | 含义 |
---|---|
elf | 生成ELF文件,通常逻辑开发都会生成ELF文件,然后通过ELF文件生成BIN或HEX文件 |
exe | 生成主机可执行文件,比如编译一个在Linux下运行的程序,该类型与elf 的区别在于它不关心LINK_FILE 和CPU |
lib | 仅生成静态库,该类型不关心LINK_FILE ,最后会把所有.o 文件打包成静态库 |
3.4 运行类型(RUN_TYPE)
Makefile
中有RUN_TYPE
变量,该变量取值有两种,只有在TARGET_TYPE = elf
下有效,裸机开发时会经常切换运行类型
,ram
调试简单,而rom
是最终部署的方式。
类型 | 含义 |
---|---|
rom | 程序被链接在不可直接修改的地址区域中,比如flash等 |
ram | 程序被链接在可直接修改的地址区域中,比如sram等 |
3.5 生成的文件
该makefile生成的文件信息如下表所示,其中ELF可以派生出很多文件,需要在Makefile
中打开CREATE_
相关的变量:
目标文件类型 | 生成文件 | 说明 |
---|---|---|
lib | libxx.a | 静态库文件 |
exe | xx.exe | Windows下生成主机可执行文件 |
xx | Linux下生成主机可执行文件 | |
elf | xx.elf | ELF文件 |
xx.dis | 反汇编文件,不带源码 | |
xx.asm | 反汇编文件,带源码 | |
xx.bin | 二进制文件,用于烧写到存储器 | |
xx.hex | HEX文件,用于烧写到存储器 | |
xx.map | 链接地址映射文件 | |
xx.gc | 垃圾回收删除的段信息的文件 |
3.6 编译前后钩子
Makefile
中有两个变量,CMD_BEFORE
CMD_AFTER
,这两个变量可以赋值为一段bash语句,多条语句使用;
隔开,make会在编译开始前和编译完成后分别调用两个变量所代表的命令。
4. 打印文件列表
执行make files
,打印如下:
==================== file list ====================
-------------------- make file --------------------
drivers/file.mk
------------------ include file -------------------
drivers/…/…/drivers/include/rtc.h
------------------- source file -------------------
drivers/…/…/drivers/rtc.c
------------------- source path -------------------
drivers/…/…/drivers/
======================= end =======================
==================== file list ====================
-------------------- make file --------------------
file.mk
drivers/file.mk
apps/mboard/file.mk
-------------------- link file --------------------
arch/ram.lds
------------------ include file -------------------
apps/mboard/include/mboard.h
------------------ include path -------------------
drivers/…/…/drivers/include
apps/mboard/include
------------------- source file -------------------
main.c
apps/mboard/mboard.c
apps/mboard/rtc.c
------------------- source path -------------------
./
apps/mboard/
--------------------- asm file --------------------
arch/crt0.S
--------------------- asm path --------------------
arch/
--------------------- lib file --------------------
build/drivers/librtc.a
======================= end =======================
- 若工程处于
clean
状态,make files
会打印出include path
下所有的.h
文件 - 若工程编译后,
make files
仅打印出使用到的.h
文件 - 若工程有多次make,则
make files
会分别打印每个make的文件列表,会发现下面打印的是顶层的make,它不再包含../drivers/rtc.c
,而是包含build/drivers/librtc.a
5. 生成Qtcreator工程文件
执行make qt
,会生成.qt/all.pro
.qt/rtc.pro
.qt/stm32f072.pro
三个文件。其中.qt/all.pro
是其它.qt/xx.pro
的合并,因为工程会执行两次make,故而会有两个.qt/xx.pro
,它们俩包含的文件列表和make fiels
打印的一致,.qt/all.pro
每次都有生成。直接使用Qtcreator打开.qt/xx.pro
文件即可,下面是.qt/all.pro
文件内容:
DEFINES +=
HEADERS +=
…/drivers/…/…/drivers/include/rtc.h
INCLUDEPATH +=
…/drivers/…/…/drivers/include
…/apps/mboard/include
SOURCES +=
…/drivers/…/…/drivers/rtc.c
DISTFILES +=
…/drivers/file.mk
DEFINES +=
HEADERS +=
…/apps/mboard/include/mboard.h
INCLUDEPATH +=
…/drivers/…/…/drivers/include
…/apps/mboard/include
SOURCES +=
…/main.c
…/apps/mboard/mboard.c
…/apps/mboard/rtc.c
DISTFILES +=
…/file.mk
…/drivers/file.mk
…/apps/mboard/file.mk
…/arch/crt0.S
…/arch/ram.lds
6. 生成标签文件ctags
执行make tags
,会生成tags
文件,该文件通常给vim是要用,用于函数跳转,make tags
支持对目录外的参与编译的文件打标签。
- 若工程处于
clean
状态,make tags
会对include path
下所有的.h
文件以及所有C文件打标签 - 若工程编译后,
make tags
仅对使用到的.h
文件以及所有C文件打标签 - 若工程有多次make,则
make tags
会分别对每个make的文件列表打标签并追加到一起
7. 打印说明
执行make help
,会打印出该makefile的使用说明,使用说明的信息都写在了tools/make/help.mk
中。
make help LANG=zh
打印中文说明make help LANG=en
打印英文说明
8. 工程克隆
执行make clone
,会生成两个新的目录../stm32f072-clone
../rtc-clone
。工程克隆的意义在于:移除不参与编译的文件,把目录外的文件拷贝进来,使得工程更整洁,便于发布给别人使用。克隆后的工程如下:
$ cd …/stm32f072-clone - - - 顶层make的目标文件
$ tree
.
├── apps
│ └── mboard
│ ├── file.mk
│ ├── include
│ │ └── mboard.h
│ ├── mboard.c
│ └── rtc.c
├── arch
│ ├── crt0.S
│ └── ram.lds
├── drivers
│ ├── file.mk
│ └── librtc.a - - - 仅拷贝静态库,不拷贝源码
├── file.mk
├── main.c
├── Makefile
└── tools
└── make
├── clone.mk
├── files.mk
├── help.mk
├── lib.mk
├── make.mk
├── qt.mk
├── slim.mk
└── tags.mk
$ cd …/rtc-clone - - - 子make的目标文件
$ tree
.
├── drivers
│ ├── file.mk
│ ├── include
│ │ └── rtc.h
│ └── rtc.c - - - 源码(…/drivers/rtc.c)不在目录下,拷贝到目录下
├── file.mk
├── Makefile
└── tools
└── make
├── clone.mk
├── files.mk
├── help.mk
├── lib.mk
├── make.mk
├── qt.mk
├── slim.mk
└── tags.mk
- 若该目标目录
../xx-clone
存在,则make clone
直接退出 - 若工程未编译通过,则
make clone
直接退出 - 所有修改都在新的拷贝工程中,原工程不变
- 新拷贝的工程可以直接编译通过
- 若原工程存在未参与编译的C文件或头文件,则这些文件不予拷贝
- 若源码文件不在目录内,则会拷贝到目录内,也即新的工程不再含有外部目录的文件
- 若工程多次make,则分别拷贝成多个独立的工程
- 若在一次make中有静态库生成,也即仅通过修改
file.mk
但没有拷贝tools/make/makefile
,例如把drivers编译成一个静态库,则新的拷贝中仅有静态库而不会有编译静态的源码,这些源码也不会被拷贝成独立的工程 file.mk
中OTHER_FILE
所包含的文件也会被拷贝
9. 工程瘦身
使用make slim
,可以移除参与编译但未用到的C文件。
$ cd …/stm32f072-clone; make
-> main.c
-> apps/mboard/mboard.c
-> apps/mboard/rtc.c
-> arch/crt0.S
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
$ make slim; make clean; make
-> main.c - - - 可以发现少编译了一些文件
-> arch/crt0.S
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
$ apps/mboard/mboard.c
apps/mboard/mboard.c - - - 文件依旧存在
$ ./make_slim_bak/recover.sh - - - 恢复工程
$ make clean; make
-> main.c
-> apps/mboard/mboard.c - - - 文件又参与编译了
-> apps/mboard/rtc.c
-> arch/crt0.S
Complete !!!
type sram file
used 4180 ram profile
unused 16300 build/stm32f072.elf
- 该功能需要工程能编译通过
- 操作在原工程上进行,该功能仅移除
file.mk
中的项并不删除源码文件 - make会在修改file.mk前备份所有的file.mk到
make_slim_bak/
目录,执行./make_slim_bak/recover.sh
可以恢复到命令执行前的状态 - 该功能不能移除被指定编译为静态库的C文件
- 该功能是通过map文件中搜索
debug_info
字符串实现的,具体详看slim.mk