2015-05-06 139 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聽起來像「要走的路」。 –