尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Lean 4 Reverse FFI 实战:用 Lake 构建共享库并从 C 程序调用
Lean 4 Reverse FFI 实战用 Lake 构建共享库并从 C 程序调用【免费下载链接】lean4Lean 4 programming language and theorem prover项目地址: https://gitcode.com/GitHub_Trending/le/lean4Lean 4 的 FFI外部函数接口通常指在 Lean 中调用 C 函数而tests/lake/examples/reverse-ffi示例演示了与之相反的反向 FFI将一个 Lean 库编译为动态共享库.so/.dylib/.dll再从 C 语言程序加载并调用其中用[export]导出的 Lean 函数。读完本文你将掌握[export]导出机制、Lake 的sharedFacet共享库构建、Lean 运行时初始化流程以及通过Makefile链接与运行 C Lean 混合程序的完整实战方案。示例总体结构与角色划分本示例位于 tests/lake/examples/reverse-ffi整个目录刻意保持最小化仅包含三类角色文件角色lib/RFFI.leanLean 源码定义并通过[export]导出的函数lib/lakefile.leanLake 构建配置把 Lean 库构建为共享库main.c外部语言C程序初始化 Lean 运行时并调用导出的函数Makefile外部构建系统负责编译、链接、设置动态库搜索路径test.sh、clean.sh一键验证与清理脚本这个结构对应了 README 所概括的核心理念一个 Lake 库lib/可以被任意外部语言与构建系统main.cMakefile使用。Lean 侧只负责产出共享库调用方是谁、用什么构建系统完全解耦。第一步用[export]把 Lean 函数导出为 C 符号lib/RFFI.lean 全文只有几行却是整个反向 FFI 的基石[export my_length] def myLength (s : String) : UInt64 : s.length.toUInt64关键点拆解[export my_length]属性指示 Lean 编译器在生成 C 代码时把函数myLength的符号名改为my_length从而暴露为可供外部 C 程序直接链接/调用的 C 函数导出的函数签名必须满足可编译为 C 的类型约束String在运行时对应lean_object*UInt64对应uint64_t。这正是 main.c 中extern uint64_t my_length(lean_obj_arg);声明能够匹配的原因函数体的s.length.toUInt64演示了在 Lean 侧完成真实计算求字符串长度把业务逻辑留在 Lean、外部只做壳的反向 FFI 典型形态。导出背后的机制从源码结构看[export]的处理位于编译器的代码生成链路中src/Lean/Compiler/下的导出export逻辑会把指定的 Lean 声明以给定名字写入生成的 C 声明供外部链接。这类导出同时服务于正向 FFILean 侧用[extern]声明外部函数与反向 FFI本示例的[export]两者共同构成 doc/dev/ffi.md 所描述的 Lean FFI 全貌。第二步用 LakesharedFacet构建共享库lib/lakefile.lean 是 Lake 侧的全部配置import Lake open System Lake DSL package rffi [default_target] lean_lib RFFI where defaultFacets : #[LeanLib.sharedFacet]逐项说明package rffi声明包名为rffilean_lib RFFI声明一个名为RFFI的 Lean 库对应本目录下的RFFI.leandefaultFacets : #[LeanLib.sharedFacet]把默认构建目标从普通的静态 olean 库改为共享库shared libraryfacet。构建产物即动态库librffi_RFFI.soLinux/.dylibmacOS/rffi_RFFI.dllWindows位于lib/.lake/build/lib/。这里用到的LeanLib.sharedFacet是 Lake 的内置 facet 之一其sharedFacetConfig定义于 src/lake/Lake/Build/Library.lean。facet 机制是 Lake 的核心抽象构建系统通过sharedFacet将.olean/.c等中间产物进一步加工为动态链接库开发者只需声明目标Lake 负责推导完整构建图。ExternLib.sharedFacet见 src/lake/Lake/Build/ExternLib.lean则用于将第三方外部 C 库同样暴露为共享库二者在 src/lake/Lake/Build/Infos.lean 中统一纳入 facet 构建流程。构建命令由 Makefile 的lake目标触发lake --dirlib build执行后生成的共享库即为外部程序的链接对象。第三步在 C 程序中初始化 Lean 运行时并调用main.c 展示了外部调用方的完整流程分为初始化与业务调用两个阶段#include stdio.h #include lean/lean.h extern uint64_t my_length(lean_obj_arg); extern void lean_io_mark_end_initialization(); extern lean_object * initialize_rffi_RFFI(uint8_t builtin); int main() { lean_object * res; uint8_t builtin 1; // 与 Lean 可执行文件使用相同的默认值 res initialize_rffi_RFFI(builtin); if (lean_io_result_is_ok(res)) { lean_dec_ref(res); } else { lean_io_result_show_error(res); lean_dec(res); return 1; // 初始化失败时禁止访问 Lean 声明 } lean_io_mark_end_initialization(); // 实际业务 lean_object * s lean_mk_string(hello!); uint64_t l my_length(s); printf(output: %ld\n, l); }这段代码蕴含了反向 FFI 最关键的运行时约束必须调用初始化函数Lean 库中的顶层声明包括[export]的函数在运行前需要初始化。Lake 会为每个包生成形如initialize_rffi_RFFI的初始化入口命名规则为initialize_包名_模块名返回lean_object*形式的IO结果必须检查初始化结果通过lean_io_result_is_ok判断成败失败时用lean_io_result_show_error打印错误并退出且注释明确指出初始化失败时禁止访问 Lean 声明否则可能访问未就绪的对象必须标记初始化结束调用lean_io_mark_end_initialization()通知运行时初始化阶段已结束源码注释给出的参考文档指向 Lean 手册的ffi-initialization小节该机制用于回收/固化初始化期使用的资源参数与返回值遵守 ABIlean_obj_arg表示被借用不递增引用计数的 Lean 对象参数lean_mk_string构造字符串对象uint64_t为返回值外部代码需自行保证引用计数正确示例中初始化结果对象通过lean_dec_ref/lean_dec释放。第四步Makefile 编译、链接与运行Makerfile 提供了两种运行方式覆盖了最常见的部署场景。方式一run—— 通过 rpath 指定动态库搜索路径LEAN_SYSROOT ? $(shell lean --print-prefix) LEAN_LIBDIR : $(LEAN_SYSROOT)/lib/lean $(OUT_DIR)/main: main.c lake | $(OUT_DIR) cc -o $ $ -I $(LEAN_SYSROOT)/include \ -L $(LEAN_LIBDIR) -L lib/.lake/build/lib \ -l$(LIB_NAME) -lInit_shared -lleanshared_2 -lleanshared_1 -lleanshared $(LINK_FLAGS)链接命令的要点-I $(LEAN_SYSROOT)/include找到lean/lean.hLean 运行时头文件实际位于 src/include/lean 下安装后位于 sysroot 的 include 目录-L $(LEAN_LIBDIR) -L lib/.lake/build/lib同时加入 Lean 自身运行时库目录与 Lake 构建出的共享库目录-l$(LIB_NAME)即-lrffi_RFFI链接本示例的 Lean 共享库-lInit_shared -lleanshared_2 -lleanshared_1 -lleanshared链接 Lean 标准库与运行时分层共享库命名非 Windows 平台通过-Wl,-rpath,...把LEAN_LIBDIR与lib/.lake/build/lib写入可执行文件保证运行期动态加载器能找到依赖Windows 下则改用env PATH...在运行前动态注入库路径$(OUT_DIR)/main依赖lake目标确保先执行lake --dirlib build再编译。方式二run-local—— 复制依赖得到可移植可执行文件如果不想配置搜索路径可以把所有共享库依赖复制到当前目录得到更便携的产物ifeq ($(shell uname -s),Darwin) LINK_FLAGS_LOCAL : -Wl,-rpath,executable_path SHLIB_EXT : dylib else LINK_FLAGS_LOCAL : -Wl,-rpath,$${ORIGIN} SHLIB_EXT : so endif $(OUT_DIR)/main-local: main.c lake | $(OUT_DIR) cp -f $(LEAN_SHLIB_ROOT)/*.$(SHLIB_EXT) lib/.lake/build/lib/$(SHLIB_PREFIX)$(LIB_NAME).$(SHLIB_EXT) $(OUT_DIR) cc -o $ $ -I $(LEAN_SYSROOT)/include -L $(OUT_DIR) \ -l$(LIB_NAME) -lInit_shared -lleanshared_2 -lleanshared_1 -lleanshared $(LINK_FLAGS_LOCAL)将 Lean 运行时的全部共享库与librffi_RFFI.so一并cp到out/随后仅-L $(OUT_DIR)即可完成链接运行期路径交给$ORIGINLinux或executable_pathmacOS解析即以可执行文件自身所在目录为基准Windows 默认即当前目录无需额外设置注意平台差异的封装SHLIB_PREFIX/SHLIB_EXT/LEAN_SHLIB_ROOT按 Windows / macOS / Linux 分支取值$(OS)与uname -s配合判断。两个目标的关系.PHONY: all run run-local lake all: run run-localmake all默认目标会依次构建并运行run与run-local两种方式预期输出均为output: 6hello!长度为 6。第五步一键验证与清理test.sh 提供端到端验证set -ex LAKE${LAKE:-../../.lake/build/bin/lake} ./clean.sh LAKE$LAKE make run LAKE$LAKE make run-localLAKE环境变量默认指向仓库内构建出的 Lake 可执行文件../../.lake/build/bin/lake也可通过环境变量覆盖为系统安装的lake先clean.sh清理上次产物rm -rf out lib/.lake lib/lake-manifest.json再分别验证两种运行方式set -ex保证任何一步失败即中止并回显命令该脚本同时作为 Lake 测试套件的一部分tests/lake 目录中的示例均可由 CI 直接驱动印证了示例的正确性。反向 FFI 的适用场景与注意事项综合整个示例可以总结出反向 FFI 在工程实践中的定位适用场景把 Lean 实现的算法/逻辑以共享库形式嵌入 C/C 宿主程序如已有的大型 C 代码库、其他语言通过 C ABI 间接调用 Lean、或分发不含完整 Lean 可执行文件的二进制组件必须做的三件事[export]导出符号、lean_libsharedFacet产出共享库、调用方完成运行时初始化与lean_io_mark_end_initialization需要小心的地方引用计数lean_obj_arg借用语义与lean_dec_ref释放、初始化失败保护、跨平台动态库路径rpath / PATH /$ORIGIN、以及导出函数签名的 ABI 兼容性仅限可编译为 C 的类型如String↔lean_object*、UInt64↔uint64_t。这个最小示例从零展示了 Lean 4 反向 FFI 的完整链路lib/Lake 库与main.cMakefile外部语言与构建系统的分离设计恰好印证了 README 的核心观点Lean 库是可被外部复用的构件而非只能通过lake build生成可执行文件的封闭单元。将其中的模式迁移到自己的项目时只需替换导出函数、包名与链接库名即可。【免费下载链接】lean4Lean 4 programming language and theorem prover项目地址: https://gitcode.com/GitHub_Trending/le/lean4创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

