What's the best approach to add a c++ unit test library to my c++ code that uses zig build? Do I need to write a build.zig for the libraries I want to use, or is there something I can do in my own build file -- I guess I can just try and emulate fetch_content and download the git repo of the unit test library as a part of running my build?
#zig build for c++ - unit tests?
1 messages · Page 1 of 1 (latest)
@warped fractal Hey, I've got this extract from my top level build.zig:
if (enable_testing) {
const optimize = b.standardOptimizeOption(.{});
const catch2_dep = b.dependency("catch2", .{.target = b.host, .optimize = optimize});
const catch2 = catch2_dep.artifact("lib");
const test_exec = b.addExecutable(.{
.name = "test",
.target = b.host,
});
test_exec.linkLibCpp();
test_exec.addIncludePath(.{ .path = "include/" });
test_exec.linkLibrary(catch2);
test_exec.installLibraryHeaders(catch2);
test_exec.addCSourceFiles(.{
.files = &source_files ++ [_][]const u8{
// test files here in `tests` dir
},
.flags = &.{ "-std=c++20", "-Wall", "-Wextra" }
});
b.installArtifact(test_exec);
}
And I'm getting this error:
-> zig build -Dtest=true
info: available artifact: 'catch2'
thread 15176 panic: unable to find artifact 'lib'
Where does the artifact name come from? The include/catch2/build.zig file you gave me left b.installArtifact(lib) alone - or does it expect the name of the static library?
oop yea, changing the catch2_dep.artifact() call to accept "catch2" seems to be doing it (still building)
So, my multiple artifacts, can I have them have different entrypoints?
wdym?
oh yeah whoops
As in, I have my main executable to run my code from main(), and I want my second test executable to run the catch2 code, which looks like it happens through this library, I think? https://github.com/catchorg/Catch2/blob/ed6ac8a629f9a4206575be784c1e340da2a94855/src/CMakeLists.txt#L411
not sure
personally the way id do it is have a thin main.cpp file which just does
#include "testing.hpp"
#include "real_main.hpp"
int main(int argc, char **argv) {
#ifdef TEST
return test_main(argc, argv);
#else
return real_main(argc, argv);
#endif
}
and then have a test step in your build.zig that recompiles and runs the executable with exe.defineCMacro("TEST", &.{});
that way zig build run will run the real_main function and zig build test will run the test_main function
I dont think you can do it without recompiling easily
That’s a clunky approach, but I’ve just realised I can just have separate main.cpp files included in the list of files I compile for each executable
@warped fractal (Sorry for the ping) -- coming back to this, I'm trying to work out how to include catch headers in my tests code now - where does zig put them? I'm not worried about actually reading them, but at compile time, I'm getting errors because the compiler can't find where the files are.
Although I think it might be down to the file that's generated here as it's the catch_user_config that's in the errors:
var catch_user_config_header = std.Build.Step.ConfigHeader.create(b, .{
.style = .{.cmake = catch2_dep.path("src/catch2/catch_user_config.hpp.in")},
.include_path = "catch2/catch_user_config.hpp",
});
I've found where the files are (zig-cache/i/54a2ed3419f58559a251abc3a975d774/include/catch2/) but that doesn't exist, so maybe it's not generating it? I'll keep digging
can you show me the build.zig that you made
This is the relevant part of it:
if (enable_testing) {
const catch2_dep = b.dependency("catch2", .{.target = b.host, .optimize = optimize});
const catch2 = catch2_dep.artifact("catch2");
const test_exec = b.addExecutable(.{
.name = "test",
.target = b.host,
});
test_exec.linkLibCpp();
test_exec.addIncludePath(.{ .path = "include/" });
test_exec.linkLibrary(catch2);
test_exec.installLibraryHeaders(catch2);
test_exec.addCSourceFiles(.{
.files = &source_files ++ &test_files,
.flags = &.{ "-std=c++20", "-Wall", "-Wextra" }
});
b.installArtifact(test_exec);
}
hm this is weird though
it should just work
maybe for some reason the ConfigHeader stuff doesnt get included in installLibraryHeaders
but also, it is definitely generating it since it uses it on build time and it finds it
ah
yeah
you need to add
lib.installConfigHeader(catch_user_config_header, .{.dest_rel_path= "catch2/"})
something like that I think
or maybe just .{} for that last struct literal
try both lol