I have a Zig codebase that I'm compiling to WebAssembly with a build.zig like this:
const std = #import("std");
pub fn build(b: *std.build.Builder) void {
const mode = b.standardReleaseOptions();
const lib = b.addSharedLibrary("main", "src/main.zig", b.version(0, 0, 0));
lib.setBuildMode(mode);
lib.setTarget(.{.cpu_arch = .wasm32, .os_tag = .freestanding});
lib.setOutputDir("web/dist");
b.default_step.dependOn(&lib.step);
}
Inside src/main.zig there's an extern that marks a function provided through the WebAssembly imports.
extern fn printString(message: [*]u8, length: usize) void;
This works fine when running in the browser, but I'm trying to add tests to the project, but whenever I attempt to run zig test on main.zig (or any file with extern) I get the following linker error.
MachO Flush... error(link): undefined reference to symbol '_printString'
It might be worth pointing out that nothing in my test "..." {} blocks actually touches any of these extern functions.
Is there a sane way to link to alternate implementations of these externs during tests? Or any other workarounds that would allow me to write tests?
You can use combine #import("builtin").is_test and usingnamespace to create stubs for extern functions during tests.
const builtin = #import("builtin");
pub usingnamespace if (!builtin.is_test) struct {
pub extern fn printString(message: [*]u8, length: usize) void;
} else struct {
pub fn printString(message: [*]u8, length: usize) void {
_ = message;
_ = length;
}
}
pub usingnamespace makes all the members of the struct part of the module's public struct, and during tests we just use a different struct that doesn't rely on any external functions.
Credit to mitchellh/zig-js.
Related
How can this const print variable behave like a function?
const print = #import("std").debug.print;
print("hello, world", .{});
I understand you can assign expressions to variables. But this seems to behave like a precompiler macro in c/c++, I wouldn't have guessed that.
Is it because "all variables declared in a comptime expression are implicitly comptime variables" and # makes it a comptime expression, so it is evaluated before compilation, much like a macro would in c?
Could someone elaborate a bit? This seems a very powerful feature.
# does not indicate a comptime expression; rather # prefixes built-in functions in Zig. #import returns a struct that provides access to the declarations made public by the imported file.
The expression #import("std").debug.print evaluates to the print function defined in the standard library file std/debug.zig; it is not the expression that is assigned to print in the posted code, but the function. That is, the posted code works because print in OP code is actually a function. This can be seen by running the code below:
const print = #import("std").debug.print;
pub fn main() void {
print("#TypeOf print: {}\n", .{ #TypeOf(print) });
}
Results:
$ zig run print_type.zig
#TypeOf print: fn(comptime []const u8, anytype) void
Function Assignment
OP has asked for another example of assigning a function that is not imported to an identifier:
const print = #import("std").debug.print;
fn my_function(msg: []const u8) void {
print("{s}\n", .{ msg });
}
const my_function_alias = my_function;
pub fn main() void {
const another_function_alias = my_function;
const yet_another_function_alias = my_function_alias;
my_function("mf");
my_function_alias("mfa");
another_function_alias("afa");
yet_another_function_alias("yafa");
}
Program output:
$ zig run function_assignment.zig
mf
mfa
afa
yafa
I'm new to Zig and wanted to use the cImport to call out to the GNU Multiprecision library GMP. I got this to work but it feels awkward because Zig apparently doesn't cast from arrays to pointers by default and GMP uses this approach to pass by reference. Is there a cleaner approach than mine? Are there existing examples of Zig calling GMP?
const gmp = #cImport({
#cInclude("gmp.h");
});
pub fn main() void {
var x: gmp.mpz_t = undefined;
gmp.mpz_init(&x[0]);
gmp.mpz_set_ui(&x[0], 7);
gmp.mpz_mul(&x[0], &x[0], &x[0]);
_ = gmp.gmp_printf("%Zd\n", x);
}
You should be able to drop the [0]:
const gmp = #cImport({
#cInclude("gmp.h");
});
pub fn main() void {
var x: gmp.mpz_t = undefined;
gmp.mpz_init(&x);
gmp.mpz_set_ui(&x, 7);
gmp.mpz_mul(&x, &x, &x);
_ = gmp.gmp_printf("%Zd\n", x);
}
Is this possible in zig? And if so how would something like the following C++ code look in Zig?
template<class T>
class vec3
{
union
{
struct{ T x,y,z; };
T vec_array[3];
};
};
No, there is no such thing supported in Zig, and it is unlikely there ever will be. The closest you'll get is something like this:
const std = #import("std");
pub fn Vec3(comptime T: type) type {
return extern union {
xyz: extern struct { x: T, y: T, z: T },
arr: [3]T,
};
}
test {
var v3: Vec3(u32) = .{ .arr = .{ 42, 73, 95 } };
try std.testing.expectEqual(v3.arr[0], v3.xyz.x);
try std.testing.expectEqual(v3.arr[1], v3.xyz.y);
try std.testing.expectEqual(v3.arr[2], v3.xyz.z);
}
where the extern qualifiers here make the containers behave in accordance with the C ABI (and in the case of the union, makes it defined behavior to access any member).
See this comment under proposal #985 for a fairly comprehensive rationale on as to why "anonymous field nesting" was rejected.
This is a much simplified version of my real issue but hopefully demonstrates my question in a concise manner.
My question is about the interface to printKeys. I have to pass in the type of the data to be printed as a comptime parameter, and the easiest way to get this is to use #TypeOf on the map at the point of calling it.
Coming from C++ this seems slightly inelegant that the type can't be inferred, although I do like being explicit too.
Is there a more idiomatic way to have a generic function in zig that doesn't need this use of #TypeOf at the point of calling, or a better way to do this in general?
const std = #import("std");
fn printKeys(comptime MapType: type, data: MapType) void {
var iter = data.keyIterator();
while (iter.next()) | value | {
std.debug.print("Value is {}\n", .{value.*});
}
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var map = std.AutoHashMap(i32, []const u8).init(allocator);
defer map.deinit();
try map.put(10, "ten");
try map.put(12, "twelve");
try map.put(5, "five");
printKeys(#TypeOf(map), map);
}
use anytype. you can find more examples in zig docs (Ctrl + F) and search anytype
fn printKeys(data: anytype) void {
...
}
pub fn main() !void {
...
printKeys(map);
}
I would like to bind the operator() using Boost::Python but I don't really see how to do this. Consider the example:
C++:
class Queuer
{
public:
void Queuer::operator()(const qfc::Queue & iq, const qfc::Message & im) const;
void Queuer::operator()(const qfc::Agent & ia, const qfc::Message & im) const;
// some other overloaded operator() methods
};
So in a Python script, after importing the module I'm using (called qfc), I would like to do:
Python:
>>> queuer = qfc.Queuer()
// instantiating a Message an Agent and a Queue object
>>> queuer(queue,message)
>>> queuer(agent,message)
>>> ...
Would you have any idea on how to do it? maybe with boost::python call<>?
Thank you,
Kevin
When exposing the Queuer class, define a __call__ method for each Queuer::operator() member function. Boost.Python will handle the appropriate dispatching based on types. The only complexity is introduced with pointer-to-member-function syntax, as the caller is required to disambiguate &Queuer::operator().
Additionally, when attempting to pass derived classes in Python to a C++ function with a parameter of the Base class, then some additional information needs to be exposed to Boost.Python:
The base C++ class needs to be exposed with class_. For example, class_<BaseType>("Base").
The derived class needs to explicitly list its base classes when being exposed with bases_. For example, class_<DerivedType, bases<BaseType> >("Derived"). With this information, Boost.Python can do proper casting while dispatching.
Here is a complete example:
#include <iostream>
#include <boost/python.hpp>
// Mockup classes.
struct AgentBase {};
struct MessageBase {};
struct QueueBase {};
struct SpamBase {};
struct Agent: AgentBase {};
struct Message: MessageBase {};
struct Queue: QueueBase {};
struct Spam: SpamBase {};
// Class with overloaded operator().
class Queuer
{
public:
void operator()(const AgentBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Agent." << std::endl;
}
void operator()(const QueueBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Queue." << std::endl;
}
void operator()(const SpamBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Spam." << std::endl;
}
};
/// Depending on the overlaod signatures, helper types may make the
/// code slightly more readable by reducing pointer-to-member-function syntax.
template <typename A1>
struct queuer_overload
{
typedef void (Queuer::*type)(const A1&, const MessageBase&) const;
static type get(type fn) { return fn; }
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose only the base class types. Do not allow the classes to be
// directly initialized in Python.
python::class_<AgentBase >("AgentBase", python::no_init);
python::class_<MessageBase>("MessageBase", python::no_init);
python::class_<QueueBase >("QueueBase", python::no_init);
python::class_<SpamBase >("SpamBase", python::no_init);
// Expose the user types. These classes inerit from their respective
// base classes.
python::class_<Agent, python::bases<AgentBase> >("Agent");
python::class_<Message, python::bases<MessageBase> >("Message");
python::class_<Queue, python::bases<QueueBase> >("Queue");
python::class_<Spam, python::bases<SpamBase> >("Spam");
// Disambiguate via a varaible.
queuer_overload<AgentBase>::type queuer_op_agent = &Queuer::operator();
python::class_<Queuer>("Queuer")
// Disambiguate via a variable.
.def("__call__", queuer_op_agent)
// Disambiguate via a helper type.
.def("__call__", queuer_overload<QueueBase>::get(&Queuer::operator()))
// Disambiguate via explicit cast.
.def("__call__",
static_cast<void (Queuer::*)(const SpamBase&,
const MessageBase&) const>(
&Queuer::operator()))
;
}
And its usage:
>>> import example
>>> queuer = example.Queuer()
>>> queuer(example.Agent(), example.Message())
Queuer::operator() with Agent.
>>> queuer(example.Queue(), example.Message())
Queuer::operator() with Queue.
>>> queuer(example.Spam(), example.Message())
Queuer::operator() with Spam.
Thanks for your help.
Actually I've already tested the static cast solution. In reality, I need to pass a qfc::lqs::Message or qfc::lqs::Agent or qfc::lqs::Spam when invoking queuer(). qfc::lqs::Message for example, as for qfc::lqs::Agent inherit from qfc::Message and qfc::Agent respectively.
So can I "cast" qfc::lqs::Message, qfc::lqs::Agent and qfc::lqs::Spam to qfc::Message, qfc::Agent and qfc::Spam when invoking the operator() so that the signature corresponds to operator() ?
This to avoid the error shown below:
error: invalid static_cast from type '<unresolved overloaded function type>' to type 'void (qfc::lqs::Queuer::*)(const qfc::lqs::Queue&, const qfc::lqs::Message&)const'