#zig build for c++ - unit tests?

1 messages · Page 1 of 1 (latest)

topaz yacht
#

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?

topaz yacht
#

@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?

topaz yacht
#

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

GitHub

A modern, C++-native, test framework for unit-tests, TDD and BDD - using C++14, C++17 and later (C++11 support is in v2.x branch, and C++03 on the Catch1.x branch) - catchorg/Catch2

warped fractal
#

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

topaz yacht
#

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
#

oh yeah that works too

#

would be effectively the same

topaz yacht
#

@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

warped fractal
#

can you show me the build.zig that you made

topaz yacht
#

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);
    }
warped fractal
#

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

topaz yacht
#

Trying it now

#

That seems to have done it with an empty struct literal

#

You've been a lifesaver. Thank you