用 Zig 集成 PRQL 编译器:prqlc-c FFI 最小示例全解析

发布时间:2026/9/24 14:06:16

用 Zig 集成 PRQL 编译器:prqlc-c FFI 最小示例全解析 后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载PRQLPipelined Relational Query Language是一种面向数据转换的现代语言目标是成为简单、强大、管道式的 SQL 替代品。本仓库中的prqlc-c是 PRQL 编译器prqlc的 C ABI 绑定任何支持 FFI 的语言——包括 Zig——都可以直接链接调用。本文将基于仓库中 minimal-zig 示例 这一份官方最小示例从零讲解如何在 Zig 项目中导入prqlc.h、链接libprqlc_c、调用compile把 PRQL 查询编译为 SQL并深入剖析其背后的Options、CompileResult等 C 结构体与 Rust 侧的内存管理约定。读完本文你将掌握在 Zig 中嵌入 PRQL 编译能力的最小可运行方案并能自行扩展处理错误信息与中间编译阶段。示例总览一条命令跑通minimal-zig 示例的定位非常明确——它是 prqlc-c C 绑定 官方提供的三种示例之一另外两个是 minimal-c 与 minimal-cpp专门演示用 Zig 的cImport机制直接消费prqlc.h头文件的用法。该示例目录结构如下prqlc/bindings/prqlc-c/examples/minimal-zig/ ├── README.md # 官方说明Run with task zig from the root of the repo ├── Taskfile.yaml # 定义 build-prql / build / run / test 等任务 ├── build.zig # Zig 构建脚本配置 include 路径、链接 prqlc_c 系统库 └── src/ └── main.zig # 调用 prqlc-c API 的最小 Zig 程序 单元测试官方 README 给出的运行方式是在仓库根目录执行task zig根目录的 Taskfile.yaml 中zig是一个 include 进来的任务别名指向prqlc/bindings/prqlc-c/examples/minimal-zig目录并以其为工作目录。因此执行task zig会进入该示例目录随后触发示例自身Taskfile.yaml中定义的default任务——一条龙完成「构建 prqlc-c → 构建 Zig 可执行文件 → 运行 → 跑测试」四个步骤default: desc: Build, run, test cmds: - task: build-prql - task: build - task: run - task: test运行成功后程序会打印类似下面的输出Compiled with 0 errors Output: SELECT album_id, title FROM albums LIMIT 3Output:后面的内容取决于是否开启format选项未开启时是单行 SQL。三步构建流程从 Rust 动态库到 Zig 可执行文件第一步构建 prqlc-ctask build-prqlprqlc-c本体是位于 prqlc/bindings/prqlc-c/src/lib.rs 的 Rust crate通过#[no_mangle] extern C导出 C ABI 符号并用 cbindgen 生成prqlc.h/prqlc.hpp头文件。示例中的build-prql任务负责完成构建与产物归位build-prql: desc: Build prqlc-c cmds: - cargo build --package prqlc-c --release - mkdir -p c/ - cp {{.project_root}}/prqlc/bindings/prqlc-c/prqlc.h c/ - cp {{.project_root}}/target/release/libprqlc_c.* c/其中project_root定义为../../../../..从prqlc/bindings/prqlc-c/examples/minimal-zig/出发正好回到仓库根目录。这条任务做了三件事cargo build --package prqlc-c --release以 release 模式编译 prqlc-c crate把仓库内现成的 prqlc.h 头文件复制到示例的c/目录把target/release/下生成的动态库libprqlc_c.somacOS 上为.dylibWindows 上为.dll复制到c/目录。值得注意的是cp .../libprqlc_c.* c/同时会把静态库libprqlc_c.a一起拷入若静态特性开启因此c/目录同时承担「头文件 库文件」的双重角色build.zig中的 include 路径和 library 路径都指向它。第二步Zig 构建脚本链接 prqlc_ctask buildbuild.zig 使用 Zig 0.11 风格的 declarative build API 构建名为minimal-zig的可执行文件。与 prqlc-c 相关的关键配置有三处exe.root_module.addIncludePath(b.path(src)); // 让 main.zig 能 #include 到 ../c/prqlc.h exe.root_module.addLibraryPath(b.path(c)); // 指向包含 libprqlc_c.* 的目录 exe.root_module.linkSystemLibrary(prqlc_c, .{}); // 链接系统库 prqlc_c exe.installHeader(b.path(c/prqlc.h), prqlc.h); // 把头文件装入安装产物此外createModule中设置了.link_libc true保证 Zig 侧链接 libc——这是使用 C ABI 头文件的必要前提。可执行文件同样以src/main.zig为根源文件构建单元测试目标addTest并对外暴露run与test两个 Zig build step。第三步运行与测试task run/task testrun: deps: - task: build cmds: - ./zig-out/bin/minimal-zig test: desc: Run tests deps: - task: build cmds: - zig build testrun直接执行zig build安装产物zig-out/bin/minimal-zigtest则调用zig build test跑 main.zig 里的单元测试。需要提醒的是由于动态库在运行时按路径搜索若直接手动执行二进制遇到找不到libprqlc_c.so的问题可显式设置LD_LIBRARY_PATHmacOS 用DYLD_LIBRARY_PATH指向c/目录或改用静态链接方案。核心代码逐行拆解main.zig用 cImport 引入 prqlc.hsrc/main.zig 是整个示例的精华第一段即演示 Zig 导入 C 头文件的标准姿势const std import(std); const prql cImport({ cInclude(../c/prqlc.h); });cInclude的路径是相对于src/目录的即src/../c/prqlc.h正好落在第一步build-prql复制出来的头文件上。build.zig中addIncludePath(b.path(src))保证了编译器在编译src/main.zig时能解析到这个相对 include。导入成功后prql命名空间下即出现prql.Options、prql.compile、prql.result_destroy等 C API。配置 Options 并指定编译目标var target sql.mssql.*; // Setup PRQL compiler options const options prql.Options{ .format false, .signature_comment false, .target target, };这里的Options对应 prqlc.h 中 cbindgen 生成的 C 结构体字段语义与 Rust 侧 src/lib.rs 中的 Options 一一对应字段类型默认值含义formatbooltrue是否将生成的 SQL 交给格式化器拆成多行并美化缩进与间距targetchar *sql.any编译目标与方言sql.any表示由查询头部的target参数决定方言signature_commentbooltrue是否在生成的 SQL 末尾追加编译器签名注释Zig 中var target sql.mssql.*;声明了一个可变的、以 NUL 结尾的 C 字符串数组Zig 字符串字面量默认不可变且非 NUL 结尾这里通过解引用.*拷贝成可写数组再把target赋给target字段——这正是 C 侧要求的char *类型。示例选取sql.mssql作为目标方言意味着输出将是 SQL Server 风格的 SQL。编译 PRQL 查询并处理结果// Compile the PRQL query const prql_query from albums | select {album_id, title} | take 3; const result prql.compile(prql_query, options); defer prql.result_destroy(result); std.debug.print(Compiled with {d} errors\n, .{result.messages_len}); std.debug.print(Output:\n\n{s}\n, .{result.output});这一段对应 Rust 侧导出的 compile 函数pub unsafe extern C fn compile( prql_query: *const c_char, options: *const Options, ) - CompileResult它把 PRQL 源字符串编译为 SQL 字符串内部等价于依次执行prql_to_pl→pl_to_rq→rq_to_sql三个阶段只是省略了阶段间的 JSON 序列化。传入options即传入非空指针也可以传null表示使用全部默认选项下面测试里就是这么做的。compile返回的CompileResult在 prqlc.h 中定义如下typedef struct CompileResult { const char *output; // 编译输出的 SQL 字符串或阶段中间产物 JSON const struct Message *messages; // 错误消息数组指针无错误时为 NULL size_t messages_len; // 错误消息条数 } CompileResult;示例用result.messages_len判断是否成功0 表示成功用result.output取 SQL。同时注意defer prql.result_destroy(result);——Zig 的defer保证函数退出时一定释放CompileResult占用的内存。这是 prqlc-c 的硬性约定Rust 侧 result_destroy 负责深度释放output字符串、messages数组以及每个Message内部堆分配的字段调用方绝不能手动 free 其内部字段且对同一个CompileResult只能调用一次result_destroy。内置单元测试test simple test { const prql_query from albums | select {album_id, title} | take 3; const result prql.compile(prql_query, null); defer prql.result_destroy(result); try std.testing.expect(result.messages_len 0); }这个测试验证了两种用法要点compile(prql_query, null)说明options参数可传NULL此时全部选项走默认值format、signature_comment为 truetarget为sql.anyresult.messages_len 0是判断编译成功与否的惯用方式——成功时messages为 null、messages_len为 0失败时output为空串、messages_len为错误条数。深入底层compile 的编译流水线与错误处理三段式编译管线从 src/lib.rs 可以看到compile的实质是prql_to_pl、pl_to_rq、rq_to_sql三个阶段的串联PRQL 源码 ──prql_to_pl──▶ PL ASTJSON ──pl_to_rq──▶ RQJSON ──rq_to_sql──▶ SQLprql_to_pl解析 PRQL 语法生成 PLPipeline Language语法树序列化为 JSONpl_to_rq解析变量引用、校验函数调用、确定 frame把 PL 转换为 RQRelational Queryrq_to_sql将 RQ 翻译为指定方言的 SQL 字符串。这三个阶段在 prqlc-c 中同样以独立 C 函数导出prql_to_pl、pl_to_rq、rq_to_sql参数与返回值均为CompileResult。若你需要调试中间 AST可以参考 minimal-c 示例 的用法先调用prql_to_pl拿 PL JSON再把res.output作为输入传给pl_to_rq逐级打印中间结果。Options 在 Rust 侧的转换convert_optionssrc/lib.rs把 C 结构体转为 Rust 侧prqlc::Optionstarget为NULL或空字符串时回退为sql.any即由查询头部的 target 注释决定方言target经Target::from_str解析若给出非法方言名则产生编译错误三个字段最终通过with_format、with_target、with_signature_comment应用到默认Options上。这解释了为什么format/signature_comment在 Rust 侧默认true——C 结构体只是镜像真正的默认值语义由prqlc::Options::default()定义并在convert_options中按字段覆盖。出错时如何取错误详情compile失败时不会 panic而是返回messages_len 0的CompileResult。每个Message结构体prqlc.h包含kind消息类型目前仅实现ErrorWarning、Lint为枚举占位code机器可读的错误标识符reason错误原因的纯文本hint修复建议列表span错误在源文件中的字符偏移区间start/enddisplay带注释的代码片段内含原因与提示适合直接打印给用户location错误的起止行号与列号start_line/start_col/end_line/end_col。Zig 侧若要实现健壮的错误输出可仿照 minimal-c 示例的print_result逻辑遍历res.messages[0..res.messages_len]优先打印display若有否则回退到[code] reason或纯reason。注意hint、code、display是二级指针const char *const *取值前需判断非 NULL。扩展思路把示例改造成自己的 Zig 工程基于这个最小示例往自己的 Zig 项目集成 prqlc-c 只需对齐三处约定依赖产物先构建 prqlc-c 并把 prqlc.h 与libprqlc_c.so/.dylib/.dll放到同一目录参考build-prql任务的复制逻辑构建脚本在build.zig中为自己的可执行文件/库调用addIncludePath、addLibraryPath、linkSystemLibrary(prqlc_c, .{})并设置link_libc true可整体照搬示例的 build.zig调用约定所有导出函数都接受 NUL 结尾的 C 字符串每个返回CompileResult的调用都必须且只能配对一次result_destroyOptions可传NULL使用默认值。至于链接时需要的系统依赖prqlc-c README 给出了 CGO 场景的参考-lprqlc_c -pthread -ldl -lmmacOS 还需-framework CoreFoundation。Zig 通过linkSystemLibrary链接动态库时通常不需要手工追加这些依赖但若选择静态链接libprqlc_c.a可参考 minimal-c/Makefile 中的链接参数。小结minimal-zig 示例虽然只有数十行代码却完整覆盖了在 Zig 中嵌入 PRQL 编译器的全部关键点cImport导入 cbindgen 生成的 prqlc.h、Options三字段format/target/signature_comment的配置方式、compile的调用与result_destroy的内存释放约定、基于messages_len的成败判断以及prql_to_pl→pl_to_rq→rq_to_sql的三段式编译流水线。以此为起点你可以轻松把它扩展为支持方言切换、错误详情展示甚至分阶段调试的完整 Zig 集成方案。赞分享后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载相关推荐PRQL 编译器 prqlc 实战指南从 CLI 管道编译到 Rust 库集成PRQL 编译器 prqlc 实战指南从 CLI 管道编译到 Rust 库集成 prqlc 是 PRQLPipelined Relational Query后端使用 prql-php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL使用 prql php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL PRQLPipelined Relational Que后端Hurl 表达式设计详解通用化表达式如何在 [Captures] 与 [Asserts] 中统一 Hurl 的请求测试模型Hurl 表达式设计详解通用化表达式如何在 Captures 与 Asserts 中统一 Hurl 的请求测试模型 本篇技术文章围绕 Hurl 的官方设计规范后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/24 14:06:16

