浏览代码

Added 2 examples

Added CGO dlopen plugin test
Added native go plugins (does not support unload)
Luis Figueiredo 8 年之前
父节点
当前提交
2a06eab754

+ 10 - 0
dlopen/Makefile

@@ -0,0 +1,10 @@
+
+
+all:
+	go build -v 
+
+plugins:
+	make -C plugins/cnative
+	make -C plugins/cgo
+
+.PHONY: all plugins

+ 12 - 0
dlopen/caller.c

@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+// C func caller test
+char *call(void *ptr,int a, int b) {
+	// Bridge
+	char *(*fnptr)(int,int) = ptr;
+	return fnptr(a,b);
+}
+
+char *testLocal() {
+	return "This is a static string";
+}

+ 7 - 0
dlopen/caller.h

@@ -0,0 +1,7 @@
+#ifndef CALLER_H
+#define CALLER_H
+char *call(void *ptr,int a, int b);
+char *testLocal();
+#endif
+
+

二进制
dlopen/dlopen


+ 71 - 0
dlopen/dlopen.go

@@ -0,0 +1,71 @@
+package main
+
+// #include <dlfcn.h>
+// #include <stdlib.h> // for free
+// #include "caller.h"
+// #cgo LDFLAGS: -ldl
+import "C"
+
+import (
+	"log"
+	"path/filepath"
+	"time"
+	"unsafe"
+)
+
+// Loop trough the plugin path to load any .so
+func main() {
+	for {
+		matches, err := filepath.Glob("plugins/bin/*.so")
+		panicIfErr(err)
+		for _, v := range matches {
+			execPlugin(v)
+
+		}
+		<-time.After(3 * time.Second)
+	}
+}
+
+func execPlugin(plugpath string) {
+	defer func() {
+		if q := recover(); q != nil {
+			log.Println("Recovering panic")
+		}
+	}()
+
+	plugname := C.CString(plugpath)
+	phandle := C.dlopen(plugname, C.RTLD_NOW) // Win32 LoadLibrary
+	if phandle == nil {
+		cerr := C.dlerror()
+		log.Println("err:", C.GoString(cerr))
+		C.free(unsafe.Pointer(cerr))
+	}
+	C.free(unsafe.Pointer(plugname))
+
+	cs := C.CString("Add")
+	// Find our Add implementation
+	sym := C.dlsym(phandle, cs)
+	C.free(unsafe.Pointer(cs))
+
+	if sym == nil { // Not thread safe since is fetching error after call (another dl might be called in between)
+		cerr := C.dlerror()
+		log.Println("err:", C.GoString(cerr))
+		C.free(unsafe.Pointer(cerr))
+	}
+
+	r := C.call(sym, 1, 2)
+	res := C.GoString(r)
+	log.Printf("From: %-30s Result --> '%s'", plugpath, res)
+	C.free(unsafe.Pointer(r))
+
+	//log.Println("Res:", C.GoString(C.testLocal())) /**/
+
+	C.dlclose(phandle)
+
+}
+
+func panicIfErr(err error) {
+	if err != nil {
+		panic(err)
+	}
+}

+ 60 - 0
dlopen/plugins/bin/cgo.h

