Automatic Binding

This section is an attempt to put into practice an idea presented by by Andre Weissflog in its post entitled Automatic Language Bindings. The main goal is to derive a C++ wrapper from my library’s public API.

To do so, I performed three steps (serving as a TLDR too):

  • Using clang to generate a JSON file containing the Abstract Syntax Tree

  • Cleaning AST to generate lighter JSON files

  • Generating a C++ header wrapping C functions and handles

AST Generation

Here’s the clang command to generate a JSON abstract syntax tree from a single header.

clang   -Xclang 
        -ast-dump=json 
        -fsyntax-only 
        -c {your-header}
		-I/{include_directories}
	>   {header-ast}.json

The generated JSON needs to be cleaned as it contains too much noise. It can be done using python and its already included json module. I wrap each step using cmake targets yielding a streamlined pipeline:

# Generate the AST
cmake --build . --target haiku-ast
# Cleaning AST to generate two other json files
cmake --build . --target haiku-filter
# Generating C++ wrapper header file
cmake --build . --target haiku-bindgen

Converting C-API into C++ objects

hk_buffer_t result = hkgfx_buffer_create(device, &(hk_gfx_buffer_desc){
    .bytesize    = 20*sizeof(uint32_t),
    .usage_flags = HK_BUFFER_USAGE_TRANSFER_SRC_BIT | HK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    .memory_type = HK_MEMORY_TYPE_GPU_TO_CPU
});

As C++20 designated-initializers are not as convenient as in C99, I chose to wrap descriptor data structures in a builder pattern. Translating the previous buffer creation snippet to C++ yields:

HkBuffer ssbo = gfx::HkBufferDesc()
                    .set_bytesize(20*sizeof(uint32_t))
                    .set_usage_flags(HK_BUFFER_USAGE_TRANSFER_SRC_BIT | HK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
                    .set_memory_type(HK_MEMORY_TYPE_GPU_TO_CPU)
                    .create(device);