一个有惊喜的makefile

1. 简介


这里我将介绍一个我日常使用的makefile框架,我本人开发单片机裸机程序较多,故这里分享给大家的makefile主要偏向于裸机开发,适合新人上手,但其中有一些技巧我个人觉得有一定的参考价值。mkefile相关文件:GitHubCSDN(后续还有更新,小改动优先更新GitHub),文章更新:一个有惊喜的makefile

1.1 功能

目前该makefile具备了以下功能:

  • 支持在Linux和Windows(git-bash)上运行(git-bash需要额外下载make.exectags.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.mkmakefile的主体文件,会根据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.ldsmake.mk
unused 16300  build/stm32f072.elf

2.2 两种编译模型

此处介绍两个编译模型,其具体指的是make如何搜索源文件进行编译。

  • VPATH模式

该模式和make的vpath命令有关,其原理是:我们把.S .c的路径都告诉vpathmain.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

修改MakefileVPATH_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/makefiledrivers/目录下(需注意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;makemake 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.aMakefile,使得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)

Makefiletools/make/makefile中都有BUILD_TYPE变量,该变量取值有四种,分别预置了一些参数,具体可以查看tools/make/make.mk文件。

版本预定义参数
优化等级(-O)段回收(-gc)可调式(-g)
未定义未定义未定义
debugO2关闭g3
profileO2GARBAGE_COLLECTIONg3
releaseO2GARBAGE_COLLECTION--strip-unneeded

3.3 目标文件类型(TARGET_TYPE)

Makefile中有TARGET_TYPE变量,该变量取值有三种,在tools/make/makefile中,该变量值固定为lib

类型含义
elf生成ELF文件,通常逻辑开发都会生成ELF文件,然后通过ELF文件生成BIN或HEX文件
exe生成主机可执行文件,比如编译一个在Linux下运行的程序,该类型与elf的区别在于它不关心LINK_FILECPU
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_相关的变量:

目标文件类型生成文件说明
liblibxx.a静态库文件
exexx.exeWindows下生成主机可执行文件
xxLinux下生成主机可执行文件
elfxx.elfELF文件
xx.dis反汇编文件,不带源码
xx.asm反汇编文件,带源码
xx.bin二进制文件,用于烧写到存储器
xx.hexHEX文件,用于烧写到存储器
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.mkOTHER_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
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值