How should i generate CC and CXX in build.zig

I want to build some C project that uses CMake as its build system. I am planning to fork the project and add a build.zig file there. CMake allows setting the C and C++ compiler, so I want to set them to use Zig as the compiler.

Naturally, CC can be zig cc and CXX can be zig c++, but I also use b.graph.zig_exe to get the full path to the zig compiler. Now the tricky part is the cross compilation. I know that I should set the value for --target also. I thought of constructing it via target.result.linuxTriple.

All these steps seem to work, but I just want to know if there is an easier way to do this? Perhaps some magic command I missed.

You’re probably better off just porting the entire build pipeline to a build.zig. You don’t even need to fork the project to do that.

Take a look at All Your Codebase · GitHub for a ton of examples.

I don’t think it’s productive to say just port it to Zig. There are enough libraries with complicated build processes. Zig has the ability to link to prebuilt libraries, and projects already have their tested and maintained build processes, so I don’t see any reason to port those build processes to Zig. I just want a way for Zig to let me tell it how to build a project, declare what will be available to it so it has the ability to link those libraries to other Zig artifacts.

1 Like

In my experience porting to the Zig build system is the shortest path to victory when you want cross-compilation.

That said, it’s certainly not the only one. If your build scripts are already designed to support cross-compilation, then maybe you will be able to make it work without too much fuss.

Personally, I port the build system first and ask questions later, so to speak.

I said it’s tricky only because I need to figure out the triplet, it’s not actually difficult after that. For sane C and C++ projects, cross compilation is usually just setting the correct compiler. In this case, I see that I only need to set the CC and CXX variable to the correct value, and everything is fine. Doing it by hand already works, I just need to figure out how to define those in build.zig.

Furthermore, I have experience in cross compiling C++ projects, but I am still new to Zig so I want to learn how to do things. So I didn’t expect to be told to just rewrite all the things I need in Zig when I just want to have something working to try out Zig in my projects.

Also, I don’t mind this approach, at least when I’m more proficient with Zig build system. However, I still don’t see myself porting projects that even the author discourages that (LuaJIT being the prime example). So I think if it is possible to build from source with Zig being the compiler by specifying a few variables correctly, it should be done so and I don’t think it’s a big ask.

CMake’s way to handle this is the toolchain file

This one serves as a good example:

To be honest, I stopped using toolchain file after CMake 3.24 because I see presets and CMAKE_PROJECT_TOP_LEVEL_INCLUDES being superior.

Just to make myself clear, I’m not asking how to use Zig as a compiler to compile CMake projects, I know how to do that already. In this topic, I’m merely asking is there a way to easily construct the CC and CXX variables. (I have encountered other problems but I will ask them in another topic)

Are you looking for this?

https://ziglang.org/documentation/master/std/#std.Build.Step.Run.setEnvironmentVariable

More or less, I eneded up with this

    const triple = target.result.linuxTriple(b.allocator) catch @panic("OOM");
    const cc = std.fmt.allocPrint(
        b.allocator,
        "-DCMAKE_C_COMPILER='{s};cc;--target={s}'",
        .{ b.graph.zig_exe, triple },
    ) catch @panic("OOM");
    const cxx = std.fmt.allocPrint(
        b.allocator,
        "-DCMAKE_CXX_COMPILER='{s};c++;--target={s}'",
        .{ b.graph.zig_exe, triple },
    ) catch @panic("OOM");
    const build_type = if (optimize == .Debug) "-DCMAKE_BUILD_TYPE=Debug" else "-DCMAKE_BUILD_TYPE=Release";
    const cmake = b.findProgram(&.{"cmake"}, &.{}) catch @panic("CMake not found");

    const cmake_configure = b.addSystemCommand(&.{
        cmake,
        "-G=Ninja",
        "-B",
        upstream.path("build").getPath(b),
        "-S",
        upstream.path("").getPath(b),
        cc,
        cxx,
        "-DWITH_PERF_TOOL=OFF",
        "-DZMQ_BUILD_TESTS=OFF",
        "-DENABLE_CPACK=OFF",
        "-DENABLE_DRAFTS=ON",
        build_type,
    });

1 Like

That’s as good a solution as any. I do find zig build a bit wordy. Actually you can use b.fmt I think instead of allocPrint – any time you think you need an allocator, there’s probably a shorter way to do it using an interface from Build.

2 Likes

that’s awesome, thanks for mentioning it.

As a follow-up to my post in your other thread (TL;DR: don’t use getPath), a more proper solution would look something like this:

const cmake = b.findProgram(&.{"cmake"}, &.{}) catch @panic("CMake not found");
const triple = target.result.linuxTriple(b.allocator) catch @panic("OOM");

const cmake_configure = b.addSystemCommand(&.{
    cmake,
    "-G=Ninja",
    "-B",
});
const build_dir = cmake_configure.addOutputDirectoryArg("build");
cmake_configure.addArg("-S");
cmake_configure.addDirectoryArg(upstream.path(""));
cmake_configure.addArgs(&.{
    b.fmt("-DCMAKE_C_COMPILER='{s};cc;--target={s}", .{ b.graph.zig_exe, triple }),
    b.fmt("-DCMAKE_CXX_COMPILER='{s};c++;--target={s}", .{ b.graph.zig_exe, triple }),
    "-DWITH_PERF_TOOL=OFF",
    "-DZMQ_BUILD_TESTS=OFF",
    "-DENABLE_CPACK=OFF",
    "-DENABLE_DRAFTS=ON",
    b.fmt("-DCMAKE_BUILD_TYPE={s}", .{if (optimize == .Debug) "Debug" else "Release"}),
});

const cmake_build = b.addSystemCommand(&.{
    cmake,
    "--build",
});
cmake_build.addDirectoryArg(build_dir);

// replace exe with whatever you want to link with libzmq.a
exe.addObjectFile(build_dir.path(b, "libzmq.a"));

// exe must also depend on the `cmake --build` command
// to ensure libzmq.a is actually built
exe.step.dependOn(&cmake_build.step);

I haven’t tested this, so some details might be off, but I believe this should be roughly correct.