[Go] CGO FFI: C 코드 내보내기

관련 포스트
https://blog.naver.com/sssang97?Redirect=Log&logNo=222901300093&from=postView

Go 프로그램을 C/C++에서 사용할 수 있도록 export하는 방법에 대해서 간단히 정리해보겠다.




Go 프로젝트 구성

우선 디렉터리 파고, mod를 초기화해준다.

그다음에 메인 패키지에 소스코드를 때려박는다.

package main

import "C"

import (
	"fmt"
	"strconv"
)

//export Add
func Add(a int, b int) int { return a + b }

//export Sub
func Sub(a int, b int) int { return a - b }

//export Mul
func Mul(a int, b int) int { return a * b }

//export Div
func Div(a int, b int) int { return a / b }

//export PrintToConsole
func PrintToConsole(msg string) {
	fmt.Println(msg)
}

func main() {
	result := Sub(Add(1, 2), 10)
	PrintToConsole(strconv.Itoa(result))
}

소스코드가 통짜인 것은 이유가 있다.
원래는 나도 저 함수 구현들을 서브패키지로 빼려고 했는데, 그러면 그걸 export할 수가 없다.
cgo는 main 패키지에서만 export를 할 줄 알고, go에는 import를 다시 export를 하는 기능이 없기 때문이다.
환장할 노릇이다.

아무튼 하나씩 짚어보자.
일단 main 패키지여야 하고, C 모듈을 포함시켜야 한다.

그래야먄 헤더파일을 생성해준다.

그리고 내보낼 함수들을 정의해준다.

당연히 대문자로 시작해야 하고, 주석으로 export될 함수임을 명시해줘야 한다.

그래서 일단

실행은 된다.




C로 내보내기

도는건 확인했으니 C 포맷으로 export를 해보자.
다음 처럼 옵션을 줘서 컴파일을 하면 된다.

go build -o libgoffi.so -buildmode=c-shared go/main.go // Linux

그럼 외부에서 갖다쓸 수 있는 공유 라이브러리(.so)와 헤더파일을 던져줄 것이다.
이걸 주워가서 쓰면 된다.

다만 문제는... dll로 내보내는 기능이 없다는 것이다.
그래서 windows에서는 활용하기 어렵다.




C에서 연동해보기

제대로 만들어진 것이 맞는지 C 코드와 함께 컴파일을 해보자.

#include <stdio.h> 
#include "./libgoffi.h"

int main() {
    int foo = Sub(10, 20);
    printf("foo %d", foo);

    char text[] = "Hello!!";

    GoString gostring = {
        p: text,
        n: sizeof(text)
    };

    PrintToConsole(gostring);
}

계산하고 출력해주는 단순한 코드다.
다만 문자열 처리가 좀 번거로운 것이 흠이다.

저걸 컴파일해서 실행해보자.
gcc를 썼다.

gcc -c main.c
gcc main.o -L. -l goffi
export LD_LIBRARY_PATH=. # LD_LIBRARY_PATH에 현재 경로가 없다면 설정
./a.out

그럼 이렇게 실행이 될 것이다.

뭔가 나중에 나와야 할 Hello 출력이 먼저 나와서 이상해보이는데, 그건 C의 표준 출력과 Go의 표준 출력을 동기화하지 않아서 그럴 것이다.



참조
https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf
https://stackoverflow.com/questions/58433624/cgo-doesnt-export-functions-in-imported-packages