What does extern "..." do?

When declaring kernel32 functions, I can omit "kernel32" in the extern declaration, and I don’t even need to pass the -lkernel32 flag. Similarly, for libc functions, I can omit "c" in the extern declaration. As long as I pass the -lc flag, everything works.

So what is the purpose of the extern "..." syntax?

It lets you specify what library/object the symbol is from extern "lib". Useful if multiple linked objects have conflicting symbol names.

Ofc you can’t grab both in the same namespace as you then have the same issue in zig land.

But you can get around that by using @extern which lets you declare the zig name and the linked symbol name separately. Though using separate namespaces is generally a better solution.

1 Like

dll1.c

__declspec(dllexport)
void a() { puts("dll1.a"); }

__declspec(dllexport)
void b() { puts("dll1.b"); }

dll2.c

__declspec(dllexport)
void a() { puts("dll2.a"); }

__declspec(dllexport)
void b() { puts("dll2.b"); }

dll1.zig

pub extern "dll1" fn a() void;

dll2.zig

pub extern "dll2" fn b() void;

main.zig

const dll1 = @import("dll1.zig");
const dll2 = @import("dll2.zig");

pub fn main() void {
  dll1.a();
  dll2.b();
}

// output:
// dll1.a
// dll1.b

Shouldn’t this print dll1.a and dll2.b?

That seems like a bug, how are you building and linking it all?

zig cc -shared -o dll1.dll src\dll1.c
zig cc -shared -o dll2.dll src\dll2.c

zig build-exe -L. src\main.zig

.\main.exe
dll1.a
dll1.b

Adding -ldll1 and -ldll2 to the build command does not change the result.