无法用cgo编译

bfnvny8b  于 2023-04-11  发布在  Go
关注(0)|答案(1)|浏览(150)

你使用的是什么版本的Go(Go版本)?

$ go version
go version go1.20.2 linux/amd64

项目结构:

Directory structure --
example --> main.go
        -->lib
            lib.c
            lib.h

main.go

package main

// #include "lib/lib.h"
// #include <stdio.h>
// #include <stdlib.h>
import "C"
import (
    "fmt"
    "unsafe"
)

func main() {
    cstrin := C.CString("welcome")
    s1 := C.struct_s1{b: cstrin, a: 100}

    C.f32_123(&s1)
    cs := C.GoString(s1.b)
    fmt.Println(cs)
    fmt.Println(s1)
    C.free(unsafe.Pointer(cstrin))
}

lib/lib.c

#include <stdlib.h>
#include <stdio.h>

void printc(char *str, int *t)
{
     str = "Test";
     printf("%d\n", *t);
     *t = 30;
     printf("%s\n", str);
}

void f32_123(struct s1 *s)
{
     printf("%s\n", s->b);
     s->a = 10;
     s->b = "Hello123";
     printf("%d\n", s->a);
     printf("%s\n", s->b);
}

lib/lib.h

struct s1 {
    int a;
    char *b;
};

void printc(char *str, int *t);
void f32_123(struct s1 *s);

编译时出错

/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-3024881602/000001.o: in function _cgo_cf24297edd23_Cfunc_f32_123': /tmp/go-build/cgo-gcc-prolog:49: undefined reference to f32_123'
collect2: error: ld returned 1 exit status

我希望代码能够成功编译,但不知何故却没有。如果我正确阅读了文档,那么我必须将lib.clib.hmain.go文件保存在同一个目录中。但我不确定是否可以实现这一点,或者我做错了什么。

  • 如果我把所有的文件都放在同一个目录下,那么编译就成功了。
  • 如果我将lib.clib.h保存在子目录中,则编译失败
  • 如果我从main.go中删除一个函数f32_123,那么编译也会成功,这很奇怪,这就是打开这个bug的原因,以便更多地了解为什么当lib.hlib.c在subdir中时,编译不会出现printc函数的问题。
k3bvogb1

k3bvogb11#

首先,@JimB给出了这个公认的答案:https://stackoverflow.com/a/28881331/5739452表示在子目录中构建对象或库不是go build可以做的事情。
假设你有这样的结构:

lib/
lib/lib.c
lib/lib.h
main.go

以下是一些简单的文件,以保持清晰:

/* lib/lib.h */
struct foo {
    int x;
};
void show(struct foo *arg);
/* lib/lib.c */
#include <stdio.h>
#include "lib.h"
void show(struct foo *arg) {
    printf("[%d]\n", arg->x);
}

所以,如果你有一个像这样的main.go,你可以从go build main.go构建所有的东西:

package main

// #cgo CFLAGS: -I${SRCDIR}/lib
// #include "lib.c"
import "C"

func main() {
    x := C.struct_foo{ x: 42 }
    C.show(&x)
}

这是可行的,因为我们实际上#include库的“C”源代码(它隐式地导入lib/lib.h文件)。
但是,对于更复杂的库,您可能需要将其构建为一个单独的,更正常的C工具链,预工作构建步骤:

$ cd lib
$ cc -c lib.c
$ ar cr libx.a lib.o
$ cd ..

然后使用另一个Go文件:main2.go

package main

// #cgo CFLAGS: -I${SRCDIR}/lib
// #cgo LDFLAGS: -L${SRCDIR}/lib -lx
// #include "lib.h"
import "C"

func main() {
    x := C.struct_foo{ x: 42 }
    C.show(&x)
}

相关问题