addTranslateC can't find library headers

I am transferring my project to zig 0.16.0 and since the @cImport is being depricated, i decided to move to addTranslateC.

Before, i just imported the dependency, added it’s include headers, and linked it with my executable:

build.zig

    const libssh_dep = b.dependency("libssh", .{
        .target = target,
        .optimize = optimize,
        .link_system_openssl = true,
    });
    exe.root_module.linkLibrary(libssh_dep.artifact("ssh"));
    exe.root_module.addIncludePath(libssh_dep.path("include"));

main.zig

const c = @cImport({
    @cInclude("libssh/libssh.h");
    @cInclude("libssh/server.h");
    @cInclude("libssh/callbacks.h");
});

And it worked perfectly.
Now, when i moved to addTranslateC, it just can’t find the headers.

build.zig

    const libssh_dep = b.dependency("libssh", .{
        .target = target,
        .optimize = optimize,
        .link_system_openssl = true,
    });
    exe.root_module.linkLibrary(libssh_dep.artifact("ssh"));

    const translate_c = b.addTranslateC(.{
        .root_source_file = b.path("src/c.h"),
        .optimize = optimize,
        .target = target,
        .link_libc = true,
    });
    translate_c.addIncludePath(libssh_dep.path("include"));
    exe_mod.addImport("c", translate_c.createModule());
$ zig build
install
└─ install meerkat
   └─ compile exe meerkat Debug native
      └─ translate-c 2 errors
error: translation failure
/.../src/c.h:1:10: error: 'libssh/libssh.h' not found
#include <libssh/libssh.h>
         ^
error: 2 compilation errors
failed command: /nix/store/5x5y75rc3l43ic0lwal6wzk7wi1ga3m1-zig-0.16.0/bin/zig translate-c -lc --cache-dir .zig-cache --global-cache-dir /home/jerpo/.cache/zig -I /.../zig-pkg/libssh-0.12.0-c_992s9iAABRROd8wCozUJ5-nnJdZhL9_wt1KqluuTlX/include /.../src/c.h --listen=-

I think you need to link the library with the translate_c module as well.

Because your C file has

#include <libssh/libssh.h>

I believe your addIncludePath call should instead be an addSystemIncludePath call. I believe that’s the main way Zig distinguishes the way the <filename.h> specifier differs from the "filename.h".

2 Likes

In your c.h use "" instead of <> to include the files:

#include "libssh/libssh.h"
#include "libssh/server.h"
#include "libssh/callbacks.h"

When using <> the C compiler looks for the file in the system locations.

2 Likes

Hi, @abdullah-b-al @dimdin @alanza, thanks for your answers but neither of them worked.

I believe that TranslateC does not have a linkLIbrary() method, only linkSystemLibrary(), which can’t find libssh because it is not installed on my system.

I have also tried using addSystemIncludePath with #include <libssh/libssh.h> and addIncludePath with #include "libssh/libssh.h", but to no avail.

I think i found the main problem here, the failed command points to the source code of the libssh dependency, not the output.

zig translate-c ... -I /.../meerkat/zig-pkg/libssh-0.12.0-c_992s9iAABRROd8wCozUJ5-nnJdZhL9_wt1KqluuTlX/include /.../meerkat/src/c.h --listen=-
$ ls zig-pkg/libssh-0.12.0-c_992s9iAABRROd8wCozUJ5-nnJdZhL9_wt1KqluuTlX
LICENSE  README.md  build.zig  build.zig.zon  zig-pkg

If that was always the case, i don’t know how the @cImport variant worked.

that was probably always the case, yeah. dependency.path() goes into the source tree of your dependency, just like b.path(). if you want to import the compiled artifact path, you’d modify that call.

So, the solution for me is this:

    const translate_c = b.addTranslateC(.{
        .root_source_file = b.path("src/c.h"),
        .optimize = optimize,
        .target = target,
        .link_libc = true,
    });
    translate_c.addIncludePath(libssh_dep.artifact("ssh").getEmittedIncludeTree());
    exe_mod.addImport("c", translate_c.createModule());
2 Likes