自从2020年12月接触OpenHarmony后,就开始对GN + Ninja的构建系统非常感兴趣。然后自己尝试着借鉴OpenHarmony的构建系统做了纯GN + Ninja实现的mcu构建系统,并借鉴了buildroot的envsetup.sh脚本,制作了简化构建命令和切换开发板的脚本。
为什么我会坚持用GN + Ninja 作为构建系统呢?主要是 GN + Ninja 构建系统有以下几个优点:
GN + Ninja 构建系统的缺点
口说无凭,我们可以看一下实际的效果
全新编译大约260个文件的(已清理过编译产物),包含腾讯TinyOS内核以及LVGL的项目,耗时仅需要5.12秒。在配置比较老的机子(例如6年前的I5处理器),也可以做到30秒内完成全新编译。开启ccache后,几乎任意电脑都可以在0.5秒内完成。
该工程大致组件和资源占用情况如图
如何查看工程的编译参数和依赖(已添加注释)
$ mdesc
// 目标配置和工具链
Target //hardware/board/ra4m2_dev:ra4m2_dev
type: executable
toolchain: //build/toolchain:arm_none_eabi_gcc
// 这里省略了一些没用的信息
// 使用到的build目录的config内容
configs (in order applying, try also --tree)
//build/config:compiler
//build/config/Renesas:ra4m2
//build/config/Renesas:default
// 编译产物最终路径和名称
outputs
//out/ra4m2_dev/bin/ra4m2_dev
// 汇编文件编译选项
asmflags
-mcpu=cortex-m33
-mthumb
-mfloat-abi=hard
-mfpu=fpv5-sp-d16
-g
-x
assembler-with-cpp
// C源码文件编译选项
cflags
-mcpu=cortex-m33
-mthumb
-mfloat-abi=hard
-mfpu=fpv5-sp-d16
-g
-O2
-fmessage-length=0
-fsigned-char
-ffunction-sections
-fdata-sections
-fdiagnostics-color=always
-fno-builtin
-fno-strict-aliasing
-Wunused
-Wuninitialized
cflags_c
-MP
-MD
-std=gnu99
cflags_cc
-std=c++11
// 公共宏定义
defines
LV_CONF_INCLUDE_SIMPLE
D_RA_CORE=CM33
D_RENESAS_RA_
// 公共头文件目录
include_dirs
//applications/dummy/
//drivers/include/
//components/lvgl/v8.3/
//components/cli/include/
//hardware/board/ra4m2_dev/
//hardware/chip/ra4m2/ra/fsp/inc/
//hardware/chip/ra4m2/ra/fsp/inc/api/
//hardware/chip/ra4m2/ra/fsp/inc/instances/
//hardware/chip/ra4m2/ra/arm/CMSIS_5/CMSIS/Core/Include/
//hardware/board/ra4m2_dev/src/
//hardware/board/ra4m2_dev/ra_cfg/fsp_cfg/
//hardware/board/ra4m2_dev/ra_cfg/fsp_cfg/bsp/
//hardware/board/ra4m2_dev/ra_gen/
// 链接选项
ldflags
-mcpu=cortex-m33
-mthumb
-mfloat-abi=hard
-mfpu=fpv5-sp-d16
-g
-O2
-T
../../hardware/chip/ra4m2/ra/fsp.ld
--specs=rdimon.specs
-nostartfiles
-Xlinker
--gc-sections
// 依赖树
Direct dependencies (try also "--all", "--tree", or even "--all --tree")
//hardware/board/ra4m2_dev:bsp
//hardware/chip/ra4m2:ra4m2_sdk
BUILD.gn文件的配置内容
# Executable for board --------------------------------------------------
#
# Executable target configuration.
#
# Setting up configeration fot chip and board.
executable("ra4m2_dev") {
# Common deps for executable target.
# --------------------------------
deps = [
":bsp",
"//hardware/chip/${chip}:${chip}_sdk",
]
# 开启RTOS内核支持,因目前未适配暂时不开启
# deps += [ "//kernel/TinyOS:kernel" ]
# 如果需要依赖工具链自带的库,用下面的写法,自定义库需要使用相对路径
# libs = [ "printf" ]
}
# 板级配置目录
# --------------------------------
source_set("bsp") {
sources = [
"ra_gen/common_data.c",
"ra_gen/hal_data.c",
"ra_gen/main.c",
"ra_gen/pin_data.c",
"ra_gen/vector_data.c",
"src/hal_entry.c",
]
}
product.gni文件配置内容
declare_args() {
# 工具链名称(指向build/toolchain/arm_none_eabi_gcc.gni)
# --------------------------------
compiler = "arm_none_eabi_gcc"
# gcc,检测工具链用
# --------------------------------
gcc = "arm-none-eabi-gcc"
# 芯片型号
# --------------------------------
chip = "ra4m2"
# 厂商
# --------------------------------
vendor = "Renesas"
# 应用
# --------------------------------
app = "dummy"
# RTOS内核
# --------------------------------
kernel = "None"
# bin类型
# --------------------------------
build_type = "release"
# ccache缓存是否开启
# --------------------------------
ccache = true
}
然后板级支持这边是搞定了,接下来搞芯片级支持目录
新建hardware/chip/ra4m2目录,并拷贝示范代码(e2 studio生成的)里的ra目录到该目录下。然后编写BUILD.gn文件。
路径为hardware/chip/ra4m2/BUILD.gn
文件内容为(可以在e2 studio 里清理构建后重新构建一次,拷贝需要编译的c文件列表)
source_set("ra4m2_sdk") {
sources = [
"ra/fsp/src/bsp/cmsis/Device/RENESAS/Source/startup.c",
"ra/fsp/src/bsp/cmsis/Device/RENESAS/Source/system.c",
"ra/fsp/src/bsp/mcu/all/bsp_clocks.c",
"ra/fsp/src/bsp/mcu/all/bsp_common.c",
"ra/fsp/src/bsp/mcu/all/bsp_delay.c",
"ra/fsp/src/bsp/mcu/all/bsp_group_irq.c",
"ra/fsp/src/bsp/mcu/all/bsp_guard.c",
"ra/fsp/src/bsp/mcu/all/bsp_io.c",
"ra/fsp/src/bsp/mcu/all/bsp_irq.c",
"ra/fsp/src/bsp/mcu/all/bsp_register_protection.c",
"ra/fsp/src/bsp/mcu/all/bsp_rom_registers.c",
"ra/fsp/src/bsp/mcu/all/bsp_sbrk.c",
"ra/fsp/src/bsp/mcu/all/bsp_security.c",
"ra/fsp/src/r_ioport/r_ioport.c",
]
}
接下来把示范代码(e2 studio生成的)里的 script/fsp.ld 和 Debug/memory_regions.ld 拷贝到 hardware/chip/ra4m2/ra目录下
然后修改hardware/chip/ra4m2/ra/fsp.ld文件的第5行,将memory_regions.ld的相对路径补全,否则链接时会失败。
/*
Linker File for Renesas FSP
*/
INCLUDE ../../hardware/chip/ra4m2/ra/memory_regions.ld
然后板级配置就完成了。
创建目录和文件,配置文件的路径是build/config/Renesas/BUILD.gn(默认会去build/config/{vendor
}/ 路径查找位置,vendor 参数由板级支持的product.gni文件提供)
build/config/Renesas/BUILD.gn的具体配置,可以从e2 studio 的示范代码里,查看makefile挖出来。主要是需要设置芯片类型,浮点支持,以及链接脚本,公共头文件等内容。
config("default") {
defines = [
"D_RA_CORE=CM33",
"D_RENESAS_RA_",
]
cflags = []
cflags += [
"-fmessage-length=0",
"-fsigned-char",
"-ffunction-sections",
"-fdata-sections",
"-fdiagnostics-color=always",
# "-fno-common",
"-fno-builtin",
"-fno-strict-aliasing",
]
cflags += [
"-Wunused",
"-Wuninitialized",
]
ldflags = [
"-nostartfiles",
"-Xlinker",
"--gc-sections",
]
asmflags = [
"-x",
"assembler-with-cpp",
]
}
config("ra4m2") {
cflags = [
"-mcpu=cortex-m33",
"-mthumb",
"-mfloat-abi=hard",
"-mfpu=fpv5-sp-d16",
]
asmflags = cflags
cflags += [
"-g",
"-O2",
]
asmflags += [ "-g" ]
cflags_c = [ "-std=gnu99" ]
cflags_cc = [ "-std=c++11" ]
ldflags = cflags
ldflags += [
"-T",
"../../hardware/chip/${chip}/ra/fsp.ld",
"--specs=rdimon.specs",
]
include_dirs = [
"//hardware/chip/${chip}/ra/fsp/inc",
"//hardware/chip/${chip}/ra/fsp/inc/api",
"//hardware/chip/${chip}/ra/fsp/inc/instances",
"//hardware/chip/${chip}/ra/arm/CMSIS_5/CMSIS/Core/Include",
"//hardware/chip/${chip}/ra/fsp/inc/api",
"//hardware/board/${product}/src",
"//hardware/board/${product}/ra_cfg/fsp_cfg",
"//hardware/board/${product}/ra_cfg/fsp_cfg/bsp",
"//hardware/board/${product}/ra_gen",
]
}
添加完毕后,就可以愉快的编译啦。
在命令行进入 git clone 下来的目录,运行以下指令加载环境
source build/envsetup.sh
若之前有配置好产品目标,则按上一次配置目标配置环境,并显示相关信息。
接下来运行 lunch 选择产品,ra4m2_dev
选择产品后会输出相关信息,并检查gn、ninja、工具链是否安装,对应路径(没安装的需要自行手动安装)
然后运行mbuild就可以开始编译了,因为文件非常少,2秒左右就完成了(ccache 命中缓存仅需 0.5秒以内)。
查看编译产物的目录,可以看到成功生成了bin、elf等文件
使用psize命令查看资源汇总使用情况,也和e2 studio 示范项目的资源使用情况差不多(flash部分的组件占用信息分析错误,需要再调整map分析代码)
开源项目链接地址: 死龙的MCU游乐场
更多回帖