繁体   English   中英

如何动态导入 zig 模块?

[英]How to import zig modules dynamically?

我正在使用 zig 0.7.0. 我正在尝试从数组中导入 zig 源文件列表。 每个源文件都有一个我想调用的main function (其返回类型为!void )。 数组module_names在编译时是已知的。

这是我试图做的:

const std = @import("std");
const log = std.log;

const module_names = [_][]const u8{
    "01.zig", "02.zig", "03.zig", "04.zig", "05.zig",
};

pub fn main() void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    for (module_names) |module_name, i| {
        const module = @import(module_name); // this fails
        log.info("i {}", .{i});
        try module.main();
    }
}

即使数组在编译时已知,@ @import(module_name)也会给我这个错误:

./src/main.zig:13:32: error: unable to evaluate constant expression
        const module = @import(module_name);
                               ^
./src/main.zig:13:24: note: referenced here
        const module = @import(module_name);

如果数组是动态生成的并且只在运行时知道,我可以理解错误,但这里的module_names数组在编译时是已知的。 所以我有点迷茫...

或者,我还尝试将整个main包装在一个comptime块中:

pub fn main() void {
    comptime {
        var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
        defer arena.deinit();

        for (module_names) |module_name, i| {
            const module = @import(module_name); // no errors here
            log.info("i {}", .{i});
            try module.main();
        }
    }
}

这里@import(module_name)没有给我任何错误,但是log.info失败并出现另一个错误:

/home/jack/.zig/lib/zig/std/mutex.zig:59:87: error: unable to evaluate constant expression
            if (@cmpxchgWeak(usize, &self.state, 0, MUTEX_LOCK, .Acquire, .Monotonic) != null)
                                                                                      ^
/home/jack/.zig/lib/zig/std/mutex.zig:65:35: note: called from here
            return self.tryAcquire() orelse {
                                  ^
/home/jack/.zig/lib/zig/std/log.zig:145:60: note: called from here
            const held = std.debug.getStderrMutex().acquire();
                                                           ^
/home/jack/.zig/lib/zig/std/log.zig:222:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/main.zig:26:21: note: called from here
            log.info("i {}", .{i});

这种动态导入可以在zig中实现吗?

我认为您所追求的那种导入是可能的,我的理解是@import正在获取一个zig源文件并将其转换为结构类型。 它实际上似乎甚至可以在运行时完成(尽管不使用@import ,它需要一个comptime参数(这是您问题的重要部分)。

第一个示例失败的原因是您传递的参数module_namecomptime ,您的for循环在程序运行之前不会执行。

您解决问题的直觉是正确的,在编译时让循环进行评估(特别是捕获值和迭代器); 我认为你可以做两件事来解决它。

像您所做的那样将循环包装在一个comptime块中是可行的,但是您需要考虑在编译时评估表达式的确切含义,以及它是否有意义。 我认为log的实现会阻止你在编译时记录,所以你需要在循环内收集你感兴趣的值,并在comptime块之外记录它们。

您可以修复它的另一种方法是通过使用内联 for展开循环来强制在编译时评估循环的捕获值:

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    inline for (module_names) |module_name, i| {
        const module = @import(module_name);
        log.info("i {}", .{i});
        try module.main();
    }
}

免责声明:可能有更好的方法,我对语言比较陌生=D

Zig 0.8.0 开始@import @import 的操作数必须是字符串文字

Zig 编译器想知道所有可能导入的文件,以便在您开始编译过程时可以急切地找到它们并编译它们。 通过使快速编译器的存在成为可能,语言的设计受到了限制。

所以,我们能做些什么? 我认为这以等效的方式完成了任务:

const std = @import("std");
const log = std.log;

const modules = struct {
    pub const module_01 = @import("01.zig");
    pub const module_02 = @import("02.zig");
    pub const module_03 = @import("03.zig");
    pub const module_04 = @import("04.zig");
    pub const module_05 = @import("05.zig");
};

pub fn main() void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    inline for (@typeInfo(modules).Struct.decls) |decl, i| {
        const module = @field(modules, decl.name);
        log.info("i {d}", .{i});
        try module.main();
    }
}

这里的巧妙之处在于,事实上,编译器能够急切地获取所有 5 个文件并启动编译过程,甚至在运行编译时代码以确定实际导入哪个文件之前。 双赢。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM