গোয়ে সি ++ কীভাবে ব্যবহার করবেন


173

নতুন গো ভাষায় আমি সি ++ কোডটি কীভাবে কল করব? অন্য কথায়, আমি কীভাবে আমার সি ++ ক্লাসগুলি গুটিয়ে রাখতে পারি এবং সেগুলিকে গো-এ ব্যবহার করতে পারি?



1
@ ম্যাট: সম্ভবত তিনি বিদ্যমান সি ++ লাইব্রেরিটি সি বা ਗੋে পোর্ট না করেই ব্যবহার করতে চান। আমি একই জিনিস চেয়েছিলেন।
গ্রীম পেরো

আমি সি ++ এর জন্য উপলব্ধ একটি একক শালীন গ্রন্থাগারটি ভাবতে পারি না এবং সি এর জন্য নয় I'd আপনার মনে কী আছে তা আমি জানতে চাই।
ম্যাট যোগদানকারী

13
@ ম্যাট: একটি উদাহরণ হ'ল বুস্ট লাইব্রেরি, এবং এখানে হাজার হাজার অন্যান্য দরকারী সি ++ গ্রন্থাগার রয়েছে। তবে আমি এখানে কেবল একটি ট্রল খাচ্ছি ...
ফ্রাঙ্ক

@ ম্যাট: আমার ক্ষেত্রে, আমি আমাদের বিদ্যমান ক্লায়েন্ট লাইব্রেরিতে একটি গো ইন্টারফেস তৈরি করতে চেয়েছিলাম তবে লাইব্রেরিটি মূলত সি ++ হয়। এটি সি বা গোতে পোর্ট করা সহজ বিকল্প নয়।
গ্রিমে পেরো

উত্তর:


154

আপডেট: আমি একটি ছোট পরীক্ষার সি ++ শ্রেণিকে গোয়ের সাথে সংযুক্ত করতে সফল হয়েছি

আপনি যদি একটি সি ইন্টারফেসের সাথে আপনার সি ++ কোডটি আবদ্ধ করেন তবে আপনাকে আপনার লাইব্রেরিটি সিজিও দিয়ে কল করতে সক্ষম হতে হবে (জিএমপি-এর উদাহরণ দেখুন $GOROOT/misc/cgo/gmp)।

আমি নিশ্চিত নই যে সি ++ তে কোনও শ্রেণীর ধারণা গোয়ে সত্যই প্রকাশযোগ্য, কারণ এর উত্তরাধিকার নেই।

এখানে একটি উদাহরণ:

আমার একটি সি ++ শ্রেণি সংজ্ঞায়িত হয়েছে:

// 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;
}

যা আমি গোতে ব্যবহার করতে চাই। আমি সি ইন্টারফেস ব্যবহার করব

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

(আমি void*সি স্ট্রাক্টের পরিবর্তে একটি ব্যবহার করি যাতে সংকলক ফু এর আকার জানতে পারে)

বাস্তবায়নটি হ'ল:

//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();
}

যা কিছু হয়েছে তার সাথে, গো ফাইলটি হ'ল:

// 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
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();
}

আপনাকে মেক ইনস্টল সহ ভাগ করা লাইব্রেরি ইনস্টল করতে হবে, তারপরে মেক টেস্ট চালান। প্রত্যাশিত আউটপুট:

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

1
এটির সাথে সাবধানতা অবলম্বন করুন, আপনি যদি দুটি ভাষার মধ্যে এটি পাঠিয়ে দেন তবে মেমরির কী ঘটতে পারে সে সম্পর্কে আমার কোনও ধারণা নেই।
স্কট ওয়েলস

11
আমি বলতে চাই, এই উদাহরণটি মনে করিয়ে দেয় কেন আমি খাঁটি গো লিখতে চাই। সি ++ পার্শ্বটি কত বড় এবং কুরুচিপূর্ণ দেখুন। Ick।
জেফ অ্যালেন

@ স্কটওয়্যালস কোনও মন্তব্য আপনি গিথুব বা অন্য কোনও কিছুর উপরে রেপোতে রেখেছেন? আমি একটি কাজের উদাহরণ দেখতে চাই
নেটপোটিটিকা

7
@ আর্ন: আপনি কোনও উত্তরকে হ্রাস করবেন না কারণ এটি সেরা নয়। আপনি একটি উত্তরকে নিম্নোক্ত করেছেন কারণ এটি সহায়ক নয়। যতক্ষণ এটি কাজ করে, আরও ভাল সমাধান থাকলেও এই উত্তরটি এখনও সহায়ক।
গ্রিম পেরো

