Golang在Mac OS上使用CGO编译时出现x86_64架构的未定义符号问题

Golang在Mac OS上使用CGO编译时出现x86_64架构的未定义符号问题 main.go

package main
/*
#cgo CFLAGS: -g -Wall
#include <stdlib.h>
#include "greeter.h"
*/
import "C"
import (
	"unsafe"
)

func main() {
	name := C.CString("Gopher")
	defer C.free(unsafe.Pointer(name))

	year := C.int(2018)

	C.greet(name, year)
}

greeter.h

#ifndef _GREETER_H
#define _GREETER_H

void greet(const char *name, int year);
#endif

greeter.c

#include "greeter.h"
#include <stdio.h>

void greet(const char *name, int year) {

    printf("Greetings, %s from %d! We come in peace :)", name, year);

}

命令 $ go build -buildmode=c-archive -o greeter.a main.go

//输出

# command-line-arguments
Undefined symbols for architecture x86_64:
  "_greet", referenced from:
      __cgo_4d6b7d3a5d3b_Cfunc_greet in _x002.o
     (maybe you meant: __cgo_4d6b7d3a5d3b_Cfunc_greet)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

你解决过这个问题吗?能给我一些建议吗? 谢谢,


更多关于Golang在Mac OS上使用CGO编译时出现x86_64架构的未定义符号问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复
$ ls
greeter.c  greeter.h  main.go

$ go build -buildmode=c-archive -o greeter.a

$ ls
greeter.a  greeter.c  greeter.h  main.go
$```

更多关于Golang在Mac OS上使用CGO编译时出现x86_64架构的未定义符号问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个问题是由于链接器找不到greet函数的实现导致的。在构建过程中,Go工具链没有将greeter.c文件包含在编译过程中。正确的做法是将C源文件与Go文件一起编译。

以下是修改后的main.go文件,通过#cgo指令指定需要编译的C源文件:

package main
/*
#cgo CFLAGS: -g -Wall
#include <stdlib.h>
#include "greeter.h"
*/
import "C"
import (
	"unsafe"
)

func main() {
	name := C.CString("Gopher")
	defer C.free(unsafe.Pointer(name))

	year := C.int(2018)

	C.greet(name, year)
}

同时,需要修改构建命令,确保C源文件被正确包含。以下是几种解决方案:

方案1:使用cgo指令指定C源文件main.go文件中添加greeter.c的引用:

package main
/*
#cgo CFLAGS: -g -Wall
#include <stdlib.h>
#include "greeter.h"
void greet(const char *name, int year);
*/
import "C"
import (
	"unsafe"
)

func main() {
	name := C.CString("Gopher")
	defer C.free(unsafe.Pointer(name))

	year := C.int(2018)

	C.greet(name, year)
}

方案2:修改构建命令 将C源文件作为参数传递给go build命令:

$ go build -buildmode=c-archive -o greeter.a main.go greeter.c

方案3:创建独立的C共享库 首先编译C代码为动态库:

$ gcc -c -fPIC -o greeter.o greeter.c
$ gcc -shared -o libgreeter.dylib greeter.o

然后在Go文件中指定链接参数:

package main
/*
#cgo CFLAGS: -g -Wall
#cgo LDFLAGS: -L. -lgreeter
#include <stdlib.h>
#include "greeter.h"
*/
import "C"
import (
	"unsafe"
)

func main() {
	name := C.CString("Gopher")
	defer C.free(unsafe.Pointer(name))

	year := C.int(2018)

	C.greet(name, year)
}

构建Go程序:

$ go build -o main main.go

方案4:使用//go:embed指令(Go 1.16+) 如果使用Go 1.16或更高版本,可以嵌入C源文件:

package main
/*
#cgo CFLAGS: -g -Wall
#include <stdlib.h>
#include "greeter.h"
*/
import "C"
import (
	_ "embed"
	"unsafe"
)

//go:embed greeter.c
var greeterSource string

func main() {
	name := C.CString("Gopher")
	defer C.free(unsafe.Pointer(name))

	year := C.int(2018)

	C.greet(name, year)
}

对于你的具体错误,最直接的解决方案是方案2,在构建命令中包含C源文件:

$ go build -buildmode=c-archive -o greeter.a main.go greeter.c

这样Go工具链会将greeter.c文件与Go代码一起编译,确保greet函数的实现被正确链接到最终的静态库中。

回到顶部