Why cannot zig find standard C header?

$ cat foo.zig

const std = @import(“std”);                                
const c = @cImport({
    @cInclude("stdio.h"); 
    @cInclude("stdlib.h"); 
    @cInclude("string.h");
});

pub fn demonstrateBasicC() void {
    // Call C printf directly
    _ = c.printf("Hello from C printf: %d\n", 42);
   // Use C memory allocation
   const buffer = c.malloc(100);

   if (buffer != null) {
       _ = c.printf("Allocated %zu bytes\n", 100);
       c.free(buffer);
   }
}

pub fn main() void {      
    demonstrateBasicC();
}

$zig run foo.zig

foo.zig:2:11: error: C import failed                       
const c = @cImport({
                     ^~~~~~~~
foo.zig:2:11: note: libc headers not available; compilation does not link against libc
    referenced by:
         demonstrateBasicC: foo.zig:10:9
         main: foo.zig:21:22
         5 reference(s) hidden; use ‘-freference-trace=7’ to see all references                                            /data/data/com.termux/files/home/.cache/zig/o/91e76d6d833a96cd1beca2420489ff01/cimport.h:1:10: error: ‘stdio.h’ file not found
  #include <stdio.h>

$cat bar.nim


proc printf(format: cstring): cint {.importc: "printf", varargs, header: "<stdio.h>".}
 proc malloc(size: csize_t): pointer {.importc: "malloc", header: "<stdlib.h>".}

proc free(aptr: pointer) {.importc: "free", header: "<stdlib.h>".} 

proc strlen(str: cstring): csize_t {.importc: "strlen", header: "<string.h>".}

 \# Using Nim’s standard library wrapper  import std/strutils 

proc demonstrateBasicC() = 

 \# Call C printf directly

discard printf(“Hello from C printf: %d\\n”, 42)

\# Use C memory allocation                                  
let buffer = malloc(100)                                       
if buffer != nil:

discard printf("Allocated %zu bytes\n", 100)             
free(buffer)
                                                                                                      
demonstrateBasicC()

$ nim c -r bar.nim

Hello from C printf: 42
Allocated 100 bytes

Regard !

1 Like

$ zig run foo.zig -lc


foo.zig:2:11: error: C import failed

                     const c = @cImport({                                                 ^\~\~\~\~\~\~\~                                         referenced by: 

demonstrateBasicC: foo.zig:10:9                            main: foo.zig:21:22 

4 reference(s) hidden; use ‘-freference-trace=6’ to see all references

/data/data/com.termux/files/usr/bin/../../usr/include/linux/types.h:9:10: 

error: ‘asm/types.h’ file not found       
#include <asm/types.h>

Hmm, works just fine on macOS, even without the -lc:

const c = @cImport({
    @cInclude("stdio.h");
});

pub fn main() void {
    _ = c.printf("Hello %s\n", "World");
}
> zig run bla.zig
Hello World!
> zig version
0.16.0-dev.2905+5d71e3051

What OS are you on?

PS: This include path looks curious:

/data/data/com.termux/files/usr/bin/../../usr/include/linux/types.h

…I would expect that Zig uses its embedded C toolchain headers.

Can you check if you have a global CFLAGS environment variable set? (e.g. echo $CFLAGS), while at it also check for a CXXFLAGS env variable. This is a surprisingly common problem for people running into similar header path confusion problems on Emscripten :wink:

PS: On my Linux laptop I need to build via zig run -lc bla.zig, but otherwise it also works as expected. My guess is still on a CFLAGS env variable adding header search paths to the C compile step.

1 Like

From what I understand, on MacOS, LibC is linked by default, on linux you should manually link it. In earlier versions, I needed to add:

exe.linkLibC();

In build.zig for it

2 Likes

What is the output of zig libc?

asm/types.h is located in the same place as sys/errno.h; for amd64 in /usr/include/x86-linux-gnu.

  • Is this directory detected by zig env as sys_include_dir?
  • Does it actually contains the asm/types.h header?

$ zig env


.{
    .zig_exe = "/data/data/com.termux/files/usr/lib/zig/zig",
    .lib_dir = "/data/data/com.termux/files/usr/lib/zig/lib",
    .std_dir = "/data/data/com.termux/files/usr/lib/zig/lib/std",
    .global_cache_dir = "/data/data/com.termux/files/home/.cache/zig",
    .version = "0.15.2",
    .target = "aarch64-linux.5.10...5.4.276-android.29",
    .env = .{
        .ZIG_GLOBAL_CACHE_DIR = null,
        .ZIG_LOCAL_CACHE_DIR = null,
        .ZIG_LIB_DIR = null,
        .ZIG_LIBC = null,
        .ZIG_BUILD_RUNNER = null,
        .ZIG_VERBOSE_LINK = null,
        .ZIG_VERBOSE_CC = null,
        .ZIG_BTRFS_WORKAROUND = null,
        .ZIG_DEBUG_CMD = null,
        .CC = null,
        .NO_COLOR = null,
        .CLICOLOR_FORCE = null,
        .XDG_CACHE_HOME = null,
        .HOME = "/data/data/com.termux/files/home",
    },
}

$ zig libc

$ zig libc
# The directory that contains `stdlib.h`.
# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`
include_dir=/data/data/com.termux/files/usr/bin/../../usr/include

# The system-specific include directory. May be the same as `include_dir`.
# On Windows it's the directory that includes `vcruntime.h`.
# On POSIX it's the directory that includes `sys/errno.h`.
sys_include_dir=/data/data/com.termux/files/usr/bin/../../usr/include

# The directory that contains `crt1.o` or `crt2.o`.
# On POSIX, can be found with `cc -print-file-name=crt1.o`.
# Not needed when targeting MacOS.
crt_dir=/data/data/com.termux/files/usr/bin/../../usr/lib

# The directory that contains `vcruntime.lib`.
# Only needed when targeting MSVC on Windows.
msvc_lib_dir=

# The directory that contains `kernel32.lib`.
# Only needed when targeting MSVC on Windows.
kernel32_lib_dir=

# The directory that contains `crtbeginS.o` and `crtendS.o`
# Only needed when targeting Haiku.
gcc_dir=

$find ~/../usr/bin/../../usr/include/ -name “types.h”

/data/data/com.termux/files/home/../usr/bin/../../usr/include/tirpc/rpc/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/openssl/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/python3.13/internal/mimalloc/mimalloc/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/aarch64-linux-android/asm/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/asm-generic/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/arm-linux-androideabi/asm/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/i686-linux-android/asm/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/linux/iio/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/linux/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/linux/sched/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/riscv64-linux-android/asm/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/gssrpc/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/sys/types.h
/data/data/com.termux/files/home/../usr/bin/../../usr/include/x86_64-linux-android/asm/types.h

So there is no sys_include_dir in `zig env`. And it doesnot contain the asm/types.h header.

$uname -a

Linux localhost 5.4.276-android12-9-gb4a927d994a0 #1 SMP PREEMPT Fri Dec 19 14:52:48 CST 2025 aarch64 Android

$cd /data/data/com.termux/files/usr/include

$ ln -s asm-generic/ asm

$zig run foo.zig -lc
error: ld.lld: unable to find library -lm
error: ld.lld: unable to find library -lc
error: ld.lld: unable to find library -ldl

Try to specify the paths of your libc:

Create a file libc.txt:

include_dir=/data/data/com.termux/files/usr/bin/../../usr/include
sys_include_dir=/data/data/com.termux/files/usr/bin/../../usr/include/aarch64-linux-android
crt_dir=/data/data/com.termux/files/usr/bin/../../usr/lib/aarch64-linux-android
msvc_lib_dir=
kernel32_lib_dir=
gcc_dir=

use it with zig flag: --libc libc.txt (build.zig calls it libc_file)

$ zig run foo.zig -lc --libc libc.txt
1 Like

$ zig run foo.zig -lc --libc libc.txt

error: ld.lld: cannot open /data/data/com.termux/files/usr/bin/../../usr/lib/aarch64-linux-android/crtbegin_static.o: No such file or directory
error: ld.lld: unable to find library -lm
error: ld.lld: unable to find library -lc
error: ld.lld: unable to find library -ldl
error: ld.lld: cannot open /data/data/com.termux/files/usr/bin/../../usr/lib/aarch64-linux-android/crtend_android.o: No such file or directory
1 Like

If you are trying to use android NDK then crt_dir must be <NDK_ROOT>/usr/lib/aarch64-linux-android/<NDK_LEVEL> and include_dir must be <NDK_ROOT>/usr/include
e.g. for API level 26 (Oreo/Android 8.0):

include_dir=/data/data/com.termux/files/usr/include
sys_include_dir=/data/data/com.termux/files/usr/include/aarch64-linux-android
crt_dir=/data/data/com.termux/files/usr/lib/aarch64-linux-android/26
msvc_lib_dir=
kernel32_lib_dir=
gcc_dir=

Android Documentation: Build System Maintainers Guide

2 Likes
$ cat foo.zig                                      const std = @import("std");
const c = @cImport({
    @cInclude("stdio.h");
    @cInclude("stdlib.h");                                });                                                

pub fn demonstrateBasicC() void {
   _ = c.printf("Hello from printf: %d\n", @as(c_int, 42)); 
    const buffer = c.malloc(100);
    if (buffer != null) {
        _ = c.printf("Allocated %zu bytes\n", @as(usize, 100));
        c.free(buffer);
    }                                                  
}

pub fn main() void {
    demonstrateBasicC();
}

$ zig build-exe -target aarch64-linux-musl foo.zig -lc

works like a charm !