If I have a dependency that can be built in different ways via a b.addOptions
entry in its build.zig
file, is there a way I can pass that option down from the package that’s importing the dependency?
had exactly the same question, but didn’t manage to tackle it yet… to emphasize, here’s a concrete example where this would be important:
- my timezone lib allows you to set a custom path to a database, e.g. to use the one on your system (
/usr/share/zoneinfo
for instance, instead of the one that ships withzdt
). Here’s the build option. However, this doesn’t make much sense if an application that uses the library has no way to set that option.
try b.addUserInputOption("name", "value");
is the same as invoking the build runner with -Dname=value
.
see: addUserInputOption
called from: zig/lib/compiler/build_runner.zig at a685ab1499d6560c523f0dbce2890dc140671e43 · ziglang/zig · GitHub
In the client package build.zig
, I do this:
const dep = b.dependency("dep", .{});
_ = dep.builder.addUserInputOption("opt", "val") catch unreachable;
In the dependency package, I have a debug.print
to print the value of the option and it remains at its default, so it’s like this isn’t actually doing anything?
Do you mean b.option
or b.addOptions
? Your opening post mentions the latter but your replies suggest you’re asking about the former.
based on what I tried so far, it seems that
fails to find the option specified in the dependency and does nothing, whereas
fails with thread 16836 panic: Option 'prefix-tzdb' declared twice
, i.e. finds the option but tries to create it (?) instead of using/configuring it.
edit: build option in dependency, attempt to set that option in toy app
Ok, I tried to reduce this by makind two small zig projects, mylib
which has in its build.zig
:
const sub = b.option(bool, "sub", "Use sub, not add.") orelse false;
const options = b.addOptions();
options.addOption(bool, "sub", sub);
const op_mod = b.addModule("op", .{
.root_source_file = .{ .path = "src/op.zig" },
});
op_mod.addOptions("options", options);
This makes mylib
either use add
or sub
as an operation.
Then myapp
has in its build.zig
:
const mylib = b.dependency("mylib", .{});
_ = mylib.builder.addUserInputOption("sub", "true") catch unreachable;
With or without the addUserInputOption
line, the result is the same, mylib
is built as if -Dsub
is never passed. I also tried addUserInputFlag
given this is just a bool flag, but same result.
Edit: I have a test in mylib
that proves the option is working when building mylib
directly.
test "Test the option" {
if (options.sub)
try std.testing.expect(op(3, 7) == -4)
else
try std.testing.expect(op(3, 7) == 10);
}
Here’s the sample:
depopt.tgz (2.3 KB)
I’ve seen an example of this in the mach project. You can pass user options of the dependency as part of the args struct:
const mylib = b.dependency("mylib", .{ .sub = true });
myapp
should set the option in it’s dependency call:
const mylib = b.dependency("mylib", .{
.sub = true,
});
Took me ages to figure this out because it’s sort of implicit and there is no explicit function you call.
that seems to work for true/false flags, but not strings: error: option 'prefix_tzdb' has unsupported type: *const [19:0]u8
In fact, this allows me to pass a boolean to an option that takes a []const u8
, which makes no sense?
Maybe that’s because of the default string litereal type in Zig being a pointer to an array and not a slice. What if you try .{ .prefix_tzdb = @as([]const u8, "foo") }
?
@sea-grass , @neurocyte : It works! I’ll mark a solution once @FObersteiner 's issue is solved too.
std.Build.addUserInputOption
is an internal API that is called by build_runner.zig
when parsing -Dfoo=bar
options, so it’s not meant to be called by user code and will not work with dependencies because their build
function has already been run and their option values resolved.
Like you’ve already discovered, you pass build options to dependencies via the anonymous args struct instance passed to b.dependency
. The arguments struct is converted to an internal map of option names and values via the private function userInputOptionsFromArgs
, which as you can see from the source code currently only accepts strings typed as []const u8
and does not accept the default pointer-to-array type that string literals are typed as (*const [n:0]u8
). (Note also that this internal map of options is just a std.StringHashMap
, so this is why you can pass booleans to options declared as strings.)
If anyone new would like to contribute to the Zig code base, extending this function to accept strings that are not explicitly typed as []const u8
would be an excellent first contribution.
jup, that’s it, nice