- 语言运行时
- 嵌入式
- 物联网
- 编译器
【免费下载链接】jerryscript
Ultra-lightweight JavaScript engine for the Internet of Things.
本篇指南围绕 JerryScript 仓库中的 Mbed OS 移植目标(targets/os/mbedos)展开,完整讲解如何在 Ubuntu 20.04 环境下,把超轻量级 JavaScript 引擎 JerryScript 与 ARM Mbed OS 6.15.0 组合编译为 FRDM-K64F 开发板固件,并通过 ST-Link 烧录、串口终端运行出第一行Hello, World!。读完本文,你将掌握 Mbed OS 移植目标的目录结构、构建参数(板型 / 工具链 / 堆大小)的调整方法、make构建与烧录的完整命令链,以及移植层jerry-port.cpp与主程序jerry-main.cpp的底层实现原理。
一、目标平台与整体思路
targets/os/mbedos是 JerryScript 官方为FRDM-K64F 开发板 + Mbed OS 实时操作系统提供的移植目标目录。FRDM-K64F 是恩智浦(NXP)推出的 Kinetis K64F(ARM Cortex-M4F)评估板,通过板载 OpenSDA 调试器以 USB 直连主机;Mbed OS 则是 ARM 主导的物联网嵌入式操作系统,提供串口、定时器等抽象层。
整个移植思路分三步:
- 将 JerryScript 引擎源码与 Mbed OS 源码放在同一工作目录(如
jerry-mbedos)下; - 用仓库自带的移植层文件(
jerry-main.cpp、jerry-port.cpp)把引擎“接”到 Mbed OS 的串口与时间服务上; - 通过
mbed-tools compile产出.bin固件,烧录进开发板后用串口终端观察 JS 执行结果。
该目录包含 7 个文件,职责划分如下:
| 文件 | 作用 |
|---|---|
| Makefile | 封装mbed-tools compile,提供make/make flash/make clean目标及板型、工具链、堆大小等参数 |
| Makefile.travis | 供 CI(Travis)验证用的构建目标,也适合在本地复现自动化构建 |
| jerry-main.cpp | 移植目标的主程序:初始化引擎、注册print、解析并执行 JS 脚本 |
| jerry-port.cpp | 引擎移植层(Port API)实现:致命错误、日志输出、本地时区、当前时间 |
| mbed_lib.json | Mbed 库配置,向编译期注入 JerryScript 全局堆大小宏 |
| mbedignore.txt | Mbed 构建排除清单,避免把无关目录编入固件 |
| README.md | 官方构建与烧录说明(本文主体) |
二、搭建构建环境(Step 1)
官方文档验证于Ubuntu 20.04操作系统。首先在工作目录下建立jerry-mbedos文件夹,并克隆两个项目:JerryScript 本体,以及指定版本分支的 Mbed OS。文档明确给出的最新测试可用版本为mbed-os-6.15.0。
mkdir jerry-mbedos && cd jerry-mbedos git clone https://github.com/jerryscript-project/jerryscript.git git clone https://github.com/ARMmbed/mbed-os.git -b mbed-os-6.15.0克隆完成后应得到如下目录结构:
jerry-mbedos + jerryscript | + targets | + os | + mbedos + mbed-os需要说明的是,克隆 JerryScript 时若使用本仓库(gh_mirrors/je/jerryscript)作为源码根目录,构建时其路径即对应上述结构中的jerryscript目录;Makefile 通过JERRY_ROOT_DIR = $(realpath $(JERRY_TARGET_DIR)/../../..)(见 Makefile)自动定位引擎根目录,因此目录相对位置必须保持:targets/os/mbedos位于引擎根目录之下,且与mbed-os平级。
三、安装构建依赖(Step 2)
在jerry-mbedos目录下依次执行依赖安装。首先是 JerryScript 自带的依赖脚本,然后是 ST-Link 烧录工具与 Mbed 命令行工具链:
# Assuming you are in jerry-mbedos folder. jerryscript/tools/apt-get-install-deps.sh sudo apt install stlink-tools pip install --user mbed-cli # Install Python dependencies of Mbed OS. pip install --user -r mbed-os/requirements.txt各依赖的作用如下:
tools/apt-get-install-deps.sh:JerryScript 仓库自带的 Ubuntu 依赖安装脚本(位于 tools/apt-get-install-deps.sh),负责安装构建所需的编译工具链等基础软件;stlink-tools:ST-Link / OpenSDA 烧录工具,FRDM-K64F 板载调试器即 OpenSDA,通过该工具完成固件写入;mbed-cli:Mbed 命令行工具(老版本mbed-cli;新版本项目亦使用mbed-tools,见 Makefile 中的mbed-tools compile);mbed-os/requirements.txt:Mbed OS 的 Python 依赖清单,包含编译配置所需的jsonschema、pyyaml等包。
此外,CI 流程(Makefile.travis)展示了等效的依赖安装方式:pip3 install mbed-tools setuptools并安装../mbed-os/requirements.txt,可作为脚本化部署的参考。
四、编译固件(Step 3)
依赖就绪后,在jerry-mbedos目录下执行:
# Assuming you are in jerry-mbedos folder. make -C jerryscript/targets/os/mbedos MBED_OS_DIR=${PWD}/mbed-osMBED_OS_DIR用于告知 Makefile 去哪里找 Mbed OS 源码。整个构建链路在 Makefile 中清晰可见:
.extra-files-copy:把mbedignore.txt复制为引擎根目录下的.mbedignore、把mbed_lib.json复制为根目录下的mbed_lib.json,让 Mbed 构建系统读取这些配置;.mbed-build:调用mbed-tools compile,并携带--clean --mbed-os-path $(MBED_OS_DIR) --program-path $(JERRY_ROOT_DIR) --toolchain $(TOOLCHAIN) --mbed-target $(BOARD) --app-config $(JERRY_ROOT_DIR)/mbed_lib.json参数;.extra-files-remove:构建结束后清理临时复制的两个文件。
构建完成后,固件输出为jerryscript/build/mbed-os目录下的mbedos.bin文件,可直接用于烧录。
4.1 可调构建参数
Makefile 顶部定义了四个可用变量(Makefile):
| 变量 | 默认值 | 含义 |
|---|---|---|
BOARD | K64F | Mbed 目标板型号,默认 FRDM-K64F,可替换为其他 Mbed 支持板型 |
TOOLCHAIN | GCC_ARM | 编译工具链,默认 ARM GCC |
BUILD_DIR | $(JERRY_ROOT_DIR)/build/mbed-os | 构建产物输出目录,可通过命令行覆盖 |
JERRY_HEAP_SIZE | 70 | JerryScript 全局内存堆大小(单位 KB) |
JERRY_HEAP_SIZE通过 mbed_lib.json 中的"macros": ["JERRY_GLOBAL_HEAP_SIZE=70"]注入编译宏。从引擎侧看,config.h 中该宏的默认值是512(KB),而 Mbed 移植目标将其缩减为70KB,这是为适应 K64F 的 256 KB SRAM 所做的内存预算。修改堆大小时只需更改mbed_lib.json中的宏值,注意引擎在 config.h 中会校验该宏必须大于 0,堆大小最终通过CONFIG_MEM_HEAP_SIZE (JERRY_GLOBAL_HEAP_SIZE * 1024)(见 jcontext.h)换算为字节数参与内存分配。
4.2 mbedignore.txt 的作用
Mbed 构建系统默认会扫描程序根目录(即 JerryScript 引擎根目录)下的全部源码,而 JerryScript 仓库含有大量与 Mbed 无关的目录(cmake、docs、tests、tools 等)。mbedignore.txt 通过cmake/*、docs/*、jerry-main/*、jerry-math/*、targets/*、tests/*、third-party/*、tools/*这 8 条规则将这些目录排除出编译范围,从而显著缩短编译时间、避免无关代码进入固件。
五、烧录固件(Step 5)
用 Micro-USB 线连接开发板(该接口同时承担充电与烧录功能),在jerry-mbedos目录下执行:
# Assuming you are in jerry-mbedos folder. make -C jerryscript/targets/os/mbedos MBED_OS_DIR=${PWD}/mbed-os flashflash目标在 Makefile 中实现:先通过.mbed-set-flash-flag给MBED_CLI_FLAGS追加--flash参数,再执行正常构建;mbed-tools compile --flash会调用stlink-tools把mbedos.bin写入板载调试器连接的 K64F 芯片。
六、串口连接与运行验证(Step 5)
烧录完成后,开发板会在宿主机上显示为串口设备/dev/ttyACM0。使用minicom以115200波特率连接:
sudo minicom --device=/dev/ttyACM0 --baud=115200连接后需要做两件事:
- 在 minicom 中按组合键
CTRL-A -> Z -> U,打开Add Carriage Ret(回车符自动追加)选项——由于移植层日志输出只发送\n,终端需要该选项才能正确换行; - 按下开发板上的
RESET按钮,触发固件重新运行。
复位后,串口终端将打印 JerryScript 应用输出:
This test run the following script code: [print ('Hello, World!');] Hello, World!第一行是主程序用调试级别日志打印的待执行脚本源码,第二行Hello, World!则是脚本中print调用在串口上的真实输出,证明 JS 引擎已在 Cortex-M4F 上完整跑通。
七、源码级解析:Hello World 背后的移植实现
7.1 主程序 jerry-main.cpp
jerry-main.cpp 演示了在嵌入式平台上使用 JerryScript C API 的完整生命周期,可视为最小可运行的引擎调用范式:
jerry_init (JERRY_INIT_EMPTY):初始化引擎(空初始化,不启用快照等特性);jerry_log (JERRY_LOG_LEVEL_DEBUG, "This test run the following script code: [%s]\n\n", script):打印待执行脚本;jerryx_register_global ("print", jerryx_handler_print):调用 jerry-ext 扩展层(jerryscript-ext/handlers.h)把print注册为全局函数,其实现会把参数转成字符串输出;jerry_parse+jerry_run:先解析脚本生成可执行代码,再在全局作用域执行;- 用
jerry_value_is_exception判断执行是否出错,据此返回0(成功)或1(失败); jerry_value_free释放返回值,最后jerry_cleanup ()清理引擎。
串口输出最终落到 stderr 上——这是由移植层的jerry_port_log决定的(见下节),因此在 minicom 中看到的就是print与jerry_log混排的输出。
另外,jerry-main.cpp 中根据MBED_MAJOR_VERSION区分了 Mbed OS 5 与 6 的串口类:版本 5 使用Serial,版本 6 使用BufferedSerial,均以 115200 波特率初始化,未支持版本会触发#error编译失败。
7.2 移植层 jerry-port.cpp
jerry-port.cpp 实现了 JerryScript 要求宿主机提供的 Port API(接口定义见 jerryscript-port.h),共四个函数:
jerry_port_fatal:致命错误处理,直接以错误码调用exit;jerry_port_log:日志输出实现——逐字符写入 stderr,并在每个\n前追加\r,这正是文档要求在 minicom 中开启Add Carriage Ret的原因;若终端侧不补\r,\n会被终端解释为仅换行不回车,导致输出错位;jerry_port_local_tza:本地时区偏移,嵌入式环境固定返回 0(即 UTC);jerry_port_current_time:当前时间(毫秒级),是移植中最精妙的部分——它以time(NULL)提供秒级基准,以us_ticker_read()提供微秒级增量;由于us_ticker_read()约每 71 分钟(UINT_MAX微秒)溢出一次,代码用静态变量记录上一次的 tick 与 time,检测到 tick 回绕时累计33ms的校正量skew(见 jerry-port.cpp),从而在无独立定时器线程的 MCU 上维持可用的毫秒级时钟。
正是jerry_port_current_time等底层服务,支撑起 JS 侧Date对象、setTimeout类功能(若上层脚本使用)的时间来源。
八、自动化构建参考(CI 流程)
如需在脚本或 CI 中复现整个流程,可参考 Makefile.travis 的目标拆解:
install-mbedos:克隆指定分支的 Mbed OS(示例中使用mbed-os-6.17.0,README 主体则以6.15.0为准),clone 到../mbed-os;install-mbedos-deps:安装mbed-tools、setuptools及 Mbed OS 的 Python 依赖;script:执行make -C targets/os/mbedos MBED_OS_DIR=$(realpath ../mbed-os)完成编译。
注意 CI 使用的是新版mbed-tools(pip3 install mbed-tools),而 README 中安装的是旧版mbed-cli;Makefile 的构建命令始终是mbed-tools compile,因此若你的环境同时存在两者,建议优先使用mbed-tools以保证与 Makefile 调用一致。
九、常见问题与调参建议
- 固件找不到:确认构建命令带有
MBED_OS_DIR=${PWD}/mbed-os且目录结构符合第二节;产物固定输出在jerryscript/build/mbed-os/mbedos.bin。 - 串口无输出:检查是否开启了 minicom 的
Add Carriage Ret(CTRL-A -> Z -> U),并确认波特率为 115200;jerry_port_log输出走 stderr,某些串口工具需开启“合并 stderr”或直接观察全部输出。 - 编译缓慢 / 无关代码被编译:确认
.mbedignore已由 Makefile 自动复制到引擎根目录(mbedignore.txt内容见 mbedignore.txt);make clean会清理build/mbed-os及临时复制文件。 - 内存不足 / 脚本过大:调整 mbed_lib.json 中的
JERRY_GLOBAL_HEAP_SIZE(单位 KB,须大于 0,见 config.h),同时权衡 K64F 的 256 KB SRAM 预算。 - 更换开发板:通过
make ... BOARD=<板型>覆盖默认的K64F,并确保该板型在 Mbed OS 中被支持。
至此,你已经完成了从源码克隆、依赖安装、固件编译、烧录到串口运行的全部闭环,并且在源码层面理解了 Mbed OS 移植目标中主程序、移植层与构建脚本的协作方式——这套流程同样适用于后续在 Mbed OS 平台上接入其他 JerryScript 应用逻辑(如 GPIO 控制、传感器读取等物联网场景)的二次开发。
- 语言运行时
- 嵌入式
- 物联网
- 编译器
【免费下载链接】jerryscript
Ultra-lightweight JavaScript engine for the Internet of Things.
相关推荐
在 ESP32 上运行 JerryScript:基于 ESP-IDF 的构建、烧录与串口验证全指南
在 ESP32 上运行 JerryScript:基于 ESP IDF 的构建、烧录与串口验证全指南 JerryScript 作为面向物联网的超轻量级 JavaS
语言运行时嵌入式物联网编译器JerryScript 在 RIOT OS 上的嵌入式移植:STM32F4-Discovery 从构建、烧录到运行完整指南
JerryScript 在 RIOT OS 上的嵌入式移植:STM32F4 Discovery 从构建、烧录到运行完整指南 本文基于 JerryScript 官
语言运行时嵌入式物联网编译器Zephyr 在 Qualcomm QCC744M EVK(qcc744m_evk)评估板上的构建、烧录与串口调试实战指南
Zephyr 在 Qualcomm QCC744M EVK(qcc744m_evk)评估板上的构建、烧录与串口调试实战指南 Qualcomm QCC744M 评
操作系统嵌入式RTOS物联网
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考