Ошибка связывания 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 в объект вместо статической библиотеки. Есть идеи?

0 ответов

Другие вопросы по тегам