|
xt-sdk 文档 v1.0.3
xt-sdk 嵌入式 SDK API 参考
|
| 文档版本 | 修改日期 | 修改内容 |
|---|---|---|
| v1 | 2026-05-09 | 调整为通用设计梳理文档,修正 builddir 相关结论,补充装配流程、组件覆盖、循环依赖和版本注入设计。 |
| v2 | 2026-06-16 | 重构:溶解 xt_core 为平台聚合层、platforms/components/ 收敛为单一 xtiny target 聚合所有 API 头文件路径(平台无关叶子节点)、引入 标准工具库 标准库、废弃 xt_port/xt_sdk_target/xt_sdk_platform_set_enable。平台实现侧通过 add_deps("xtiny") 统一拿 API 头文件,规避循环依赖。 |
梳理 xt-sdk xmake 构建系统 v2 的设计,覆盖:
v2 采用"API 定义 → 平台实现 → 标准组件 → 工程"四层装配:
flowchart TD
A[1. platforms/components/] --> B[2. platforms/<plat>/<target>/]
B --> C[3. components/]
C --> D[4. 用户工程]
D --> E[5. platforms/<plat>/xmake.lua]
顶层的实际装配顺序:
这个顺序的关键含义:
platforms/components/ 不再为每个 xt_xxx API 单独创建 target。整个目录收敛为**唯一一个** target:xtiny。
xtiny 关键特征:
xtiny 是仅次于 标准工具库 的最小系统接口聚合点。任何依赖它的 target 都能直接 #include "xt_hal.h"、#include "xt_log.h" 等,无需关心来自哪个 target。
flowchart TD
app["app (binary)"] --> xt_main["xt_main (用户工程)"]
xt_main --> xt_core["xt_core (static)"]
xt_core --> xtiny
xt_core --> impls["各实现 target (static)"]
impls --> xtiny
impls --> priv["平台私有 target (xt_soc 等)"]
xt_core 由 platforms/<plat>/<target>/xmake.lua 定义,将一个平台需要的能力 target 聚合为单一依赖入口。以 Windows 平台为例:
平台实现 target 模板(以 xt_hal(HAL 驱动总入口) 为例):
**为什么放弃同名 target merge**:
旧设计下,每个 xt_xxx API target 独立存在(xt_hal(HAL 驱动总入口)、xt_log 等),平台实现侧通过**同名 target merge** 关联。这导致循环依赖无法根治:
同名 merge 把"API 头文件路径"和"实现层依赖"绑死在同一个 target,业务上必然出现的双向引用无法解耦。
**xtiny 单一聚合如何解决**:
把"API 头文件路径"从每个 xt_xxx target 抽离,统一收口到 xtiny 这个 headeronly target。xtiny 不依赖任何平台实现,是依赖图的叶子节点。
xtiny 通过 add_includedirs(<每个子目录>, {public=true}) 显式列举所有 API 子目录,不依赖每个 API target 自身的 public include 传播——这是设计能成立的关键。
顶层 xmake.lua 当前依赖:
| 环境变量 | 作用 |
|---|---|
| XT_SDK_ROOT | SDK 根目录 |
| XT_SDK_PROJECT_PATH | 用户工程路径 |
| XT_SDK_TARGET_PATH | 平台 target 路径 |
| XT_SDK_TOOLCHAIN | 工具链路径 |
其中 XT_SDK_PROJECT_PATH、XT_SDK_TARGET_PATH、XT_SDK_TOOLCHAIN 都是当前构建的关键前提。
scripts/env.lua 当前做了 4 件事:
xt_sdk_build_dir() 当前返回:
也就是说,它已经明确把产物目录绑定到工程目录,而不是 SDK 根目录。
env.lua 当前负责"解析、归一化和校验",但不负责统一 xmake 的配置缓存目录、工作目录和中间文件路径语义。因此:
README 中写"目前必须切到示例目录",这一点当前实现上是成立的。
根因不是 targetdir / objectdir,而是顶层 xmake.lua 里这一句:
这里的 .build 是相对路径,相对的是当前工作目录,而不是 XT_SDK_PROJECT_PATH。虽然顶层后面又通过 xt_sdk_build_dir() 设置了:
但 xmake 内部仍有一部分配置和临时文件受 builddir 的相对路径影响。实际试过把它改成绝对路径时,xmake 内部又会把它转回相对路径,从而导致 .d 等文件的位置出现问题。
因此当前阶段 README 的结论应保持不变:
如果直接用 xmake 构建,必须先切到示例目录,再执行顶层 xmake.lua。
这一点不是操作习惯,而是当前实现的现实约束。
顶层 xmake.lua 重写了 target(name)。它做的事情不是改 target 的本义,而是给每个被声明的 target 先隐式加上一层:
这样做的目的是:
组件被 includes() 进来,不等于它就应该参加默认构建。
否则只要被扫描到的组件,都有机会进入默认编译链,工程就很难控制真正需要的依赖集合。
最终二进制 target(如 app)通过 set_default(true) 把整条依赖链拉起来。v2 不再需要 v1 的 xt_sdk_platform_set_enable 中转。
当前用户组件覆盖系统组件,不是通过替换文件完成的,而是通过 target 名优先级实现的。
流程如下:
这样用户组件就自然覆盖了系统同名组件。
这个机制已经有正式示例:
平台实现需要 SDK 头文件,但 target 依赖保持单向:
通过 xtiny 收口 API 头文件路径 + 单向实现层依赖:
允许 API 头文件全局可见,不允许 target 图形成闭环。
xtiny 本身不依赖任何平台实现 target,所以平台实现之间的相互引用不会通过 xtiny 形成环。
顶层 xmake.lua 会在 on_config 里处理版本信息。优先级是:
最终由 xt_sdk_version(SDK 版本号) 组件把这些 config 导出为公开宏。
这里解决的是两件事:
xtiny 是仅次于 标准工具库 的最小系统接口聚合点,定位上升到平台 API 头文件库——所有 API(xt_hal、xt_log、xt_audio 等)的头文件路径都通过它传播。
**xtiny 的硬性使用方式**:平台实现 target 想拿 API 头文件,必须 add_deps("xtiny")。这是构建机制的硬性要求。
**xtiny 的隐性使用约定**(约定俗成,非机制强制):
**关于隐性约定**:旧设计(同名 merge)下 xtiny 不能被平台组件依赖,否则破坏循环依赖规避。新设计下 xtiny 已经是叶子节点,平台组件依赖它不会形成循环。但"业务组件按需依赖具体 xt_xxx"仍然是推荐做法——纯粹出于依赖关系可读性,而非硬性约束。
虽然 xtiny 单一聚合了所有 API 头文件路径,任何 add_deps("xtiny") 的 target 编译器都能"看见"全部 API 头文件,但**平台实现组件源码仍应仅 #include 与本组件职责相关的头文件**。
**核心规则**:
**为什么这条很重要**:
**反面例子**(违反约定):
**正面例子**(遵循约定):
**当前已知不规范用法**:platforms/lm620_internal/components/ 下部分源码(如 xt_hal/xt_hal_internal.h、platform_entry/main.c 等)直接 #include "xtiny.h",属于历史遗留的不规范用法,未来会逐步改造为按需 include 具体头文件。新组件应从一开始就遵循本约定。
**机制 vs 约定**:xtiny 的聚合保证头文件路径全局可见(机制),但源码层的 include 仍受组件职责约束(约定)。两者不冲突——前者解决构建便利和循环依赖,后者保证代码组织清晰。
| v1 设计 | v2 替代 |
|---|---|
| xt_sdk_platform_set_enable | 二进制 target 直接 set_default(true) |
| xt_sdk_platform phony 转发 | 二进制 target 自身作为入口 |
| xt_port / xt_sdk_target | 平台实现直接成独立 static target |
| $(xt_core_path) 头文件路径 | xtiny target 的 public include 传播 |
| xt_core 作为 SDK 核心组件 | 标准工具库 作为标准库,xt_core 作为平台聚合入口 |
| 同名 target merge 关联 API 与实现 | xtiny 单一聚合 API 头文件路径 |
set_config("builddir", ".build") 的相对路径行为决定了当前仍须切到示例目录执行。这是 v1 的遗留约束,v2 未改变。
| 维度 | v1 | v2 |
|---|---|---|
| API 层 | xt_core 组件内嵌 | platforms/components/ 收敛为 xtiny 单一 target |
| 标准库 | xt_core/components/utils/ | components/xt_std/ |
| 平台实现 | xt_port phony → xt_sdk_target | 独立 static target,add_deps("xtiny") 拿 API 头文件 |
| 平台入口 | xt_sdk_platform phony | xt_core static 聚合 |
| 启用机制 | xt_sdk_platform_set_enable | 二进制 target set_default(true) |
| 用户依赖 | add_deps("xt_core")(SDK 组件) | add_deps("xt_core")(平台聚合) |
| 总头文件 | components/xt_core/xtiny.h | platforms/components/xtiny/ |
| 加载顺序 | target → 工程 → components → 平台 | platforms/components → target → components → 工程 → 平台 |
| 循环依赖 | $(xt_core_path) include path | xtiny 收口 API 头文件路径 |