Skip to content

Instantly share code, notes, and snippets.

@dresswithpockets
Last active April 14, 2022 04:49
Show Gist options
  • Save dresswithpockets/5cb3f2ac5e90939014b4234211362e0e to your computer and use it in GitHub Desktop.
Save dresswithpockets/5cb3f2ac5e90939014b4234211362e0e to your computer and use it in GitHub Desktop.
Testing odin interop

In an attempt to sus out why gdnative doesnt work on linux, testing interop between C and odin here.

Run ./build_and_run.sh gcc or ./build_and_run.sh clang to build and execute both test cases (shared linked vs dlopen).

Success output:

$ ./build_and_run.sh gcc

[mode: dlopen]
loaded libtest.so
executing test_func:
hello from odin without a context
hello from odin
setting callback
calling callback
hello from callback
finished

[mode: linked]
loaded libtest.so
executing test_func:
hello from odin without a context
hello from odin
setting callback
calling callback
hello from callback
finished
odin build test.odin -file -build-mode:shared -out:libtest.so || exit $?;
$1 -Wall -Werror -o test_dlopen main.c || exit $?;
$1 -Wall -Werror -o test_linked main.c -ltest -L. -DTEST_LINKED || exit $?;
printf '\n[mode: dlopen]\n'
LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} ./test_dlopen || exit $?;
printf '\n[mode: linked]\n'
LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} ./test_linked || exit $?;
#include <stdio.h>
#include <stdlib.h>
typedef struct callback_struct {
void (*callback)();
} callback_struct;
typedef struct test_funcs_struct {
void (*imported_print)(const char *);
void (*set_callback)(callback_struct *);
} test_funcs_struct;
callback_struct *_callback_inst = NULL;
void execute();
void print_func(const char *msg);
void set_callback_func(callback_struct *);
#ifdef TEST_LINKED
void test_func(test_funcs_struct *p);
void execute() {
printf("loaded libtest.so\n");
test_funcs_struct p = {
.imported_print = &print_func,
.set_callback = &set_callback_func
};
printf("executing test_func:\n");
test_func(&p);
if (_callback_inst) {
printf("calling callback\n");
(*_callback_inst->callback)();
}
printf("finished\n");
exit(EXIT_SUCCESS);
}
#else // TEST_LINKED
#include <dlfcn.h>
void execute() {
void *handle;
void (*test_func)(test_funcs_struct *p);
char *error;
handle = dlopen("libtest.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
printf("loaded libtest.so\n");
dlerror();
*(void **)(&test_func) = dlsym(handle, "test_func");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
test_funcs_struct p = {
.imported_print = &print_func,
.set_callback = &set_callback_func
};
printf("executing test_func:\n");
(*test_func)(&p);
if (_callback_inst) {
printf("calling callback\n");
(*_callback_inst->callback)();
}
printf("finished\n");
dlclose(handle);
exit(EXIT_SUCCESS);
}
#endif // TEST_LINKED
void print_func(const char *msg) {
printf("%s", msg);
}
void set_callback_func(callback_struct *c) {
printf("setting callback\n");
_callback_inst = c;
}
int main(void) {
execute();
return 0;
}
package test
import "core:runtime"
import "core:fmt"
import "core:mem"
ImportedPrintStruct :: struct {
imported_print: #type proc "c" (msg: cstring),
set_callback: #type proc "c" (c: ^CallbackStruct),
}
CallbackStruct :: struct {
callback: #type proc "c" (),
}
_callback := CallbackStruct {
callback,
}
@(export)
test_func :: proc "c" (p: ^ImportedPrintStruct) {
test_print(p, "hello from odin without a context\n")
context = runtime.default_context()
fmt.println("hello from odin")
p.set_callback(&_callback)
}
test_print :: proc "contextless" (p: ^ImportedPrintStruct, msg: string) {
d := transmute(mem.Raw_String)msg
cstr := cstring(d.data)
p.imported_print(cstr);
}
callback :: proc "c" () {
context = runtime.default_context()
fmt.println("hello from callback")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment