Как связать библиотеки во время выполнения? [Дубликат]

Отсутствует «extern» в объявлениях / определениях переменной const (только для C ++)

Для людей, прибывающих с C, может показаться неожиданным, что в C ++ глобальные переменные const имеют внутренние (или статические) связь. В C это не так, поскольку все глобальные переменные неявно extern (т.е. когда отсутствует ключевое слово static).

Пример:

// file1.cpp
const int test = 5;    // in C++ same as "static const int test = 5"
int test2 = 5;

// file2.cpp
extern const int test;
extern int test2;

void foo()
{
 int x = test;   // linker error in C++ , no error in C
 int y = test2;  // no problem
}

correct would использовать файл заголовка и включить его в file2.cpp и file1.cpp

extern const int test;
extern int test2;

. В качестве альтернативы можно было бы объявить переменную const в файле file1.cpp с явным extern

12
задан Kissaki 9 November 2013 в 15:15
поделиться

5 ответов

Обновление: теперь возможно сделать это в mainline Go, см. Режимы выполнения Go

Из примечаний к выпуску Go 1.5 :

Только для архитектуры amd64 у компилятора есть новая опция -dynlink, которая помогает динамической компоновке, поддерживая ссылки на символы Go, определенные во внешних разделяемых библиотеках.

Старый ответ ( полезное обсуждение других опций ):

В настоящее время невозможно создать динамически связанные библиотеки * в главной строке Go. Об этом говорили некоторые, поэтому вы можете увидеть поддержку в будущем. Тем не менее, существует проект стороннего проекта под названием goandriod , который нуждается в той же функциональности, в которой вы нуждаетесь, поэтому они поддерживают исправления, которые должны позволить вам исправлять официальную базу кода Go, чтобы поддерживать динамическую связанную поддержку, которую вы запрашиваете .

Если вы хотите использовать стандартное время выполнения Go, я бы порекомендовал одно из следующего. Вызовите свою программу Go из своей другой программы и обменивайтесь ею с помощью:

  1. Трубы для связи
  2. Сокет домена UNIX
  3. Монументированный регион общей памяти , То есть создайте файл на / dev / shm и у вас есть обе программы mmap. Перейти к библиотеке mmap: https://github.com/edsrzf/mmap-go

Каждый последовательный вариант потребует больше усилий для настройки, но потенциально более мощным, чем предыдущий.

* Примечание. Это DLL в мире Windows и .so файлы в мире UNIX / Linux.

8
ответ дан Tarion 25 August 2018 в 16:00
поделиться

Возможность создания разделяемых библиотек будет в Go 1.5 в августе 2015 года.

От « Состояние Go » говорит Andrew Gerrand:

Общие библиотеки

Go 1.5 может создавать общие библиотеки, которые могут быть использованы программами Go.

Построить стандартную библиотеку в качестве общих библиотек:

$ go install -buildmode=shared std

Создайте программу «Hello, world», которая связывается с разделяемыми библиотеками:

$ go build -linkshared hello.go
$ ls -l hello
-rwxr-xr-x 1 adg adg 13926 May 26 02:13 hello

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

[см.]: golang.org/s/execmodes

¹ Примечание, gccgo уже в течение некоторого времени поддерживала ограниченную поддержку, Go 1.5 будет в первый раз поддерживаться обычными инструментами сборки go.

20
ответ дан Dave C 25 August 2018 в 16:00
поделиться
-1
ответ дан snuk182 25 August 2018 в 16:00
поделиться

Это очень возможно, вы даже можете скомпилировать его как собственную общую библиотеку

go build -buildmode=c-shared goc.go 

# file goc
goc: ELF 32-bit LSB  shared object, ARM, EABI5 version 1 (SYSV),
dynamically linked, 
BuildID[sha1]=f841e63ee8e916d7848ac8ee50d9980642b3ad86, 
not stripped

nm -D --defined-only ./goc | grep "T"

0004ebe8 T _cgoexp_f88ec80374ab_PrintInt
000a6178 T _cgo_panic
0004e954 T _cgo_sys_thread_start
000a48c8 T _cgo_topofstack
0004e88c T _cgo_wait_runtime_init_done
000a61a4 T crosscall2
0004ebc8 T crosscall_arm1
0004e7b0 T fatalf
00102648 T _fini
0004e544 T _init
0004e76c T PrintInt
0004ebe4 T __stack_chk_fail_local
0004eb5c T x_cgo_free
0004ea60 T x_cgo_init
0004eb24 T x_cgo_malloc
0004e8e0 T x_cgo_notify_runtime_init_done
0004eb14 T x_cgo_setenv
0004e820 T x_cgo_sys_thread_create
0004eb64 T x_cgo_thread_start
0004eb20 T x_cgo_unsetenv

, подобный так (проверено на go 1.5.1 linux / arm)

goc.go:

package main

import (
    "C"
    "fmt"
)

//export PrintInt
func PrintInt(x int) {
    fmt.Println(x)
}

// http://stackoverflow.com/questions/32215509/using-go-code-in-an-existing-c-project
// go build -buildmode=c-archive goc.go
// go build -buildmode=c-shared goc.go 

// https://groups.google.com/forum/#!topic/golang-nuts/1oELh6joLQg
// Trying it on windows/amd64, looks like it isn't supported yet.  Is this planned for the 1.5 release? 
// It will not be in the 1.5 release.
// It would be nice if somebody worked on it for 1.6.
// https://golang.org/s/execmodes

// http://stackoverflow.com/questions/19431296/building-and-linking-dynamically-from-a-go-binary
// go build -linkshared hello.g
// go install -buildmode=shared std



func main() {
    fmt.Println("Hello world")
}
2
ответ дан Stefan Steiger 25 August 2018 в 16:00
поделиться

Я думаю, что go плагины могут быть также связаны с этим вопросом, они поддерживаются с версии 1.8. Это позволяет вам динамически связывать исполняемые файлы, реализующие требуемые интерфейсы во время выполнения.

Например, ваш код имеет зависимость для бэкэнда ведения журнала, но вы хотите поддержать несколько из них и разрешить его во время выполнения elasticsearch и splunk. Возможно, вам необходимо иметь 2 файла: es.go и splunk.go, которые должны содержать структуру типа LoggingBackend, реализующую метод Write(log string).

Для создания плагинов вам необходимо использовать buildmode plugin во время компиляции:

go build -buildmode = plugin -o es.so es.go

go build -buildmode = plugin -o splunk.so splunk.go

После этого вы можете передать необходимый плагин через аргументы командной строки и загрузить его:

package main

import "plugin"
import "flag"


type LoggingBackend interface {
    Write(log string)
}
var (
    backend = flag.String("backend", "elasticsearch", "Default logging backend is elasticsearch")
)

func main() {
    flag.Parse()
    var mode string
    switch backend {
    case "elasticsearch":
        mode = "./es.so"
    case "splunk":
        mode = "./splunk.so"
    default:
        fmt.Println("Didn't recognise your backend")
        os.Exit(1)
    plug, _ := plugin.Open(mod)
    loggingBackend, _ := plug.Lookup("LoggingBackend")
    logWriter, _ := loggingBackend.(LoggingBackend)
    logWriter.Write("Hello world")
}
0
ответ дан vvraskin 25 August 2018 в 16:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: