How bad are multiple @cImport's

According to the docs, you should only use @cImport once:

Usually you should only have one @cImport in your entire application, because it saves the compiler from invoking clang multiple times, and prevents inline functions from being duplicated.
Documentation - The Zig Programming Language

I have a few questions regarding this:

  • When including multiple C libraries in my project, should I use 1 @cImport that imports all of their header/source files, so that they are all under the same “C” namespace?
  • Isn’t it practically impossible to guarantee only one @cImport if you depend on other zig modules, which might themselves do their own @cImport’s?
  • How strict is this recommendation? I’m assuming that the fact that clang gets invoked multiple times would mean slower build times, so if you can live with that then it’s ok?

Hey @Loaf, welcome aboard Ziggit.

You are correct about the multiple-namespace issue.

The problem that people get themselves into is a situation like the following:

  +-----------.h-----------+
  |                        |
a.zig                    b.zig
  |                        |
  +------communicates------+
               |
               v
             Result

The issue here is that both a.zig and b.zig have their own header imports so they may have common declarations (like typedef’s) and you might think that they should be able to communicate. Like if a function foo in a.zig returns a T that was imported from the header file and a function bar in b.zig takes the same T in defined in the same header file, you might assume they should be able to communicate. After all, it’s the same header, right?

Here, if a.zig and b.zig have their own cimports, those types will not be considered the same and they’ll each get their own declarations, etc.

Instead, if we make a common include between them and import that to both .zig files, we can now communicate.


The other situation you are referring to is having multiple cimports for different header files. Say a.zig takes foo.h and b.zig takes bar.h. If both of these do not expect to communicate on some common user-defined C type, there’s no issue here really. Each one is insular and thus it doesn’t really matter - no types to be confused between the two.

Hope that helps.

3 Likes