---
title: "Writing C Modules"
description: "Extending ƿit with native code"
weight: 50
type: "docs"
---

ƿit makes it easy to extend functionality with C code. C files in a package are compiled into a dynamic library and can be imported like any other module.

## Basic Structure

A C module exports a single function that returns a JavaScript value:

```c
// mymodule.c
#include "cell.h"

#define CELL_USE_NAME js_mypackage_mymodule_use

static JSValue js_add(JSContext *js, JSValue self, int argc, JSValue *argv) {
  double a = js2number(js, argv[0]);
  double b = js2number(js, argv[1]);
  return number2js(js, a + b);
}

static JSValue js_multiply(JSContext *js, JSValue self, int argc, JSValue *argv) {
  double a = js2number(js, argv[0]);
  double b = js2number(js, argv[1]);
  return number2js(js, a * b);
}

static const JSCFunctionListEntry js_funcs[] = {
  MIST_FUNC_DEF(mymodule, add, 2),
  MIST_FUNC_DEF(mymodule, multiply, 2),
};

CELL_USE_FUNCS(js_funcs)
```

## Symbol Naming

The exported function must follow this naming convention:

```
js_<package>_<filename>_use
```

Where:
- `<package>` is the package name with `/` and `.` replaced by `_`
- `<filename>` is the C file name without extension

Examples:
- `mypackage/math.c` -> `js_mypackage_math_use`
- `gitea.pockle.world/john/lib/render.c` -> `js_gitea_pockle_world_john_lib_render_use`

## Required Headers

Include `cell.h` for all ƿit integration:

```c
#include "cell.h"
```

This provides:
- QuickJS types and functions
- Conversion helpers
- Module definition macros

## Conversion Functions

### JavaScript <-> C

```c
// Numbers
double js2number(JSContext *js, JSValue v);
JSValue number2js(JSContext *js, double g);

// Booleans
int js2bool(JSContext *js, JSValue v);
JSValue bool2js(JSContext *js, int b);

// Strings (must free with JS_FreeCString)
const char *JS_ToCString(JSContext *js, JSValue v);
void JS_FreeCString(JSContext *js, const char *str);
JSValue JS_NewString(JSContext *js, const char *str);
```

### Blobs

```c
// Get blob data (returns pointer, sets size in bytes)
void *js_get_blob_data(JSContext *js, size_t *size, JSValue v);

// Get blob data in bits
void *js_get_blob_data_bits(JSContext *js, size_t *bits, JSValue v);

// Create new stone blob from data
JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes);

// Check if value is a blob
int js_is_blob(JSContext *js, JSValue v);
```

## Function Definition Macros

### JSC_CCALL

Define a function with automatic return value:

```c
JSC_CCALL(mymodule_greet,
  const char *name = JS_ToCString(js, argv[0]);
  char buf[256];
  snprintf(buf, sizeof(buf), "Hello, %s!", name);
  ret = JS_NewString(js, buf);
  JS_FreeCString(js, name);
)
```

### JSC_SCALL

Shorthand for functions taking a string first argument:

```c
JSC_SCALL(mymodule_strlen,
  ret = number2js(js, strlen(str));
)
```

### MIST_FUNC_DEF

Register a function in the function list:

```c
MIST_FUNC_DEF(prefix, function_name, arg_count)
```

## Module Export Macros

### CELL_USE_FUNCS

Export an object with functions:

```c
static const JSCFunctionListEntry js_funcs[] = {
  MIST_FUNC_DEF(mymod, func1, 1),
  MIST_FUNC_DEF(mymod, func2, 2),
};

CELL_USE_FUNCS(js_funcs)
```

### CELL_USE_INIT

For custom initialization:

```c
CELL_USE_INIT(
  JSValue obj = JS_NewObject(js);
  // Custom setup...
  return obj;
)
```

## Complete Example

```c
// vector.c - Simple 2D vector operations
#include "cell.h"
#include <math.h>

#define CELL_USE_NAME js_mypackage_vector_use

JSC_CCALL(vector_length,
  double x = js2number(js, argv[0]);
  double y = js2number(js, argv[1]);
  ret = number2js(js, sqrt(x*x + y*y));
)

JSC_CCALL(vector_normalize,
  double x = js2number(js, argv[0]);
  double y = js2number(js, argv[1]);
  double len = sqrt(x*x + y*y);
  if (len > 0) {
    JSValue result = JS_NewObject(js);
    JS_SetPropertyStr(js, result, "x", number2js(js, x/len));
    JS_SetPropertyStr(js, result, "y", number2js(js, y/len));
    ret = result;
  }
)

JSC_CCALL(vector_dot,
  double x1 = js2number(js, argv[0]);
  double y1 = js2number(js, argv[1]);
  double x2 = js2number(js, argv[2]);
  double y2 = js2number(js, argv[3]);
  ret = number2js(js, x1*x2 + y1*y2);
)

static const JSCFunctionListEntry js_funcs[] = {
  MIST_FUNC_DEF(vector, length, 2),
  MIST_FUNC_DEF(vector, normalize, 2),
  MIST_FUNC_DEF(vector, dot, 4),
};

CELL_USE_FUNCS(js_funcs)
```

Usage in ƿit:

```javascript
var vector = use('vector')

var len = vector.length(3, 4)  // 5
var n = vector.normalize(3, 4) // {x: 0.6, y: 0.8}
var d = vector.dot(1, 0, 0, 1) // 0
```

## Combining C and ƿit

A common pattern is to have a C file provide low-level functions and a `.cm` file provide a higher-level API:

```c
// _vector_native.c
// ... raw C functions ...
```

```javascript
// vector.cm
var native = this  // C module passed as 'this'

var Vector = function(x, y) {
  return {x: x, y: y}
}

Vector.length = function(v) {
  return native.length(v.x, v.y)
}

Vector.normalize = function(v) {
  return native.normalize(v.x, v.y)
}

return Vector
```

## Build Process

C files are automatically compiled when you run:

```bash
pit build
pit update
```

The resulting dynamic library is placed in `~/.pit/lib/`.

## Platform-Specific Code

Use filename suffixes for platform variants:

```
audio.c           # default
audio_playdate.c  # Playdate
audio_emscripten.c # Web/Emscripten
```

ƿit selects the appropriate file based on the target platform.

## Static Declarations

Keep internal functions and variables `static`:

```c
static int helper_function(int x) {
  return x * 2;
}

static int module_state = 0;
```

This prevents symbol conflicts between packages.
