无法使用cgo编译。

huangapple go评论82阅读模式
英文:

Not able to compile with cgo

问题

你正在使用的Go版本是什么(go version)?

$ go version
go version go1.20.2 linux/amd64

项目结构:

目录结构 --
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文件放在同一个目录中。但我不确定是否可以实现这一点,或者我是否做错了什么。

  • 如果我将所有文件放在同一个目录example中,则编译成功。
  • 如果我将lib.clib.h放在子目录中,则编译失败。
  • 如果我从main.go中删除一个函数f32_123,则编译也会成功,这非常奇怪,这就是我打开这个错误的原因,希望能更好地理解为什么当lib.hlib.c在子目录中时,编译没有问题。
英文:

What version of Go are you using (go version)?

$ go version
go version go1.20.2 linux/amd64

Project structure:

Directory structure --
example --&gt; main.go
        --&gt;lib
            lib.c
            lib.h

main.go

package main

// #include &quot;lib/lib.h&quot;
// #include &lt;stdio.h&gt;
// #include &lt;stdlib.h&gt;
import &quot;C&quot;
import (
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

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

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

lib/lib.c

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

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

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

lib/lib.h

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

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

Error while compiling

/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&#39;: /tmp/go-build/cgo-gcc-prolog:49: undefined reference to f32_123&#39;
collect2: error: ld returned 1 exit status

I am expecting the code to compile successfully, but somehow it is not. If I've read the documentation correctly, then I have to keep lib.c and lib.h in the same directory with the main.go file. But I am not sure if this can be achieved or I am doing something wrong.

  • If I keep all the files into same directory example then compile is successful.

  • If I keep lib.c and lib.h into subdir then compile fails

  • If I remove one function f32_123 from main.go then also compile is successful and that is pretty strange and that is the reason opening this bug to get more understanding why compile has not issue with printc function when lib.h and lib.c is in subdir.

答案1

得分: 0

首先,@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)
}
英文:

First, @JimB gave this accepted answer a while back: https://stackoverflow.com/a/28881331/5739452 which says that building an object or library in a sub directory isn't something go build can just do.

Given that, let's say you have this structure:

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

Here are some simpler files to keep things clear:

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

So, you can get this to build all from go build main.go if you have a main.go like this:

package main

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

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

which works because we actually #include the "C" source code for the library (which implicitly imports the lib/lib.h file).

However, for more complicated libraries, you will likely need to build them as a separate, more normal C tool chain, pre-work build step:

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

and then use a different Go file: main2.go:

package main

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

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

huangapple
  • 本文由 发表于 2023年3月26日 20:29:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75847750.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定