How to incorporate the C++ standard library into a Zig program?

Viewed 75

In reading the documentation for zig, I was under the impression that zig could compile both C and C++ code. Consequently, I thought you could import a C++ file's header via @cImport and have zig build succeed. However, I can't seem to get this to work for a C++ library integration.

I first create my project, zig init-lib and then add my import to src/main.zig via the @cImport directive. Specifically, I @cInclude("hooks/hooks.h") the C++ header file of this library. If I attempt to zig build at this point, the build fails, unable to find the header. I fix this by modifying build.zig to lib.addIncludeDir("/usr/include/library").

Since this C++ library is now being parsed and uses the C++ standard library, the next error I get when I zig build is that the stdexcept header is not found. To fix this, I modify build.zig to lib.linkSystemLibrary("c++").

Lastly, and the error I'm stuck on now, is an assortment of errors in /path/to/zig-linux-x86_64-0.9.1/lib/libcxx/include/<files>. I get stuff like unknown type name '__LIBCPP_PUSH_MACROS, unknown type name 'namespace', or unknown type name 'template'. Googling this, the only thing of partial relevance that I could find was that this is due to clang's default interpretation of .h files is as C files which obviously don't have namespace or template keywords, but I don't know what to do with that knowledge. LLVM on MacOs - unknown type name 'template' in standard file iosfwd

Does anyone have any insight as to how to actually integrate with a C++ (not pure C) library through zig?

1 Answers

Specifically, I @cInclude("hooks/hooks.h") the C++ header file of this library.

@cImport() is for translating C header files into zig so they can be used without writing bindings. Unfortunately, it does not support C++ headers. To use a C++ library, you'll have to write C bindings for it and then @cImport() those headers.

// src/bindings.cpp
#include <iostream>

extern "C" void doSomeCppThing(void) {
    std::cout << "Hello, World!\n";
}
// src/bindings.h
void doSomeCppThing(void);
// build.zig
const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const target = b.standardTargetOptions(.{});

    const mode = b.standardReleaseOptions();

    const exe = b.addExecutable("tmp", "src/main.zig");
    exe.setTarget(target);
    exe.setBuildMode(mode);

    exe.linkLibC();
    exe.linkSystemLibrary("c++");
    exe.addIncludeDir("src");
    exe.addCSourceFile("src/bindings.cpp", &.{});

    exe.install();
}
// src/main.zig
const c = @cImport({
    @cInclude("bindings.h");
});

pub fn main() !void {
    c.doSomeCppThing();
}
Related