SkillAgentSearch skills...

Bindgen

Binding and wrapper generator for C/C++ libraries

Install / Use

/learn @Papierkorb/Bindgen
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Bindgen

Standalone C, C++, and/or Qt binding and wrapper generator.

Logo Build Status

Installation

Add the dependency to shard.yml:

dependencies:
  bindgen:
    github: Papierkorb/bindgen
    version: ~> 0.7.0

Table of Contents

<!--ts--> <!-- Added by: docelic, at: Thu 28 May 2020 09:55:45 PM CEST --> <!--te-->

How To

When you have a Crystal project and want to bind to C, C++, or Qt libraries with the help of bindgen, do as follows:

  1. Add bindgen to your project's shard.yml as instructed above under "Installation" and then run shards
  2. Copy lib/bindgen/assets/bindgen_helper.hpp into your ext/ subdirectory, creating it if missing
  3. Copy lib/bindgen/TEMPLATE.yml into your_template.yml (adjust the name to your linking) and customize it for the library you want to bind to
  4. Run lib/bindgen/tool.sh your_template.yml. This will generate the bindings, and by default place the outputs in the ext/ subdirectory
  5. Develop your Crystal application as usual

Note: If you ship the output produced by bindgen along with your application, then bindgen will not be not required to compile it. In that case, you can move its entry in shard.yml from dependencies to development_dependencies.

The .yml file that you copy from TEMPLATE.yml will contain the complete configuration template along with accompanying documentation embedded in the comments. If you prefer working with shorter files, you can simply remove all the comments.

Projects using bindgen

You can use the following projects' .yml files as a source of ideas or syntax for your own bindings:

Have you created and published a usable binding with bindgen? Want to see it here? Send a PR!

Mapping behaviour

The following rules are automatically applied to all bindings:

  • Method names get underscored: addWidget() -> #add_widget
    • Setter methods are rewritten: setWindowTitle() -> #window_title=
    • Getter methods are rewritten: getWindowTitle() -> #window_title
    • Bool getters are rewritten: getAwesome() -> #awesome?
    • is getters are rewritten: isEmpty() -> #empty?
    • has getters are rewritten: hasSpace() -> #has_space?
  • On signal methods (For Qt signals):
    • Keep their name for the emit version: pressed() -> #pressed
    • Get an on_ prefix for the connect version: #on_pressed do .. end
  • Enum fields get title-cased if not already: color0 -> Color0

Features

| Feature | Support | |--------------------------------------------------|---------| | Automatic Crystal binding generation | YES | | Automatic Crystal wrapper generation | YES | | Mapping C++ classes | | | +- Member methods | YES | | +- Static methods | YES | | +- Getters and setters for instance variables | YES | | +- Getters and setters for static variables | YES | | +- Constructors | YES | | +- Overloaded operators | Partial | | +- Conversion functions | TBD | | Mapping C/C++ global functions | | | +- Mapping global functions | YES | | +- Wrapping as Crystal class | YES | | Overloaded methods (Also default arguments) | YES | | Copying default argument values | | | +- Integer, float, boolean types | YES | | +- String | YES | | Enumerations | YES | | Copying structures | YES | | Custom type conversions between C/++ and Crystal | YES | | Automatic type wrapping and conversion | YES | | Integration with Crystals GC | YES | | C++ Template instantiation for containers types | YES | | Virtual methods | YES | | Override virtual methods from Crystal | YES | | Abstract classes | YES | | Multiple inheritance wrapping | YES | | Qt integration | | | +- QObject signals | YES | | +- QFlags types | YES | | +- QMetaObject generation (mimic moc) | TBD | | #define macro support | | | +- Mapping as enumeration | YES | | +- Mapping as constant (Including strings) | YES | | Copying in-source docs | TBD | | Platform specific type binding rules | YES | | Portable path finding for headers, libs, etc. | YES |

Architecture of bindgen

Bindgen employs a pipeline-inspired code architecture, which is strikingly similar to what most compilers use.

The code flow is basically Parser::Runner to Graph::Builder to Processor::Runner to Generator::Runner.

Architecture flow diagram

The Graph

An important data structure used throughout the program is the graph. Code-wise, it's represented by Graph::Node and its sub-classes. The nodes can contain child nodes, making it a hierarchical structure.

This allows to represent (almost) arbitrary structures as defined by the user configuration.

Say we're wrapping GreetLib. As any library, it comes with a bunch of classes (Greeter and Listener), enums (Greetings, Type) and other stuff like constants (PORT). The configuration file could look like this:

module: GreetLib
classes: # We copy the structure of classes
  Greeter: Greeter
  Listener: Listener
enums: # But map the enums differently
  Type: Greeter::Type
  Greeter::Greetings: Greetings

Which will generate a graph looking like this:

Graph example

Note: The concept is really similar to ASTs used by compilers.

Parser step

This is the beginning of the actual execution pipeline. It calls out to the clang-based parser tool () to read the C/C++ source code and write a JSON-formatted "database" onto standard output. This is directly read by bindgen and subsequently parsed as Parser::Document.

Graph::Builder step

The second step takes the Parser::Document and transforms it into a Graph::Namespace. This step is where the user configuration mapping is used.

Processor step

The third step runs all configured processors in order. These work with the Graph and mostly add methods and Calls so they can be bound later. But they're allowed to do whatever they want really, which makes it a good place to add more complex rewriting rules if desired.

Processors are responsible for many core features of bindgen. The TEMPLATE.yml has an already set-up example pipeline.

Generator step

The final step now takes the finalized graph and writes the result into an output of one or more files. Generators do not change the graph in any way, and also don't build anything on their own. They only write to output.

Processors

The processor pipeline can be configured through the processors: array. Its elements are run in the order they're defined, starting at the first element.

Note: Don't worry: The TEMPLATE.yml file already comes with the recommended pipeline pre-configured.

There are three kinds of processors:

  1. Refining ones modify the graph in some way, without a dependency to a later generator.
  2. Generation processors add data to the graph so that the generators run later have all data they need to work.
  3. Information processors don't modify the graph, but do checks or print data onto the screen for debugging purposes.

The order in the configured pipeline is to have Refining processors first, Generation processors second. Information processors

View on GitHub
GitHub Stars190
CategoryDevelopment
Updated1mo ago
Forks18

Languages

Crystal

Security Score

100/100

Audited on Feb 15, 2026

No findings