cgo вызов разделяемой библиотеки: не удается найти lib или функцию? - PullRequest
0 голосов
/ 19 января 2020

Я использую пример кода главы 13 из Язык программирования Go , как показано ниже:

$ cat bzip2.c
#include <bzlib.h>

int bz2compress(bz_stream *s, int action,
                char *in, unsigned *inlen, char *out, unsigned *outlen) {
    s->next_in = in;
    s->avail_in = *inlen;
    s->next_out = out;
    s->avail_out = *outlen;
    int r = BZ2_bzCompress(s, action);
    *inlen -= s->avail_in;
    *outlen -= s->avail_out;
    s->next_in = s->next_out = NULL;
    return r;
}

$ cat usebzip2.go
// Package bzip provides a writer that uses bzip2 compression (bzip.org).
package main
import "C"

import (
    "io"
    "log"
    "os"
    "testing"
    "unsafe"
)

type writer struct {
    w      io.Writer // underlying output stream
    stream *C.bz_stream
    outbuf [64 * 1024]byte
}

// Close flushes the compressed data and closes the stream.
// It does not close the underlying io.Writer.
func (w *writer) Close() error {
    if w.stream == nil {
        panic("closed")
    }
    defer func() {
        C.BZ2_bzCompressEnd(w.stream)
        C.bz2free(w.stream)
        w.stream = nil
    }()
    for {
        inlen, outlen := C.uint(0), C.uint(cap(w.outbuf))
        r := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,
            (*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
        if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
            return err
        }
        if r == C.BZ_STREAM_END {
            return nil
        }
    }
}

// NewWriter returns a writer for bzip2-compressed streams.
func NewWriter(out io.Writer) io.WriteCloser {
    const blockSize = 9
    const verbosity = 0
    const workFactor = 30
    w := &writer{w: out, stream: C.bz2alloc()}
    C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
    return w
}

func main() {
    w := NewWriter(os.Stdout)
    if _, err := io.Copy(w, os.Stdin); err != nil {
        log.Fatalf("bzipper: %v\n", err)
    }
    if err := w.Close(); err != nil {
        log.Fatalf("bzipper: close: %v\n", err)
    }
}

Сначала я скомпилирую файл. c:

gcc -I/usr/include -L/usr/lib -lbz2 --shared bzip2.c -fPIC -o libbzip2.so

Среда linux LD_LIBRARY_PATH содержит ".", А затем сборка go завершается неудачно:

go build usebzip2.go
# command-line-arguments
/tmp/go-build677611698/b001/_x002.o: In function `_cgo_22d5d7fabfe4_Cfunc_bz2compress':
/tmp/go-build/cgo-gcc-prolog:118: undefined reference to `bz2compress'
collect2: error: ld returned 1 exit status

Так как это исправить? Я использую Ubuntu 18.04 LTS. Большое спасибо.

1 Ответ

1 голос
/ 19 января 2020

Не запускайте:

go build usebzip2.go

, а скорее:

go build

(и вам не нужно вызывать gcc непосредственно для bzip2.c). При использовании этого процесса вы получите гораздо больше (но разных) ошибок, потому что вы не указали правильные директивы перед строкой:

import "C"

. Вам нужен комментарий (или серия комментариев), рассказывающий cgo о функциях, которые вы намереваетесь предоставить, или о предоставлении этих функций встроенным, и указание фазе связи использовать -lbz2. В частности, вам необходимо:

  • #include <bzlib.h>
  • предоставить bz2alloc функцию
  • предоставить bz2free функцию
  • предоставьте объявление для вашей bz2compress функции
  • установите LDFLAGS для включения -lbz2

Фактические bz2alloc и bz2free являются короткими и простыми и поэтому могут быть включенным непосредственно в этот блок заголовка:

package main

/*
#cgo LDFLAGS: -lbz2     
#include <bzlib.h>
#include <stdlib.h>
bz_stream *bz2alloc() { return calloc(1, sizeof(bz_stream)); }
int bz2compress(bz_stream *s, int action,
    char *in, unsigned *intlen, char *out, unsigned *outlen);
void bz2free(bz_stream* s) { free(s); }
*/      
import "C"

Если вы вставите это и запустите go build, вы увидите другую и более полезную ошибку:

./usebzip2.go:60:2: cannot use w (type *writer) as type io.WriteCloser in return argument:
        *writer does not implement io.WriteCloser (missing Write method)

, что, конечно, потому что type writer не реализует Write.

(есть законченная версия упражнения 13.3 - не моя - в https://github.com/torbiak/gopl/tree/master/ex13.3. Обратите внимание, что они дополнили свою, чтобы использовать блокировку как хорошо, делая безопасным одновременный вызов функции записи из нескольких программ.)

...