首页 > 编程语言 >《从零开始的 Zig 编程》Zig 是什么?如何构建并运行一个 Zig 项目

《从零开始的 Zig 编程》Zig 是什么?如何构建并运行一个 Zig 项目

时间:2023-09-23 22:55:09浏览次数:72  
标签:语言 编译 编程 zig Zig 从零开始 构建 build

Zig 概述

从现在开始我们来一起学习一门新的语言 Zig,这门语言估计很多人都没听过,因为即便在国外用的也不是很多,国内几乎还没有公司在用。但这门语言非常优秀,它被称为现代化的 C 语言,具有安全、快速以及富有表现力等特点。下面我们就从计算机原理的角度,来介绍一下 Zig,看看为什么会诞生这样一门语言,以及它都用在什么地方。

计算机只能理解由二进制数字(0 和 1,即低电压和高电压水平)组成的低级语言,这些语言被称为机器语言。而汇编语言的抽象帮助开发者减少了机器码的极端复杂性,但也是非常底层、依赖于平台的语言,它将 0 和 1 的模式映射到可读的字符,而这对人类也并不那么友好,所以便有了 C 语言。但随着时代的发展,人们发现 C 语言还是不够方便,因此后续又诞生了如 C++、Python、Java、Go、Rust 等语言。这些语言有的是为了执行效率,有的是为了开发效率,也有的是为了成为某个已经成熟语言的替代品,例如 Rust 是 C++ 的替代,Kotlin 是 Java 的替代。

那么 Zig 的诞生是为了什么呢?首先它是一种功能齐全的系统编程语言,被视为 C 的友好替代品,具有最小化的 Rust 式语法,但保持了 C 的简单性。总的来说就是 C 语言的功能性以及开发效率太低了,所以 Zig 的目的就是在拥有 C 性能的同时,并减轻开发人员的心智负担。Zig 使用了类似 C、Rust 的语法,以未来主义的方法解决 C 开发者经常遇到的问题,并且考虑现有的 C 生态,它提供了一个高效的 C-interop 解决方案,让 C 开发者可以将 C 代码库直接迁移到 Zig。

另外 Zig 不仅仅是一种语言,它还是一个完整、功能齐全的工具链,这意味着你可以使用 Zig 来创建、开发、测试和构建程序和库,无需第三方构建自动化工具。Zig 工具链还可以交叉编译 C/C++ 项目,因此可以直接有效地使用 Zig 工具链来构建现有的 C/C++ 项目。因此 Zig 虽然被设计为一种底层、对硬件友好的系统编程语言(保证高效),但它的语法和功能对开发者也同样友好,这使得它也适合构建现代软件系统。

Zig 项目最初由 Andrew Kelley 发起,现在由 Zig 软件基金会(ZSF)维护,通过提供一套完整的系统编程解决方案和一个高效的 C-interop,从而与 C 竞争。总之 Zig 不仅力求成为一种更好的 C 语言,用于低级系统编程,还努力具备以下特点。

以简单性为先的设计

人性化的现代语言的目标是提供一种设计良好的语法,它不是像汇编那样原子化的。如果语言的抽象过于接近汇编,开发者可能需要编写冗长的代码。另一方面,当一种语言被抽象为接近人类可读时,它可能就会离硬件太远,可能不适合系统编程需求。

为此 Zig 提供了轻量级的、类似 Rust 的语法,拥有 C 提供的大多数功能。它不提供 Rust 和 C++ 拥有的复杂功能集和语法,但像 Go 一样提供了以简单性为先的开发环境。

性能和安全性

在选择特定的编程语言之前,性能和安全性是需要检查的关键因素。特定语言的性能通常取决于其标准库、核心运行时特性和编译器生成的二进制文件的质量。同时,安全设计实现了边界检查、溢出处理和内存范围,并帮助开发者减少关键安全漏洞。Zig 构建系统提供了四种构建模式,开发者可以根据他们的性能和安全性需求来使用,此外 Zig 还可以在编译时了解变量是否溢出。

然后 Zig 可以生成带有运行时安全检查的优化二进制文件,就像 Rust 一样,也可以生成没有运行时安全检查的超轻量二进制文件。Zig 官方文档声称,由于其基于 LLVM 的优化和改进的未定义行为,Zig 理论上比 C 更快!

完整的系统编程解决方案

大多数编程语言都有一个或多个标准编译器和标准库实现,例如你可以用以下方式编译 C 代码:

  • GNU C
  • Apple Clang
  • 带有 libc、BSD-libc 和 Microsoft C 运行时的 MSVC 编译器

