Error "expected type `T`, found `T`" with types imported from C headers

Hello,

I am migrating a shared library (pkcs11 module) to zig 0.15. I’ve hit an error that I can’t resolve. For some types imported from .h files, I get errors like the following

src/p11_object_management.zig:171:87: error: expected type '[]cimport.struct_CK_ATTRIBUTE', found '[]cimport.struct_CK_ATTRIBUTE'
        search_template = object.parseAttributes(current_session.allocator, template.?[0..count]) catch |err|
src/p11_object_management.zig:171:87: note: pointer type child 'cimport.struct_CK_ATTRIBUTE' cannot cast into pointer type child 'cimport.struct_CK_ATTRIBUTE'
.zig-cache/o/54dbc096318bceda383adc744f238447/cimport.zig:139:40: note: struct declared here (2 times)
pub const struct_CK_ATTRIBUTE = extern struct {
                                ~~~~~~~^~~~~~
src/object.zig:288:15: note: parameter type declared here
    template: []pkcs.CK_ATTRIBUTE,

I noticed this happens when the zig file where the function is called is different from the file where the function is defined. In both files, the C type is imported the same way, directly from the C header. I don’t import or use any C functions, only type definitions.

It also happens with zig structs that have fields using types imported from a C header:

src/certificate.zig:69:27: error: expected type 'cimport.struct_CK_DATE', found 'cimport.struct_CK_DATE'
        .start_date = pkcs.CK_DATE{},
.zig-cache/o/54dbc096318bceda383adc744f238447/cimport.zig:146:35: note: struct declared here (2 times)
pub const struct_CK_DATE = extern struct {

Function signatures also (in this case, types are different, but this error isn’t present on v0.14):

src/p11_general.zig:119:20: error: expected type '*const fn (c_ulong, [*c]cimport.struct_CK_SLOT_INFO) callconv(.c) c_ulong', found '*const fn (c_ulong, ?*cimport.struct_CK_SLOT_INFO) callconv(.c) c_ulong'
    .C_GetSlotInfo = p11_slot_and_token.C_GetSlotInfo,

Here is a minimal example that demonstrates this behavior:

// build.zig
const std = @import("std");

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

    const mod = b.createModule(.{
        .target = target,
        .optimize = optimize,
        .root_source_file = b.path("src/p11_general.zig"),
        .link_libc = true,
    });

    const lib = b.addLibrary(.{
        .linkage = std.builtin.LinkMode.dynamic,
        .name = "srb-id-pkcs11",
        .root_module = mod,
    });

    lib.addIncludePath(b.path("include"));
    b.installArtifact(lib);
}
// src/p11_general.zig
const pkcs = @cImport({
    @cInclude("a.h");
});

const a = @import("a.zig");

pub export fn C_FindObjectsInit(
    template: ?[*]pkcs.CK_ATTRIBUTE,
    count: usize,
) void {
    a.parseAttributes(template.?[0..count]);
}
// a.zig
const pkcs = @cImport({
    @cInclude("a.h");
});

pub fn parseAttributes(
    _: []pkcs.CK_ATTRIBUTE,
) void {}
// a.h
typedef struct CK_ATTRIBUTE {
  int        type;
  void*      pValue;
  int        ulValueLen; 
} CK_ATTRIBUTE;
1 Like

every c import is unique regardless of if they have the same content/args.

Ideally only have one in a project.

Obligatory, @cImport/Include is deprecated in favour of the build systems addTranslateC + normal @import.
That is due to zig wanting to make llvm optional which includes clang that is used for c translation.

2 Likes

To add a little bit of explanation to this:
If you still use @cImport make sure that you only use it in one place, there you can declare it as a public declaration, then from the other place where you need it you can import and use that public declaration.

And if you change towards the new way then the addTranslateC gives you a *TranslateC which you can call add-/createModule module on, the resulting module can be imported at multiple places just like regular modules.

One of the benefits of the new way is that this mistake is less likely to happen (unless you manually create multiple separate translate-c modules).

1 Like

I actually do this with other libraries (for different reason), and it crossed my mind to try this.

Thank both of you for informative answers :slight_smile:

1 Like