最近对AliOS-Things感兴趣,根据官网的快速开始可以很方便的在Linux下编译出来helloworld的范例并运行。
编译的命令行如下:
aos make helloworld@linuxhost
利用该命令即可编译出在linux下运行的基于AliOS-Things的helloworld的例程。
敲一下which aos,找到aos的路径,直接vi打开aos:
from aos.aos import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(main())
可以看到这里直接调用了aos.py里面的main函数,aos.py是aos-Cube的一个脚本,在快速开始中是通过pip install aos-cube直接安装的。一般可以在”/lib/python2.7/site-packages/aos/aos.py”中找到aos.py。
代码下载后直接解压打开aos.py,定位到main函数,发现main函数在try中会将命令aos传入的参数解析成command进行调用:
try:
very_verbose = pargs.very_verbose
verbose = very_verbose or pargs.verbose
info('Working path \"%s\" (%s)' % (os.getcwd(), Repo.pathtype(cwd_root)))
status = pargs.command(pargs)
继续定位到make命令的实现部分,make函数将第二个入参之后的参数也就是helloworld@linuxhost传递给了make_build之后又传递给了_run_make:
# Make command
@subcommand('make',
help='Make aos program/component',
description="Make aos program/component.")
def make():
...
# Get the make arguments
args = sys.argv[2:]
...
make_build(make_args)
_run_make中又组装了一个make_cmd_str 后通过popen进行了Linux调用
# Run make command
make_cmd_str = ' '.join([make_cmd, 'HOST_OS=' + host_os, 'TOOLS_ROOT=' + tools_dir] + list(arg_list))
popen(make_cmd_str, shell=True, cwd=os.getcwd())
在make_build和_run_make中加几行调试信息来检查传递的参数信息,输出如下:
Makefile TestInfo: make_args in make_build - helloworld@linuxhost
Makefile TestInfo: arg_list in _run_make - ['-e', '-f build/Makefile', 'helloworld@linuxhost']
Makefile TestInfo: make_cmd_str in _run_make - /home/shenwei/AliOS-Things/build/cmd/linux64/make HOST_OS=Linux64 TOOLS_ROOT=/home/shenwei/AliOS-Things/build -e -f build/Makefile helloworld@linuxhost
可以看出,我们的编译参数helloworld@linuxhost从make_build进去后,就被加上了编译选项,然后传递给了_run_make,在_run_make中确定了使用的make程序的版本后通过popen进行了调用执行。
在make_build中我们确定了编译使用的makefile是-f build/Makefile,打开这个文件,我们直奔主题:
main_app: $(OUTPUT_DIR)/config.mk $(YOS_SDK_PRE_APP_BUILDS) $(MAKEFILES_PATH)/aos_target_build.mk
main_app依赖两个mk,config.mk和aos_target_build.mk。想当然一下,aos_target_build.mk是通用的,config.mk是在这里自动生成的,不同的project使用的源代码一定是不一样的,先重点看下config.mk都搞了些什么(其实build一次后,可以在out/helloworld@linuxhost/config.mk中看到,所有的源代码都include在这个mk中)。
config.mk依赖于aos_target_config.mk来生成:
$(OUTPUT_DIR)/config.mk: $(MAKEFILES_PATH)/aos_target_config.mk $(MAKEFILES_PATH)/aos_host_cmd.mk
在编译的时候,注意到会有如下输出:
processing components: helloworld linuxhost platform/mcu/linux vcall init auto_component
其中helloworld和linuxhost就是通过我们传递的target字符串helloworld@linuxhost解析出来的:
# Separate the build string into components
COMPONENTS := $(subst @, ,$(MAKECMDGOALS))
其他的components都是在aos_target_config.mk中进行自动添加的:
# Process all the components + AOS
COMPONENTS += platform/mcu/$(PLATFORM_MCU_BOARD) vcall init
ifneq ($(ONLY_BUILD_LIBRARY), yes)
COMPONENTS += auto_component
endif
.......
对应在aos_target_config.mk中就是进行了如下处理:
$(info processing components: $(COMPONENTS))
$(eval $(call FIND_COMPONENT, $(COMPONENTS)))
# remove repeat component
$(eval COMPONENTS := $(sort $(COMPONENTS)) )
$(eval $(call PROCESS_COMPONENT, $(COMPONENTS)))
FIND_COMPONENT先不管,直接看PROCESS_COMPONENT都干了些啥,先是定义了TEMP_MAKEFILE,这个语句感觉十分复杂,具体的各个参数功能可以自行百度,总之最后的结果就是找到build所需要的mk文件:
$(eval TEMP_MAKEFILE :=
$(strip
$(wildcard
$(foreach dir,
$(if $(filter-out out, $(BUILD_DIR)),$(OUTPUT_DIR) $(OUTPUT_DIR)/syscall,)
$(if $(APPDIR),$(APPDIR)/$(comp),)
$(if $(CUBE_AOS_DIR),$(CUBE_AOS_DIR) $(CUBE_AOS_DIR)/remote)
$(addprefix $(SOURCE_ROOT),$(COMPONENT_DIRECTORIES)),
$(dir)/$(COMP_LOCATION)/$(COMP_MAKEFILE_NAME).mk
)
)
)
)
简单粗暴点,我们加上一句info来看看这句的输出,可以看到,这句语句就找到了我们编译所需要的各个component的mk文件:
TEMP_MAKEFILE: ./platform/arch/linux/linux.mk
TEMP_MAKEFILE: ./out/helloworld@linuxhost/auto_component/auto_component.mk
TEMP_MAKEFILE: ./tools/cli/cli.mk
TEMP_MAKEFILE: ./kernel/hal/hal.mk
TEMP_MAKEFILE: ./example/helloworld/helloworld.mk
TEMP_MAKEFILE: ./kernel/init/init.mk
TEMP_MAKEFILE: ././kernel/vfs/device/device.mk
TEMP_MAKEFILE: ./board/linuxhost/linuxhost.mk
TEMP_MAKEFILE: ./utility/log/log.mk
TEMP_MAKEFILE: ././platform/mcu/linux/linux.mk
TEMP_MAKEFILE: ./kernel/rhino/rhino.mk
TEMP_MAKEFILE: ./kernel/vcall/vcall.mk
TEMP_MAKEFILE: ./kernel/vfs/vfs.mk
TEMP_MAKEFILE: ./kernel/yloop/yloop.mk
再继续往下看, (NAME)_LOCATION和(NAME)_SOURCES就根据TEMP_MAKEFILE找到了所有的include和source文件:
$(eval $(NAME)_LOCATION := $(dir $(TEMP_MAKEFILE)))
$(eval $(NAME)_SOURCES := $(sort $($(NAME)_SOURCES)) )
加个打印确认下:
$(info NAME_LOCATION: $($(NAME)_LOCATION))
$(info NAMESOURCES : $($(NAME)_SOURCES))
......
TEMP_MAKEFILE: ./kernel/hal/hal.mk
NAME_LOCATION: ./kernel/hal/
NAMESOURCES : ota.c wifi.c
TEMP_MAKEFILE: ./example/helloworld/helloworld.mk
NAME_LOCATION: ./example/helloworld/
NAMESOURCES : helloworld.c
......
完整的走一遍makefile的过程总算了解了AliOS-Things根据target的名称来找到对应的源代码的方式,所以在搞这个的时候应该是要注意不要定义同名的文件夹。。。否则可能会出现莫名其妙的编译问题吧。。。。>_<