Можно ли динамически загружать код Go?

Как говорится в названии, я хочу динамически загружать пакет Go (или нет) на основе информации, доступной только во время выполнения.

Цель состоит в том, чтобы позволить пользователю расширять программу через пользовательские пакеты, которые добавляют новые собственные команды script. В настоящее время каждый раз, когда я добавляю новые команды или хочу запретить некоторые команды, мне нужно отредактировать программу и перекомпилировать, тогда как если бы я мог сделать какую-то dll или что-то подобное, тогда я мог бы создать команду "import" script для поиска и загрузите именованную библиотеку команд.

Для любопытных рассматриваемая программа представляет собой обычную командную библиотеку сценариев, которую я использую для всех видов вещей.

Я делал некоторые поиски раньше времени, и результаты не выглядят хорошо, но я не мог найти четкое сообщение.

Ответ 1

Go не поддерживает динамические библиотеки. Недавно Элиас Наур опубликовал некоторые исправления, но они еще не были рассмотрены, и вряд ли они будут включены в Go 1.2. Вы можете прочитать обсуждения в группах Google:

Насколько я знаю, это самые последние дискуссии по этой теме.

Существует, однако, другой подход. Вы можете запускать свои плагины в отдельных процессах и использовать пакет net/rpc для связи с вашим основным приложением. Это также позволяет вам динамически запускать/останавливать/перекомпилировать отдельные плагины, и это имеет то преимущество, что плохой плагин не может сбой вашей программы. Идите в сети, вы просто должны хорошо ее использовать.

Мне нужно отредактировать программу и перекомпилировать,

Вы также можете написать небольшую script, которая следит за изменениями в текущем каталоге (используя fsnotify) и выполняет "go build", а затем перезапуск вашей программы. Я использую этот подход для некоторых своих веб-проектов во время локального развития, и он отлично работает. Я не могу наблюдать какое-либо время компиляции, и я довольно быстро переключаю и обновляю окно браузера. Мой цикл разработки Python, в котором необходимо перезапустить интерпретатор, и все модули должны быть реимпортированы при каждом изменении (и это может занять значительное время в более крупных проектах!), Чувствует себя действительно неуклюжим по сравнению с Go.

Ответ 2

Поддержка этого в Go 1.8. В настоящий момент он довольно незрелый и рудиментарный, но в конечном итоге это возможно.

Также интересен проект Mateusz Gajewski go-bind-plugin, поскольку он упрощает использование загруженных плагинов.

Из документа плагина:

Например, плагин, определенный как

package main

// // No C code needed.
import "C"

import "fmt"

var V int

func F() { fmt.Printf("Hello, number %d\n", V) }

может быть загружен функцией Open, а затем доступны экспортированные символы V и F пакета экспорта

p, err := plugin.Open("plugin_name.so")
if err != nil {
    panic(err)
}
v, err := p.Lookup("V")
if err != nil {
    panic(err)
}
f, err := p.Lookup("F")
if err != nil {
    panic(err)
}
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
type Symbol interface{}

Ответ 3

Ну, есть dlopen-package для Go - так, по крайней мере, вы можете загрузить свою общую библиотеку (DLL) в свою Go-program now... Вам, вероятно, придется кодировать расширение в C, С++ или что-то еще, для чего у вас есть инструменты, способные генерировать разделяемые библиотеки.