From a C API with functions such as:
SWIFT_API HYPERCUBE_PTR CreateHypercubeParameterizer(const char* strategy);
Generate the glue code to surface it to R, Python, Matlab, .NET, etc.
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.
A typical C API, build on top of C++ for a better cross-language interoperability, often looks like this hydrologic modelling example:
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:
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. 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:
// [[Rcpp::export]]
XPtr<opaque_pointer_handle> CreateHypercubeParameterizer_Rcpp(CharacterVector strategy)
{
auto result = CreateHypercubeParameterizer(strategy[0]);
auto x = XPtr<opaque_pointer_handle>(new opaque_pointer_handle(result));
return x;
}
and boilerplate R
code such as:
#' 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 repository.
From the development command line prompt of visual studio (or a compiler toolchain):
MSBuild c:\src\c-api-wrapper-generation\ApiWrapperGenerator\ApiWrapperGenerator.sln /t:Build /p:Configuration=Debug
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. There are other ways to obtain dotnet.
cd ~/Downloads
ls dotnet*
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
tar zxf dotnet-sdk-2.1.811-linux-x64.tar.gz -C "$HOME/dotnet"
Optionally if you want newer versions:
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
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet
If you want to generate code from the R package capigen
, you need rClr. This may be deprecated as of April 2022.
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
# cd ~/src/github_jm/c-api-wrapper-generation
cd engine/ApiWrapperGenerator
dotnet restore ApiWrapperGenerator.sln
dotnet build --configuration Release --no-restore ApiWrapperGenerator.sln
dotnet build --configuration Debug --no-restore ApiWrapperGenerator.sln
cd ../TestApiWrapperGenerator/
dotnet test TestApiWrapperGenerator.csproj