Solod 0.4:改进的C互操作性
摘要
Solod 0.4通过自动生成绑定、更多独立软件包和为开发者改进的工具,增强了C互操作性。
<p><a href="https://lobste.rs/s/oz5ju3/solod_0_4_better_c_interop">评论</a></p>
查看缓存全文
缓存时间: 2026/09/12 14:39
# Solod 0.4:更好的C语言互操作性
来源:https://antonz.org/solod-0.4/
Solod是Go语言的一个子集,可翻译成标准的C代码——无需运行时、采用手动内存管理并支持源代码级互操作。它主要面向两类开发者:
- 希望获得底层控制力而又不想学习新语言的Go开发者。
- 喜欢Go语言风格的C开发者。
此次Solod新版本提供了便捷的第三方C库调用方式,使大部分标准库可独立运行,并改进了开发工具链。
- 自动生成绑定 (https://antonz.org/solod-0.4/#automatic-binding-generator)
- 独立包 (https://antonz.org/solod-0.4/#more-freestanding-packages)
- 类型断言 (https://antonz.org/solod-0.4/#type-assertions)
- C语言互操作助手 (https://antonz.org/solod-0.4/#c-interop-helpers)
- 多包测试 (https://antonz.org/solod-0.4/#multi-package-testing)
- 检查与目标平台 (https://antonz.org/solod-0.4/#checks-and-targets)
- Windows支持 (https://antonz.org/solod-0.4/#limited-windows-support)
- 总结 (https://antonz.org/solod-0.4/#wrapping-up)
## 自动绑定生成器
Sobind (https://github.com/solod-dev/sobind) 能自动生成绑定——即从Solod调用第三方C库所需的存根代码。它解析`.h`头文件,并生成包含必要结构体、联合体、常量、变量、函数指针类型定义和函数声明的Solod源文件。
随后可在标准Solod代码中使用生成的类型和函数:
```
package main
import (
"solod.dev/raylib/libraylib"
"solod.dev/so/c"
)
func main() {
// 使用Raylib绑定。
libraylib.InitWindow(screenWidth, screenHeight, "☀️ Solod / Raylib")
defer libraylib.CloseWindow()
// ...
}
```
通常生成的绑定可直接使用,无需手动修改。我还为常见C库准备了绑定:
- libuv (https://github.com/solod-dev/libuv)
- raylib (https://github.com/solod-dev/raylib)
- sodium (https://github.com/solod-dev/sodium)
- sqlite (https://github.com/solod-dev/sqlite)
与Go不同,从Solod调用C代码毫无性能开销——Solod代码本质上就是标准的C代码。
## 更多独立包
我曾致力于让尽可能多的包实现独立运行——不依赖任何libc实现或特定操作系统运行时。这一目标进展顺利。Solod目前拥有37个标准库包,其中31个支持独立模式。
以下包可在独立模式下无限制运行:
```
bufio bytealg bytes c cmp encoding encoding/binary
encoding/hex encoding/json errors io maps math/bits
math/rand mem path runtime slices strconv strings
unicode unicode/utf8 unsafe
```
以下包在独立模式下运行时有一定限制:
- `crypto/crand` 依赖用户提供的随机数生成钩子
- `fmt` 依赖用户提供的文本输出钩子
- `math` 提供功能子集
- `net/netip` 可完整运行,但无法解析IPv6区域名
- `sync/atomic` 在支持无锁指令的平台运行
- `testing` 依赖用户提供的测试结果输出钩子
- `time` 通过用户提供的钩子读取时钟
- `uuid` 同时依赖 `crypto/crand` 和 `time` 的钩子
相关详情可参阅单独的文章 (https://antonz.org/going-freestanding/)。
## 类型断言
现在完全支持对非空接口的逗号-OK模式类型断言:
```
var s1 Shape = &rect
r, ok := s1.(*Rect) // r 为 &rect,ok 为 true
var s2 Shape = &circle
c, ok := s2.(*Rect) // c 为 nil,ok 为 false
```
对应的C代码如下:
```c
main_Shape s1 = (main_Shape){.self = &rect, .Area = main_Rect_Area};
bool ok = (s1.Area == main_Rect_Area);
main_Rect* r = ok ? (main_Rect*)s1.self : NULL;
// ok == true, r == &rect
main_Shape s2 = (main_Shape){.self = &circle, .Area = main_Circle_Area};
ok = (s2.Area == main_Rect_Area);
main_Rect* c = ok ? (main_Rect*)s2.self : NULL;
// ok == false, c == NULL
```
此前仅支持直接断言 `r := s.(*Rect)` 和仅检查模式 `_, ok := s.(*Rect)`。
## C语言互操作助手
`c` 包新增更多常用C类型支持:
```
size_t - c.Size
ssize_t - c.SSize
ptrdiff_t - c.Ptrdiff
intptr_t - c.Intptr
long double - c.LongDouble
```
新增 `c.ConstVoid` 类型,对应C的 `const void`。可在C需要 `const void*` 指针的位置使用:
```c
// C代码
so_ssize_t find_first(const void* items, size_t count, size_t size,
bool (*match)(const void*));
```
```
// Solod代码
//so:extern
func find_first(items *c.ConstVoid, count c.Size, size c.Size,
match func(item *c.ConstVoid) bool) c.SSize
```
新增实用的类型转换函数:
`c.Bitcast` 可按目标类型重新解释相同大小的值:
```go
bits := c.Bitcast[uint64](1.0) // 0x3ff0000000000000
f := c.Bitcast[float64](bits) // 1.0
```
可用于替代指针转换如 `*(*float64)(unsafe.Pointer(&b))`。
`c.StringData` 和 `c.SliceData` 返回指向字符串或切片数据的类型化指针:
```go
b := []byte{1, 2, 3}
p := c.SliceData[c.UChar](b) // unsigned char*
q := c.StringData[c.UChar]("ab") // unsigned char*
```
可替代 `(*T)(unsafe.SliceData(b))` 和 `(*T)(unsafe.StringData(s))`。
## 多包测试
`so test` 现在支持同时测试多个包。使用以 `...` 结尾的模式时,会自动选择基础目录下所有包含 `test` 子目录的包:
```
so test ./so/... # 整个标准库
so test ./so/net/... # 仅网络相关包
```
整个过程只需一次翻译、一次编译、一次执行,比逐包测试更快捷。
使用 `-pkg-file` 标志可限定测试范围:
```text
# freestanding.txt
so/bytes
so/mem
so/time
```
```
so test -pkg-file=freestanding.txt ./so/...
```
## 检查与目标平台
`so build`、`so test`、`so bench` 和 `so run` 新增两个标志:`-target` 和 `-check`。
`-target` 指定交叉编译的目标平台,使用与 `clang` 和 `zig cc` 的 `--target=` 相同的值:
```
export CC="zig cc"
so build -target=x86_64-windows-gnu -o app.exe .
so build -target=wasm32-freestanding -o main.wasm .
```
`-check` 启用代码分析:
```
so test -check=warn . # -Wall -Wextra -Werror -Wno-shadow -Wno-unused-label
so test -check=sanitize . # warn + AddressSanitizer + UndefinedBehaviorSanitizer
so test -check=analyze . # warn + GCC静态分析器
```
默认优化级别为 `-O2`,可通过 `CFLAGS` 变量调整。
## 有限的Windows支持
标准库现已支持 `windows/amd64` 和 `windows/arm64` 目标。所有独立包均可运行,但依赖POSIX的包(`conc`、`flag`、`log/slog`、`net`、`os`、`sync`)暂不支持。
可使用 `zig cc` 交叉编译Windows版本:
```
export CC="zig cc"
export CFLAGS="--target=x86_64-windows-gnu"
export LDFLAGS="-lbcrypt -liphlpapi"
so build -o app.exe .
```
虽不及Go的Windows支持全面,但已是良好开端。
## 总结
Solod v0.4 通过自动绑定机制可与几乎所有C库协作。独立感知的标准库使本语言成为嵌入式开发的可行选择。互操作助手提升了C调用代码的可读性,优化的工具链保持测试高效。
当然仍有诸多待办事项。下个版本计划重点完善标准库,引入Go语言的哈希与加密包,并集成更多C库。
若感兴趣,可查阅Solod自述文件 (https://github.com/solod-dev/solod#readme) 获取完整入门指南,或直接 在线体验Solod (https://codapi.org/solod)。
★ 订阅 (https://antonz.org/subscribe/) 以获取最新文章推送。
相似文章
Solod v0.2:网络支持、新目标、更友好的互操作
Solod v0.2 发布,新增网络支持(TCP、UDP、Unix 套接字)、新的编译目标(32位、WebAssembly、裸机)以及改进的 C 互操作性。
Solod: Go 可以成为更好的 C
Solod 是 Go 的一个严格子集,可编译为可读的 C11,零运行时,无GC,拥有丰富的标准库,让 Go 开发者获得系统级控制,同时为 C 程序员提供熟悉的工具链。
独立运行
本文介绍了如何将一个名为 Solod 的 Go 到 C 翻译工具变得独立运行的技术,方法是移植标准库包以使其无需 libc 即可工作,使用独立头文件和编译器内建函数等手段。
依赖 Go
Solod 是一种新的系统编程语言,它是 Go 的一个子集,复用 Go 的工具链和标准库,同时编译为 C11,提供手动内存管理。
Better Sol
Better Sol 是一款工具,使开发者能够使用 TypeScript 构建端到端的 Solana 应用程序。