2015-05-06 52 views
4

我有一个完全用C语言编写的程序,它使用多个对象(.o)文件。这些文件全部打包在归档文件(.a)内,而该文件又在程序的主要文件(.c)的编译时使用。在现有C项目中使用Go

我想在Go中为这个项目编写一个新文件。我的想法是写这.go文件,然后从它创建一个对象(.o)文件。之后,我想把这个目标文件放在已经提到的档案(.a)文件中。

这基本上意味着我想从C程序调用Go函数。我读过this question,虽然它告诉我,通过GCCGO我想要的是什么,但如何做到这一点还不是100%清楚。

即使是最基本的测试,我在链接阶段也会遇到错误。更具体地讲,这里的一些基本例子之一:


printString.go

package main 

import 
(
    "fmt" 
) 

func PrintString(buff string) int { 
    fmt.Printf(buff) 
    return 1 
} 

c_caller.c

#define _GNU_SOURCE 
#include <stdio.h> 

extern int PrintString(char*) __asm__ ("print.main.PrintString"); 

int main() { 
    char *string_to_pass= NULL; 
    asprintf(&string_to_pass, "This is a test."); 

    int result= PrintString(string_to_pass); 
    if(result) {printf("Everything went as expected!\n");} 
    else  {printf("Uh oh, something went wrong!\n");} 

    return result; 
} 

编译

为了编译转到文件,我用这个命令:

gccgo -c printString.go -o printString.o -fgo-prefix=print -Wall -Werror -march=native 

为了编译整个事情,我用这个命令:

gccgo -o main c_caller.c printString.o -Wall -Werror -march=native 

我得到的返回消息:

/usr/lib64/libgo.so.4.0.0: undefined reference to `main.main' 
/usr/lib64/libgo.so.4.0.0: undefined reference to `__go_init_main' 
collect2: error: ld returned 1 exit status 

这意味着GCCGO期待Go文件中的主函数而不是C函数。

使用第二命令--static-libgo-static-Wl,-R,/path/to/libgo.so's_folder选择产生不同的结果:

/usr/bin/ld: cannot find -lgo 
collect2: error: ld returned 1 exit status 

这是没有意义的,因为我有LD_LIBRARY_PATH环境变量正确指向libgo.so的文件夹中。


我意识到我可能在这里做错了什么,但我不知道那是什么。没有GCCGO的例子和它与C的交互的例子,我能找到的唯一参考是this page,我个人觉得这是不够的。

我对此事提出了一些建议,并感谢您的时间。 :)

回答

8

这可能不是你想要的,但是在Go 1.5,即将在今年八月发布,你将能够使用go工具构建C兼容库。所以用这个你_main.c

#include <stdio.h> 

int main() 
{ 
    char *string_to_pass = NULL; 
    if (asprintf(&string_to_pass, "This is a test.") < 0) { 
     printf("asprintf fail"); 
     return -1; 
    } 

    PrintString(string_to_pass); 
    return 0; 
} 

,这在您的main.go

package main 

import "C" 
import "fmt" 

//export PrintString 
func PrintString(cs *C.char) { 
    s := C.GoString(cs) 
    fmt.Println(s) 
} 

func main() {} 

你可以这样做,对静态库:

go build -buildmode c-archive -o mygopkg.a 
gcc -o main _main.c mygopkg.a -lpthread 

对于共享库:

go build -buildmode c-shared -o mygopkg.so 
LD_RUN_PATH=$(pwd) gcc -o main _main.c mygopkg.so -lpthread 

LD_RUN_PATH用于使链接程序查找您正在构建的同一目录中的共享库。)

有关更多信息,请参阅Go execution modes design document

+1

耻辱现在不会使用它,但很高兴知道该选项将在不久的将来。感谢您的详细解答! –

2

目前没有支持的方式来做你想做的。 Go始终需要其运行时支持,并且入口点始终为main。AFAIK,gccgo也做出了这些相同的假设,并没有提供轻松链接到其他程序的方法。

如果您希望以受支持的方式执行此操作,您必须等到go1.5 +才能完成从Go代码编译共享库的工作。

如果你现在真的想破解这个,你可以使用缺省的gc工具链,-linkmode external来重新编译目标文件中的main,并在外部调用它。

+0

感谢您的回答。虽然Android的东西听起来像是一个体面的方式来解决这个问题,等待版本1.5听起来像“要走的路”。 –