Zig可能是适合进行嵌入式开发和交叉编译的语言。
缘起
最近在家里的服务器上搭建私有云服务,发现电信宽带无法获取公网IP地址,也就是说无法在外面访问家里的服务器。这个问题有不少解决方案,在综合考虑安全性、通用性、连接速度等多个因素后选择了“UDP反向隧道+Wireguard”的方案。
该方案的基本思路如下。首先购买拥有公网IP的虚拟服务器作为连接跳板;然后家里路由器向虚拟服务器建立隧道连接,将虚拟服务器的某UDP端口反向代理到家里路由器的Wireguard端口上;最后,在外的移动设备如手机等,通过虚拟服务器上的隧道端口与家里路由器建立Wireguard连接。
这个方案中的关键技术是第二步,UDP端口反向代理。为了保证连接吞吐量,最好是使用UDP直接代理,而不是通过SSH等TCP隧道。为此,通过网络搜索找到了一个叫做udp reverse tunnel的工具,正好符合要求。
这个工具用C语言开发,只提供源代码,需要自己编译。我的开发机是x86架构,虚拟服务器也是x64架构,编译不成问题。但路由器是armv7架构,因此需要在x86开发机上编译armv7的可执行文件,也就是所谓的交叉编译。
交叉编译是嵌入式开发中的基础操作,因为通常需要用一个架构的开发机支持好几种架构的嵌入式设备。但是我从来没有进行过嵌入式开发,也不知道如何配置交叉编译环境。
一番网络搜索后,找到不少如何配置c语言交叉编译环境的资料。但无论是gcc还是clang,都涉及到下载大量的文件、配置各种环境变量等等繁琐的操作,实在提不起精神去折腾。我想要是像linux包管理软件那样,一条命令就能配置好的交叉编译环境。
Zig语言?
继续在网上搜索,偶然看到一篇文章《如何用Zig语言交叉编译C/C++程序》。这个题目马上抓住了我的注意力,第一反应是为什么一种语言的编译器能编译另一种语言的代码?
仔细阅读文章后发现这种叫Zig的语言,它的编译器居然内嵌了基于LLVM的C/C++编译器。更厉害的是它直接内嵌了六十几种常见架构的编译环境,可以直接一条命令将C/C++代码交叉编译成这些架构上的可执行文件。
也就是说,不需要任何配置,理论上只需要一条命令
zig cc -target arm-linux-gnueabi
就能编译出可以运行在家里路由器上的程序。
看起来Zig完美的符合我的需求。事实上也是如此,我用一条命令安装了Zig,然后一分钟修改反向代理程序的Makefile,然后就成功的交叉编译出了可以用在路由器上的可执行文件!
Zig语言!
这下Zig语言真正引起了我的兴趣。我接下来访问了Zig语言的官方网站,阅读了上面的简介和教程。得出的结论是Zig是一门非常值得我学习的语言。
关于编程语言,我的个人哲学是:没有“最好”,只有“最合适”。虽然理论上所有图灵完备的语言等价,但是不存在某个领域所有语言都适用,也不存在某种语言适应于所有领域。所谓“适用”表达力强,方便易用,运行安全高效等特征的统称。
我当前主要使用三种语言:Python、Rust、C++。三种语言扮演不同角色。Python作为一种高抽象度、弱类型的语言,主要用于写脚本完成一些临时任务。Rust强安全检查、强类型,适合开发逻辑复杂、运行效率可靠性要求高的项目。C++的生态位与Rust重合,新项目我一般用Rust,但大量已有程序的扩展和维护需要C++。
这三种语言满足我绝大多数的开发需求,但最近我开始对嵌入式开发有些兴趣,例如智能家居、机电结合扥等。理论上Rust和C++都可以用于嵌入式开发,但都有各自的不足。
对于Rust来说,语言本身非常优秀,但嵌入式生态不完整,原生的Rust语言的SDK太少,大量的嵌入式芯片只提供C语言的SDK。虽然也可以从Rust中调用,但需要各种配置,使用体验不好。
C++虽然可以方便的调用C语言SDK,但C++语言本身设计历史包袱太重。类型系统不完整、没有包管理、模板系统行为难以理解。
Zig语言正好补上了这个生态位的空缺。Zig一方面和Rust类似,有原生的包管理系统,有强类型系统;另一方面又和C++一样,有非常易用的C语言API整合。
除此之外,针对嵌入式系统资源非常紧张的特点,Zig语言还能最大化节省资源。首先是方便的手动资源管理,所有资源分配和释放都有开发者明确控制,最大化节约。然后是一流的代码编译期间运行,尽量把代码运行放到编译期,节省运行期的算力。
Zig语言特性
待续。。。
总结
如果对嵌入式开发有兴趣,Zig语言非常值得一学。