#include <stdlib.h>
#include <dlfcn.h>
+#include <pthread.h>
+#include <unistd.h>
#include "lib/defines.h"
#include "lib/utils.h"
static void *load_symbol(void *lib, const char *prefix, const char *name)
{
- auto_free char *symbol = kr_strcatdup(3, prefix, "_", name);
+ auto_free char *symbol = kr_strcatdup(2, prefix, name);
return dlsym(lib, symbol);
}
return kr_error(ENOENT);
}
+static int bootstrap_libgo(struct kr_module *module)
+{
+ /* Check if linked against compatible libgo */
+ void (*go_check)(void) = dlsym(module->lib, "runtime_check");
+ void (*go_args)(int, void*) = dlsym(module->lib, "runtime_args");
+ void (*go_init_os)(void) = dlsym(module->lib, "runtime_osinit");
+ void (*go_init_sched)(void) = dlsym(module->lib, "runtime_schedinit");
+ void (*go_init_main)(void) = dlsym(module->lib, "__go_init_main");
+ if ((go_check && go_args && go_init_os && go_init_sched && go_init_main) == false) {
+ return kr_error(EINVAL);
+ }
+
+ /*
+ * Bootstrap runtime - this is minimal runtime, we would need a running scheduler
+ * and gc for coroutines and memory allocation. That would require a custom "world loop",
+ * message passing, and either runtime sharing or module isolation.
+ * https://github.com/gcc-mirror/gcc/blob/gcc-4_9_2-release/libgo/runtime/proc.c#L457
+ */
+ char *fake_argv[2] = {
+ getenv("_"),
+ NULL
+ };
+ go_check();
+ go_args(1, fake_argv);
+ go_init_os();
+ go_init_sched();
+ go_init_main();
+
+ return kr_ok();
+}
+
+
+static int load_libgo(struct kr_module *module, module_api_cb **module_api)
+{
+ /* Bootstrap libgo */
+ int ret = bootstrap_libgo(module);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Enforced prefix for now. */
+ const char *module_prefix = "main.";
+
+ *(void **) (module_api) = load_symbol(module->lib, module_prefix, "Api");
+ *(void **) (&module->init) = load_symbol(module->lib, module_prefix, "Init");
+ *(void **) (&module->deinit) = load_symbol(module->lib, module_prefix, "Deinit");
+ *(void **) (&module->config) = load_symbol(module->lib, module_prefix, "Config");
+ *(void **) (&module->layer) = load_symbol(module->lib, module_prefix, "Layer");
+
+ return kr_ok();
+}
+
int kr_module_load(struct kr_module *module, const char *name, const char *path)
{
if (module == NULL || name == NULL) {
/* Load all symbols. */
module_api_cb *module_api = NULL;
- *(void **) (&module_api) = load_symbol(module->lib, name, "api");
- *(void **) (&module->init) = load_symbol(module->lib, name, "init");
- *(void **) (&module->deinit) = load_symbol(module->lib, name, "deinit");
- *(void **) (&module->config) = load_symbol(module->lib, name, "config");
- *(void **) (&module->layer) = load_symbol(module->lib, name, "layer");
+ auto_free char *module_prefix = kr_strcatdup(2, name, "_");
+ *(void **) (&module_api) = load_symbol(module->lib, module_prefix, "api");
+ *(void **) (&module->init) = load_symbol(module->lib, module_prefix, "init");
+ *(void **) (&module->deinit) = load_symbol(module->lib, module_prefix, "deinit");
+ *(void **) (&module->config) = load_symbol(module->lib, module_prefix, "config");
+ *(void **) (&module->layer) = load_symbol(module->lib, module_prefix, "layer");
+
+ /* Module initializer not found, attempt to load as Go shared library. */
+ if (module_api == NULL) {
+ int ret = load_libgo(module, &module_api);
+ if (ret != 0) {
+ return ret;
+ }
+ }
/* Check module API version (if declared). */
- if (module_api && module_api() > KR_MODULE_API) {
+ if (module_api && module_api() != KR_MODULE_API) {
return kr_error(ENOTSUP);
}
/* Initialize module */
if (module->init) {
- return module->init(module);
+ module->init(module);
}
return kr_ok();
if (module->lib && module->lib != RTLD_DEFAULT) {
dlclose(module->lib);
}
-}
\ No newline at end of file
+}
-package gostats
+package main
/*
#include "lib/layer.h"
#include "lib/module.h"
-extern int gostats_begin(knot_layer_t *, void *);
-extern int gostats_finish(knot_layer_t *);
+extern int begin(knot_layer_t *, void *) __asm__ ("main.Begin");
+extern int finish(knot_layer_t *) __asm__ ("main.Finish");
static inline const knot_layer_api_t *_gostats_layer(void)
{
static const knot_layer_api_t _module = {
- .begin = &gostats_begin,
- .finish = &gostats_finish
+ .begin = &begin,
+ .finish = &finish
};
return &_module;
}
import "unsafe"
import "fmt"
-//export gostats_init
-func gostats_init(module *C.struct_kr_module) C.int {
- fmt.Println("go_init()")
+func Api() C.uint32_t {
+ return C.KR_MODULE_API
+}
+
+func Init(module *C.struct_kr_module) C.int {
+ fmt.Printf("go_init(%s)\n", C.GoString((*C.char)(module.data)))
return 0
}
-//export gostats_deinit
-func gostats_deinit(module *C.struct_kr_module) C.int {
+func Deinit(module *C.struct_kr_module) C.int {
fmt.Println("go_deinit()")
return 0
}
-//export gostats_begin
-func gostats_begin(ctx *C.knot_layer_t, param unsafe.Pointer) C.int {
+func Begin(ctx *C.knot_layer_t, param unsafe.Pointer) C.int {
fmt.Println("go_begin()")
return 0
}
-//export gostats_finish
-func gostats_finish(ctx *C.knot_layer_t) C.int {
+func Finish(ctx *C.knot_layer_t) C.int {
fmt.Println("go_finish()")
return 0
}
-//export gostats_layer
-func gostats_layer() *C.knot_layer_api_t {
+func Layer() *C.knot_layer_api_t {
return C._gostats_layer()
}
\ No newline at end of file
# Go target definition
define go_target
-$(1): $(2)/$(1)$(LIBEXT)
-$(2)/_obj/_cgo_.o: $$($(1)_SOURCES)
- $(INSTALL) -d $(2)/_obj
+$(1)_OBJS := $(addprefix $(2)/_obj/,_cgo_defun.o _cgo_export.o $(subst /,_,$(2))_$(1).cgo2.o)
+$(1)_GOBJS := $(addprefix $(2)/_obj/,_cgo_gotypes.go $(subst /,_,$(2))_$(1).cgo1.go)
+$(2)/_obj/_cgo_export.h: $$($(1)_SOURCES)
+ @$(INSTALL) -d $(2)/_obj
$(call quiet,CGO,$$^) -gccgo=true -objdir=$(2)/_obj -- $(CFLAGS) $$^
-$(2)/_obj/$(1).o: $(2)/_obj/_cgo_.o
- $(call quiet,GCCGO,$$@) -fPIC -c $(2)/_obj/*.go
-$(2)/$(1)$(LIBEXT): $(2)/_obj/$(1).o $$($(1)_DEPEND)
- $(call quiet,GCCGO,$$@) $(CFLAGS) -$(LIBTYPE) -fPIC -Wno-return-type -o $$@ $(2)/_obj/*.o $(2)/_obj/*.c -lgcc $$($(1)_LIBS)
+$(2)/$(1).o: $(2)/_obj/_cgo_export.h $$($(1)_GOBJS)
+ $(call quiet,GCCGO,$$@) -I$(2)/_obj -c -fPIC $$($(1)_GOBJS) -o $$@
+$(2)/$(1)$(LIBEXT): $(2)/_obj/_cgo_export.h $(2)/$(1).o $$($(1)_OBJS) $$($(1)_DEPEND)
+ $(call quiet,GCCGO,$$@) -g -fPIC -I$(2)/_obj $(2)/$(1).o $$($(1)_OBJS) -o $$@ -$(LIBTYPE) -lgcc -lgo $$($(1)_LIBS)
+$(1): $(2)/_obj/_cgo_export.h $(2)/$(1)$(LIBEXT)
$(1)-clean:
$(RM) -r $(2)/_obj $(2)/$(1)$(LIBEXT)
$(1)-install: $(2)/$(1)$(LIBEXT)