Hi, first time posting on Ziggit!
I had a shower thought today and I’d like to know how plausible it is.
I am one of those people who is unfortunately stuck with C++ in their day job. One area that is very frustrating for me in C++ is the metaprogramming (do not get me started on the syntax for the newly accepted reflection in C++26). So, my thought was this: what if I can use Zig for my metaprogramming needs by generating C headers and then gluing it all together with some minimal C++ code?
I would ideally like to leverage the caching functionality of the Zig buildsystem and then just minimally modify the main CMake file to call something like zig build gen.
I noticed that there is functionality for generating header files, but it is not clear how well of a supported use case it is currently, seeing that there is this open issue #9698
I would appreciate input from anyone who has tried or has experience with this type of thing, thanks!
3 Likes
Hi @minkatter, welcome to Ziggit.
That is an intriguing proposition. While I haven’t personally done what you are suggesting, I wanted to add some context.
Currently, the emit-h capabilities of the compiler have not been added back to the self-hosted compiler, although there have been attempts. There was a recent PR attempt, but it got stale and didn’t make it in. Most people write their own header files. Tigerbeetle actually has a program to do it: tigerbeetle/src/clients/c/tb_client_header.zig at main · tigerbeetle/tigerbeetle · GitHub
Are you wanting to take C++ files and run those through zig to do the metaprogramming? Or are you wanting to write structs/comptime in Zig and translate that into C/C++ headers?
I am looking to do more like the latter. I would like to use comptime to generate some structs and helper functions that I can then translate to C structs. My understanding is that I might be limited by the fact that Zig actively tries to prevent injecting new types, so I might need workarounds like having my own string processing, but I would still be more comfortable doing that in Zig.
Having now taken a look at @Southporter 's link, it would seem string processing is what TigerBeetle does:
fn emit_struct(
buffer: *std.ArrayList(u8),
comptime type_info: anytype,
comptime c_name: []const u8,
) !void {
try buffer.writer().print("typedef struct {s} {{\n", .{c_name});
inline for (type_info.fields) |field| {
try buffer.writer().print(" {s} {s}", .{
resolve_c_type(field.type),
field.name,
});
switch (@typeInfo(field.type)) {
.array => |array| try buffer.writer().print("[{d}]", .{array.len}),
else => {},
}
try buffer.writer().print(";\n", .{});
}
try buffer.writer().print("}} {s};\n\n", .{c_name});
}
Thanks for the reference!
3 Likes