
Fluent Bit 中基于 WAMR 的 WASM 应用编译使用 clang 编译器与 Docker 构建 wasm 二进制【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit导读本文围绕 Fluent Bit 仓库内置的 WebAssembly Micro RuntimeWAMR所附带的《使用其他 WASM 编译器》文档系统讲解如何在 Linux 环境下使用标准clang编译器以 clang-8 为例将 C 源码编译为可供 WAMR 运行时执行的.wasm二进制以及如何借助 Docker 容器化工具链完成同样工作。读完本文你将掌握 clang 直连编译的完整命令行参数语义stack/initial-memory/export/no-entry/strip-all 等、apt.llvm.org 仓库源的配置方法、wasm-ld 软链接的建立并能结合 WAMR 的iwasm与 Fluent Bit 的filter_wasm插件理解这些编译选项在真实产品链路中的作用。关联文档位于仓库内 lib/wasm-micro-runtime-WAMR-2.4.1/doc/other_wasm_compilers.md它是 WAMR 官方《构建 WASM 应用》系列文档build_wasm_app.md中关于非 wasi-sdk 编译器的补充章节。为什么需要其他编译器WAMR 的 WASM 构建生态概览WAMR 官方推荐的 WASM 应用构建方式是 WASI-SDK 19.0其二进制位于/opt/wasi-sdk/bin/clang同时也支持 Emscriptenemcc/em。但这两者并非唯一选择标准 clang 编译器同样可以完成 C/C 到 wasm32 目标码的交叉编译只需显式指定--targetwasm32并借助 LLVM 自带的 wasm-ld 链接器。本关联文档正是对这一路径的完整落地说明其价值在于不需要额外安装庞大的 wasi-sdk 或 emsdk只要系统里有对应版本的 clang/lld 工具链即可编译选项与 wasi-sdk 模式高度一致如-Wl,--initial-memory、-z stack-size知识可以平滑迁移可以精确控制导出符号、线性内存大小、是否保留入口函数等细节适合嵌入式、受限内存场景。从仓库源码看Fluent Bit 通过 plugins/filter_wasm/filter_wasm.c 的filter_wasm插件加载 WASM 二进制并在 examples/filter_wasm_c 中提供了使用 WASI 模式-nostdlib libc-builtin编译的 C 过滤器示例。而本文要讲的 clang-8 直连方式属于同一类非 wasi-sdk工具链路径理解它能帮助你阅读与改造各类 WAMR 示例。使用 clang 编译器构建 WASM 二进制文档明确推荐使用clang-8来构建 WASM 二进制并给出了从软件源配置到软链接、再到编译命令的完整四步流程。第 1 步向系统软件源添加 LLVM 仓库需要先将 apt.llvm.org 的源加入系统源列表。以 Ubuntu 16.04代号 xenial为例在/etc/apt/sources.list中添加deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main # 8 deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main # 9 deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main若使用 Ubuntu 18.04代号 bionic则添加对应的 bionic 源# i386 not available deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main # 8 deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main # 9 deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main注意文档在 18.04 源中特别标注了# i386 not available即 bionic 的 llvm-toolchain 仓库不再提供 i386 架构包这提示我们在较新 Ubuntu 上应使用 amd64 环境。第 2 步下载并安装 clang-8 工具链依次执行以下命令导入 apt.llvm.org 的签名密钥、更新索引并安装llvm-8 lld-8 clang-8sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - # Fingerprint: 6084 F3CF 814B 57C1 CF12 EFD5 15CF 4D18 AF4F 7421 sudo apt-get update sudo apt-get install llvm-8 lld-8 clang-8这里lld-8至关重要WASM 链接是由 LLVM 的 wasm-ld 完成的它是 lld 的一部分clang 负责编译和驱动链接。第 3 步创建 wasm-ld 软链接链接阶段 clang 会调用wasm-ld这个名字而 lld-8 安装后提供的是wasm-ld-8因此需要在/usr/bin下建立软链接cd /usr/bin sudo ln -s wasm-ld-8 wasm-ld这一步是新手最容易遗漏的缺少软链接时clang 会报找不到wasm-ld链接器导致-Wl,...链接选项全部失效。第 4 步用 clang-8 将 C 源码编译为 WASM 二进制对test.c执行如下命令clang-8 --targetwasm32 -O3 \ -z stack-size4096 -Wl,--initial-memory65536 \ -Wl,--allow-undefined,--exportmain \ -Wl,--strip-all,--no-entry -nostdlib \ -o test.wasm test.c命令执行成功后会在当前目录生成test.wasm即 WASM 应用二进制。下表逐项解释每个选项的语义与 WAMR build_wasm_app.md 中 wasi-sdk 选项一一对应选项含义约束/说明--targetwasm32交叉编译目标为 32 位 WebAssembly必须显式指定否则 clang 按宿主架构编译-O3最高优化级别同时配合--strip-all可显著减小体积-z stack-size4096辅助栈大小线性内存中的一块区域必须小于初始内存大小-Wl,--initial-memory65536线性内存初始大小必须是 65536 的整数倍文档规定-Wl,--allow-undefined允许链接产物中存在未定义符号对应 WAMR 运行时的外部导入/未解析符号场景-Wl,--exportmain强制导出main符号供运行时按名字调用-Wl,--strip-all剥离所有符号减小体积、保护符号信息-Wl,--no-entry不输出任何入口点与_start风格入口区分开-nostdlib链接时不使用标准系统启动文件与库此时运行方必须启用 libc-builtin见下文文档特别强调使用-nostdlib编译出的 WASM 二进制不包含 libc因此承载它的运行时必须构建 libc-builtin 支持。对 WAMR 来说即在 CMake 配置时指定-DWAMR_BUILD_LIBC_BUILTIN1若不用-nostdlibwasi 模式则需-DWAMR_BUILD_LIBC_WASI1。iwasm 在 Linux 下默认启用 libc-builtin。使用 Docker 构建 WASM 二进制文档给出的第二种方式是容器化构建。前提是你已经配置好 Docker 并进入一个可交互的 shell当前 WAMR 的 Dockerfile 只支持用 clang 编译应用Emscripten 支持规划在未来加入以仓库内文档表述为准。在容器环境中使用的 clang-8 命令与宿主机完全一致clang-8 --targetwasm32 -O3 \ -z stack-size4096 -Wl,--initial-memory65536 \ -Wl,--allow-undefined,--exportmain \ -Wl,--strip-all,--no-entry -nostdlib \ -o test.wasm test.c同样会得到test.wasm。Docker 方案的价值在于把 apt 源配置、clang/lld 安装、wasm-ld 软链接等环境准备工作固化到镜像中任何团队成员拉取镜像即可获得一致的 WASM 构建工具链避免本机能编、别人机器编不了的环境漂移问题。仓库内可参照的容器化工具链实现位于 lib/wasm-micro-runtime-WAMR-2.4.1/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile它基于gcc:12.2.0安装 cmake/ninja/make下载 wasi-sdk-19.0 解压到/opt/wasi-sdk编译wamrc并连同wamr-sdk/app与build_wasm.sh一起放入/home/wasm-toolchain最终通过ln -s .../wamrc /usr/bin/wamrc提供全局可用的wamrc命令。可见 WAMR 官方维护的 WASM 工具链镜像正是clang/wasi-sdk wamrc的完整组合本文的 Docker 小节与其思路一致。从 clang 直连到 Fluent Bit编译选项在真实产品链路中的对应关系clang 直连编译的最终产物要真正发挥作用需要接入运行时。以本仓库为例链路如下编译用上面的 clang-8 命令或 wasi-sdk 的/opt/wasi-sdk/bin/clang见 examples/filter_wasm_c/Makefile把 C 过滤器源码编成c_filter.wasm加载Fluent Bit 的filter_wasm插件通过 filter_wasm.c 读取WASM_Path指向的.wasm文件并在cb_wasm_pre_run中做运行前检查调用插件按Function_Name指定的导出函数名通过flb_wasm_call_function_format_json/msgpack把每条日志事件交给 WASM 程序处理filter_wasm.c 第 139-166 行输出WASM 返回的 JSON/msgpack 字符串被flb_pack_json重新打包为 msgpack 记录后继续流向下一级。这里可以清晰地看到文档中-Wl,--exportmain的含义导出的符号名必须与插件配置的Function_Name或运行时调用的入口严格一致否则运行时无法按名找到函数。WAMR 的 build_wasm_app.md 中-Wl,--exportvalue的定义正是强制导出某个符号本文命令里导出main、examples/filter_wasm_c/Makefile 里导出c_filter都是这一机制的实例。实战补充clang 直连 vs wasi-sdk 的差异与注意事项将本文 clang-8 命令与仓库内已有的 wasi-sdk 构建命令对比可以提炼出几条关键差异避免踩坑1. 入口函数的处理方式不同。clang-8 命令使用-Wl,--no-entry且不生成_start而 wasi 模式不带-nostdlib会导出_start由 iwasm 默认执行。如果运行方如 Fluent Bit 的 filter_wasm需要按函数名调用应使用--no-entry--exportfunc的组合。2. 内存选项必须满足倍数约束。-Wl,--initial-memory必须是 65536 的倍数-z stack-size必须小于初始内存。WAMR 文档还提示在-nostdlib模式下若额外导出__heap_base与__data_end两个全局WAMR 运行时会在线性内存的__heap_base处截断并追加 app heap从而不必为 64KB 的最小初始内存买单——这对内存受限的嵌入式设备意义重大可参考 build_wasm_app.md 的 footprint 小节。3. libc 模式必须与运行时构建选项对齐。-nostdlib产物需要运行时开启-DWAMR_BUILD_LIBC_BUILTIN1wasi 模式产物需要-DWAMR_BUILD_LIBC_WASI1。两者错配会导致运行时无法解析 libc 相关导入符号。4. 验证运行。编译产物可直接用 WAMR 的iwasm验证./iwasm test.wasm或 AOT 模式./iwasm test.aot先用wamrc -o test.aot test.wasm转换详见 build_wasm_app.md能打印Hello world!即说明二进制与运行时匹配。5. 版本注意。本文命令以 clang-8 为基准与关联文档一致。如果你使用的是 wasi-sdk 19.0 自带的 clang-z stack-size、-Wl,--initial-memory等选项语义完全兼容可直接替换编译器路径使用。仓库 examples/filter_wasm_c/README.md 中还给出了基于 wasi-sdk 14 的安装步骤与 Fluent Bit 配置示例WASM_Path、Function_Name、accessible_paths可作为 clang 直连之外的第二条 C 过滤器编译路线。总结本文完整复现并扩展了 WAMR 文档《使用其他 WASM 编译器》的全部内容通过 apt.llvm.org 配置软件源、安装 llvm-8/lld-8/clang-8、创建wasm-ld软链接最终用一条clang-8 --targetwasm32命令产出.wasm二进制同时也给出了 Docker 容器化构建的同源方案。在此基础上我们结合 WAMR 的 build_wasm_app.md 与 Fluent Bit 的 filter_wasm 插件 源码讲清了--export、--no-entry、--initial-memory、-nostdlib等选项在编译 → 加载 → 按名调用完整链路中的实际影响并给出了 libc-builtin/libc-wasi 模式对齐、内存倍数约束、入口函数选择等关键注意事项。掌握这套 clang 直连编译方法后你可以为 Fluent Bit 编写并构建轻量、可控的 WASM 过滤器也可以在嵌入式等受限环境中自由裁剪 WASM 二进制的内存与体积。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考