Nhost Constellation 远程关系(Remote Relationships)深度解析:跨连接器 GraphQL 关联的规划与解析

Nhost Constellation 远程关系(Remote Relationships)深度解析:跨连接器 GraphQL 关联的规划与解析

Nhost Constellation 远程关系(Remote Relationships)深度解析:跨连接器 GraphQL 关联的规划与解析 【免费下载链接】nhost The Open Source Firebase Alternative with GraphQL. 项目地址: https://gitcode.com/GitHub_Trending/nh/nhost …

📅 2026/9/16 12:03:10
全栈实战:基于Vue、Node.js与MySQL的二手车在线售卖系统开发

全栈实战:基于Vue、Node.js与MySQL的二手车在线售卖系统开发

二手车系统这种项目,这几年问的人一直不少。学生要做毕业设计,刚转行的朋友想练手,甚至还有小团队想快速搭一套内网用的车辆管理工具,需求五花八门,但技术选型出奇一致:前端Vue,后端Node.js&…

📅 2026/9/16 12:03:10
Carbon Design System 色彩 Sass 模块全指南:@carbon/colors 的用法、API 与源码解析

Carbon Design System 色彩 Sass 模块全指南:@carbon/colors 的用法、API 与源码解析

Carbon Design System 色彩 Sass 模块全指南:carbon/colors 的用法、API 与源码解析 【免费下载链接】carbon A design system built by IBM 项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon carbon/colors 是 IBM Carbon Design System&#x…

