Zig从XX到放弃(1)C/C++/Zig混合工程

Zig

Zig是一门野心有点大,语法有点别扭,目前还在0.10版本的系统编程语言。

都不记得我是怎么开始拉开网站看了几眼的。问就是加班到人脑宕机,问就是扩展视野,问就是寻找创新灵感。

具体的介绍就不抄了,团队的中文化工作做的不错,说明版本开发的速度超慢……

有意思的特点

Zig有几个很有意思的地方:

  1. 只有一个可执行文件zig.exe
  2. 可以作为C语言工具链,zig cc main.c
  3. 可以作为C++工具链,zig c++ main.cpp
  4. 可以作为Zig的工具链,zig main.zig
  5. 语言自带构建系统,Zig构建系统,并且构建程序用zig语言编写,zig build
  6. 自带单元测试,zig build test

稍微看一看,可玩性非常强。

目前的缺点:文档相对薄弱。

C/C++/Zig混合工程

概貌

稍微一看,我就想做一个玩具工程,这个玩具工程中:一个模块用c编写,一个模块用Zig编写,一个模块用c++编写。

这个玩具就是测量一段代码的运行时间,用微秒来计算,分辨率是纳秒。准备用c做一个被测函数,用zig做一个被测函数,测量时间的代码用c++完成(chrono很好用)。

安装zig之后,创建一个工程:

zig init-exe

增加几个目录和模块,最后的目录结构如下。

工程目录
其中可以zig帮助创建的文件包括:

  1. build.zip:构建用的文件;
  2. src:源代码目录;
  3. src/main.zig:可执行程序

自行增加的文件包括:

  1. src/include:头文件
  2. src/sum:c模块
  3. src/timeit:c++模块
  4. fabinaci.zip:zig模块

主程序

主程序的逻辑非常简单:

  1. 导入标准库中的输出函数;
  2. 导入zig模块fabinaci;
  3. 导入c语言模块sum;
  4. 导入c++模块timeit;
  5. 编写用C语言调用模式的两个被测函数;
  6. 主函数:测试两个函数的运行时间,打印出来。
const print = @import("std").debug.print;
// Zig package
const fabinaci_zig = @import("fabinaci").fabinaci;
// c package
const sum_c = @cImport({
    @cInclude("sum.h");
});
// c++ package
const timeit_cpp = @cImport(@cInclude("timeit.h"));

fn fabinaci23() callconv(.C) void {
    _ = fabinaci_zig(20);
}
fn sum_test() callconv(.C) void {
    _ = sum_c.sum(10, 20);
}

pub fn main() !void {
    print("{} + {} = {}\t\t{d:>12.3} ms\n", .{ 20, 10, sum_c.sum(10, 20), timeit_cpp.time_it(sum_test) });

    print("fabinaci({}) = {}\t{d:>12.3} ms\n", .{ 20, fabinaci_zig(20), timeit_cpp.time_it(fabinaci23) });
}

跟一般教程中多出来的就是callconv(.C),这里限定了函数的调用方式。

fn sum_test() callconv(.C) void {
    _ = sum_c.sum(10, 20);
}

Zig模块

代码乏善可陈。据说递归调用可能会堆栈溢出。

pub fn fabinaci(n: u128) u128 {
    if (n == 0) return 0;
    if (n == 1) return 1;
    return fabinaci(n - 1) + fabinaci(n - 2);
}

C语言模块

没错,这是几行侮辱智商的代码。

头文件:

#ifndef __SUM_IT_H
#define __SUM_IT_H
int sum(int x, int y);
#endif /* __TIME_IT_H */

.c文件

#include "sum.h"
int sum(int x, int y)
{
    return x + y;
}

C++模块

头文件:

#ifndef __TIME_IT_H
#define __TIME_IT_H
// time the execution of the code
float time_it(void(*f)(void));
#endif /*__TIME_IT_H*/

cpp文件:

#include <chrono>

#ifdef __cplusplus
extern "C" {
#endif

    #include "timeit.h"

    float time_it(void(*f)(void))
    {
        auto start = std::chrono::high_resolution_clock::now();
        f();
        auto end = std::chrono::high_resolution_clock::now();
        return std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() * 1e-3;
    }   

#ifdef __cplusplus
}
#endif

构建脚本

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{});

    // Standard release options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
    const mode = b.standardReleaseOptions();
    const exe = b.addExecutable("hello-world", "src/main.zig");
    exe.linkLibCpp();
    exe.addIncludePath("src/include");
    exe.addCSourceFiles(&.{ "src/sum/sum.c", "src/timeit/timeit.cpp" }, &[_][]const u8{});
    exe.addPackagePath("fabinaci", "src/fabinaci.zig");    
    exe.setTarget(target);
    exe.setBuildMode(mode);
    exe.install();
    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_tests = b.addTest("src/main.zig");
    exe_tests.setTarget(target);
    exe_tests.setBuildMode(mode);

    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&exe_tests.step);
}

这个脚本在系统默认的文件中,增加了几行。

    exe.linkLibCpp();
    exe.addIncludePath("src/include");
    exe.addCSourceFiles(&.{ "src/sum/sum.c", "src/timeit/timeit.cpp" }, &[_][]const u8{});
    exe.addPackagePath("fabinaci", "src/fabinaci.zig");   

第一行是链接C++的库文件,这样才能使用chrono;第二行是设置包含文件目录;第三行增加两个文件(c和c++);第四行,增加zig文件(这里第一个参数就是包的名字)。

结果

zig build run

即可以运行:

在这里插入图片描述

总结

  1. Zig看起来挺好玩,编译时计算、内存管理、所见即所得;
  2. 工具使用起来也比C和C++要现代很多很多倍,我已经很多年不用C和C++就是工具链的品质实在是太上古……
  3. 整个概念相当完美,下一个正经的不正经工程可以用下Zig。
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大福是小强

除非你钱多烧得慌……

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值