但是这些组件对于现代系统编程需求来说还不够,程序员经常需要构建工具、包管理器和交叉编译工具提供的保护。因此 CMake、Ninja、Meson 等构建工具以及 Conan 等包管理器在 C 生态系统中变得流行。而像 Go 和 Rust 这样的现代语言则已经考虑了这一点,因此内置了包管理器、构建工具/API、交叉编译支持和测试运行器。

同样,Zig 也有一个内置的包管理器、构建系统 API、交叉编译支持和测试运行器,这提高了 Zig 成为更好的 C 的机会,因为它解决了 C(和 C++)开发者面临的关键系统编程问题。并且 C 已经存在了大半个世纪,拥有非常多成熟的库,而 Zig 提供了低级 C 开发者期望从高效 C-interop 中获得的所有功能,因此 C 程序员可以逐步将他们的系统迁移到现代 Zig,而无需重写整个旧代码库。换句话说,Zig 可以直接使用现有的 C 库,而不需要把这些库用 Zig 重写一遍。


为什么要学习 Zig?

编程语言成千上万,但只有一小部分在开发者社区中变得受欢迎,相信未来还会出现更多的编程语言,它们旨在替代现有语言的功能。当然啦,我们不需要学习所有的语言,毕竟人的一生何其短暂。但如果有一种语言能带来充满希望的未来,并提供了强有力、有效且经过验证的论据来解释为什么它应该被用作现有语言的替代品,那么我们还是有必要了解其目标和内部设计概念的,而不是完全忽视它。

比如谷歌于 2012 年发布了 Go 1.0,现在 Go 已经成为很多技术公司的主力语言。在 1990 年代,Python 还只是一种新的、实验性的脚本语言,但现在数字世界混的风生水起。同样地,Zig 最初于 2016 年出现,于 2017 年发布了其第一个预发布版本,并已展示了作为 C 的现代替代品的能力。经过几年的积极开发,Zig 甚至提供了一个完整的系统编程工具链,并确立了一个充满希望的未来。鉴于它与 C 的相似性和与 C 的互操作性,它还可以在 AI 开发、游戏开发等方面为你提供更广泛的机会。

总之学习 Zig 不仅为你的技能树电量了一个有前途的与 C 相邻的语言,而且还通过其巧妙、平衡性能与安全性的设计,增强你对系统编程的了解。

都有谁在使用 Zig?

文章的最开始我们就说了,Zig 还是一门很新的语言,国内基本没有公司在用,而且国外用的都很少。但这门语言很优秀,是值得我们深入学习的。不过语言虽然新,但仍然有一些项目或公司在使用它,比如:

  • Bun:这是集打包器、测试运行器和包管理器为一体的 JavaScript 运行时,它具有不可思议的运行效率。
  • Mach:面相未来的游戏引擎和图像处理工具包。
  • Uber 公司:该公司使用 Zig C++ 编译器通过 Hermetic CC 工具链(包含 Zig 代码)在 arm64 硬件上运行 Uber 服务。
  • TigerBeetle公司:该公司提供了一个用 Zig 语言编写的财务会计数据库。

毫无疑问,该语言很新,如果你学了 Zig 之后想用它来找工作,近几年是行不通的。换句话说,如果你想学习一门语言去尽快找到工作,那么 Zig 当前一定不是你的选择。学习 Zig 的前提是你已经拥有其它语言的基础,并能在工作中自由使用,但你希望再学习一门高性能的语言来辅助你开发,或者提升你的编程水平,那么 Zig 应该成为你的选择。而且 Zig 在国外被评为钱途最高的编程语言,如果你现在开始学,那么等 Zig 将来在国内开始流行的时候,你就能成为第一批吃螃蟹的人。

Hello,Zig

现在你应该已经了解了什么是 Zig,下面我们就来安装它。首先去 Zig 的官网下载对应的安装包,然后直接安装即可,然后 IDE 选择 VS Code,并且有对应的插件。安装完之后,我们在命令行输入 zig -h:

我们看到它提供了非常多的选项,除了编译、运行之外,还提供了单元测试、代码格式化、处理静态库动态库、和 C++ 交互等等,可以说一整套工具链都可以通过 zig 命令实现。然后我们注意到里面还有一个 translate-c 子命令,我们通过 zig translate-c 即可将 C 代码转成 zig 代码,非常人性化。

下面让给我们来创建一个 Zig 文件:hello.zig,看看一个最基本的 Zig 文件长什么样子。注:Zig 源文件以 .zig 结尾。

// @import 是一个导入语句,该行表示导入标准库 std,并赋值给常量 std
// 如果用 Python 举例的话,就是 std = __import__("std"),或者 import std
const std = @import("std");

// 和 C 一样,程序必须有一个 main 函数,它是程序的主入口
pub fn main() void {
    std.debug.print("Hello Zig\n", .{});
}

首先和大部分静态语言一样,Zig 使用 // 表示注释,然后通过 fn 关键字定义一个 main 函数,函数名后面是返回值类型。至于开头的 pub 关键字暂时不用管,你把它去掉也是可以的,不过相信你能猜出它是做什么用的。

编译和运行 Zig 文件

源文件编写完成后,我们来编译它:zig build-exe hello.zig,我的系统是 Windows,所以会在当前目录下生成一个 hello.exe。然后执行该文件,终端就会打印出 Hello Zig。当然啦,在编译的时候也可以手动指定生成的可执行文件的名字,比如 zig build-exe --name hello_world hello.zig,那么此时就会生成 hello_world.exe。另外在 Windows 系统上,通过 --name 指定文件名的时候,不需要指定扩展名,会自动在结尾添加上 .exe。

除了 zig build-exe 之外,还有一个 zig build 也用于编译,那么这两者有什么区别呢?首先 build-exe 用于直接将源文件编译成可执行文件,这种方式非常适合简单的编译任务,所以当你有一个单独的 .zig 文件,并希望将它编译为可执行文件时,该命令会很方便。

而 zig build 用于运行由 Zig 的构建系统定义的构建脚本,通常在一个名为 build.zig 的文件中。当你有一个较大的项目,需要自定义构建步骤、依赖关系、多个目标或其他复杂性时,使用 build 就方便多了。build.zig 文件允许你自定义构建步骤、依赖项、输出类型等,从而为项目提供更大的灵活性和控制力。通过在包含 build.zig 文件的目录中运行 zig build,构建系统将执行这个文件中定义的所有构建步骤。

对于我们当前来说,直接使用 build-exe 即可。当然,如果每次都是先手动编译成可执行文件,然后再运行,就会有些麻烦。所以 Zig 还提供了 zig run 命令,它等价于编译加运行,比如 zig run hello.zig。另外在编译的时候,还可以指定 -O 参数用于优化。

比如:zig run -O ReleaseSafe hello.zig,或者 zig build-exe -O ReleaseSafe hello.zig,

Zig 编译器的强大之处在于,它还提供了交叉编译,我们在 Windows 系统上也可以编译出 Linux 可以执行文件,同理其它系统也是。交叉编译方式是通过 -target 指定,比如我们要在 Windows 系统上编译出 Linux 可以执行文件,并且还要进行优化,那么就可以这么做。

Windows 系统的可执行文件会带有一个 .exe 后缀,但 Linux 系统没有,而我们交叉编译的结果就是 Linux 可执行文件,所以此时生成的文件就不包含 .exe 后缀了,文件名就叫 hello。同理,除了 x86_64-linux 之外,还有 x86_64-windows 和 x86_64-macos,不过交叉编译基本都是在其它系统上编译生成 Linux 可执行文件。比如你的服务器没有 Zig 环境,那么交叉编译就很方便了。

使用构建器 API 编译 zig 文件

我们说编译 zig 文件有两种方式,分别是 zig build-exe 和 zig build,前者用于编译单个源文件,适用于简单的编译场景。而如果是一个大的项目,里面文件众多,那么就应该使用 zig build。不过在介绍 zig build 之前,我们先来说一说如何构建一个项目,首先我们创建一个 zig_demo 目录,然后在终端中 cd 到该目录中,执行命令 zig init-exe,会自动帮我们初始化相应的工程。

我们看到帮我们创建了一个 src 目录和一个 build.zig,前面我们说了 Zig 允许你自定义编译过程,而具体细节就写在 build.zig 里面。我们在 build.zig 所在目录下(即 zig_demo)执行 zig build 命令,便可进行编译,具体编译过程 Zig 已经帮我们写好了,我们不用动它。然后是 src 目录,它是源代码所在的目录,我们在 Zig 项目中编写的代码就放在 src 目录中。该目录中有一个 main.zig 源文件,这也是 Zig 自动帮我们生成的,运行的时候会自动找该文件下的 main 函数。

我们执行命令 zig build,会发现在 zig_demo 目录下多了两个子目录:zig-cache 和 zig-out。zig-cache 包含了编译时生成的中间文件,用作缓存,zig-out 里面还有一个 bin 目录,bin 目录下面则存放编译生成的可执行文件。当然啦,此时只有编译没有执行,如果你希望编译之后自动执行,那么通过 zig build run 即可。

zig 的打印语句

然后再来说一说打印,我们后面会反复使用它,所以这里先说一说。打印语句使用 std.debug.print,第一个参数是 format,里面的占位符通过 {} 表示;第二个参数就是要打印的值,并且个数要和 format 里面占位符的个数保持一致。

const std = @import("std");

