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 и внешний мир
    Алексей Акулович
    backend dev VK
    2018.12.07#2

    View Slide

  2. Жизнь кода на Go
    1. Написание
    2. Тестирование
    3. Сборка
    4. Деплой
    5. Запуск

    View Slide

  3. Жизнь кода на Go
    1. Написание
    2. Тестирование
    3. Сборка
    4. Деплой
    5. Запуск

    View Slide

  4. Сборка бинарника
    $ go build

    View Slide

  5. Сборка бинарника
    $ go build

    View Slide

  6. Сборка бинарника
    $ go build
    $ ./binary-file

    View Slide

  7. Сборка бинарника
    $ go help build

    -x
    print the commands.

    View Slide

  8. Сборка бинарника
    $ 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

    View Slide

  9. Сборка бинарника
    $ 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

    View Slide

  10. Сборка бинарника
    $ go build -buildmode=exe

    View Slide

  11. Вызов Go из стороннего кода

    View Slide

  12. Вызов Go из стороннего кода
    $ go help build

    -buildmode mode
    build mode to use. See 'go help buildmode' for more.

    View Slide

  13. Вызов Go из стороннего кода
    $ go help buildmode

    -buildmode=c-shared
    -buildmode=c-archive

    View Slide

  14. c-shared

    View Slide

  15. 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() {}

    View Slide

  16. 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() {}

    View Slide

  17. c-shared
    $ go build -o mylib.so -buildmode=c-shared mylib.go
    $ ls
    mylib.go
    mylib.h
    mylib.so

    View Slide

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

    View Slide

  19. c-shared
    // libtest.c:
    #include
    #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
    }

    View Slide

  20. c-shared
    $ gcc -o libtest libtest.c ./mylib.so
    $ ./libtest
    Hello from go: i:42 msg:C Caller

    View Slide

  21. 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");
    }

    View Slide

  22. c-shared

    View Slide

  23. 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)

    View Slide

  24. 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!")

    View Slide

  25. c-archive

    View Slide

  26. c-archive
    $ go build -o mylib.a -buildmode=c-archive mylib.go

    View Slide

  27. c-archive
    $ go build -o mylib.a -buildmode=c-archive mylib.go
    $ gcc -o libtest -pthread libtest.c mylib.a

    View Slide

  28. 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

    View Slide

  29. c-shared & c-archive
    Плюсы и минусы:
    ● c-archive вкомпиливается, c-shared нет
    ● runtime языка
    ● fork

    View Slide

  30. http://jemgunay.co.uk/gopher/

    View Slide

  31. Вызов стороннего кода из Go

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  40. Вызов стороннего кода из 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

    View Slide

  41. Вызов стороннего кода из 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
    }

    View Slide

  42. Вызов стороннего кода из Go
    /*
    #include
    #include
    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)
    }

    View Slide

  43. Вызов стороннего кода из 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)
    }

    View Slide

  44. Вызов стороннего кода из 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{}),
    )
    }

    View Slide

  45. Вызов стороннего кода из Go
    $ go run main.go
    Bar size: 5
    Foo size: 8
    C.Foo size: 8

    View Slide

  46. Вызов стороннего кода из Go
    $ go run main.go
    Bar size: 5
    Foo size: 8
    C.Foo size: 8
    http://golang-sizeof.tips

    View Slide

  47. Вызов стороннего кода из Go
    package main
    /*
    #cgo LDFLAGS: -lm
    #include
    */
    import "C"
    import "fmt"
    func main() {
    fmt.Println(C.pow(2, 5))
    }

    View Slide

  48. Go scheduler и cgo
    func foo() {}
    go func() {
    foo()
    }()

    View Slide

  49. Go scheduler и cgo
    func foo() {}
    go func() {
    foo()
    syscall.GetPid()
    }()

    View Slide

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

    View Slide

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

    View Slide

  52. 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
    }()

    View Slide

  53. Выводы
    ● Удобное встраивание в обе стороны

    View Slide

  54. Выводы
    ● Удобное встраивание в обе стороны
    ● Есть проблемы из-за разных миров

    View Slide

  55. Выводы
    ● Удобное встраивание в обе стороны
    ● Есть проблемы из-за разных миров
    ● Без необходимости так лучше не делать

    View Slide

  56. Полезные ссылки:
    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/

    View Slide

  57. View Slide

  58. Вопросы?
    ater.me/conf/go_nn.pdf Презентация
    vk.com/ac
    @atercattus
    Вопросы

    View Slide