mozilla / cbindgen

A project for generating C bindings from Rust code
Mozilla Public License 2.0
2.29k stars 294 forks source link

Implement runtime binding generation #923

Open kang-sw opened 5 months ago

kang-sw commented 5 months ago

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:

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"

## _C Backend_ ```c #include #include #include #include typedef struct Bar Bar; typedef struct { } Foo; extern const int32_t NUMBER; extern Foo FOO; extern const Bar BAR; void root(void); ``` ## _CDynamic Backend_ ```c #include #include #include #include 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