@@ -0,0 +1,60 @@
+/* Created by "go tool cgo" - DO NOT EDIT. */
+
+/* package dev.hexasoftware.com/stdio/plugintest/go_dlopen/plugins/cgo */
+
+/* Start of preamble from import "C" comments.  */
+
+
+
+
+/* End of preamble from import "C" comments.  */
+
+
+/* Start of boilerplate cgo prologue.  */
+#line 1 "cgo-gcc-export-header-prolog"
+
+#ifndef GO_CGO_PROLOGUE_H
+#define GO_CGO_PROLOGUE_H
+
+typedef signed char GoInt8;
+typedef unsigned char GoUint8;
+typedef short GoInt16;
+typedef unsigned short GoUint16;
+typedef int GoInt32;
+typedef unsigned int GoUint32;
+typedef long long GoInt64;
+typedef unsigned long long GoUint64;
+typedef GoInt64 GoInt;
+typedef GoUint64 GoUint;
+typedef __SIZE_TYPE__ GoUintptr;
+typedef float GoFloat32;
+typedef double GoFloat64;
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
+
+/*
+  static assertion to make sure the file is being used on architecture
+  at least with matching size of GoInt.
+*/
+typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
+
+typedef struct { const char *p; GoInt n; } GoString;
+typedef void *GoMap;
+typedef void *GoChan;
+typedef struct { void *t; void *v; } GoInterface;
+typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
+
+#endif
+
+/* End of boilerplate cgo prologue.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern char* Add(int p0, int p1);
+
+#ifdef __cplusplus
+}
+#endif

二进制
dlopen/plugins/bin/cgo.so


二进制
dlopen/plugins/bin/ctest.so


+ 5 - 0
dlopen/plugins/cgo/Makefile

@@ -0,0 +1,5 @@
+
+all:
+	go build -o ../bin/cgo.so -buildmode=c-shared
+
+.PHONY: all

+ 60 - 0
dlopen/plugins/cgo/cgo.h

@@ -0,0 +1,60 @@
+/* Created by "go tool cgo" - DO NOT EDIT. */
+
+/* package dev.hexasoftware.com/stdio/plugintest/godlopen/plugins/cgo */
+
+/* Start of preamble from import "C" comments.  */
+
+
+
+
+/* End of preamble from import "C" comments.  */
+
+
+/* Start of boilerplate cgo prologue.  */
+#line 1 "cgo-gcc-export-header-prolog"
+
+#ifndef GO_CGO_PROLOGUE_H
+#define GO_CGO_PROLOGUE_H
+
+typedef signed char GoInt8;
+typedef unsigned char GoUint8;
+typedef short GoInt16;
+typedef unsigned short GoUint16;
+typedef int GoInt32;
+typedef unsigned int GoUint32;
+typedef long long GoInt64;
+typedef unsigned long long GoUint64;
+typedef GoInt64 GoInt;
+typedef GoUint64 GoUint;
+typedef __SIZE_TYPE__ GoUintptr;
+typedef float GoFloat32;
+typedef double GoFloat64;
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
+
+/*
+  static assertion to make sure the file is being used on architecture
+  at least with matching size of GoInt.
+*/
+typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
+
+typedef struct { const char *p; GoInt n; } GoString;
+typedef void *GoMap;
+typedef void *GoChan;
+typedef struct { void *t; void *v; } GoInterface;
+typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
+
+#endif
+
+/* End of boilerplate cgo prologue.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern GoString Add(GoInt p0, GoInt p1);
+
+#ifdef __cplusplus
+}
+#endif

+ 16 - 0
dlopen/plugins/cgo/cgotest.go

@@ -0,0 +1,16 @@
+package main
+
+import "C"
+import (
+	"fmt"
+	"log"
+)
+
+//export Add
+func Add(a, b C.int) *C.char {
+	return C.CString(fmt.Sprintf("Go plugin: %d", a+b))
+}
+
+func main() {
+	log.Println("Main of cgotest")
+}

+ 6 - 0
dlopen/plugins/cnative/Makefile

@@ -0,0 +1,6 @@
+
+
+all:
+	gcc -fPIC -shared ctest.c -o ../bin/ctest.so
+
+.PHONY: all

+ 10 - 0
dlopen/plugins/cnative/ctest.c

@@ -0,0 +1,10 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+
+
+char *Add(int a,int b) {
+	char *ret;
+		
+	asprintf(&ret, "C plugin: %d",a+b);
+	return ret;
+}

+ 12 - 0
native/Makefile

@@ -0,0 +1,12 @@
+
+
+all:
+	go build
+
+
+plugins:
+	make -C plugins/plugin1/
+
+
+
+.PHONY: plugins all

+ 3 - 0
native/README.md

@@ -0,0 +1,3 @@
+plugintest
+================
+Testing go1.8 plugins

二进制
native/native


+ 7 - 0
native/plugbase/plugbase.go

@@ -0,0 +1,7 @@
+package plugbase
+
+//PlugInfo plugin base information
+type PlugInfo struct {
+	Author  string
+	Contact string
+}

二进制
native/plugins/bin/plugin1.so


+ 5 - 0
native/plugins/plugin1/Makefile

@@ -0,0 +1,5 @@
+
+BIN=../bin/plugin1.so
+
+all: plug.go
+	go build -o ${BIN} -buildmode=plugin

+ 20 - 0
native/plugins/plugin1/plug.go

@@ -0,0 +1,20 @@
+package main
+
+import (
+	"log"
+
+	"dev.hexasoftware.com/stdio/plugintest/native/plugbase"
+)
+
+var (
+	//Info entrypoint
+	Info = plugbase.PlugInfo{"luisf@hexasoftware124.com", "luisf@hexasoftware.com"}
+)
+
+func PInfo() plugbase.PlugInfo {
+	return Info
+}
+
+func ExportedFunc() {
+	log.Println("Hello plugin 123 changed")
+}

+ 48 - 0
native/plugintest.go

@@ -0,0 +1,48 @@
+package main
+
+import (
+	"log"
+	"plugin"
+	"time"
+
+	"dev.hexasoftware.com/stdio/plugintest/native/plugbase"
+)
+
+func main() {
+
+	for {
+		callPlugin()
+		<-time.After(2 * time.Second) // wait 2 sec
+	}
+}
+
+func callPlugin() {
+
+	defer func() {
+		if r := recover(); r != nil {
+			log.Println("Recover")
+		}
+	}()
+
+	var err error
+	//Reopen plugin
+	plug, err := plugin.Open("plugins/bin/plugin1.so")
+	panicIfErr(err)
+
+	pluginfo, err := plug.Lookup("Info")
+	panicIfErr(err)
+
+	log.Println("s:", pluginfo.(*plugbase.PlugInfo).Author)
+
+	fn, err := plug.Lookup("ExportedFunc")
+	panicIfErr(err)
+
+	fn.(func())()
+
+}
+
+func panicIfErr(err error) {
+	if err != nil {
+		panic(err)
+	}
+}

+ 0 - 8
plugintest.go

@@ -1,8 +0,0 @@
-package plugintest
-
-import "fmt"
-
-func Hello() {
-
-	fmt.Println("Hello")
-}