diff --git a/doc/qmk/01. Intro_Qmk_A_Makefile_Framework_For_TencentOS.md b/doc/qmk/01. Intro_Qmk_A_Makefile_Framework_For_TencentOS.md index 2f57f6b8..3e05aa46 100644 --- a/doc/qmk/01. Intro_Qmk_A_Makefile_Framework_For_TencentOS.md +++ b/doc/qmk/01. Intro_Qmk_A_Makefile_Framework_For_TencentOS.md @@ -7,19 +7,24 @@ qmk, 是TecentOS的一个Makefile编译框架。 ### Qmk 的特点 -- 多架构支持,支持多种 MCU ARCH、多种CC工具链; -- 使用简单,任意目录均可make; +- 使用简单,任意目录均可make,支持帮助`make help`; +- 支持Makefile调试,任何 目录`make BP= dm`打印Makefile 的所有变量值。 +- 支持编译调试, `make V=1`,`Make V=2`。 +- 支持宏扩展调试。`make E=1`。 +- 目录分离。源码,编译产物目录分离。 - 入门简单,新源码目录 Makefile 拷贝即可使用; -- 扩展性,简单的修改即可支持新MCU、新的board、新CC工具链的支持; -- 模板化,多种场景的Makefile拷贝即用; -- 耦合低,跟源码目录结构的耦合低; -- 子目录单独make支持,支持子目录编译.a静态库; +- 多架构支持。支持多种 MCU ARCH、多种CC工具链; +- 模板化。多种场景的Makefile拷贝即用; +- 配置化。board-pack提供mcu/arch/bsp等编译时参数、目录的配置; +- 耦合低。跟源码目录结构的耦合低; +- 子目录单独make支持。支持子目录编译.a静态库; + ## TencentOS的make编译 ### TencentOS的整体make ```shell # 进入board目录支持qmk的board -cd board/TencentOS_tiny_EVB_MX_Plus +cd board/TencentOS_tiny_EVB_MX_Plus/GCC-QMK # 本目录编译 make @@ -28,82 +33,94 @@ make make help ``` TencentOS的整体编译过程是: -3. 从`board/`下的顶级Makefile开始,该Makefile 确定BP 。 -3. make访问 `arch/`, 生成`libarch.a` 。 -3. make递归访问其他源码目录节点,各Makefile,生成`libxxx.a` 。 +- 先编译静态库 + +3. 从`board/`下的顶级Makefile开始,该Makefile 确定了BP 。 +3. Makefile 通过 `make -C BP=`访问各个目录,BP用于选择`qmk/board-pack`下的一个`bp.xxx`作为编译参数集合。 +3. `make -C BP=` 进入 `arch/` `kernel/` `platform/vendor_bsp`等需要的目录。 +3. make进入各个目录,根据`BP`,生成对应的`.a`静态库,如访问 `arch/`, 生成`libarch.a`,具备编译哪些arch/下的源码文件由`board-pack`确定。 +3. make递归访问其他源码目录,目录的`节点Makefile`通过BP渲染`include Make.tpl`模板生成。 +3. 依据目录的`节点Makefile`,生成`libxxx.a` 。 3. 各个源码目录节点,依次生成`.a`静态库文件,均位于 `build/`目录下 。 -3. make 回到 `board/`的顶级Makefile,使用`.a`静态库文件以及链接参数,进行链接。 -3. 整体构建完成。 + +- 再链接 +3. make 回到 `board/`的顶级Makefile。 +3. 需要链接生成`elf`的目录通过`include Make.exec` 。 +3. 编译本目录及其子目录下所有源文件,生成`.o`文件。 +3. 根据 `LD_A_FILES`和`LD_L_LISTS`进行链接。 +3. 整体链接完成,生成文件位于`build/`目录下。 ### TecentOS的子目录make ```shell # 进入某包含Makefile的目录 -cd kernel/core +cd kernel/ -# 本目录编译 +# 本目录编译,使用Linux_Posix作为Board-Pack make BP=Linux_Posix +# 本目录编译,使用TencentOS_tiny_EVB_MX_Plus作为Board-Pack +make BP=TencentOS_tiny_EVB_MX_Plus # 查看帮助 make help ``` 单目录的编译过程是: 3. make访问本目录,读取本目录Makefile,根据命令行`make BP=xxx`的BP,选择`mk/board-pack`。 -3. 根据BP选择的构建参数,以及`TREE_LIB_ENABLE`、`lib`进行编译。 +3. 根据BP选择的构建参数。 3. 使用ar进行打包,.a 文件放在`build/`目录。 3. 构建完成。 ## Qmk 的概念 ### generic-Makefile(mk/generic) - +`qmk/generic/Make.tpl` 属于这类。 又称全局通用型Makefile模板。位于 `mk/generic)`。 -要求对所有board、所有mcu arch适用。 +要求对所有board、所有gcc-toolchain、cpu、arch、bsp适用。 +所以一般只包含通用的规则。 -### board-Makefile(mk/board-pack) +### boardpack-Makefile(mk/board-pack) +`board-pack/bp.TencentOS_tiny_EVB_MX_Plus` 属于这类。 -又称板级Makefile模板。位于mk/board-pack 的 bp.${BP},属于board配置型Makefile。 +又称板级Makefile模板。是一个硬件产品工程开发过程中在编译时的参数抽象文件。 -一般只对某一个board适用。 -是一个硬件产品工程开发过程中,在编译时,工具链,arch、board等参数的抽象。 +位于mk/board-pack 的 bp.${BP},属于board配置型Makefile,需要确定工具链,mcu,arch、board、bsp等方面的编译时参数集合。 嵌入式应用开发工程师主要修改这部分Makefile。 -### arch-Makefile(mk/arch-pack) -又称 mcu arch 级别Makefile模板。位于mk/arch-pack 的 ap.xx,属于arch配置型Makefile。 +### srctree-Makefile +`kernel/Makefile` `arch/Makefile` 都属于这类。 +又称节点Makefile,位于各个源码目录的 Makefile。多个board都适用的Makefile,属于源码节点配置型Makefile。 -要求对同一类arch 的所有board适用。 -### src-Makefile节点 -又称节点Makefile,位于各个源码目录的 Makefile。 - -所有board都适用,属于源码节点配置型Makefile。 不能包含arch,board级别的编译参数。 - +### link-Makefile +`board/TencentOS_tiny_EVB_MX_Plus/GCC-QMK/app_tencent_os_mqtt/Makefile` 属于这类。 ## Qmk 的使用 ### 当前目录所有.c,编译成一个.a库 +`这类Makefile编写参考 osal/posix/Makefile`。 复制粘贴 以下 Makefile 内容到源码目录 Makefile。 无需修改。 -有特别的CFLAG请根据情况配置 `CFGFLAGS`。 > >3. 注意`TREE_LIB_ENABLE=0`,,cc和ar时,只搜索当前目录源码,不包含子目录; > >3. 注意`lib=`,表示链接后的库名使用目录名; +>3. 有特别的CFLAG请根据情况配置 `CFGFLAGS`。 >3. 注意板级的编译参数请配置到pack-Makefile,否则会导致其他pack编译报错. + ```Makefile ################################################################### #automatic detection QTOP and LOCALDIR -CUR_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) +CUR_DIR := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))) TRYQTOP := $(shell if [ -n "$$QTOP" ] ; then\ echo $$QTOP;\ else\ - cd $(CUR_DIR); while /usr/bin/test ! -d mk ; do \ + cd $(CUR_DIR); while /usr/bin/test ! -d qmk ; do \ dir=`cd ../;pwd`; \ if [ "$$dir" = "/" ] ; then \ echo Cannot find QTOP in $(firstword $(MAKEFILE_LIST)) 1>&2; \ @@ -127,17 +144,14 @@ TREE_LIB_ENABLE=0 lib= subdirs= -CFGFLAGS += -I${QTOP}/kernel/core/include -CFGFLAGS += -I${QTOP}/kernel/evtdrv/include -CFGFLAGS += -I${QTOP}/kernel/hal/include -CFGFLAGS += -I${QTOP}/kernel/pm/include +CFGFLAGS += -I$(CUR_DIR)/include -include ${QTOP}/mk/generic/Make.tpl +include ${QTOP}/qmk/generic/Make.tpl ``` ### 某目录及其子目录的所有.c,编译成一个.a库 - +`这类Makefile编写参考 kernel/Makefile`。 复制粘贴 以下 Makefile 内容到源码目录 Makefile。 无需修改。 有特别的CFLAG请根据情况配置 `CFGFLAGS`。 @@ -148,14 +162,15 @@ include ${QTOP}/mk/generic/Make.tpl >3. 注意板级的编译参数请配置到pack-Makefile,否则会导致其他pack编译报错. > + ```Makefile ################################################################### #automatic detection QTOP and LOCALDIR -CUR_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) +CUR_DIR := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))) TRYQTOP := $(shell if [ -n "$$QTOP" ] ; then\ echo $$QTOP;\ else\ - cd $(CUR_DIR); while /usr/bin/test ! -d mk ; do \ + cd $(CUR_DIR); while /usr/bin/test ! -d qmk ; do \ dir=`cd ../;pwd`; \ if [ "$$dir" = "/" ] ; then \ echo Cannot find QTOP in $(firstword $(MAKEFILE_LIST)) 1>&2; \ @@ -181,13 +196,15 @@ subdirs= CFGFLAGS += -I${QTOP}/kernel/core/include CFGFLAGS += -I${QTOP}/kernel/evtdrv/include +CFGFLAGS += -I${QTOP}/kernel/hal/include +CFGFLAGS += -I${QTOP}/kernel/pm/include -include ${QTOP}/mk/generic/Make.tpl +include ${QTOP}/qmk/generic/Make.tpl ``` ### 当前目录进入所有子目录、进入指定目录编译 - +`这类Makefile编写参考 platform/Makefile`。 复制粘贴 以下 Makefile 内容到源码目录 Makefile。 无需修改。 有特别的CFLAG请根据情况配置 `CFGFLAGS`。 @@ -195,15 +212,14 @@ include ${QTOP}/mk/generic/Make.tpl > 如果需要指定子目录请给`subdirs`赋值。 > - ```Makefile ################################################################### #automatic detection QTOP and LOCALDIR -CUR_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) +CUR_DIR := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))) TRYQTOP := $(shell if [ -n "$$QTOP" ] ; then\ echo $$QTOP;\ else\ - cd $(CUR_DIR); while /usr/bin/test ! -d mk ; do \ + cd $(CUR_DIR); while /usr/bin/test ! -e qmk ; do \ dir=`cd ../;pwd`; \ if [ "$$dir" = "/" ] ; then \ echo Cannot find QTOP in $(firstword $(MAKEFILE_LIST)) 1>&2; \ @@ -219,67 +235,94 @@ ifeq ($(QTOP),) $(error Please run this in a tree) endif LOCALDIR = $(patsubst %/,%,$(subst $(realpath $(QTOP))/,,$(CUR_DIR))) - #################################################################### TREE_LIB_ENABLE=0 lib= subdirs= -subdirs= subdir-a subdir-b -include ${QTOP}/mk/generic/Make.tpl + +include ${QTOP}/qmk/generic/Make.tpl + ``` -### 新增一个 board-pack +### 新增一个 board-pack,支持新的board + 参考 `mk/board-pack/`下的各个文件。 +参考 `qmk/board-pack/bp.TencentOS_tiny_EVB_MX_Plus`。 + board-pack 是对 board 在编译时的一个抽象。 -一个board 确定了 MCU arch、工具链、app(main入口),把这些编译时参数写成一个bp.xxx。 +一个board 确定了 MCU、 arch、工具链,把这些编译时参数写成一个bp.xxx。 -可以对同一个board 编写多个不同的board-pack,以满足同一个board下, -选用不通的工具链,编译参数不通,等需求。 +新整一个board-pack的步骤: +- qmk/board-pack/目录下,新建一个bp.xxx. +- 在bp.xxx定义以下变量: -## Qmk 的变量 -### QTOP 全局变量 -标识TencentOS 源码Toplevel目录绝对路径。 + 注意 CFGFLAGS 需要包括 cpu、arch、board 等类型的FLAG。 + 赋值建议用`+=`,不允许用 `:=`。注意 可以引用`QTOP`,`BLDROOT`变量,不建议引用其他`qmk/generic/`模板的变量。 -命令`git rev-parse --show-toplevel`可以显示。 +| Makefile变量名 | 变量赋值举例 | 变量说明 | +| :-------- | ------ | :--------------------- | +| CROSS_COMPILE | CROSS_COMPILE =arm-none-eabi- | 工具链前缀 | +| CC | CC = $(CROSS_COMPILE)gcc | 工具链 | +| CXX | CXX = $(CROSS_COMPILE)g++ | 工具链 | +| LD | LD = $(CROSS_COMPILE)ld | 工具链 | +| ARFLAGS | ARFLAGS = -rc | 工具链 | +| STRIP | STRIP = $(CROSS_COMPILE)strip| 工具链 | +| CFGFLAGS | 参考`bp.TencentOS_tiny_EVB_MX_Plus` | 对CFLAGS、CXXFLAGS 进行增加 | +| ARCH_LSRCS | 参考`bp.TencentOS_tiny_EVB_MX_Plus` | board-pack对应的arch/源码,`make -C arch/时需要编译的源码,绝对路径,或相对于QTOP的相对路径 | +| BSP_LSRCS | 参考`bp.TencentOS_tiny_EVB_MX_Plus` | board-pack对应的board/bsp源码 | +| PLATFORM_VENDOR_BSP_LSRCS | 参考`bp.TencentOS_tiny_EVB_MX_Plus` | board-pack对应的vendor_bsp 源码,`make -C platform/vendor_bsp时需要编译的源码 | +| PLATFORM_VENDOR_BSP_LSRCS | 参考`bp.TencentOS_tiny_EVB_MX_Plus` | board-pack对应的vendor_bsp 源码,`make -C platform/vendor_bsp时需要编译的源码 | +| PLATFORM_HAL_LSRCS | 参考`bp.TencentOS_tiny_EVB_MX_Plus` | board-pack对应的 hal 源码,`make -C platform/hal时 | -所有的Makefile都需要QTOP去寻找mk/下的Makefile模板。 - -### BP 全局变量 -选取board-pack,`make BP=Linux_Posix`会选取`mk/board-pack/bp.Linux_Posix` -board-pack 确定CC工具链、确定MCU的arch,确定,board的app源码目录。 +## Qmk 的模板的内置变量 -### V 调试变量 -VERBOSE 输出。编译时,`make V=1` 会打印命令行,用于调试编译过程。 - -### EEEE 调试变量 -CC 编译 .o 文件前,保存预处理文件.i。用于调试宏、头文件包含问题。 - -## Makefile 节点的关键变量 - -### TREE_LIB_ENABLE -控制编译时源码的范围。 - -`TREE_LIB_ENABLE=1`会处理当前目录及其所有子目录的源码。 -`TREE_LIB_ENABLE=`只处理当前目录源码。 - -可以参考`kernel/Makefile`,把整个`kernel/`编译成`libkernel.a` +| 变量名 |赋值| 变量值说明 | 值举例 | +| :-------- |:------|:------ |:------- | +|AR |bp中赋值| 工具链 | "arm-none-eabi-ar"| +|ARCH_LSRCS|bp中赋值| 进入arch/需要编译的源码,绝对路径或相对于QTOP的源码路径 | "/root/democode/TencentOS-tiny/arch/arm/arm-v7m/cortex-m4/gcc/port_c.c /root/democode/TencentOS-tiny/arch/arm/arm-v7m/cortex-m4/gcc/port_s.S /root/democode/TencentOS-tiny/arch/arm/arm-v7m/common/tos_fault.c /root/democode/TencentOS-tiny/arch/arm/arm-v7m/common/tos_cpu.c /root/democode/TencentOS-tiny/arch/arm/arm-v7m/cortex-m4/gcc/port_c.c /root/democode/TencentOS-tiny/arch/arm/arm-v7m/cortex-m4/gcc/port_s.S /root/democode/TencentOS-tiny/arch/arm/arm-v7m/common/tos_fault.c /root/democode/TencentOS-tiny/arch/arm/arm-v7m/common/tos_cpu.c "| +|ARFLAGS |bp中赋值 | 工具链参数|ar 参数,含义见`ar --help`| "-rc"| +|BLDDIR |禁止赋值|标识.o等编译产物所在的目录,跟源码LOCALDIR有关| "/root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos/arch"| +|BLDROOT |禁止赋值 | 标识编译产物位置目录。| "/root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos"| +|BLD_SUFFIX|禁止赋值 |编译产物位置目录的后缀名 | | ".tos"| +|BOBJS |禁止赋值 | 所有OBJ集合,绝对路径 | "/root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos/arch/arm/arm-v7m/cortex-m4/gcc/port_c.o /root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos/arch/arm/arm-v7m/cortex-m4/gcc/port_s.o /root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos/arch/arm/arm-v7m/common/tos_fault.o /root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos/arch/arm/arm-v7m/common/tos_cpu.o"| +|CC | bp中赋值 |"arm-none-eabi-gcc"| +|CROSS_COMPILE | 工具链 | "arm-none-eabi-"| +|CURDIR |禁止赋值|标识当前Makefile 所在的目录 | "/root/democode/TencentOS-tiny/arch"| +|CUR_DIR |禁止赋值|标识当前Makefile 所在的目录 | "/root/democode/TencentOS-tiny/arch"| +|CUR_MK_NODE_DIR |禁止赋值|标识当前Makefile 所在的目录 | "/root/democode/TencentOS-tiny/arch"| +|CXX |bp中赋值| "arm-none-eabi-g++"| +|LD |bp中赋值| "arm-none-eabi-ld"| +|LDFLAGS |bp中赋值 | " "| +|LOBJS |禁止赋值|OBJ文件集合,相对路径,相对于当前Makefile目录 | "arm/arm-v7m/cortex-m4/gcc/port_c.o arm/arm-v7m/cortex-m4/gcc/port_s.o arm/arm-v7m/common/tos_fault.o arm/arm-v7m/common/tos_cpu.o"| +|LOCALDIR |禁止赋值|源码目录位置,相对路径,相对于QTOP | "arch"| +|LSRCS |禁止在bp中赋值,可以在src-Makefile赋值|编译源代码文件集合,相对路径,相对于当前Makefile目录,或者绝对路径 | "arm/arm-v7m/cortex-m4/gcc/port_c.c arm/arm-v7m/cortex-m4/gcc/port_s.S arm/arm-v7m/common/tos_fault.c arm/arm-v7m/common/tos_cpu.c "| +|QTOP |禁止赋值|源码一级目录| "/root/democode/TencentOS-tiny"| +|RANLIB |bp中赋值 | "arm-none-eabi-ranlib"| +|STRIP |bp中赋值| "arm-none-eabi-strip"| +|TREE_LIB_ENABLE |src-Makefile赋值,非0 表示编译所有子目录源码| LSRCS是否把子目录源码 | "0"| +|lib |不建议赋值|`.a`库名变量,默认目录名| "libarch"| +|targetlib |禁止赋值| "/root/democode/TencentOS-tiny/build/TencentOS_tiny_EVB_MX_Plus.arm-none-eabi-gcc.tos/libarch.a"| -### CFGFLAGS -给当前目录编译时补充CFLAGS。 -会变成CFLAGS的一部分,传递给编译器。 - -### subdirs -`subdirs`控制make 递归进入哪些子目录。 -默认值为本目录下所有存在Makefile的子目录集合。 -需要进入指定子目录,请给`subdirs`赋值。 - -### lib -控制.a静态库的名称。默认值为本目录的名称。 +## qmk的 make 命令行参数 +```cookie +make help +``` +### make V=1 E=1 +```cookie +# verbose打印编译时的命令 +make V=1 +# 调试头文件包含,宏扩展时很有用,会在生成`.o`文件的同时生成`.i`预处理文件 +make E=1 +``` +```cookie +# verbose打印链接时的库搜索过程 +make V=2 +make V=3 +``` ## Qmk 后续 -3. Kbuild 方向,参考Linux-Kernel的Kbuild以及busybox的`Kbuild` diff --git a/qmk/generic/Make.exec b/qmk/generic/Make.exec index c12df6e6..027a1b87 100644 --- a/qmk/generic/Make.exec +++ b/qmk/generic/Make.exec @@ -18,7 +18,7 @@ targetexec = ${OUTDIR}/${exec}.elf all:: ${OUTDIR}/.tree ${targetexec} -$(info $(wildcard $(LIBDIR)/%.a) ) +$(info $(wildcard $(BLDROOT)/%.a) ) ifeq (,$(LD_O_FILES)) LD_O_FILES = $(sort $(BOBJS)) @@ -40,17 +40,17 @@ endif $(targetexec): $(OUTDIR)/.tree ${LD_O_FILES} @/bin/rm -f $@ # Prevent core dump if currently running @$(ECHO) "[$(BP)] LINK $@" # This is needed for error parsing - $(Q)/bin/ls $(LIBDIR) + $(Q)/bin/ls $(BLDROOT) $(Q)$(CC) \ $(patsubst -I%,,${CFLAGS} ${EXTRA_CFLAGS} ${LDFLAGS}) \ - -o $@ -L${LIBDIR} \ + -o $@ -L${BLDROOT} \ $(_LD_START_GROUP) $(LD_O_FILES) $(LD_A_FILES) $(_LD_END_GROUP) $(LD_L_LISTS) $(LD_INFO_OPTS) $(Q)$(STRIP) --strip-debug $@ -o $(OUTDIR)/$(basename $(notdir $@)).strip $(Q)$(OBJCOPY) -O binary -S $@ $(OUTDIR)/$(basename $(notdir $@)).bin $(Q)$(OBJCOPY) -O ihex $@ $(OUTDIR)/$(basename $(notdir $@)).hex - $(CP) $(OUTDIR)/$(basename $(notdir $@)).* $(LIBDIR)/ + $(CP) $(OUTDIR)/$(basename $(notdir $@)).* $(BLDROOT)/ @$(ECHO) -e "[$(BP)] INFO [$(BP)] INFO \e[1;32mLINK OK,OK,OK!!!\e[m" - @$(ECHO) -e "\e[1;32m$$(/bin/ls $(LIBDIR)/$(basename $(notdir $@)).*)\e[m" + @$(ECHO) -e "\e[1;32m$$(/bin/ls $(BLDROOT)/$(basename $(notdir $@)).*)\e[m" install:: all @@ -59,7 +59,7 @@ clean:: $(Q)$(RM) ${BOBJS} $(Q)$(RM) $(filter %.a ,$(LD_A_FILES)) $(Q)$(RM) $(OUTDIR)/$(basename $(notdir ${targetexec})).* - $(Q)$(RM) $(LIBDIR)/$(basename $(notdir ${targetexec})).* + $(Q)$(RM) $(BLDROOT)/$(basename $(notdir ${targetexec})).* distclean:: clean diff --git a/qmk/generic/Make.lib b/qmk/generic/Make.lib index 73eaf3c2..77806d3f 100644 --- a/qmk/generic/Make.lib +++ b/qmk/generic/Make.lib @@ -8,10 +8,10 @@ ifndef lib lib = lib$(shell basename ${LOCALDIR}) endif -targetlib = ${LIBDIR}/${lib}.a +targetlib = ${BLDROOT}/${lib}.a -${LIBDIR}/%.a: ${BOBJS} +${BLDROOT}/%.a: ${BOBJS} ifeq (@,$(Q)) @$(ECHO) "[$(BP)] ARLIB $(subst $(QTOP)/,,$@)" endif