https://github.com/csiro-hydroinformatics/c-api-wrapper-generation
Generate language bindings around an existing C/C++ API
https://github.com/csiro-hydroinformatics/c-api-wrapper-generation
api-wrapper cffi codegen interoperability pinvoke rcpp
Last synced: 6 months ago
JSON representation
Generate language bindings around an existing C/C++ API
- Host: GitHub
- URL: https://github.com/csiro-hydroinformatics/c-api-wrapper-generation
- Owner: csiro-hydroinformatics
- License: gpl-3.0
- Created: 2015-04-16T00:53:37.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2025-08-22T03:45:37.000Z (11 months ago)
- Last Synced: 2025-09-10T17:04:44.765Z (11 months ago)
- Topics: api-wrapper, cffi, codegen, interoperability, pinvoke, rcpp
- Language: C#
- Homepage:
- Size: 273 KB
- Stars: 3
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Generate bindings for a C API
[](https://raw.githubusercontent.com/csiro-hydroinformatics/c-api-wrapper-generation/master/LICENSE)

[](https://zenodo.org/badge/latestdoi/34026446)
From a C API with functions such as:
```c++
SWIFT_API HYPERCUBE_PTR CreateHypercubeParameterizer(const char* strategy);
```
Generate the glue code to surface it to R, Python, Matlab, .NET, etc.
## Background
Around 2014 I needed in a project to (re)generate bindings for C++ scientific research modelling code _via a C API_ for at least R, Python, Matlab and C#. A manual approach was not a sustainable option. I first tried to apply or adapt a few of the many third party options (incl. some heavyweights in the wrapping field such as SWIG). I ended up with more difficulties than I bargained for, and despite my reluctance enacted plan B, a custom solution.
It may, or may not, suit your needs. It is used on an ongoing basis for quite large APIs with hundreds of functions. I hope it can help alleviate your language interop glue code maintenance.
## Overview
A typical C API, build on top of C++ for a better cross-language interoperability, often looks like this [hydrologic modelling](https://www.mssanz.org.au/modsim2015/L15/perraud.pdf) example:
```c++
SWIFT_API HYPERCUBE_PTR CreateHypercubeParameterizer(const char* strategy);
SWIFT_API void AddParameterDefinition(HYPERCUBE_PTR hypercubeParameterizer, const char* variableName, double min, double max, double value);
SWIFT_API double GetParameterValue(HYPERCUBE_PTR hypercubeParameterizer, const char* variableName);
SWIFT_API void DisposeSharedPointer(VOID_PTR_PROVIDER_PTR ptr);
```
with C macro expanded:
```c++
extern void* CreateHypercubeParameterizer(const char* strategy);
extern void AddParameterDefinition(void* hypercubeParameterizer, const char* variableName, double min, double max, double value);
extern double GetParameterValue(void* hypercubeParameterizer, const char* variableName);
extern void DisposeSharedPointer(void* ptr);
```
This present code generation tool was created to generate bindings around native libraries with a C API.
Say you want to surface this API in R using [Rcpp](http://www.rcpp.org/). There are plenty of design options of course, but chances are you will need some boilerplate `C++` code with Rcpp classes (`XPtr`, `CharacterVector`, etc.) looking like:
```c++
// [[Rcpp::export]]
XPtr CreateHypercubeParameterizer_Rcpp(CharacterVector strategy)
{
auto result = CreateHypercubeParameterizer(strategy[0]);
auto x = XPtr(new opaque_pointer_handle(result));
return x;
}
```
and boilerplate `R` code such as:
```R
#' CreateHypercubeParameterizer_R
#'
#' CreateHypercubeParameterizer_R Wrapper function for CreateHypercubeParameterizer
#'
#' @param strategy R type equivalent for C++ type const char*
#' @export
CreateHypercubeParameterizer_R <- function(strategy) {
strategy <- cinterop::getExternalXptr(strategy)
result <- CreateHypercubeParameterizer_Rcpp(strategy)
return(cinterop::mkExternalObjRef(result, 'HYPERCUBE_PTR'))
}
```
`opaque_pointer_handle` and `mkExternalObjRef` are managing native object lifetime. They are not included in the present repository, but if useful to you in the related [cpp interop commons](https://github.com/csiro-hydroinformatics/c-interop) repository.
## Getting started
### Windows
From the development command line prompt of visual studio (or a compiler toolchain):
```bat
MSBuild c:\src\c-api-wrapper-generation\ApiWrapperGenerator\ApiWrapperGenerator.sln /t:Build /p:Configuration=Debug
```
### Linux
#### prerequisites
Check dotnet is available with `which dotnet`, and `dotnet --info`.
As of April 2022, dotnet can be installed on Linux Debian using debian package repositories managed by Microsoft. This is the prefered way, and seems to work fine for generating code from F# scripts
_Possibly deprecated_: if need be follow the [Manual Install](https://docs.microsoft.com/en-us/dotnet/core/install/linux-debian#manual-install). There are other ways to obtain dotnet.
`cd ~/Downloads` `ls dotnet*`
```text
dotnet-sdk-5.0.101-linux-x64.tar.gz
dotnet-sdk-3.1.404-linux-x64.tar.gz
dotnet-sdk-2.1.811-linux-x64.tar.gz
dotnet-sdk-3.1.402-linux-x64.tar.gz
```
```bash
tar zxf dotnet-sdk-2.1.811-linux-x64.tar.gz -C "$HOME/dotnet"
```
Optionally if you want newer versions:
```bash
tar zxf dotnet-sdk-3.1.404-linux-x64.tar.gz -C "$HOME/dotnet"
tar zxf dotnet-sdk-5.0.101-linux-x64.tar.gz -C "$HOME/dotnet"
```
`nano ~/.bashrc` then adding
```sh
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet
```
#### prerequisites for capigen
If you want to generate code from the R package `capigen`, you need rClr. This may be deprecated as of April 2022.
```sh
sudo apt install mono-xbuild
sudo apt install libmono-2.0-dev
sudo apt install msbuild
cd ~/src/github_jm/rClr
cd ~/src/github_jm
export BUILDTYPE=Debug
R CMD INSTALL --no-test-load rClr
cd ~/src/github_jm
R CMD build --no-build-vignettes rClr
R CMD INSTALL rClr_0.9.0.tar.gz
```
#### Building our codegen engine
```sh
# cd ~/src/github_jm/c-api-wrapper-generation
cd engine/ApiWrapperGenerator
dotnet restore ApiWrapperGenerator.sln
```
```bash
dotnet build --configuration Release --no-restore ApiWrapperGenerator.sln
dotnet build --configuration Debug --no-restore ApiWrapperGenerator.sln
cd ../TestApiWrapperGenerator/
dotnet test TestApiWrapperGenerator.csproj
```