সুসংবাদ, গো এখন সিপিসি সংকলন করবে তাই মেকফিলটি আর প্রয়োজন হয় না। অনিরাপদ.পয়েন্টার মোড়ক আমার পক্ষে কাজ করে নি। আমার জন্য একটি সামান্য পরিবর্তন সংকলিত: play.golang.org/p/hKuKV51cRp মেকফাইল go test ছাড়াই কাজ করা উচিত
ড্রিউ

47

দেখে মনে হচ্ছে যে বর্তমানে এসডব্লিউআইজি এর পক্ষে সেরা সমাধান:

http://www.swig.org/Doc2.0/Go.html

এটি উত্তরাধিকারকে সমর্থন করে এবং এমনকি গো স্ট্রাক্টের সাথে সি ++ শ্রেণিকে সাবক্লাস করার অনুমতি দেয় তাই যখন সি ++ কোডে ওভাররাইড পদ্ধতিগুলি বলা হয়, গো কোডটি বরখাস্ত করা হয়।

গো এফএকিউ-তে সি ++ সম্পর্কিত বিভাগ আপডেট করা হয়েছে এবং এখন এসডিজিআইজি-র উল্লেখ রয়েছে এবং " কারণ গো ময়লা-আবর্জনা সংগ্রহ করা এটি বুদ্ধিমানের কাজ হবে না, কমপক্ষে নির্লজ্জভাবে "।


9
আমি আশা করি এটিকে ধাক্কা দেওয়ার কোনও উপায় ছিল। অন্যান্য উত্তরগুলি পুরানো। প্লাস এসডব্লিউআইজি swig.org/Doc3.0/Go.html
ড্রাগনেক্স

34

আমি প্রায়শই জিজ্ঞাসিত প্রশ্নে যা পড়েছি তা থেকে আপনি এখনও পুরোপুরি পারবেন না :

গো প্রোগ্রামগুলি সি / সি ++ প্রোগ্রামগুলির সাথে লিঙ্ক করে?

দুটি গো সংকলক বাস্তবায়ন রয়েছে, গিসি (g জি প্রোগ্রাম এবং বন্ধু) এবং জিসিসিগো। জিসি একটি ভিন্ন কলিং কনভেনশন এবং লিঙ্কার ব্যবহার করে এবং তাই একই সম্মেলনটি ব্যবহার করে কেবল সি প্রোগ্রামগুলির সাথেই লিঙ্ক করা যেতে পারে। এমন সি সংকলক রয়েছে তবে কোনও সি ++ সংকলক নেই। জিসিসিগো একটি জিসিসি ফ্রন্ট-এন্ড যা যত্ন সহ, জিসিসি-সংকলিত সি বা সি ++ প্রোগ্রামগুলির সাথে যুক্ত হতে পারে।

কো কোড থেকে সি লাইব্রেরিগুলিকে নিরাপদে কল করার অনুমতি দেওয়ার জন্য কোগো প্রোগ্রামটি "বিদেশী ফাংশন ইন্টারফেস" এর প্রক্রিয়া সরবরাহ করে। এসডাব্লুআইজি এই ক্ষমতাটি সি ++ লাইব্রেরিতে প্রসারিত করে।



13

আমি স্কট ওয়েলসের উত্তরের ভিত্তিতে নিম্নলিখিত উদাহরণটি তৈরি করেছি । আমি এটি ম্যাকোস হাই সিয়েরা 10.13.3 চলমান goসংস্করণে পরীক্ষা করেছি go1.10 darwin/amd64

(1) এর জন্য কোড library.hpp, C ++ API কল করার লক্ষ্য আমাদের aim

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

(২) এর জন্য কোড library.cpp, সি ++ বাস্তবায়ন।

#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কার্যকর করা হয়েছে 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

(৪) library-bridge.cppসেতুটি কার্যকর করার জন্য কোড Code

#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 ++ এপিআই কল করে।

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"

সম্পূর্ণ উদাহরণের সাথে গিটহাব রেপোতে লিঙ্ক করুন


আপনাকে ধন্যবাদ - এটি খুব সহায়ক ছিল!
রবার্ট কাউহাম

11

