Mbed OS 文档翻译 之 参考(贡献(工具(添加导出器)))

添加导出器

这是向 Arm Mbed OS 工具添加导出器的指南。首先,本文档描述了导出器的含义以及遵循的规则。然后,它涵盖了导出子系统和单个导出器的结构。最后,本文档提供了一些实现建议。

       注意: 所有路径都与 https://github.com/ARMmbed/mbed-os/ 相关。

导出器是什么

导出器是 Mbed OS 工具的 Python 插件,它使用 Arm Mbed CLI 将项目转换为专用于特定 IDE 的项目。为了获得最佳用户体验,导出器:

  • 从资源扫描中获取输入。
  • 使用构建配置文件中的标志。
  • 为每个生成的文件类型都有一个模板文件。例如,Eclipse CDT 项目将有一个用于 .project 文件的模板和一个用于 .cproject 文件的模板。
  • 不要调用 Mbed CLI。可以从网站导出,该网站不包含 Mbed CLI。

导出子系统结构

导出子系统被组织为一组公共代码和一组 IDE 或工具链特定插件。

公共代码包含在三个文件中:

  • tools/project.py 包含命令行界面并处理 Mbed OS 2 测试和 Mbed OS 5 项目之间的差异。
  • tools/export/__init__.py 包含 Arm Mbed 在线编译器和 project.py 使用的 API。此文件负责每个导出器必须执行的样板操作,例如扫描资源或收集工具链标志。
  • tools/export/exporters.py 包含所有插件的基类。它提供有用的导出器特定操作。

IDE 或工具链特定插件是一个 Python 类,它继承自 Exporter 类,并列在 tools/export/__ init__.py 导出器映射中。

常用代码

公共代码做了两件事:为插件设置内容,并提供一个有用的工具库供插件使用。

建立

设置代码扫描导出过程中使用的资源,并收集构建项目所需的配置。

这些步骤构造导出器映射中列出的导出器插件类之一的对象,并使用有用的属性填充该对象,包括:

  • toolchain - 一个 mbedToolchain 对象,可用于查询工具链的配置。
    • toolchain.target - 可用于查询目标配置的 Target 对象。
  • project_name - 项目的名称。
  • flags - mbedToolchain 实例在调用时将用于编译 c/cpp/asm 文件的标志。
  • resources - 一个 Resources 对象,包含许多导出器将发现有用的文件列表,例如 C 和 Cpp 源以及标头搜索路径。该插件应仅使用 Resources 对象的属性,因为这些方法仅在设置时使用。您可以在 tools/toolchains/__ init__.py 中查看所有可用的 Resources 类属性。

插件工具

另一半公共代码是一个供插件使用的库。此 API 包括:

  • gen_file 使用 Jinja2 从模板生成文件。
  • get_source_paths 返回包含程序集,C,C++ 文件等的目录列表。
  • group_project_files 对由其包含目录传入的所有文件进行分组。这些组适用于 IDE。

插件代码

插件代码包含在 tools/export 目录的子目录中,该目录以插件导出的 IDE 或工具链命名。

例如,uVision 导出器的模板和 Python 代码包含在目录 tools/export/uvision 中,Makefile 导出器的代码和模板包含在 tools/export/makefile 中。

该插件的 Python 代码是:

  1. 放入 __init__.py 文件。
  2. 导入到 tools/export/__ init__.py 中。
  3. 添加到导出器映射。

生成方法

每个导出器都需要实现一个方法 generate,该方法负责为 IDE 或插件所针对的工具链创建所有必需的项目文件。

该方法可以使用公共代码包括的任何属性和 API。

is_target_supported 类方法

每个导出器都通过类方法 is_target_supported 报告其特定的目标支持。使用目标调用此类方法,并且当导出器支持目标时,期望返回 True,否则返回 False。请求导出到 is_target_supported 的目标会返回 False,这是一个错误。

TOOLCHAIN 类变量

每个导出器都会报告它将用于通过类变量 TOOLCHAIN 编译源代码的特定工具链。

NAME 类变量

每个导出器通过类变量 NAME 报告导出器的名称。这与 tools/export/__ init__.py 导出器映射中的键匹配。

