Cgo 可以调用在另一个目录中声明的 C 函数吗?

Posted

技术标签:

【中文标题】Cgo 可以调用在另一个目录中声明的 C 函数吗?【英文标题】:Can Cgo call C function declared in another directory? 【发布时间】:2016-06-18 10:10:43 【问题描述】:

似乎我不能使用 Cgo 来调用在另一个目录而不是当前 Go 包中声明的 C 函数。

所有文件的代码:

// TestGoCallOC.go
package main
/*
#include "test.h"
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
*/
import "C"
import (
    "fmt"
)
func main()  
    fmt.Println(C.fortytwo())


// test.h
#include <stdio.h>
#include <stdlib.h>
int fortytwo();

// test.m
#include "test.h"
int fortytwo() 
    return 42;

如果我将所有文件放在一个目录中:

|--src
   |--TestGoCallOC
      |--TestGoCallOC.go
      |--test.h
      |--test.m

运行Go main函数,这两个C函数就可以调用了。

但如果我将 C 文件(实际上它们是 Objective-C 文件)放在另一个目录中:

|--src
   |--TestGoCallOC
      |--TestGoCallOC.go
   |--SomeOCCodes
      |--test.h
      |--test.m

,将序言中#include "test.h"的文件路径改成绝对路径,运行Go main函数,这两个C函数不能调用。

错误信息是

架构 x86_64 的未定义符号: “_fortytwo”,引用自: TestGoCallOC.cgo2.o 中的 __cgo_b3674ecbf56b_Cfunc_fortytwo (也许你的意思是:__cgo_b3674ecbf56b_Cfunc_fortytwo) ld:未找到架构 x86_64 的符号 clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) 退出状态2

我做错了吗?还是Cgo没有这个能力?

【问题讨论】:

【参考方案1】:

根据https://golang.org/cmd/cgo/ 一个包中的所有 cgo CPPFLAGS 和 CFLAGS 指令被连接起来并用于编译该包中的 C 文件。包中的所有 CPPFLAGS 和 CXXFLAGS 指令被连接起来并用于编译该包中的 C++ 文件。程序中任何包中的所有 LDFLAGS 指令都在链接时连接并使用。所有 pkg​​-config 指令都被连接起来并同时发送到 pkg-config 以添加到每个适当的命令行标志集。

Go 包边界是 src 文件夹,因此您可以将所有 c 文件放在同一个文件夹中/或使用 include C 文件(不是 h 文件)解决方法,如下所示:

// main.go
package main

//#include "../ctest/test.c"
import "C"
import "fmt"

func main() 
    r := C.Add(10, 20)
    fmt.Println(r)

和ctest目录中的c文件:

//test.c

int Add(int a, int b)
    return a+b;

这很好用。

【讨论】:

非常感谢。我试过#include "../../test.m" 然后我可以调用这些C 函数。但是为什么#include 标头不起作用? 它是源文件包含:当预处理器找到#include 指令时,它会用指定文件的全部内容替换它。

以上是关于Cgo 可以调用在另一个目录中声明的 C 函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

CGO类型转换

c语言中,在一个自定义函数里面只能调用一个自定义函数吗?可以调用多个吗?如果可以怎么调用?

调用 cgo 宏函数

为啥CGO不能直接在C中调用函数指针?

Javascript的函数定义在一个script标记对中,能不能在另一个script中调用?

CGO内部机制