Tried to import a custom c header file and failed werror: root source file struct 'cimport' has no memberith

i have a small c bitmap implementation that includes, a header c, a bitmap.c and a main.c, i then used the code:

pub const import_c = @cImport({
    
    @cDefine("BITMAP_H", {});
    @cInclude("bitmap.h");
});

i compiled with “zig build-exe main.zig -lc -I /home/alice7/.dev/day8/bitmap/zig/src”, the “-I” was because zig cant find the bitmap.h, which they are all in the same directory.

after that, i had error:

zig build-exe main.zig -lc -I /home/alice7/.dev/day8/bitmap/zig/src
main.zig:23:17: error: root source file struct 'cimport' has no member named 'bitmap_create'
    _ = import_c.bitmap_create(rows, cols);
        ~~~~~~~~^~~~~~~~~~~~~~
/home/alice7/.dev/day8/bitmap/zig/.zig-cache/o/12ba35f73bd6c6fb58ff4052278a3ce1/cimport.zig:1:1: note: struct declared here
pub const __builtin_bswap16 = @import("std").zig.c_builtins.__builtin_bswap16;
^~~
referenced by:
    main: /nix/store/whqfx1y8x9274qhqvfamyyp4157b9l1a-zig-0.14.0-dev.2639+15fe99957/lib/std/start.zig:656:37
    comptime: /nix/store/whqfx1y8x9274qhqvfamyyp4157b9l1a-zig-0.14.0-dev.2639+15fe99957/lib/std/start.zig:58:30
    2 reference(s) hidden; use '-freference-trace=4' to see all references

truth is, the bitmap.h has everything correctly stated, because i tested those c programs by running gcc, they works fine, and here is the bitmap.h file, you can clearly see, ‘bitmap_create’ is there:

#ifndef BITMAP_H
#define BITMAP_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

/**
 * struct Bitmap
 * brief A bitmap data structure to store binary data.
 */
typedef struct {
    uint64_t* rows;  ///< Array of uint64_t values representing the bitmap.
    int num_rows;    ///< Number of rows in the bitmap.
} Bitmap;

/**
 * brief Creates a new bitmap with the specified number of rows and columns.
 *
 * param rows The number of rows in the bitmap.
 * param cols The number of columns in the bitmap.
 * return A pointer to the newly created bitmap, or NULL on failure.
 */
Bitmap* bitmap_create(int rows, int cols);

/**
 * brief Sets a bit in the bitmap at the specified row and column to 1.
 *
 * param b The bitmap to modify.
 * param row The row index of the bit to set.
 * param col The column index of the bit to set.
 */
void bitmap_set_bit(Bitmap* b, int row, int col);

/**
 * brief Retrieves the value of a bit in the bitmap at the specified row and column.
 *
 * param b The bitmap to query.
 * param row The row index of the bit to retrieve.
 * param col The column index of the bit to retrieve.
 * return 1 if the bit is set, 0 otherwise.
 */
int bitmap_get_bit(Bitmap* b, int row, int col);

#endif  // BITMAP_H

at this point, i am very lost as to how to troubleshot, also, i do not like using zig build-exe main.zig, within ./src, i want to build like, zig build run, i found something could be useful: Using a single-header C library from Zig, but i cant apply the exact logic to my own code here, since it does not even compile, and zig documentation about using c code is little to none, where do i even search for the correct compile command based on different situations? here, it really isnt very complicated case, imho.

anyone with some ideas willing to share are greatly appreciated

all ‘@’ has been deleted, otherwise i can not post.

I edited to add code fences and make it easier to read

thank you so much, could you please tell me how did you edit the code? because they looks much better and cleaner.

thanks again

You can use markdown syntax. To add a code fence, use ```

You should remove @cDefine("BITMAP_H", {}); from your Zig code. After including bitmap.h, your @cImport code looks like this:

#define BITMAP_H
#ifndef BITMAP_H
#define BITMAP_H

/* the rest of your code */

#endif

which turns into an empty file, since the #ifndef condition is false (BITMAP_H is defined at that point).


The purpose of the C header guard pattern you’re using in bitmap.h is to prevent against duplicate definitions, for example if you had another header file image.h which also included bitmap.h, the pattern makes it safe to write

#include "bitmap.h"
#include "image.h"

since after the first inclusion of bitmap.h anywhere in the compilation unit, BITMAP_H will be defined, and any further inclusions won’t expand to anything.

4 Likes
const c_bitmap = @cImport({
    @cInclude("bitmap.h");
});

_ = c_bitmap.bitmap_create(10, 10);

this code gives linkage error:
error: ld.lld: undefined symbol: bitmap_create
note: referenced by main.zig:22
note: main.o:(main.main)

should I just include bitmap.c as well? otherwise i need to modify this line ‘zig build-exe main.zig -I /home/alice7/.dev/day8/bitmap/zig/src -lc’ or the build.zig file, not sure how to do that though.

apologize for being such a noob but, this is what i got finally to compile the code:

zig run bitmap.c main.zig -I /home/alice7/.dev/day8/bitmap/zig/src -lc

i am indeed very puzzled as to what just happened here, in addition, someone help me to get rid of “-I /home/alice7/.dev/day8/bitmap/zig/src -lc”, maybe i should modify build.zig, so that i can build like normally, using “zig build run”.

thanks in advance.

Assuming you already have a build.zig (e.g. from zig init), here are the functions you’ll need to use to translate your extra zig run arguments into the compilation of your executable. One of the core concepts of the Zig build system is the “module”, which contains your source files and associated information for compilation such as libraries to be linked against, include paths, etc. If you’re using Zig master, then the zig init build.zig will have a module named exe_mod as the root module of your executable, and if you’re using Zig 0.13.0, you’ll need to refer to it as exe.root_module.

  • main.zig - this is the root_source_file in the options used when creating exe_mod (or exe if you’re using Zig 0.13.0).

  • bitmap.c - addCSourceFile (for a single C source file) or addCSourceFiles (for multiple). Example:

    exe_mod.addCSourceFiles(.{
        .files = &.{"bitmap.c"},
    });
    
  • -I /home/alice7/.dev/day8/bitmap/zig/src - addIncludePath. Example:

    exe_mod.addIncludePath(b.path("src"));
    

    Here, b.path("src") refers to src relative to the build root (the directory where your build.zig is located). Using this instead of an absolute path makes your build portable to other systems. (I’m assuming here that your build.zig is located in /home/alice7/.dev/day8/bitmap/zig; you’ll need to update the path if not)

  • -lc - add .link_libc = true to the options used when creating exe_mod (or exe if you’re using Zig 0.13.0).

If you want to learn more about the Zig build system, there is an official guide: Zig Build System ⚡ Zig Programming Language It doesn’t cover everything you can do with it, but it’s a good overview of the core concepts and what it’s capable of.

2 Likes

i made exact change, and it worked exactly what i intended.

Thank you!

it now might also be a good time for me to read some more documentation too.

1 Like