Ошибка связывания CGO: неопределенная ссылка на MemoryFreeLibrary
Я пытаюсь обернуть библиотеку C с помощью Go. Библиотека построена с использованием CMake и создает статический файл библиотеки. Я добавил #cgo
вещи в начале .go
файл с правильным CFLAGS
а также LDFLAGS
Тем не менее, я продолжаю получать undefined reference
ошибки при запуске go build memorymodule.go
,
Вот мой код:
package main
/*
#cgo CFLAGS: -IMemoryModule
#cgo LDFLAGS: MemoryModule/build/MemoryModule.a
#include "MemoryModule/MemoryModule.h"
*/
import "C"
import (
"fmt"
"io/ioutil"
"os"
"unsafe"
)
const SIZE int = 1024
func end(msg string) {
fmt.Println(msg)
os.Exit(1)
}
func check(err error, msg string) {
if err != nil {
end(msg)
}
}
func main() {
bin, err := ioutil.ReadFile(os.Args[0])
check(err, "error reading file")
// Convert the args passed to this program into a C array of C strings
var cArgs []*C.char
for _, goString := range os.Args {
cArgs = append(cArgs, C.CString(goString))
}
// Load the reconstructed binary from memory
handle := C.MemoryLoadLibraryEx(
unsafe.Pointer(&bin[0]), // void *data
(C.size_t)(len(bin)), // size_t
(*[0]byte)(C.MemoryDefaultAlloc), // Alloc func ptr
(*[0]byte)(C.MemoryDefaultFree), // Free func ptr
(*[0]byte)(C.MemoryDefaultLoadLibrary), // loadLibrary func ptr
(*[0]byte)(C.MemoryDefaultGetProcAddress), // getProcAddress func ptr
(*[0]byte)(C.MemoryDefaultFreeLibrary), // freeLibrary func ptr
unsafe.Pointer(&cArgs[0]), // void *userdata
)
// Execute binary
C.MemoryCallEntryPoint(handle)
// Cleanup
C.MemoryFreeLibrary(handle)
}
Вот результаты из go build ...
с -x
чтобы помочь с отладкой:
cd /home/wlaw/go-memory-module
i686-w64-mingw32-gcc -I . -m32 -mthreads -fmessage-length=0 -fdebug-prefix-map=$WORK=/tmp/go-build -gno-record-gcc-switches -o $WORK/command-line-arguments/_obj/_cgo_.o $WORK/command-line-arguments/_obj/_cgo_main.o $WORK/command-line-arguments/_obj/_cgo_export.o $WORK/command-line-arguments/_obj/memorymodule.cgo2.o -g -O2 MemoryModule/build/MemoryModule.a
# command-line-arguments
/tmp/go-build590803163/command-line-arguments/_obj/_cgo_main.o:_cgo_main.c:(.data+0x0): undefined reference to `MemoryDefaultLoadLibrary'
/tmp/go-build590803163/command-line-arguments/_obj/_cgo_main.o:_cgo_main.c:(.data+0x4): undefined reference to `MemoryDefaultGetProcAddress'
/tmp/go-build590803163/command-line-arguments/_obj/_cgo_main.o:_cgo_main.c:(.data+0x8): undefined reference to `MemoryDefaultFreeLibrary'
/tmp/go-build590803163/command-line-arguments/_obj/_cgo_main.o:_cgo_main.c:(.data+0xc): undefined reference to `MemoryDefaultFree'
/tmp/go-build590803163/command-line-arguments/_obj/_cgo_main.o:_cgo_main.c:(.data+0x10): undefined reference to `MemoryDefaultAlloc'
/tmp/go-build590803163/command-line-arguments/_obj/memorymodule.cgo2.o: In function `cgo_50ced23471ff_Cfunc_MemoryCallEntryPoint':
/tmp/go-build/command-line-arguments/_obj/cgo-gcc-prolog:40: undefined reference to `MemoryCallEntryPoint'
/tmp/go-build590803163/command-line-arguments/_obj/memorymodule.cgo2.o: In function `cgo_50ced23471ff_Cfunc_MemoryLoadLibraryEx':
/tmp/go-build/command-line-arguments/_obj/cgo-gcc-prolog:76: undefined reference to `MemoryLoadLibraryEx'
/tmp/go-build590803163/command-line-arguments/_obj/memorymodule.cgo2.o: In function `cgo_50ced23471ff_Cfunc_MemoryFreeLibrary':
/tmp/go-build/command-line-arguments/_obj/cgo-gcc-prolog:54: undefined reference to `MemoryFreeLibrary'
collect2: error: ld returned 1 exit status
Makefile:9: recipe for target 'all' failed
make: *** [all] Error 2
Что интересно, если я скомпилирую зависимость MemoryModule, используя make вместо CMake (путем редактирования моего Makefile), так что он создает объектный файл вместо статического библиотечного файла, и вместо этого изменю свой исходный код для связи с этим, у меня не возникает проблем:
package main
/*
#cgo CFLAGS: -IMemoryModule
#cgo LDFLAGS: MemoryModule/MemoryModule.o
#include "MemoryModule/MemoryModule.h"
*/
import "C"
...
Мой Makefile для справки:
ifneq ("$(shell which i686-w64-mingw32-gcc)","")
compiler = i686-w64-mingw32-gcc
else
compiler = i586-mingw32msvc-gcc
endif
# Build the dependencies first (subdirs), then move onto the meat and potatoes.
all: MemoryModule
CC=$(compiler) CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -x memorymodule.go
# Dependency build.
SUBDIRS = MemoryModule
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
# Override default subdir build behavior (make) with cmake.
MemoryModule:
[ "`ls -A MemoryModule`" ] || git submodule update --init
# $(MAKE) -C $@
cmake -HMemoryModule -BMemoryModule/build
cmake --build MemoryModule/build --target MemoryModule
# Clean targed.
CLEANDIRS = $(SUBDIRS:%=clean-%)
clean: $(CLEANDIRS)
rm -f memorymodule.exe
$(CLEANDIRS):
$(MAKE) -C $(@:clean-%=%) clean
test:
$(MAKE) -C tests test
.PHONY: subdirs $(INSTALLDIRS) $(SUBDIRS) clean test
Любая помощь будет оценена!
Git проекта здесь: https://github.com/wheelerlaw/go-memory-module
Обновить:
Хорошо, я наткнулся на этот ТАК вопрос. Так что если я поменяю go build
команда для:
GOOS="windows" GOARCH="amd64" CGO_ENABLED="1" CC="x86_64-w64-mingw32-gcc" go build -x
от:
GOOS="windows" GOARCH="386" CGO_ENABLED="1" CC="i686-w64-mingw32-gcc" go build -x
... оно работает. Так что это выглядит как несовместимость между различными арками. Я собираюсь скачать 32-битную версию Go, чтобы посмотреть, поможет ли это.
Но чего я не понимаю, так это того, что программа прекрасно компилируется даже с несовпадающими арками, когда я собираю библиотеку C в объект вместо статической библиотеки. Есть идеи?