构建静态方法

CI 测试的插件必须实现构建方法。

此类静态方法在从继承自 Exporter 的类生成之后运行。它负责在用户指示编译时调用 IDE 或工具链所需的构建工具。它必须在成功时返回 0 或在失败时返回 -1。

实现示例插件

本节将介绍如何使用一个模板实现导出器 my_makefile,它是一个 Makefile。

您将创建两个文件并讨论它们的内容:带有 Python 插件代码的 __init__.py 和带有模板的 Makefile.tmpl。

由于此插件名为 my_makefile,因此您将所有支持代码放入 tools/export/my_makefile 中。

__init__.py 的 Python 代码

首先,使类成为 Exporter 的子类:

from tools.targets import TARGET_MAP
from tools.export.exporters import Exporter

class My_Makefile(Exporter):

定义名称,工具链和目标兼容性列表。类级静态变量包含这些。

将导出器命名为 my_makefile:

NAME = 'my_makefile'

此导出器使用 GCC_ARM 工具链进行编译:

TOOLCHAIN = 'GCC_ARM'

IDE 支持的所有目标都是 TARGET_MAP 包含的子集。像这样导入这个映射:

from tools.targets import TARGET_MAP

您可以说支持的目标将是支持 GCC_ARM 的 Mbed 目标的子集:

@classmethod
def is_target_supported(cls, target_name):
    target = TARGET_MAP[target_name]
    return "GCC_ARM" in target.supported_toolchains

实现 generate 方法

要生成 Makefile,您需要一个可执行文件将使用的目标文件列表。如果使用 .o 替换扩展名,则可以从源构建列表。

为此,请在所需的 generate 方法中使用以下 Python 代码:

to_be_compiled = [splitext(src)[0] + ".o" for src in
                  self.resources.s_sources +
                  self.resources.c_sources +
                  self.resources.cpp_sources]

此外,您可能需要链接某些库。使用 -l:GCC 命令行语法指定库:

libraries = ["-l:" + lib for lib in self.resources.libraries]

现在,通过填写不太复杂的资源来构建 Jinja2 模板渲染引擎的上下文:

ctx = {
    'name': self.project_name,
    'to_be_compiled': to_be_compiled,
    'object_files': self.resources.objects,
    'include_paths': self.resources.inc_dirs,
    'library_paths': self.resources.lib_dirs,
    'linker_script': self.resources.linker_script,
    'libraries': libraries,
    'hex_files': self.resources.hex_files,
}

要呈现模板,请将导出项目中的模板文件名,上下文和目标位置传递给库提供的 gen_file 方法:

self.gen_file('my_makefile/Makefile.tmpl', ctx, 'Makefile')

模板

现在您已将上下文对象传递给 Jinja2 模板呈现引擎,您可以查看模板 Makefile,tools/export/my_makefile/Makefile.tmpl。

有关更多信息,请参阅关于 Jinja2 模板中可用内容的文档

###############################################################################
# Project settings

PROJECT := {{name}}

# Project settings
###############################################################################
# Objects and Paths

{% for obj in to_be_compiled %}OBJECTS += {{obj}}
{% endfor %}
{% for obj in object_files %} SYS_OBJECTS += {{obj}}
{% endfor %}
{% for path in include_paths %}INCLUDE_PATHS += -I{{path}}
{% endfor %}
LIBRARY_PATHS :={% for p in library_paths %} {{user_library_flag}}{{p}} {% endfor %}
LIBRARIES :={% for lib in libraries %} {{lib}} {% endfor %}
LINKER_SCRIPT := {{linker_script}}

# Objects and Paths
###############################################################################
# Tools

AS      = arm_none_eabi_gcc -x assembler-with-cpp
CC      = arm_none_eabi_gcc -std=gnu99
CPP     = arm_none_eabi_gcc -std=gnu++98
LD      = arm_none_eabi_gcc

# Tools
###############################################################################
# Rules

.PHONY: all lst size

all: $(PROJECT).bin $(PROJECT).hex size

