1,工程构建
参见:https://github.com/alibaba/AliOS-Things/wiki/AliOS-Things-build-system
注意最新的AliOS Things 3.0版本如果使用VSCode IDE编译,需要安装AliOS Studio插件和aos-cube。
当在VSCODE中执行AliOS-Studio:Build的时候,会调用aos make app@board,比如这里我选择mqtt@stm32f429zi-nucleo,则会调用aos make mqtt@stm32f429zi-nucleo.
下面我们分析一下具体都做了什么。
1),调用关系:
aos make helloworld@linuxhost
|-- make()
|-- make_build()
|-- _run_make(arg_list)
|-- popen(make_cmd_str, shell=True, cwd=os.getcwd())
2)./build/Makefile
变量的值:build_dir = 'BUILD_DIR=./out/'app_dir = 'APPDIR=./'make_args = helloworld@linuxhostarg_list = ['-e', '-f build/Makefile', make_args, app_dir, build_dir]make_cmd = ./build/cmd/linux64/makemake_cmd_str = make_cmd + 'HOST_OS=Linux64' + 'TOOLS_ROOT=./build' + + list(arg_list)
其中,popen是Python的标准库中的subprocess包的类,用来fork一个子进程并运行一个外部程序,进入 ./build/Makefile
3)Makefile中最主要的是aos_target_config.mk,定义了构建关系。
由aos_target_config.mk生成所有组件的config.mk(包含组件源文件以来关系等信息),然后在编译、链接的时候由aos_target_build.mk依次调用,最终生成./out里面的可执行文件。
config.mk依赖于aos_target_config.mk来生成:
$(OUTPUT_DIR)/config.mk: $(MAKEFILES_PATH)/aos_target_config.mk $(MAKEFILES_PATH)/aos_host_cmd.mk
4)Makefile中的输出为main_app,以及out/config.mk中定义的输出和aos_target_build.mk中定义的输出,以及init-build-env创建的文件夹。
main_app: prebuild $(OUTPUT_DIR)/config.mk $(YOS_SDK_PRE_APP_BUILDS) $(MAKEFILES_PATH)/aos_target_build.mk init-build-env
$(if $(MBINS_ERROR), $(call MBINS_EXIT))
$(QUIET)$(ECHO) Build AOS Now
$(QUIET)$(ECHO) TOOLCHAIN_PATH=$(TOOLCHAIN_PATH)
$(QUIET)$(MAKE) -r $(JOBSNO) $(SILENT) -f $(MAKEFILES_PATH)/aos_target_build.mk $(CLEANED_BUILD_STRING) $(PASSDOWN_TARGETS)
$(QUIET)$(ECHO) Build complete: $(BUILD_STRING)
5)board\stm32f429zi-nucleo\aos.mk举例mk文件内容说明
NAME := board_stm32f429zi-nucleo
#编译硬件board基本信息;
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.1.1
$(NAME)_SUMMARY := configuration for board stm32f429zi-nucleo
MODULE := 1062
HOST_ARCH := Cortex-M4
HOST_MCU_FAMILY := mcu_stm32f4xx_cube
SUPPORT_MBINS := no
HOST_MCU_NAME := STM32F429ZIT6
ENABLE_VFP := 1
# 组件添加kernel_init netmgr两个组件,位于kernel/init,和network/netmgr,具体可以
# 参考这两个位置的*.mk文件获取编译加入了哪些源文件;
$(NAME)_COMPONENTS += $(HOST_MCU_FAMILY) kernel_init netmgr
# 添加源文件;
$(NAME)_SOURCES += aos/board_partition.c \
aos/soc_init.c \
mbmaster_hal/port_serial.c
$(NAME)_SOURCES += Src/stm32f4xx_hal_msp.c \
Src/can.c \
Src/timer.c \
Src/i2c.c \
Src/eth.c \
Src/gpio.c \
Src/usart.c \
Src/usb_otg.c \
Src/dma.c \
Src/main.c
$(NAME)_SOURCES += drv/board_drv_led.c
ywss_support ?= 0
GLOBAL_DEFINES += KV_CONFIG_TOTAL_SIZE=32768 #32kb
GLOBAL_DEFINES += KV_CONFIG_BLOCK_SIZE_BITS=14 #(1 << 14) = 16kb
#depends on sal module if select sal function via build option "AOS_NETWORK_SAL=y"
AOS_NETWORK_SAL ?= n
ifeq (y,$(AOS_NETWORK_SAL))
$(NAME)_COMPONENTS += sal
module ?= wifi.mk3060
else
HTTPD_ENABLED ?= y
$(NAME)_SOURCES += ethernetif.c
$(NAME)_SOURCES += httpserver-netconn.c
$(NAME)_COMPONENTS += lwip
endif
ifeq ($(COMPILER), armcc)
$(NAME)_SOURCES += startup_stm32f429xx_keil.s
$(NAME)_LINK_FILES := startup_stm32f429xx_keil.o
else ifeq ($(COMPILER), iar)
$(NAME)_SOURCES += startup_stm32f429xx_iar.s
else
$(NAME)_SOURCES += startup_stm32f429xx.s
endif
GLOBAL_INCLUDES += . \
aos/ \
Inc/
GLOBAL_CFLAGS += -DSTM32F429xx -DCENTRALIZE_MAPPING
ifeq ($(COMPILER),armcc)
GLOBAL_LDFLAGS += -L --scatter=board/stm32f429zi-nucleo/STM32F429ZITx.sct
else ifeq ($(COMPILER),iar)
GLOBAL_LDFLAGS += --config board/stm32f429zi-nucleo/STM32F429.icf
else
GLOBAL_LDFLAGS += -T board/stm32f429zi-nucleo/STM32F429ZITx_FLASH.ld
endif
CONFIG_SYSINFO_PRODUCT_MODEL := ALI_AOS_f429-nucleo
CONFIG_SYSINFO_DEVICE_NAME := f429-nucleo
GLOBAL_CFLAGS += -DSYSINFO_PRODUCT_MODEL=\"$(CONFIG_SYSINFO_PRODUCT_MODEL)\"
GLOBAL_CFLAGS += -DSYSINFO_DEVICE_NAME=\"$(CONFIG_SYSINFO_DEVICE_NAME)\"
# Keil project support
$(NAME)_KEIL_VENDOR = STMicroelectronics
$(NAME)_KEIL_DEVICE = STM32F429ZITx
可以看到一个mk文件的基本组成为:
其中全局是指编译所有组件时都要用到的设置,局部是指仅在编译本组件时用到。一个mk文件就是描述了一个组件的配置信息。其实配置的设定都可以在 _CFLAGS 和 _LDFLAGS中指定,包括链接使用的链接脚本。
具体实现说明
下面按照上面所说的要素来展开说明构建体系的具体实现,相关关键代码等:
1)工具链选择
宿主平台在aos.py中设置。辅助命令工具在 aos_host_cmd.mk 中设置,目前主要支持 windows 和 linux64 上两种编译宿主机平台。
编译工具链的设置,在aos_target_xx.mk和 aos_library_xx.mk中会设置。
2)找到源文件
编译命令通常是app名@board名,app和board即为查找所有依赖的两个入口组件。
依赖查找过程递归实现。
事实上上面的查找除了找到源文件之外还会解析出mk中定义编译选项等信息,实际上是在递归解析组件的mk文件。为后面的编译链接步骤做好准备。
3)config.mk生成
将上面递归解析出的mk中的信息存储在config.mk中:
config.mk其实就是把所有组件 mk 中的信息汇总到一起。而后面产生的opts文件则是针对每个组件把config.mk中信息重新组合到一起产生的一个独立的文件。
4)编译
编译命令, aos_target_build.mk中,每个组件的编译选项产生, aos_target_config.mk中。
5)链接
链接命令, aos_target_build.mk中
链接选项的产生, aos_target_config.mk中
二进制及其他处理
统一进行的二进制处理如strip等
关键宏调用关系梳理
FIND_COMPONENT --找到所有需要的组件 参数:所有基本组件,递归调用
PREPROCESS_TEST_COMPONENT --将所有测试所需的组件也加入到组件中,无参数
PROCESS_COMPONENT --解析每个组件的 mk,参数:所有组件
PROCESS_ONE_COMPONENT --解析一个组件,参数:某一个组件
WRITE_FILE_CREATE --在config.mk中写入所有相关信息,包括写入所有编译,链接选项到opts文件中。