মনে হচ্ছে এটি গোলাং সম্পর্কে প্রাথমিক জিজ্ঞাসিত একটি প্রশ্ন। এবং একই সাথে উত্তরগুলি কখনই আপডেট হয় না। এই তিন থেকে চার বছরের মধ্যে, অনেকগুলি নতুন গ্রন্থাগার এবং ব্লগ পোস্ট বেরিয়েছে। নীচের কয়েকটি লিঙ্ক যা আমি দরকারী বলে মনে করি।

এসডাব্লুআইজি এবং গো

সি ++ কোড থেকে ফায়ার এস এস এস আই জি জি-র কল করা হচ্ছে

ভাষার তুলনা করতে, সি ++ এবং যান

GoForCPPProgrammers


3

সেখানে কথা হলো সি এবং যান মধ্যে উৎপন্ন যখন জিসিসি যান কম্পাইলার ব্যবহার করে, gccgo। আন্তঃব্যবহারযোগ্যতা এবং জিসিসিগো ব্যবহার করার সময় গো এর প্রয়োগকৃত বৈশিষ্ট্য সেট উভয়ই সীমাবদ্ধতা রয়েছে (যেমন, সীমিত গোরোটাইনস, কোনও আবর্জনা সংগ্রহ নয়)।


2
ম্যানুয়াল মেমোরি ব্যবস্থাপনার জন্য কোনও সুযোগ-সুবিধা না নিয়ে একটি ভাষা তৈরি করুন, ২. আবর্জনা সংগ্রহ সরান? আমি কি একমাত্র এই যে আমার মাথা আঁচড়ান?
গিরিগিরিস আন্দ্রেসেক

2

আপনি এখানে নিরক্ষিত অঞ্চলে হাঁটছেন। সি কোড কল করার জন্য এখানে গো উদাহরণ দেওয়া আছে, সম্ভবত আপনি সি ++ নাম ম্যাংলিং এবং কলিং কনভেনশনগুলি পড়ার পরে এবং প্রচুর পরীক্ষা এবং ত্রুটির পরে এমন কিছু করতে পারেন ।

আপনি যদি এখনও চেষ্টা করে দেখতে চান তবে শুভকামনা রইল।


1

এখানে সমস্যাটি হল যে একটি কমপ্লায়েন্ট বাস্তবায়নের জন্য আপনার ক্লাসগুলি একটি সংকলন .cpp ফাইলে রাখার দরকার নেই। যদি সংকলক কোনও শ্রেণীর অস্তিত্বকে অনুকূল করে তুলতে পারে, যতক্ষণ না প্রোগ্রামটি একইভাবে আচরণ করে, তবে এটি নির্বাহযোগ্যকে আউটপুট থেকে বাদ দেওয়া যেতে পারে।

সি এর একটি মানক বাইনারি ইন্টারফেস রয়েছে। সুতরাং আপনি জানতে পারবেন যে আপনার ফাংশনগুলি রফতানি হয়েছে। তবে এর পিছনে সি ++ এর কোনও মান নেই has


1

আপনি যোগ করতে হবে পারে -lc++থেকে LDFlagsGolang / CGO মান গ্রন্থাগার প্রয়োজনীয়তার সনাক্ত করা।


0

এই ঘোষণাটি কীভাবে বিস্তৃত হয়েছে তা মজার বিষয়। ড্যান লাইক তার ওয়েবসাইট ফ্লুটারবিতে নতুন ভাষার বুটস্ট্র্যাপিংয়ের পদ্ধতি হিসাবে (এবং অন্যান্য পদক্ষেপগুলি, তবে এটিই জার্মানী is) এটির জন্য ইন্টারপ্রসেস স্ট্যান্ডার্ডগুলি বিকাশের বিষয়ে একটি খুব বিনোদনমূলক এবং চিন্তাশীল আলোচনা করেছিলেন ।


0

কমান্ড cgo ব্যবহার করে এটি অর্জন করা যেতে পারে।

সংক্ষেপে 'যদি "সি" এর আমদানি একটি মন্তব্যের সাথে সাথেই আগে ঘটে থাকে, প্যাকেজটির সি অংশগুলি সংকলন করার সময় এই মন্তব্যটিকে, উপস্থাপনা নামে অভিহিত করা হয় a উদাহরণস্বরূপ: '
উত্স: https://golang.org/cmd/cgo/

// #include <stdio.h>
// #include <errno.h>
import "C"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.