Nim C Interop
Use when nim-C interoperability including calling C from Nim, wrapping C libraries, importc/exportc pragmas, header generation, FFI patterns, and building high-performance systems code integrating Nim with existing C codebases.
What this skill does
# Nim C Interop
## Introduction
Nim compiles to C, enabling seamless interoperability with C code and libraries.
This bi-directional integration allows Nim developers to leverage decades of C
libraries while exposing Nim code to C applications. Understanding C interop is
essential for systems programming and library wrapping.
The interop mechanism uses pragmas like importc, exportc, and header to declare
foreign functions and types. Nim's type system maps naturally to C, with explicit
control over memory layout and calling conventions. This enables zero-overhead
abstraction while maintaining C ABI compatibility.
This skill covers importing C functions and types, wrapping C libraries, header
file generation, memory layout control, callback handling, and patterns for safe
type-safe C interop in systems programming.
## Importing C Functions
Import C functions using pragmas to make them callable from Nim code.
```nim
# Basic C function import
proc printf(format: cstring): cint {.importc, varargs, header: "<stdio.h>".}
proc main() =
printf("Hello from C!\n")
printf("Number: %d\n", 42)
# C function with explicit name
proc c_sqrt(x: cdouble): cdouble {.importc: "sqrt", header: "<math.h>".}
proc useSqrt() =
let result = c_sqrt(16.0)
echo result # 4.0
# Multiple headers
proc malloc(size: csize_t): pointer {.importc, header: "<stdlib.h>".}
proc free(p: pointer) {.importc, header: "<stdlib.h>".}
proc manualAlloc() =
var p = malloc(100)
# Use memory
free(p)
# C types mapping
proc strlen(s: cstring): csize_t {.importc, header: "<string.h>".}
proc strcpy(dest, src: cstring): cstring {.importc, header: "<string.h>".}
# Variadic C functions
proc snprintf(buf: cstring, size: csize_t, format: cstring): cint
{.importc, varargs, header: "<stdio.h>".}
proc formatString(): string =
var buffer: array[256, char]
discard snprintf(cstring(addr buffer), 256, "Value: %d", 42)
result = $cstring(addr buffer)
# C macros as inline procs
proc EXIT_SUCCESS(): cint {.importc: "EXIT_SUCCESS", header: "<stdlib.h>".}
proc EXIT_FAILURE(): cint {.importc: "EXIT_FAILURE", header: "<stdlib.h>".}
# Function pointers
type
CompareFunc = proc (a, b: pointer): cint {.cdecl.}
proc qsort(base: pointer, nmemb, size: csize_t, compar: CompareFunc)
{.importc, header: "<stdlib.h>".}
proc compareInts(a, b: pointer): cint {.cdecl.} =
let x = cast[ptr cint](a)[]
let y = cast[ptr cint](b)[]
return x - y
proc sortArray() =
var arr = [5, 2, 8, 1, 9]
qsort(addr arr[0], arr.len, sizeof(cint), compareInts)
# C struct access
type
TimeSpec {.importc: "struct timespec", header: "<time.h>".} = object
tv_sec: int
tv_nsec: int
proc clock_gettime(clk_id: cint, tp: ptr TimeSpec): cint
{.importc, header: "<time.h>".}
# Calling conventions
proc win_api_func(): cint {.stdcall, importc, dynlib: "kernel32.dll".}
# C++ name mangling
proc cpp_function(x: cint): cint
{.importcpp, header: "<myheader.hpp>".}
# C library linking
{.passL: "-lm".} # Link math library
proc cos(x: cdouble): cdouble {.importc, header: "<math.h>".}
```
Import pragmas enable calling C code with full type safety from Nim.
## Wrapping C Libraries
Create type-safe Nim wrappers around C libraries for idiomatic usage.
```nim
# Simple wrapper
type
FileHandle = distinct cint
proc c_open(path: cstring, flags: cint): cint
{.importc: "open", header: "<fcntl.h>".}
proc c_close(fd: cint): cint
{.importc: "close", header: "<unistd.h>".}
proc openFile(path: string): FileHandle =
let fd = c_open(cstring(path), 0)
if fd < 0:
raise newException(IOError, "Failed to open file")
FileHandle(fd)
proc close(fh: FileHandle) =
discard c_close(cint(fh))
# Wrapping libcurl
type
Curl = distinct pointer
const CURLE_OK = 0
proc curl_easy_init(): Curl {.importc, header: "<curl/curl.h>".}
proc curl_easy_cleanup(curl: Curl) {.importc, header: "<curl/curl.h>".}
proc curl_easy_setopt(curl: Curl, option: cint, parameter: pointer): cint
{.importc, varargs, header: "<curl/curl.h>".}
type
CurlHandle = object
handle: Curl
proc newCurl(): CurlHandle =
result.handle = curl_easy_init()
if result.handle.pointer == nil:
raise newException(Exception, "Failed to initialize curl")
proc close(curl: CurlHandle) =
curl_easy_cleanup(curl.handle)
proc setUrl(curl: CurlHandle, url: string) =
discard curl_easy_setopt(curl.handle, 10002, cstring(url))
# RAII wrapper with destructor
type
CurlSession = object
curl: Curl
proc `=destroy`(session: var CurlSession) =
if session.curl.pointer != nil:
curl_easy_cleanup(session.curl)
session.curl = Curl(nil)
proc newSession(): CurlSession =
result.curl = curl_easy_init()
# Wrapping complex C API
type
SqliteDb = distinct pointer
SqliteStmt = distinct pointer
proc sqlite3_open(filename: cstring, db: ptr SqliteDb): cint
{.importc, header: "<sqlite3.h>".}
proc sqlite3_close(db: SqliteDb): cint
{.importc, header: "<sqlite3.h>".}
proc sqlite3_prepare_v2(
db: SqliteDb, sql: cstring, nbyte: cint,
stmt: ptr SqliteStmt, tail: ptr cstring
): cint {.importc, header: "<sqlite3.h>".}
type
Database = object
handle: SqliteDb
proc openDatabase(filename: string): Database =
var db: SqliteDb
let rc = sqlite3_open(cstring(filename), addr db)
if rc != 0:
raise newException(IOError, "Cannot open database")
result.handle = db
proc `=destroy`(db: var Database) =
if db.handle.pointer != nil:
discard sqlite3_close(db.handle)
# C callback wrapping
type
EventCallback = proc (data: pointer) {.cdecl.}
proc c_register_callback(cb: EventCallback, data: pointer)
{.importc: "register_callback", header: "events.h".}
proc nimCallback(data: pointer) {.cdecl.} =
echo "Callback triggered"
proc registerEvent() =
c_register_callback(nimCallback, nil)
```
Wrappers provide Nim-idiomatic interfaces while preserving C library functionality.
## Exporting to C
Export Nim functions to C using exportc pragma for library creation.
```nim
# Basic export
proc add(a, b: cint): cint {.exportc.} =
a + b
# Export with specific name
proc multiply(a, b: cint): cint {.exportc: "nim_multiply".} =
a * b
# Export with dynlib
proc divide(a, b: cint): cint {.exportc, dynlib.} =
if b == 0: return 0
a div b
# Export complex types
type
Point {.exportc.} = object
x: cint
y: cint
proc createPoint(x, y: cint): Point {.exportc.} =
Point(x: x, y: y)
proc pointDistance(p1, p2: Point): cdouble {.exportc.} =
let dx = (p2.x - p1.x).float
let dy = (p2.y - p1.y).float
sqrt(dx * dx + dy * dy)
# Export string operations
proc processString(input: cstring): cstring {.exportc.} =
let s = $input
result = cstring(s.toUpperAscii())
# Generating header file
{.emit: """/*TYPESECTION*/
typedef struct {
int x;
int y;
} Point;
""".}
proc generateHeader() {.exportc: "lib_init".} =
echo "Library initialized"
# Export callbacks
type
Callback = proc (value: cint) {.cdecl.}
proc registerCallback(cb: Callback) {.exportc.} =
cb(42)
# Building shared library
# Compile with: nim c --app:lib --noMain mylib.nim
# Library initialization
proc NimMain() {.importc.}
proc libInit() {.exportc: "lib_init".} =
NimMain()
echo "Nim library initialized"
# Export with error handling
proc safeOperation(value: cint): cint {.exportc.} =
try:
if value < 0:
raise newException(ValueError, "Negative value")
result = value * 2
except:
result = -1
```
Exportc enables creating C-compatible libraries from Nim code.
## Memory Layout and Alignment
Control memory layout for C struct compatibility and performance.
```nim
# Packed structures
type
PackedStruct {.packed.} = object
a: uint8
b: uint32
c: uint8
echo sizeof(PackedStruct) # 6 bytes (no padding)
# Aligned structures
type
AlignedStruct {.align(16).} = object
data: array[4, float32]
echo sizeof(AlignedStruct) # Aligned to 16 bytes
# C struct layout
type
CStruct {.importc, header: "myheader.h".} = object
field1: cinRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.