Open
Description
In certain specialized scenarios such as #20382, it's important to be able to designate constructor/destructor (henceforth init/fini) functions. Init functions allow running initialization code before main()
in the case of a program, or when a shared library is loaded and thus before any exported functions are invoked. Conversely, fini functions allow running cleanup after main()
returns in the case of a program, or when a shared library is unloaded.
To make this functionality available in Zig, I propose the following:
@appendInitFiniArray(comptime ptr: *const anyopaque, comptime options: std.builtin.InitFiniOptions) void;
// std.builtin
const InitFiniOptions = struct {
array: enum { init, fini },
priority: i32 = std.math.maxInt(u16),
};
This builtin function appends ptr
to the designated array (.init_array
/.fini_array
) or the equivalent for the object format.
ptr
must be comptime-known and resolve to a function with the signaturefn () callconv(.c) void
.priority
can be anyi32
, but it should be documented that priorities in the range0
through100
tend to be used for low-level libraries like libc. That's why C compilers defaultpriority
to65535
, which seems sensible for us to do, too.- It is valid to append the same
ptr
multiple times, even with the samepriority
value, though obviously not particularly sensible.- I see no point in attempting to prevent this in Sema as there are ways to circumvent it at link time anyway, and doing so is perfectly valid at the object format level.
- The language reference should strongly discourage using this builtin function as a general-purpose initialization/cleanup mechanism, since doing so does not lead to particularly idiomatic Zig code. Basically, if you don't know whether you need
@appendInitFiniArray()
, you don't.- That's also part of why I chose this name, rather than the relatively innocent-sounding
__attribute__((constructor))
/__attribute__((destructor))
in GCC/Clang.
- That's also part of why I chose this name, rather than the relatively innocent-sounding
Example usage:
comptime {
@appendInitFiniArray(&ctor, .{ .array = .init });
@appendInitFiniArray(&dtor, .{ .array = .fini });
}
fn ctor() callconv(.c) void {
// ...
}
fn dtor() callconv(.c) void {
// ...
}