Kotlin Academy · Lesson

C Interop with cinterop and .def Files

Call C libraries from Kotlin/Native using cinterop tool and definition files.

Lesson 3 of 413 steps

C Interop with cinterop and .def Files is a free Kotlin Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, and your progress syncs across the web and the CoddyKit app. The Kotlin Academy course includes 4 lessons in total.

Why C Interop?

Kotlin/Native can call C libraries directly — no JNI wrappers, no bridging layer. This enables using platform system libraries, hardware drivers, or any C-compatible library from Kotlin code compiled to native binaries.

The .def File

A .def file describes the C library to import. It specifies headers, library name, and optional compiler/linker flags. Place it in src/nativeInterop/cinterop/:

# src/nativeInterop/cinterop/libcurl.def
headers = curl/curl.h
headerFilter = curl/**
linkerOpts.linux = -lcurl
linkerOpts.macos = -lcurl

Registering the Interop in Gradle

Reference the .def file in the target's compilations block:

kotlin {
    linuxX64 {
        compilations["main"].cinterops {
            val libcurl by creating {
                defFile(project.file("src/nativeInterop/cinterop/libcurl.def"))
            }
        }
    }
}

Running cinterop

Run ./gradlew cinteropLibcurlLinuxX64 to generate a .klib from the C headers. The generated Kotlin bindings appear in build/cinterop/ and are automatically added to the compilation classpath.

Using C Functions in Kotlin

After generation, import the package declared in the .def file and call C functions as Kotlin functions. Pointer types are represented as CPointer:

import libcurl.*
import kotlinx.cinterop.*

fun fetchUrl(url: String): String = memScoped {
    val handle = curl_easy_init() ?: error("curl init failed")
    curl_easy_setopt(handle, CURLOPT_URL, url.cstr.ptr)
    curl_easy_perform(handle)
    curl_easy_cleanup(handle)
    "done"
}

memScoped: Stack-Allocated Memory

memScoped { } creates a memory scope where native allocations (alloc(), allocArray()) are automatically freed when the block exits. Always use it for temporary C memory to avoid leaks.

memScoped {
    val value = alloc<IntVar>()
    value.value = 42
    println(value.value)  // 42
    // freed automatically at end of memScoped
}

Pinning Kotlin Objects for C

To pass a Kotlin object's address to a C function (e.g., a callback), pin it with StableRef or Pinned to prevent the GC from moving it:

val stableRef = StableRef.create(myKotlinObject)
try {
    c_function_expecting_user_data(stableRef.asCPointer())
} finally {
    stableRef.dispose()
}

C Strings and Kotlin Strings

Convert between Kotlin String and C const char* using:

  • "hello".cstr → CValues, valid inside memScoped
  • cPointer.toKString() → Kotlin String from a CPointer<ByteVar>
memScoped {
    val cStr = "Hello, C!".cstr.ptr   // CPointer<ByteVar>
    val back = cStr.toKString()         // "Hello, C!"
}

Struct Access

C structs become Kotlin classes with properties. Access struct fields using the dot operator. Allocate structs with alloc() inside a memScoped { }:

memScoped {
    val addr = alloc<sockaddr_in>()
    addr.sin_family = AF_INET.convert()
    addr.sin_port = htons(8080u).convert()
}

Embedding Inline C Code

For short C snippets, use the cCode block in the .def file to write inline C that gets compiled with the binding:

# In .def file
headers = stdio.h
---
// Inline C code after ---
static inline int add(int a, int b) { return a + b; }

Debugging C Interop Issues

Common issues: missing headers (check headerFilter), missing linker flags (add linkerOpts), mismatched types (check generated .klib API). Enable verbose cinterop with -verbose in the def file or Gradle task configuration.

Quick Check

What is the purpose of memScoped { } in Kotlin/Native C interop?

Recap: C Interop with cinterop and .def Files

Key takeaways:

  • .def file specifies headers, linker options, and optional inline C
  • Register in Gradle via cinterops { val name by creating { defFile(...) } }
  • Run the cinterop<Name><Target> Gradle task to generate bindings
  • Use memScoped { } for temporary native allocations
  • Pin long-lived objects with StableRef; convert strings with .cstr / .toKString()
Free to start

Learn Kotlin with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
51
Lessons
203

Frequently Asked Questions

Is the “C Interop with cinterop and .def Files” lesson free?

Yes — any 3 lessons of the Kotlin Academy learning path, including “C Interop with cinterop and .def Files”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Kotlin Academy course includes 4 lessons in total.

What will I learn in “C Interop with cinterop and .def Files”?

Call C libraries from Kotlin/Native using cinterop tool and definition files. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “C Interop with cinterop and .def Files” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Kotlin/Native Overview: Targets, Toolchain & Compilation
  2. Memory Management in Kotlin/Native: The New MM
  3. C Interop with cinterop and .def Files
  4. Kotlin/WASM: Compiling to WebAssembly for the Browser
← Back to Kotlin Academy