문제

새로운 가다 언어, C ++ 코드를 어떻게 호출합니까? 다시 말해, C ++ 클래스를 어떻게 포장하고 이동할 수 있습니까?

도움이 되었습니까?

해결책

업데이트: 작은 테스트 C ++ 클래스를 GO와 연결하는 데 성공했습니다.

C 인터페이스로 C ++ 코드를 래핑하면 CGO로 라이브러리를 호출 할 수 있어야합니다 (GMP의 예 참조를 참조하십시오. $GOROOT/misc/cgo/gmp).

C ++ 클래스의 아이디어가 상속이 없기 때문에 실제로 표현할 수 있는지 확실하지 않습니다.

예는 다음과 같습니다.

C ++ 클래스가 다음과 같이 정의되어 있습니다.

// foo.hpp
class cxxFoo {
public:
  int a;
  cxxFoo(int _a):a(_a){};
  ~cxxFoo(){};
  void Bar();
};

// foo.cpp
#include <iostream>
#include "foo.hpp"
void
cxxFoo::Bar(void){
  std::cout<<this->a<<std::endl;
}

이동 중에 사용하고 싶습니다. C 인터페이스를 사용하겠습니다

// foo.h
#ifdef __cplusplus
extern "C" {
#endif
  typedef void* Foo;
  Foo FooInit(void);
  void FooFree(Foo);
  void FooBar(Foo);
#ifdef __cplusplus
}
#endif

(나는 a를 사용한다 void* C 구조 대신 컴파일러가 FOO의 크기를 알고 있습니다)

구현은 다음과 같습니다.

//cfoo.cpp
#include "foo.hpp"
#include "foo.h"
Foo FooInit()
{
  cxxFoo * ret = new cxxFoo(1);
  return (void*)ret;
}
void FooFree(Foo f)
{
  cxxFoo * foo = (cxxFoo*)f;
  delete foo;
}
void FooBar(Foo f)
{
  cxxFoo * foo = (cxxFoo*)f;
  foo->Bar();
}

모든 작업을 수행하면 GO 파일은 다음과 같습니다.

// foo.go
package foo
// #include "foo.h"
import "C"
import "unsafe"
type GoFoo struct {
     foo C.Foo;
}
func New()(GoFoo){
     var ret GoFoo;
     ret.foo = C.FooInit();
     return ret;
}
func (f GoFoo)Free(){
     C.FooFree(unsafe.Pointer(f.foo));
}
func (f GoFoo)Bar(){
     C.FooBar(unsafe.Pointer(f.foo));
}

내가 컴파일하는 데 사용한 makefile은 다음과 같습니다.

// makefile
TARG=foo
CGOFILES=foo.go
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
foo.o:foo.cpp
    g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<
cfoo.o:cfoo.cpp
    g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<
CGO_LDFLAGS+=-lstdc++
$(elem)_foo.so: foo.cgo4.o foo.o cfoo.o
    gcc $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS)) -o $@ $^ $(CGO_LDFLAGS)

다음과 같이 테스트 해보십시오.

// foo_test.go
package foo
import "testing"
func TestFoo(t *testing.T){
    foo := New();
    foo.Bar();
    foo.Free();
}

Make Install을 사용하여 공유 라이브러리를 설치 한 다음 Make Test를 실행해야합니다. 예상 출력은 다음과 같습니다.

gotest
rm -f _test/foo.a _gotest_.6
6g -o _gotest_.6 foo.cgo1.go foo.cgo2.go foo_test.go
rm -f _test/foo.a
gopack grc _test/foo.a _gotest_.6  foo.cgo3.6
1
PASS

다른 팁

현재 SWIG가이를위한 최상의 솔루션 인 것 같습니다.

http://www.swig.org/doc2.0/go.html

상속을 지원하고 GO Struct를 사용하여 서브 클래스 C ++ 클래스를 허용하므로 재정의 메소드가 C ++ 코드로 호출되면 GO 코드가 발사됩니다.

Go FAQ의 C ++ 섹션 업데이트되고 이제 Swig를 언급하고 더 이상 말하지 않습니다. "Go는 쓰레기 수집 되었기 때문에 적어도 순진하게 그렇게하는 것은 현명하지 않을 것입니다.".

당신은 내가 읽은 내용에서 아직 볼 수 없습니다 FAQ에서:

GO 프로그램이 C/C ++ 프로그램과 연결됩니까?

GC (6G 프로그램 및 친구)와 GCCGO라는 두 가지 GO 컴파일러 구현이 있습니다. GC는 다른 통화 규칙과 링커를 사용하므로 동일한 컨벤션을 사용하여 C 프로그램과 만 연결될 수 있습니다. 이러한 C 컴파일러는 있지만 C ++ 컴파일러는 없습니다. GCCGO는 GCC 컴파일 C 또는 C ++ 프로그램과 연결될 수있는 GCC 프론트 엔드입니다.

CGO 프로그램은 GO 코드에서 C 라이브러리를 안전하게 호출 할 수 있도록 "외부 기능 인터페이스"의 메커니즘을 제공합니다. SWIG는이 기능을 C ++ 라이브러리로 확장합니다.

GO1.2+기준으로 CGO는 C ++ 코드를 자동으로 통합하고 컴파일합니다.

http://golang.org/doc/go1.2#cgo_and_cpp

Golang에 대한 초기 질문 중 하나 인 것 같습니다. 그리고 동시에 업데이트되지 않는 답변. 이 3-4 년 동안 너무 많은 새로운 라이브러리와 블로그 게시물이 나왔습니다. 다음은 내가 유용하다고 느꼈던 몇 가지 링크입니다.

Swig와가

SWIG와 함께 GO에서 C ++ 코드를 호출합니다

