clonoa 0.0.4

A tool that generates D bindings from C files using ImportC.


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:

Clonoa

A tool that generates D bindings from C files using ImportC.

dw

Usage

Clonoa is a single D file: clonoa.d. By default, it takes a C file and prints the generated bindings to stdout. The CLI follows this structure:

Usage: clonoa <compiler> <file.c|file.h> [options]
Options:
  -M=<name>   Module name
  -I=<path>   Header include path
  -P=<prefix> Header prefix(es) (e.g. SDL:KMOD:AUDIO:DUMMY:WindowShapeMode:ShapeMode)
  -S=<name>   Opaque struct(s) to add (e.g. rAudioBuffer:rAudioProcessor)
  -T=<name>   Exclude type(s) (e.g. Vector2:Vector3:Vector4)
  -F=<name>   Exclude function(s) (e.g. DrawText:DrawTextEx:DrawTextPro:MeasureText)
  -H=<path>   Module symbol header path (e.g. raylib_header.txt)
  -R=<path>   Type map path (e.g. raylib_types.ini)
  -X=<prefix> Exclude prefix(es) from function names (e.g. -X=SDL_ turns SDL_Init to Init)
  -L          Lower the first character of function names (e.g. turns InitWindow to initWindow)
  -E          Remove repeated enums (e.g. alias theThing = Enum.theThing;)
  -V          Print skipped symbols to stderr

To run Clonoa from any folder via DUB, use:

dub run clonoa -- <compiler> <file.c|file.h> [options]

SIMD Guards

Some files fail to parse with ImportC due to unsupported SIMD symbols. This can be fixed by adding the following at the top of the file:

#if __IMPORTC__
    #include "../clonoa_simd_guards.h"
#endif

The included header and an example of an __IMPORTC__ block can be found in this repository. Note that some files may also need additional stub definitions for missing builtins. They can be added inside the __IMPORTC__ block manually as needed.

Library

Clonoa can be used as a library by defining the ClonoaLibrary version flag. This is defined by default when using Clonoa as a DUB dependency. The main entry points are:

int clonoaMain(string[] cliArgs...);
ClonoaResult clonoaRun(ref ClonoaArgs clonoaArgs, ref Array!char output);

struct ClonoaResult {
    int fault;
    string faultMessage;
    alias fault this;
}

struct ClonoaArgs {
    string compiler = defaultCompiler;
    string headerPath;
    string moduleName;
    string[] headerIncludes;
    string[] headerPrefixes;
    string[] opaqueStructs;
    string[] excludePrefixes;
    bool lowerFirstChar;
    bool removeRepeatedEnums;
    bool verbose;

    string moduleSymbolHeader = defaultModuleSymbolHeader;
    string indentation = defaultIndentation;
    string[string] typeMap;
    string[] typeSkipList;
    string[] funcSkipList;
    string[] lineSkipList;

    void useDefaults() {
        typeMap = defaultTypeMap;
        typeSkipList = defaultTypeSkipList;
        funcSkipList = defaultFuncSkipList;
        lineSkipList = defaultLineSkipList;
    }

    void appendHeaderInclude(string path) {
        auto prefix = "-P=-I"; // NOTE: The default is DMD.
        if (compiler.endsWith("ldc2")) prefix = "-P -I";
        if (compiler.endsWith("gdc"))  prefix = "-Xpreprocessor -I";
        headerIncludes ~= prefix ~ path;
    }

    void appendHeaderPrefix(string prefix) {
        headerPrefixes ~= prefix;
        headerPrefixes ~= "_" ~ prefix;
        if (prefix[0].isUpper) headerPrefixes ~= prefix.toLower();
        if (prefix[0].isLower) headerPrefixes ~= prefix.toUpper();
    }
}

Examples

SDL2

Below is an example using the SDL2/SDL.h header (that needs an __IMPORTC__ block) on Linux:

# Filtering with prefixes and creating opaque structs that got skipped by ImportC.
rdmd source/clonoa.d dmd headers/SDL2/SDL.h \
  -P=SDL:KMOD:AUDIO:DUMMY:WindowShapeMode:ShapeMode \
  -S=SDL_Window:SDL_Cursor:SDL_BlitMap:_SDL_iconv_t \
  > sdl.d

To test the bindings, create an app.d file in the same folder:

import sdl;

void main() {
    SDL_Init(SDL_INIT_VIDEO);
    auto running = true;
    auto window = SDL_CreateWindow("D + SDL", 100, 100, 800, 600, 0);
    auto renderer = SDL_CreateRenderer(window, -1, 0);
    auto event = SDL_Event();
    while (running) {
        while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) running = false;
        SDL_SetRenderDrawColor(renderer, 107, 122, 85, 255);
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);
    }
    SDL_DestroyWindow(window);
    SDL_Quit();
}

Compile and run with:

rdmd -L=-lSDL2 app.d

The SDL_ prefix can be removed from functions by passing the -X=SDL_ flag. With this enabled, the code becomes:

import sdl;

void main() {
    Init(SDL_INIT_VIDEO);
    auto running = true;
    auto window = CreateWindow("D + SDL", 100, 100, 800, 600, 0);
    auto renderer = CreateRenderer(window, -1, 0);
    auto event = SDL_Event();
    while (running) {
        while (PollEvent(&event)) if (event.type == SDL_QUIT) running = false;
        SetRenderDrawColor(renderer, 107, 122, 85, 255);
        RenderClear(renderer);
        RenderPresent(renderer);
    }
    DestroyWindow(window);
    Quit();
}

raylib

Below is an example using the raylib.h header on Linux:

# Creating opaque structs that got skipped by ImportC.
rdmd source/clonoa.d dmd headers/raylib.h \
    -S=rAudioBuffer:rAudioProcessor \
    > raylib.d

To test the bindings, create an app.d file in the same folder:

import raylib;

void main() {
    InitWindow(800, 450, "D + raylib");
    while (!WindowShouldClose) {
        BeginDrawing();
        ClearBackground(Color(40, 40, 40, 255));
        DrawText("Hello, World!", 16, 16, 20, Color(200, 200, 200, 255));
        EndDrawing();
    }
    CloseWindow();
}

Compile and run with:

rdmd -L=-lraylib -L=-lX11 app.d

The PascalCase can be changed to camelCase for function names by passing the -L flag. With this enabled, the code becomes:

import raylib;

void main() {
    initWindow(800, 450, "D + raylib");
    while (!windowShouldClose) {
        beginDrawing();
        clearBackground(Color(40, 40, 40, 255));
        drawText("Hello, World!", 16, 16, 20, Color(200, 200, 200, 255));
        endDrawing();
    }
    closeWindow();
}

What is a Clonoa?

It's a play on the names C and Klonoa, with Klonoa being a character from a game.

dw

Authors:
  • Alexandros F. G. Kapretsos
Dependencies:
none
Versions:
0.0.4 2026-Apr-25
0.0.3 2026-Apr-24
0.0.2 2026-Apr-24
0.0.1 2026-Apr-23
~main 2026-Apr-25
Show all 5 versions
Download Stats:
  • 0 downloads today

  • 12 downloads this week

  • 12 downloads this month

  • 12 downloads total

Score:
0.4
Short URL:
clonoa.dub.pm