pub fn main() void {
    std.debug.print("name: {s}, age: {d}\n", .{"古明地觉", 17});  // name: 古明地觉, age: 17
}

{s} 和 {d} 就类似 C 语言的 %s 和 %d,至于后面的 .{} 是什么语法,我们后续再详细说。

目前我们就简单了解了 Zig 的构建和编译,后面我们就在这里的 zig_demo 项目中编写代码,来学习 Zig 的语法。

标签:语言,编译,编程,zig,Zig,从零开始,构建,build
From: https://www.cnblogs.com/traditional/p/17725295.html

相关文章

  • linux编程总结
    这块很难说,不太好入门,并且这个知识点涉及繁多,学了还很多没用着,记录的笔记也有些粗糙,所有就不上传了,杂一点的网站就不记录来了牛客网附带项目四十小时从linux全套到webserver,其实就是嗯讲api,项目讲到一半很乱,赶工,可以速刷一遍,项目先别做大丙c++全套知识都有,适合有一点点基础的......
  • VS2015 与 ctypes 联合编程
    Python使用的版本是3.7-32bit,使用 VS2015开发dll文件。 32bit要求VS编译工程的时候必须要选择使用的是x86或者是win32. 发现的问题:使用vs2015默认的dll项目模板,标注的是Windows通用的,生成的dll不可用,在Pycharm中报126的错误,网络上有提醒可以用De......
  • Python CGI编程
    什么是CGICGI目前由NCSA维护,NCSA定义CGI如下:CGI(CommonGatewayInterface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户端HTML页面的接口。网页浏览为了更好的了解CGI是如何工作的,我们可以从在网页上点击一个链接或URL的流程:1、使用你的浏览器访......
  • 《Unix/Linux系统编程》教材学习笔记第十章
    chapter10sh编程sh脚本包含sh语句的文本文件,命令解释程序sh要执行该语句。eg.mysh.sh#!/bin/bash#commentlineechohello使用chmod+xmysh可以执行该文件。#!开头一般称为shebang,若未指定,则将运行默认sh,即Linux中的/bin/bash。sh脚本与C程序比较不难看出两者有......
  • windows系统编程(win32)
    一、编程环境操作系统:windows10-1809(17763.1557)-x64;windowskits:C:\ProgramFiles(x86)\WindowsKits\10\Include\10.0.19041.0\sharedvisualstudio2019:C:\ProgramFiles(x86)\MicrosoftVisualStudio\2019\Community\VC\Tools\MSVC\14.29.30133\include......
  • Linux服务器编程 基本API与概念
    Linux服务器编程基本API与概念基本参数和结构体协议族参数:PF_UNIX,PF_INET,PF_INET6;地址族参数(sa_family_t):AF_UNIX,AF_INET,AF_INET6;服务类型参数:SOCK_STREAM流服务;SOCK_UGRAM数据报服务;与SOCK_NONEBLOCK相与非阻塞类型;与SOCK_CLOEXEC相与fork子进程在子进程......
  • 【Java 基础篇】Java继承:打开面向对象编程的大门
    继承是面向对象编程(Object-OrientedProgramming,OOP)中的一个重要概念。在Java中,继承允许一个类(子类)从另一个类(父类)继承属性和方法。这种机制使得代码重用、扩展和维护变得更加容易。本篇博客将深入探讨Java中继承的概念、语法和最佳实践,适用于初学者,让你轻松理解和运用继承的强大功......
  • 【Java 基础篇】Java 面向对象详解:面向对象编程的艺术
    如果你正在学习Java编程,面向对象编程(Object-OrientedProgramming,OOP)是一个不可或缺的概念。Java是一种面向对象的编程语言,这意味着它的编程范式基于对象、类和继承。在本篇博客中,我们将深入探讨Java中面向对象编程的核心概念,从什么是对象开始,逐步介绍类、继承、封装、多态等重要概......
  • 编程基础C Assignments
    编程基础CAssignments喵嘤,发现舍友和同学对于课堂留的一些作业有疑惑,因此准备发一篇博客来解释一下每次课的作业。但是博客园神奇的系统,“文章”是不支持显示到主页上的,只有“随笔”可以。因此建立这个目录,它的主要作用是可以跳转到每一次作业的解释文章上面。编程基础C922A......
  • 【Java 基础篇】Java 泛型:类型安全的编程指南
    在Java编程中,泛型是一项强大的特性,它允许您编写更通用、更安全和更灵活的代码。无论您是初学者还是有经验的Java开发人员,了解和掌握泛型都是非常重要的。本篇博客将从基础概念一直深入到高级应用,详细介绍Java泛型。什么是泛型?泛型是Java编程语言的一项特性,用于实现通用性更......