Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go и внешний мир

Go и внешний мир

Iskander (Alex) Sharipov

December 08, 2018
Tweet

More Decks by Iskander (Alex) Sharipov

Other Decks in Programming

Transcript

  1. Сборка бинарника $ go build -x … go/pkg/tool/platform/compile -o pkg.a

    ./main.go … go/pkg/tool/platform/link -o a.out -buildmode=exe pkg.a …
  2. Сборка бинарника $ go build -x … go/pkg/tool/platform/compile -o pkg.a

    ./main.go … go/pkg/tool/platform/link -o a.out -buildmode=exe pkg.a …
  3. Вызов Go из стороннего кода $ go help build …

    -buildmode mode build mode to use. See 'go help buildmode' for more. …
  4. c-shared // mylib.go: package main import "C" import ( "fmt"

    ) //export HelloWorld func HelloWorld(i int32, msg string) { fmt.Printf("Hello from go: i:%d msg:%s\n", i, msg) } func main() {}
  5. c-shared // mylib.go: package main import "C" import ( "fmt"

    ) //export HelloWorld func HelloWorld(i int32, msg string) { fmt.Printf("Hello from go: i:%d msg:%s\n", i, msg) } func main() {}
  6. c-shared // libtest.c: #include <stdio.h> #include "mylib.h" int main() {

    GoInt i = 42; GoString msg = {"C Caller", 9}; // HelloWorld(i int32, msg string) HelloWorld(i, msg); }
  7. c-shared // libtest.c: #include <stdio.h> #include "mylib.h" int main() {

    GoInt i = 42; GoString msg = {"C Caller", 9}; // HelloWorld(i int32, msg string) HelloWorld(i, msg); } // mylib.h: typedef struct { const char *p; ptrdiff_t n; } _GoString_; typedef _GoString_ GoString; // src/reflect/value.go: type StringHeader struct { Data uintptr Len int }
  8. c-shared // mylib.go: //export HelloWorld2 func HelloWorld2(i int32, msg *C.char)

    { fmt.Printf("Hello from go: i:%d msg:%s\n", i, C.GoString(msg)) } // libtest.c: int main() { GoInt i = 42; GoString msg = {"C Caller", 9}; HelloWorld(i, msg); HelloWorld2(100500, "C caller#2"); }
  9. c-shared // libtest.py: $ python libtest.py from ctypes import *

    lib = cdll.LoadLibrary("./mylib.so") class GoString(Structure): _fields_ = [("p", c_char_p), ("n", c_longlong)] lib.HelloWorld.argtypes = [c_int, GoString] msg = GoString("Hello from Python", 17) lib.HelloWorld(42, msg)
  10. c-shared // libtest.lua: $ luajit libtest.lua local ffi = require("ffi")

    ffi.cdef[[ void HelloWorld2(int p0, const char* p1); ]] local mylib = ffi.load("./mylib.so") mylib.HelloWorld2(42, "Hello from lua!")
  11. c-archive $ go build -o mylib.a -buildmode=c-archive mylib.go $ gcc

    -o libtest -pthread libtest.c mylib.a $ ./libtest Hello from go: i:42 msg:C Caller
  12. Вызов стороннего кода из Go package main /* int sum(int

    a, int b) { return a + b; } */ import "C" import ( "fmt" ) func main() { fmt.Println(C.sum(40, 2)) }
  13. Вызов стороннего кода из Go package main /* int sum(int

    a, int b) { return a + b; } */ import "C" import ( "fmt" ) func main() { fmt.Println(C.sum(40, 2)) }
  14. Вызов стороннего кода из Go package main /* int sum(int

    a, int b) { return a + b; } */ import "C" import ( "fmt" ) func main() { fmt.Println(C.sum(40, 2)) }
  15. Вызов стороннего кода из Go /* ... */ import "C"

    import ( "fmt" ) /* ... */ import ( "C" "fmt" )
  16. Вызов стороннего кода из Go /* ... */ import "C"

    import ( "fmt" ) /* ... */ import ( "C" "fmt" ) /* ... */ import "C" import ( "fmt" )
  17. Вызов стороннего кода из Go package main /* #include <stdio.h>

    void hello(char* s) { printf("From C: %s\n", s); } */ import "C" func main() { C.hello("Hello, NN!") }
  18. Вызов стороннего кода из Go package main /* #include <stdio.h>

    void hello(char* s) { printf("From C: %s\n", s); } */ import "C" func main() { C.hello("Hello, NN!") }
  19. Вызов стороннего кода из Go $ go run main.go #

    command-line-arguments ./main.go:17:29: cannot use "Hello, NN!" (type string) as type *_Ctype_char in argument to _Cfunc_hello
  20. Вызов стороннего кода из Go $ go run main.go #

    command-line-arguments ./main.go:17:29: cannot use "Hello, NN!" (type string) as type *_Ctype_char in argument to _Cfunc_hello // src/reflect/value.go: type StringHeader struct { Data uintptr Len int }
  21. Вызов стороннего кода из Go /* #include <stdio.h> #include <stdlib.h>

    void hello(char* s) { printf("From C: %s\n", s); } */ import "C" import ( "unsafe" ) func main() { cs := C.CString("Hello, NN!") defer C.free(unsafe.Pointer(cs)) C.hello(cs) }
  22. Вызов стороннего кода из Go /* typedef struct { int32_t

    a; int32_t b; int32_t r; } Foo; void sum(Foo *req) { req->r = req->a + req->b; } */ import "C" import "fmt" func main() { req := C.Foo{ a: 12, b: 30, } C.sum(&req) fmt.Println(req.r) }
  23. Вызов стороннего кода из Go /* #pragma pack(push,1) typedef struct

    { int8_t a; int32_t b; } Bar; #pragma pack(pop) typedef struct { int8_t a; int32_t b; } Foo; void test() { printf("Bar size: %lu\n", sizeof(Bar)); printf("Foo size: %lu\n", sizeof(Foo)); } */ import "C" import ( "fmt" "unsafe" ) func main() { C.test() fmt.Printf("C.Foo size: %d\n", unsafe.Sizeof(C.Foo{}), ) }
  24. Вызов стороннего кода из Go $ go run main.go Bar

    size: 5 Foo size: 8 C.Foo size: 8 http://golang-sizeof.tips
  25. Вызов стороннего кода из Go package main /* #cgo LDFLAGS:

    -lm #include <math.h> */ import "C" import "fmt" func main() { fmt.Println(C.pow(2, 5)) }
  26. Go scheduler и cgo func foo() {} go func() {

    foo() syscall.GetPid() // https://morsmachine.dk/go-scheduler }()
  27. Go scheduler и cgo func foo() {} go func() {

    foo() syscall.GetPid() // https://morsmachine.dk/go-scheduler C.bar() }()
  28. Go scheduler и cgo func foo() {} go func() {

    foo() syscall.GetPid() // https://morsmachine.dk/go-scheduler C.bar() // https://github.com/golang/go/issues/8636#issuecomment-66098275 }()
  29. Выводы • Удобное встраивание в обе стороны • Есть проблемы

    из-за разных миров • Без необходимости так лучше не делать
  30. Полезные ссылки: Call Go function from C function https://dev.to/mattn/call-go-function-from-c-function-1n3 cgo

    https://github.com/golang/go/wiki/cgo RustGo: вызов Rust из Go с почти нулевым оверхедом https://habr.com/post/337348/ Пишем модульную Go программу с плагинами https://4gophers.ru/articles/plugins/