.asm.o:
	+@$(call MAKEDIR,$(dir $@))
	+@echo "Assemble: $(notdir $<)"
	@$(AS) -c $(INCLUDE_PATHS) -o $@ $<

.s.o:
	+@$(call MAKEDIR,$(dir $@))
	+@echo "Assemble: $(notdir $<)"
	@$(AS) -c $(INCLUDE_PATHS) -o $@ $<

.S.o:
	+@$(call MAKEDIR,$(dir $@))
	+@echo "Assemble: $(notdir $<)"
	@$(AS) -c $(INCLUDE_PATHS) -o $@ $<

.c.o:
	+@$(call MAKEDIR,$(dir $@))
	+@echo "Compile: $(notdir $<)"
	@$(CC) $(INCLUDE_PATHS) -o $@ $<

.cpp.o:
	+@$(call MAKEDIR,$(dir $@))
	+@echo "Compile: $(notdir $<)"
	@$(CPP) $(INCLUDE_PATHS) -o $@ $<

$(PROJECT).elf: $(OBJECTS) $(SYS_OBJECTS) $(LINKER_SCRIPT)
	+@echo "link: $(notdir $@)"
	@$(LD) -T $(filter %{{link_script_ext}}, $^) $(LIBRARY_PATHS) --output $@ $(filter %.o, $^) $(LIBRARIES)

建议实施

有几条前进道路可以导致易于维护的导出器:

  • 专门化或替代 GNU Arm Eclipse 导出器。
  • 专门化或别名 Eclipse + Make 导出器。
  • 专业化 Make 导出器。

GNU Arm Eclipse

如果您的 IDE 使用 Eclipse 并使用 GNU Arm Eclipse 插件,那么使用通用 GNU ARM Eclipse 对导出器进行专门化或别名化。

别名

如果您不需要导出的任何特化,那么使用 GNUARMEclipse 类替换 EXPORT_MAP 中的导出器类。例如,如果 KDS 满足所有这些要求,您可以:

EXPORTERS = {
     'iar': iar.IAR,
     'embitz' : embitz.EmBitz,
     'coide' : coide.CoIDE,
+    'kds' : gnuarmeclipse.GNUARMEclipse,
     'simplicityv3' : simplicity.SimplicityV3,
     'atmelstudio' : atmelstudio.AtmelStudio,
     'sw4stm32'    : sw4stm32.Sw4STM32,

专业化

如果您需要更多专业化并使用基于 Eclipse 的 IDE 和 GNU Arm Eclipse 插件,那么您的导出器类将继承自 GNUARMEclipse 类。例如(再次使用 KDS):

from tools.export.gnuarmeclipse import GNUARMEcilpse

class KDS(GNUARMEcilpse):
     NAME = 'Kinetis Design Studio'
     TOOLCHAIN = 'GCC_ARM'
     ...

     def generate(self):
         """Generate eclipes project files, and some KDS specific files"""
         super(KDS, self).generate()
         ...

继承自 GNUARMEclipse 类之后,以您需要的任何方式专门化 generate 方法。

Eclipse + Make

如果您的 IDE 使用 Eclipse 而不使用 GNU Arm Eclipse 插件,则可以使用 “Unmanaged makefile” Eclipse 导出器类,EclipseGcc,EclipseArmc5和EclipseIar。与 GNU Arm Eclipse 部分非常相似,您可以决定别名或专门化。

Make

如果您的 IDE 不是基于 Eclipse 但仍可以使用 Makefile,那么您可以专门化 Makefile 导出器。专门研究 Makefile 实际上是 Arm Mbed 如何实现 Eclipse + Make 导出器。

基于 Makefile 导出器创建导出器的过程分为两步:从相应的 Makefile 类继承,并调用其 generate 方法。以 Eclipse + Make 使用GCC Arm为例,您的导出器如下所示:

class EclipseGcc(GccArm):
    NAME = "Eclipse-GCC-ARM"

您的 generate 方法类似于:

    def generate(self):
        """Generate Makefile, .cproject & .project Eclipse project file,
        py_ocd_settings launch file, and software link .p2f file
        """
        super(EclipseGcc, self).generate()
        ...
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值