#Properly mixing C and Zig code.

1 messages · Page 1 of 1 (latest)

river hill
#

Hello,

I wanted to write a minimal example to see how I could call Zig functions fron C, and vice versa. I came up wth the following code :

src/main.zig

const std = @import("std");
const c = @cImport({
    @cInclude("code.h");
});

pub fn zig_from_c() void {
    std.debug.print("Step 4: Zig called from C.\n", .{});
}

pub fn main() void {
    std.debug.print("Step 1: Calling C from Zig\n", .{});
    c.calling_c_from_zig();
}

src/code.c

#include <stdio.h>
#include "zig.h"

void
calling_c_from_zig(void)
{
  printf("Step 2: C Called from Zig.");
}

void
calling_zig_from_c(void)
{
  printf("Step 3: Calling Zig from C.");
  zig_from_c();
}

src/code.h

#pragma once

void calling_c_from_zig(void);
void calling_zig_from_c(void);

src/zig.h

#pragma once

extern void zig_from_c(void);

And with the following build.zig

const std = @import("std");
const Build = std.build;

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

    const exe = b.addExecutable(.{
        .name = "main",
        .root_source_file = .{ .path = "src/main.zig" },
        .optimize = optimize,
        .target = target,
    });
    exe.addCSourceFiles(&.{
        "src/code.c",
    }, &.{
        "-std=c17",
        "-Wpedantic",
        "-Wall",
        "-Wextra",
        "-Wshadow",
    });

    exe.addIncludePath("src");

    exe.linkSystemLibrary("c");
    b.installArtifact(exe);

    const run = b.addRunArtifact(exe);
    run.step.dependOn(b.getInstallStep());
}

Unfortunately, I get a liking error, that I don't know how to fix.

error: ld.lld: undefined symbol: zig_from_c

What is the line of code that I'm missing?

supple dove
#

your zig function needs to be marked with export and needs a C calling convention

river hill
#

Thank you for your answer @supple dove. Would you mind showing me how, please?

spiral atlas
#
export fn zig_from_c() void {
    std.debug.print("Step 4: Zig called from C.\n", .{});
}

That should be enough.

river hill
#

Alright, it was just a matter of changing the function to pub export fn zig_from_c().