📅 2026/9/16 11:58:09
MORE NEWS

更多资讯

📰

BERT模型原理与实战:从预训练到微调全解析

1. BERT模型概述:NLP领域的里程碑式突破2018年10月,谷歌AI团队发布的BERT(Bidirectional Encoder Representations from Transformers)模型彻底改变了自然语言处理领域的游戏规则。这个基于Transformer架构的预训练语言模型&#…

📰

LLM在教育领域的应用:个性化学习路径生成实践

1. 项目概述:当AI导师遇上个性化学习三年前我在教育科技公司参与过一个失败项目——试图用传统算法为在线学员生成学习路径。当时我们收集了数十个维度的用户数据,但最终产出的推荐结果却像流水线作业般千篇一律。直到GPT-3问世,我才意识到问…

📰

AIGC降噪工具:千笔如何优化AI生成内容

1. 项目背景与产品定位"千笔降AI率助手"是一款针对AIGC(人工智能生成内容)领域开发的专业降噪工具。在当前AI内容爆发式增长的环境下,该产品通过独特的算法设计,能够有效识别并降低文本中明显的AI生成痕迹,使…

📰

React Native条形图开发:百分比计算与标签防溢出实战

1. 项目背景与核心需求在移动端应用开发中,数据可视化是一个高频需求场景。最近我在开发一个React Native跨平台应用时,遇到了一个看似简单但实际暗藏玄机的需求:需要根据当前值(value)和最大值(max)计算百分比,并以宽度百分比的形…

📰

多路视频上帝视角融合:从坐标系对齐到实时全景监控实战指南

1. "上帝视角"到底解决什么问题:先说说监控系统的三个通病最早看到"gods-eye-view"这个词,是在一个园区安防的项目方案里。当时客户的需求很简单:几十路摄像头,分布在园区各个角落,保安室里一整面…

📰

Spring Boot集成RXTX串口通信的完整解决方案

简介:本资源是一个基于Spring Boot集成RXTX库实现串口通信的完整Java项目,面向物联网、嵌入式系统及工业自动化领域的Java开发者,尤其适合需在Web后端与传感器、PLC、串口打印机等硬件设备交互的中高级学习者。项目提供开箱即用的串口配置、数…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