Implement runtime binding generation
Since this PR written from the changes not yet applied to master, file changes are a bit too verbose including non-PR changes. Actual change is only resides this file
As subsequent implementation of PR #853, implements C language backend for generating dynamic language bindings on runtime.
Two new structs are defined and exposed to public:
-
CDynamicBindingBackend -
CDynamicBindingConfig
And user can use this to generate runtime-loadable C binding instead of static binding using following scheme.
crate::Builder::new()
.with_config(config)
.with_crate(&CRATE_DIR)
.generate()
.unwrap()
.write_with_backend(
std::fs::File::options()
.write(true)
.create(true)
.open(OUT_FILE_NAME)
.unwrap(),
&mut super::CDynamicBindingBackend::new("USER_API_STRUCT", Default::default()),
);
This will generate global symbols and functions as loadable fields within the struct named as user provided USER_API_STRUCT string.
The generated loader methods will accept the Api definition struct and user-provided platform-agnostic API loader interface structure. Basically the generated loader methods is invisible to user. Once the user writes #define INCLUDE_CBINDGEN_LOADER_{USER_API_STRUCT} prior to the inclusion of generated header, then the loader methods is visible to the user as inline function.
Outputs with USER_API_STRUCT as "MyApiStruct"
USER_API_STRUCT as "MyApiStruct" C Backend
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct Bar Bar;
typedef struct {
} Foo;
extern const int32_t NUMBER;
extern Foo FOO;
extern const Bar BAR;
void root(void);
CDynamic Backend
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct Bar Bar;
typedef struct Foo {
} Foo;
struct MyApiStruct {
const int32_t *NUMBER;
struct Foo *FOO;
const struct Bar *BAR;
void (*root)(void);
};
#ifdef INCLUDE_CBINDGEN_LOADER_MyApiStruct
# ifndef CBINDGEN_LOADER_LOOKUP_INTERFACE_DEFINED
# define CBINDGEN_LOADER_LOOKUP_INTERFACE_DEFINED
struct CBindgenSymbolLookupIface {
void* module;
void* (*find_symbol)(void* module, const char* symbol_name);
void* (*opt_find_function)(void* module, const char* function_name);
};
# endif
# ifndef CBINDGEN_LOADER_MyApiStruct_DEFINED
# define CBINDGEN_LOADER_MyApiStruct_DEFINED
inline int MyApiStruct_load (
struct MyApiStruct* api,
struct CBindgenSymbolLookupIface* module
) {
int notfound = 0;
void* mod = module->module;
void* (*fsym)(void*, const char*) = module->find_symbol;
void* (*ffunc)(void*, const char*) = module->opt_find_function;
if (!ffunc) {
ffunc = module->find_symbol;
}
{
api->NUMBER = (const int32_t*)fsym(mod, "NUMBER");;
api->FOO = (struct Foo*)fsym(mod, "FOO");;
api->BAR = (const struct Bar*)fsym(mod, "BAR");;
api->root = (void(*)(void))fsym(mod, "root");;
notfound += (int)!api->root;
notfound += (int)!api->NUMBER;
notfound += (int)!api->FOO;
notfound += (int)!api->BAR;
}
return notfound;
}
# endif
#endif
TODOs
- [ ] Should configuration for
CDynamicbe merged into crate-wiseConfig? - [ ] Should we generate platform-specific module interface backends for user?
- [ ] How should I write integration test code for this?
- [ ] This is not tested yet enough; I'll apply this to my personal project first. Then elevate to this as merge request later.
- [ ] Wait merging #853; then rebase