언어를 비교할 때 C ++ 및 Go

Goforcppprogrammers

나는 다음 예를 기반으로 한 예를 만들었습니다 Scott Wales의 답변. MacOS High Sierra 10.13.3에서 테스트했습니다 go 버전 go1.10 darwin/amd64.

(1) 코드 library.hpp, 우리가 호출하려는 C ++ API.

#pragma once
class Foo {
 public:
  Foo(int value);
  ~Foo();
  int value() const;    
 private:
  int m_value;
};

(2) 코드 library.cpp, C ++ 구현.

#include "library.hpp"
#include <iostream>

Foo::Foo(int value) : m_value(value) {
  std::cout << "[c++] Foo::Foo(" << m_value << ")" << std::endl;
}

Foo::~Foo() { std::cout << "[c++] Foo::~Foo(" << m_value << ")" << std::endl; }

int Foo::value() const {
  std::cout << "[c++] Foo::value() is " << m_value << std::endl;
  return m_value;
}

(3) 코드 library-bridge.h 다리는 노출해야했습니다 C API가 구현되었습니다 C++ ~하도록 하다 go 그것을 사용할 수 있습니다.

#pragma once
#ifdef __cplusplus
extern "C" {
#endif

void* LIB_NewFoo(int value);
void LIB_DestroyFoo(void* foo);
int LIB_FooValue(void* foo);

#ifdef __cplusplus
}  // extern "C"
#endif

(4) 코드 library-bridge.cpp, 다리의 구현.

#include <iostream>

#include "library-bridge.h"
#include "library.hpp"

void* LIB_NewFoo(int value) {
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ")" << std::endl;
  auto foo = new Foo(value);
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ") will return pointer "
            << foo << std::endl;
  return foo;
}

// Utility function local to the bridge's implementation
Foo* AsFoo(void* foo) { return reinterpret_cast<Foo*>(foo); }

void LIB_DestroyFoo(void* foo) {
  std::cout << "[c++ bridge] LIB_DestroyFoo(" << foo << ")" << std::endl;
  AsFoo(foo)->~Foo();
}

int LIB_FooValue(void* foo) {
  std::cout << "[c++ bridge] LIB_FooValue(" << foo << ")" << std::endl;
  return AsFoo(foo)->value();
}

(5) 마지막으로, library.go, C ++ API를 호출하는 GO 프로그램.

package main

// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"
import "unsafe"
import "fmt"

type Foo struct {
    ptr unsafe.Pointer
}

func NewFoo(value int) Foo {
    var foo Foo
    foo.ptr = C.LIB_NewFoo(C.int(value))
    return foo
}

func (foo Foo) Free() {
    C.LIB_DestroyFoo(foo.ptr)
}

func (foo Foo) value() int {
    return int(C.LIB_FooValue(foo.ptr))
}

func main() {
    foo := NewFoo(42)
    defer foo.Free() // The Go analog to C++'s RAII
    fmt.Println("[go]", foo.value())
}

다음 makefile을 사용합니다

liblibrary.so: library.cpp library-bridge.cpp
    clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared

다음과 같이 예제 프로그램을 실행할 수 있습니다.

$ make
clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared
$ go run library.go
[c++ bridge] LIB_NewFoo(42)
[c++] Foo::Foo(42)
[c++ bridge] LIB_NewFoo(42) will return pointer 0x42002e0
[c++ bridge] LIB_FooValue(0x42002e0)
[c++] Foo::value() is 42
[go] 42
[c++ bridge] LIB_DestroyFoo(0x42002e0)
[c++] Foo::~Foo(42)

중요한

위의 의견 import "C" 에서 go 프로그램은 선택 사항이 아닙니다. 당신은 그것들을 보여준대로 정확하게 넣어야합니다 cgo 이 경우로드 할 헤더 및 라이브러리를 알고 있습니다.

// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"

전체 예제와 함께 Github Repo 링크.

이야기가 있습니다 C와 GO 간의 상호 운용성 GCC GO 컴파일러를 사용할 때 GCCGO. 그러나 GCCGO를 사용할 때 상호 운용성과 구현 된 기능 세트에 대한 제한 사항이 있습니다 (예 : 제한된 goroutines, 쓰레기 수집 없음).

당신은 여기서 미지의 영토를 걷고 있습니다. 여기 C 코드를 호출하기위한 이동 예일 것입니다. 아마도 당신은 아마도 읽은 후에 그런 일을 할 수 있습니다. C ++ 이름 Mangling 그리고 컨벤션 및 많은 시행 착오.

아직도 시도하고 싶다고 느끼면 행운을 빕니다.

여기서 문제는 준수 구현이 클래스를 컴파일 .CPP 파일에 넣을 필요가 없다는 것입니다. 컴파일러가 클래스의 존재를 최적화 할 수 있다면 프로그램이 동일한 방식으로 동작하는 한 출력 실행 파일에서 생략 할 수 있습니다.

C에는 표준화 된 이진 인터페이스가 있습니다. 따라서 기능이 내보내 었다는 것을 알 수 있습니다. 그러나 C ++는 그 뒤에 그러한 표준이 없습니다.

이 발표가 얼마나 많은 더 넓은 문제가 준설되었는지 재밌습니다. Dan Lyke는 그의 웹 사이트 인 Flutterby에서 개발에 관한 매우 재미 있고 사려 깊은 토론을했습니다. 간호 표준 새로운 언어 (및 기타 파급 효과, 그러나 그것은 독일어 인 언어)를 부트 스트랩하는 방법으로.

추가해야 할 수도 있습니다 -lc++ ~로 LDFlags Golang/CGO가 표준 라이브러리의 필요성을 인식하기 위해.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top