DeepSeek接入公共管理服务:可行性分析、技术路径与落地实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/24 14:06:16

合肥市芜湖市马鞍山市企业HR系统选型:深耕本地服务落地数字化

合肥市、芜湖市、马鞍山市作为皖江城市带承接产业转移示范区的核心枢纽,是安徽省工业经济、产业集群、实体经济的核心承载地。三地产业互补、联动发展,汇聚了新能源、汽车制造、高端装备、钢铁新材料、智能机器人等支柱产业,聚集了大量中大型…

2026/9/24 14:01:15

【Dv2Admin】用自己服务器部署d2curd样例站点

由于 d2-crud-plus 作者已停止维护,其官方样例站点也无法访问。但对于仍在使用该组件库的项目来说,保留样例站点作为参考模板是非常有必要的。 本文介绍一种基于 宝塔面板 快速部署 d2-crud-plus-example 的方式,用于搭建本地演示站点,供团队内部预览和参考使用。 文章目录…

2026/9/24 15:01:26

天天 AI Coding 的你,出去面试的竞争力是什么?

1. 引言 这两年 AI 编程工具铺天盖地,Cursor、Copilot、通义灵码、Claude Code…… 几乎每个开发者都在用。于是面试官开始问一个很扎心的问题:“既然 AI 都能写代码了,天天用 AI Coding 的你,凭什么比不用 AI 的人更有竞争力&…

2026/9/24 15:01:26

单片机毕设项目:基于 STM32 或 51 单片机的蓝牙 APP 联动智能温控风扇设计 基于 STM32 或 51 单片机的人体感应与语音交互风扇系统开发(025508)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/9/24 15:01:26

红队钓鱼场景下的Nginx反向代理技术分析

在红队钓鱼中,攻击者通过Nginx反向代理(AiTM)透明转发受害者流量至真实站点,同时利用 proxy_pass 配合日志变量捕获明文账密($request_body)与会话Cookie($http_cookie);…

2026/9/24 14:56:25

在 Redwood 8.0 中集成 Sentry:错误与性能监控完整配置指南

后端前端Web框架开发工具 【免费下载链接】redwood RedwoodGraphQL 项目地址: https://gitcode.com/gh_mirrors/re/redwood 点击查看 免费下载 本指南基于 RedwoodJS 8.0 版本文档,系统讲解如何通过一条 CLI 命令在 Redwood 应用中接入 Sentry&#xff…

2026/9/23 12:07:00

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/24 0:00:21

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:21

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:21

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码