编程语言语言运行时编译器解释器嵌入式【免费下载链接】mrubyLightweight Ruby项目地址https://gitcode.com/gh_mirrors/mr/mruby点击查看免费下载mruby 的 Amalgamation合并构建机制参照 SQLite 的分发模型把整个运行时压缩为mruby.c与mruby.h两个文件让宿主程序无需任何构建系统即可把 Ruby 解释器嵌入自己的 C 工程。本文从生成命令、嵌入编译、Gem 兼容性到MRB_AMALGAMATION宏与头部/源文件合并的底层原理逐层展开帮助你彻底掌握这一能力并在实际项目中直接落地。什么是 AmalgamationAmalgamation 将 mruby 的所有源文件合并为单一翻译单元中的两个文件见 amalgamation.mdmruby.h—— 按依赖顺序拼接的全部公共头文件mruby.c—— 按初始化顺序拼接的全部源码核心 Gem 编译后的 mrblib。这种分发方式与 SQLite 的 amalgamation 发行包思路一致使用者拿到两个文件复制进自己的工程即可不需要了解 mruby 内部的模块划分也不需要安装任何构建工具链。四大优势集成极简向项目添加的只有两个文件无需引入 mruby 的 Rake 构建体系。单一编译单元整个运行时在同一翻译单元内编译编译器可以在函数边界之间做跨文件优化如常量传播、内联这是多文件编译难以获得的优化空间。免构建系统任意符合 C 标准的编译器直接编译mruby.c即可不依赖 make、rake 或特定链接脚本。可移植核心运行时除标准 C 库外无外部依赖但注意下文「平台相关 Gem」一节中 HAL 引入的平台约束。生成 Amalgamation在仓库根目录执行rake amalgam任务定义位于 amalgam.rake它先为build/target/include下的 presym 头文件建立依赖:gensym再以MRuby::Amalgam生成头文件与源文件最后输出路径提示。生成物位于build/target/amalgam/ ├── mruby.h # 按依赖顺序拼接的全部头文件 └── mruby.c # 拼接的全部源码核心 gems mrblib使用自定义构建配置合并产物中包含构建配置里声明的 Gem。例如使用最小化配置MRUBY_CONFIGbuild_config/minimal.rb rake amalgamminimal.rb 是一个CrossBuild仅添加MRB_NO_STDIO宏产出体积明显更小。构建配置选定的 boxing 方式MRB_NAN_BOXING/MRB_WORD_BOXING/ 无 boxing、整数宽度如MRB_INT64等功能开关会一并决定mruby.h中mrb_value的布局因此生成 amalgamation 所用的配置与最终编译宿主程序时使用的头文件必须一致。在宿主程序中嵌入使用基本用法在你的 C 程序中包含唯一的头文件并调用标准 mruby API#include mruby.h int main(void) { mrb_state *mrb mrb_open(); mrb_load_string(mrb, puts Hello from mruby!); mrb_close(mrb); return 0; }mrb_load_string需要mruby-compilerGem见下文 Gem 兼容性。后续还可以使用mrb_load_file、mrb_funcall、mrb_vm_run等常规 API 扩展宿主能力。编译直接把mruby.c当作一个源文件参与编译并指向 amalgam 目录作为头文件搜索路径gcc -I./build/host/amalgam your_app.c ./build/host/amalgam/mruby.c -o your_app -lm-lm用于链接数学库mruby-math等 Gem 会用到。优化构建正式发布建议开启优化并关闭断言gcc -O2 -DNDEBUG -I./build/host/amalgam your_app.c ./build/host/amalgam/mruby.c -o your_app -lm-DNDEBUG与MRB_DEBUG的关系见下文「构建配置宏」一节amalgamation 刻意不把MRB_DEBUG写进mruby.h是否启用断言由编译者自己决定-DNDEBUG正是同一类选择。Gem 兼容性已知可用的 Gem以下 Gem 与 amalgamation 兼容在生成时被正确合并并保持功能mruby-compiler——mrb_load_string等加载/编译功能的前提mruby-eval——eval、Binding扩展类 Gemmruby-array-ext、mruby-string-ext、mruby-hash-ext、mruby-numeric-ext、mruby-range-ext、mruby-symbol-ext、mruby-proc-ext、mruby-kernel-ext、mruby-object-ext、mruby-class-ext、mruby-enum-ext、mruby-compar-ext功能类 Gemmruby-error、mruby-math、mruby-struct、mruby-bigint、mruby-rational、mruby-complexmruby-io配合当前激活的ports/name/HALmruby-task同样依赖ports/name/HAL。平台相关 GemHAL使用 HAL硬件抽象层的 Gem 会把平台相关代码合并进mruby.c。以mruby-io为例其 ports 目录 下提供posix/与win/两套端口若在 Linux 上构建生成物内嵌 POSIX 实现该mruby.c无法在 Windows 上编译。因此需要多平台产物的场景应当为每个目标平台或交叉构建配置分别生成一份 amalgamation。此外mruby-task的 mrbgem.rake 显示其端口还支持glib等后端并可通过conf.ports :glib选择——这类 Gem 的合并产物同样绑定所选端口。被排除的 Gem二进制 Gemmruby-bin-*会被自动排除它们各自带有main()入口如 mruby-bin-mruby 的入口而 amalgamation 产出的是库而非可执行程序。这也解释了 default.gembox 中为何将mruby-bin-mrbc、mruby-bin-debugger、mruby-bin-mirb、mruby-bin-mruby、mruby-bin-strip等命令与运行库分开管理。实现层面MRuby::Amalgam#library_gems正是以gem.name.start_with?(mruby-bin-)过滤掉这些 Gem见 amalgam.rb。示例配置为 amalgamation 定制一个最小可用配置原文档示例文件路径建议为build_config/amalgam.rb# build_config/amalgam.rb MRuby::Build.new do |conf| conf.toolchain :gcc conf.gem core: mruby-compiler conf.gem core: mruby-error conf.gem core: mruby-eval conf.gem core: mruby-array-ext conf.gem core: mruby-string-ext conf.gem core: mruby-hash-ext conf.gem core: mruby-io end生成MRUBY_CONFIGbuild_config/amalgam.rb rake amalgam输出体积典型体积随包含的 Gem 数量浮动mruby.h约 270–800 KBmruby.c约 1.4–6.9 MB。体积差异主要来自 Gem 的 C 源码、编译后的 mrblib如mrblib.c、gem_mrblib.c以及 X-macro 表的多次内联。追求极致体积时可参考build_config/minimal.rb的MRB_NO_STDIO思路关闭不需要的子系统。技术细节头文件处理合并mruby.h时实现见 amalgam.rb 的HEADER_ORDER与write_ordered_headers剥离 include guard去除每个头文件的#ifndef GUARD / #endif包裹使内容能直接拼接#define GUARD保留供后续#ifdef检查使用按依赖排序先基础类型mruby.h及其内联的value.h、object.h等再各功能头文件内部 include 注释化已被并入mruby.h的#include mruby/...被注释掉避免重复定义。boxing 头文件不直接平铺而是保留条件包含结构在 value.h 中按MRB_NAN_BOXING/MRB_WORD_BOXING/ 默认依次展开保证生成物与构建配置的mrb_value布局严格一致。Gem 自带头文件如mruby-compiler的mrc_*.h、vendored prism 头也会按依赖做 DFS 后序排序后并入无 include guard 的头文件被识别为 X-macro 表改为在每次 include 处内联而不是去重。源文件处理合并mruby.c时按初始化顺序拼接核心源码按CORE_SOURCE_ORDER排序allocf → readnum/readint → state → symbol → class → object → gc → …… → vm → load/dump → init保证函数定义与注册顺序正确X-macro 头内联如mruby/ops.h这类依赖调用点宏定义的头文件在每个 include 处整体内联而非注释掉局部文件内联#include xxx.cstub等局部文件如known_errors_def.cstub被读取后直接嵌入源码生成文件并入编译后的build/*/mrblib/mrblib.c与build/*/mrbgems/gem_init.cGem 注册表被写入源文件尾部。合并过程中还会处理两类冲突其一同一宏在不同源文件中语义不同如mrb_stat、CASE、NEXT等每个源文件结束后统一#undef清理见CONFLICTING_MACROS其二不同 Gem 的静态符号同名如mruby-bigint与mruby-regexp都有pool_alloc生成器会扫描各源文件的static定义对冲突符号用#define临时改名再在 Gem 源码段结束后#undef还原。MRB_AMALGAMATION宏的意义生成的mruby.c在一切内容之前定义MRB_AMALGAMATION其作用是标记当前翻译单元承载的是整个运行时而非单个源文件从而让那些按翻译单元规模请求编译器工作的源码保持与逐文件构建相同的优化边界。最典型的例子是 VM。mrb_vm_exec()携带__attribute__((flatten))该属性会把函数内部的所有调用递归内联到翻译单元允许的深度见 vm.c 中的 MRB_FLATTEN 定义在逐文件构建中内联在 VM 自身的静态操作码处理器处停止这正是该属性的设计意图在 amalgamation 中整个运行时处于同一翻译单元内联下探会触及分配 → 垃圾回收 → 异常抛出相互构成的调用环如mrb_realloc → mrb_realloc_simple → mrb_full_gc → sweep → mrb_realloc递归永不收敛——GCC 会在内联器中耗尽内存、连一个函数都发不出来因此 GCC 下 amalgamation 会丢弃该属性让mrb_vm_exec()像普通函数一样被优化Clang 能保持下探有界几秒内完成同样文件的编译且带属性比不带属性运行更快因此 Clang 保留该属性。这一取舍正是MRB_AMALGAMATION存在的原因它让 VM 源码知道现在是合并构建从而按平台差异调整优化策略。构建配置宏写进 mruby.h 的 defines生成mruby.h时构建所用的 defines 被写在首个#include之前见 amalgam.rb 的write_baked_defines/collect_build_defines这样宿主程序只要包含mruby.h就获得与生成时完全一致的mrb_value布局、整数宽度和功能集。写入内容包括构建配置显式声明的宏conf.cc.defines如MRB_NO_STDIO、MRB_INT64、boxing 选择Gem 贡献的宏spec.build.defines、spec.cc.defines如mruby-io声明的 HAVE_MRUBY_IO_GEM、mruby-task声明的MRB_USE_TASK_SCHEDULER。每个宏都用#ifndef包裹因此命令行重复传入同名宏不会产生重定义。但并非 Gem 声明的所有宏都会进入头文件MRB_*与MRBGEM_*被丢弃——前者改变mruby.h本身的解释方式如 value boxing属于整个构建的 ABI 决策不应由单个 Gem 决定后者是版本字符串不是合法 C 常量。Gem 若确有需要进入头文件的MRB_*宏应声明在spec.build.defines__STDC_*被丢弃由生成器自行为 amalgamation 写出所需的部分。位置安排在一切#include之前与普通构建中每个-D先于每个头文件的效果一致这保证了 libc feature test 宏的正确性。例如某 Gem 需要使用 GNU 扩展在mrbgem.rake中写spec.cc.defines _GNU_SOURCE该声明就能到达 amalgamation 使用者的普通编译器命令行反之若在 Gem 源码文件顶部直接写#define _GNU_SOURCE合并后该文件落在翻译单元中部、第一个 libc 头文件之后宏将完全失效。同时必须注意在合并后的翻译单元中Gem 的宏会作用于所有源文件而非像普通构建那样只作用于该 Gem 自己的对象。添加声明的宏_GNU_SOURCE、_DEFAULT_SOURCE是安全的而限制 libc 特性集的宏_POSIX_C_SOURCE、_XOPEN_SOURCE可能遮蔽其他源文件依赖的声明需要谨慎使用。有两类宏故意不写入mruby.h交由编译者自行决定MRB_DEBUG——它只决定mrb_assert是否生效与前面-DNDEBUG属于同类选择MRB_USE_CXX_EXCEPTION与MRB_USE_CXX_ABI——它们要求 C 编译器而mruby.c是纯 C写进头文件会导致生成物无法按原样编译。构建顺序mruby.c的拼接次序严格遵循初始化依赖与 amalgam.rake 中source_deps对mrblib.c、gem_init.c的依赖一致核心源码src/*.c按CORE_SOURCE_ORDERGem 源码mrbgems/*/src/*.c或core/*.c含所选端口源码与生成源码如mruby-compiler的 prism 生成物生成的 mrblibbuild/*/mrblib/mrblib.c即编译后的 Ruby 标准库字节码表Gem 初始化build/*/mrbgems/gem_init.c注册所有 Gem 的 init/final 函数。小结Amalgamation 让 mruby 的嵌入成本降到两个文件 一条编译命令rake amalgam生成产物宿主程序包含mruby.h并连同mruby.c一起编译即可。理解其背后的 include guard 剥离、依赖排序、X-macro 内联、静态符号改名、MRB_AMALGAMATION对 VM 内联策略的调节以及构建宏的烘焙规则能帮助你在定制配置、处理平台相关 Gem 和定位编译问题时做出正确的工程决策。进一步阅读可参考 doc/README.md 中的文档索引或在 amalgam.rb 中研读生成器的完整实现。赞分享编程语言语言运行时编译器解释器嵌入式【免费下载链接】mrubyLightweight Ruby项目地址https://gitcode.com/gh_mirrors/mr/mruby点击查看免费下载相关推荐mruby 编译与交叉编译完全指南从构建配置到嵌入集成nghttp2 内置 mruby 实战mruby 编译与交叉编译完全指南从构建配置到嵌入集成nghttp2 内置 mruby 实战 导读 mruby 是一套轻量级、可嵌入的 Ruby 实现其可观测性日志分析云原生流处理H2O 项目内嵌 mruby 的编译与构建配置完全指南H2O 项目内嵌 mruby 的编译与构建配置完全指南 mruby 是一套轻量级、可嵌入的 Ruby 实现其核心价值在于能编译成静态库 libmruby.a后端网络H2O 内置 mruby-json 完全指南在 mruby 处理器中解析与生成 JSONH2O 内置 mruby json 完全指南在 mruby 处理器中解析与生成 JSON mruby json 是面向 mruby轻量级嵌入式 Ruby的后端网络上一篇最前沿的方向awesome-harness-engineering 自进化Harness与元框架资源深度解析下一篇如何从零开发 Blockly 硬件扩展以 vk1633-display 为例的完整开发者指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考