Dalam bahasa Go yang baru , bagaimana cara saya memanggil kode C ++? Dengan kata lain, bagaimana saya bisa membungkus kelas C ++ saya dan menggunakannya di Go?
Dalam pembicaraan teknologi, SWIG sangat singkat disebutkan, sesuatu seperti "..sampai kita menyelesaikan
swig
1
@Matt: Kemungkinan dia ingin menggunakan pustaka C ++ yang sudah ada tanpa harus porting ke C atau Go. Saya menginginkan hal yang sama.
Graeme Perrow
Saya tidak bisa memikirkan satu perpustakaan yang layak tersedia untuk C ++ dan bukan untuk C. Saya ingin tahu apa yang ada dalam pikiran Anda.
Matt Joiner
13
@ Matt: Salah satu contohnya adalah perpustakaan Boost, dan ada ribuan perpustakaan C ++ lainnya yang bermanfaat. Tapi mungkin aku hanya memberi makan troll di sini ...
Frank
@ Matt: dalam kasus saya, saya ingin membuat antarmuka Go ke pustaka klien kami yang sudah ada tetapi pustaka utamanya adalah C ++. Porting ke C atau Go bukan pilihan.
Graeme Perrow
Jawaban:
154
Pembaruan: Saya telah berhasil menghubungkan tes C ++ kelas kecil dengan Go
Jika Anda membungkus Anda kode C ++ dengan antarmuka C Anda harus dapat memanggil perpustakaan Anda dengan cgo (lihat contoh gmp in $GOROOT/misc/cgo/gmp).
Saya tidak yakin apakah gagasan tentang kelas di C ++ benar-benar dapat diekspresikan di Go, karena tidak memiliki warisan.
Ini sebuah contoh:
Saya memiliki kelas C ++ yang didefinisikan sebagai:
Hati-hati dengan ini, saya tidak tahu apa yang mungkin terjadi pada memori jika Anda mengirimnya di antara dua bahasa.
Scott Wales
11
Harus saya katakan, contoh ini mengingatkan saya mengapa saya ingin menulis Go murni. Lihat seberapa besar dan jelek sisi C ++. Ya
Jeff Allen
@ScottWales kemungkinan Anda mungkin telah menempatkan ini di repo di Github atau apa pun? Saya akan senang melihat contoh kerja
netpoetica
7
@ Andre: Anda tidak menurunkan pilihan jawaban karena itu bukan yang terbaik. Anda menurunkan jawaban karena itu tidak membantu. Selama ini berfungsi, jawaban ini masih membantu bahkan jika ada solusi yang lebih baik.
Graeme Perrow
Berita bagus, Go akan mengkompilasi cpp sekarang sehingga makefile tidak lagi diperlukan. Pembungkus unsafe.Pointer tidak berfungsi untuk saya. Sedikit modifikasi yang dikompilasi untuk saya: play.golang.org/p/hKuKV51cRpgo test harus bekerja tanpa makefile
Drew
47
Tampaknya saat ini SWIG adalah solusi terbaik untuk ini:
Ini mendukung warisan dan bahkan memungkinkan untuk mensubkelas kelas C ++ dengan Go struct sehingga ketika metode yang ditimpa dipanggil dalam kode C ++, kode Go dipecat.
Bagian tentang C ++ di Go FAQ diperbarui dan sekarang menyebutkan SWIG dan tidak lagi mengatakan " karena Go adalah sampah, tidak bijaksana untuk melakukannya, setidaknya secara naif ".
Anda belum bisa membaca apa yang saya baca di FAQ :
Apakah program Go terhubung dengan program C / C ++?
Ada dua implementasi kompilator Go, gc (program 6g dan teman-teman) dan gccgo. Gc menggunakan konvensi panggilan dan tautan yang berbeda dan karenanya hanya dapat dihubungkan dengan program C yang menggunakan konvensi yang sama. Ada kompiler C seperti itu tetapi tidak ada kompiler C ++. Gccgo adalah front-end GCC yang dengan hati-hati dapat dihubungkan dengan program C atau C ++ yang dikompilasi GCC.
Program cgo menyediakan mekanisme untuk "antarmuka fungsi asing" untuk memungkinkan panggilan yang aman dari perpustakaan C dari kode Go. SWIG memperluas kemampuan ini ke pustaka C ++.
Saya telah membuat contoh berikut berdasarkan jawaban Scott Wales . Saya sudah mengujinya di macOS High Sierra 10.13.3 goversi yang sedang berjalango1.10 darwin/amd64 .
(1) Kode untuk library.hpp, API C ++ yang ingin kami panggil.
#pragma once
classFoo{public:Foo(intvalue);~Foo();intvalue()const;private:int m_value;};
Saya dapat menjalankan contoh program sebagai berikut:
$ 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()is42[go]42[c++ bridge] LIB_DestroyFoo(0x42002e0)[c++]Foo::~Foo(42)
Penting
Komentar import "C"di atas dalam goprogram BUKAN OPSIONAL . Anda harus meletakkannya persis seperti yang ditunjukkan sehingga cgotahu header dan pustaka mana yang akan dimuat, dalam hal ini:
Sepertinya itu salah satu pertanyaan awal tentang Golang. Dan jawaban yang sama untuk tidak pernah diperbarui. Selama tiga hingga empat tahun ini, terlalu banyak perpustakaan dan posting blog baru telah habis. Di bawah ini adalah beberapa tautan yang saya rasa berguna.
Ada pembicaraan tentang interoperabilitas antara C dan Go saat menggunakan kompiler gcc Go, gccgo. Ada beberapa batasan untuk interoperabilitas dan set fitur Go yang diterapkan saat menggunakan gccgo, namun (misalnya, goroutine terbatas, tidak ada pengumpulan sampah).
1. Membuat bahasa tanpa fasilitas untuk manajemen memori manual, 2. Menghapus pengumpulan sampah? Apakah aku satu-satunya yang menggaruk kepalaku?
György Andrasek
2
Anda berjalan di wilayah yang belum dipetakan di sini. Berikut ini adalah contoh Go untuk memanggil kode C, mungkin Anda dapat melakukan sesuatu seperti itu setelah membaca tentang C ++ nama mangling dan konvensi pemanggilan, dan banyak trial and error.
Jika Anda masih merasa ingin mencobanya, semoga berhasil.
Masalahnya di sini adalah implementasi yang sesuai tidak perlu menempatkan kelas Anda dalam file .cpp kompilasi. Jika kompiler dapat mengoptimalkan keberadaan suatu kelas, selama program berperilaku dengan cara yang sama tanpanya, maka ia dapat dihilangkan dari output yang dapat dieksekusi.
C memiliki antarmuka biner standar. Karenanya, Anda dapat mengetahui bahwa fungsi Anda diekspor. Tetapi C ++ tidak memiliki standar seperti itu.
Lucu berapa banyak masalah yang lebih luas yang pengumuman ini dikeruk. Dan Lyke melakukan diskusi yang sangat menghibur dan penuh pertimbangan di situs webnya, Flutterby, tentang mengembangkan Standar Prosesproses sebagai cara bootstrap bahasa baru (dan konsekuensi lainnya, tapi itulah yang berhubungan erat di sini).
Ini dapat dicapai dengan menggunakan perintah cgo.
Intinya 'Jika impor "C" segera didahului dengan komentar, komentar itu, yang disebut preamble, digunakan sebagai header ketika menyusun bagian-bagian C dari paket. Misalnya: '
sumber: https://golang.org/cmd/cgo/
Jawaban:
Pembaruan: Saya telah berhasil menghubungkan tes C ++ kelas kecil dengan Go
Jika Anda membungkus Anda kode C ++ dengan antarmuka C Anda harus dapat memanggil perpustakaan Anda dengan cgo (lihat contoh gmp in
$GOROOT/misc/cgo/gmp
).Saya tidak yakin apakah gagasan tentang kelas di C ++ benar-benar dapat diekspresikan di Go, karena tidak memiliki warisan.
Ini sebuah contoh:
Saya memiliki kelas C ++ yang didefinisikan sebagai:
yang ingin saya gunakan di Go. Saya akan menggunakan antarmuka C.
(Saya menggunakan
void*
bukan C struct sehingga kompiler tahu ukuran Foo)Implementasinya adalah:
dengan semua yang dilakukan, file Go adalah:
Makefile yang saya gunakan untuk mengkompilasi ini adalah:
Coba mengujinya dengan:
Anda harus menginstal pustaka bersama dengan make install, lalu jalankan make test. Output yang diharapkan adalah:
sumber
go test
harus bekerja tanpa makefileTampaknya saat ini SWIG adalah solusi terbaik untuk ini:
http://www.swig.org/Doc2.0/Go.html
Ini mendukung warisan dan bahkan memungkinkan untuk mensubkelas kelas C ++ dengan Go struct sehingga ketika metode yang ditimpa dipanggil dalam kode C ++, kode Go dipecat.
Bagian tentang C ++ di Go FAQ diperbarui dan sekarang menyebutkan SWIG dan tidak lagi mengatakan " karena Go adalah sampah, tidak bijaksana untuk melakukannya, setidaknya secara naif ".
sumber
Anda belum bisa membaca apa yang saya baca di FAQ :
sumber
Pada go1.2 +, cgo secara otomatis menggabungkan dan mengkompilasi kode C ++:
http://golang.org/doc/go1.2#cgo_and_cpp
sumber
Saya telah membuat contoh berikut berdasarkan jawaban Scott Wales . Saya sudah mengujinya di macOS High Sierra 10.13.3
go
versi yang sedang berjalango1.10 darwin/amd64
.(1) Kode untuk
library.hpp
, API C ++ yang ingin kami panggil.(2) Kode untuk
library.cpp
, implementasi C ++.(3) Kode untuk
library-bridge.h
jembatan diperlukan untuk mengeksposC
API yang diimplementasikanC++
sehinggago
dapat menggunakannya.(4) Kode untuk
library-bridge.cpp
, implementasi jembatan.(5) Akhirnya,,
library.go
program go memanggil C ++ API.Gunakan Makefile berikut
Saya dapat menjalankan contoh program sebagai berikut:
Penting
Komentar
import "C"
di atas dalamgo
program BUKAN OPSIONAL . Anda harus meletakkannya persis seperti yang ditunjukkan sehinggacgo
tahu header dan pustaka mana yang akan dimuat, dalam hal ini:Tautan ke repo GitHub dengan contoh lengkap .
sumber
Sepertinya itu salah satu pertanyaan awal tentang Golang. Dan jawaban yang sama untuk tidak pernah diperbarui. Selama tiga hingga empat tahun ini, terlalu banyak perpustakaan dan posting blog baru telah habis. Di bawah ini adalah beberapa tautan yang saya rasa berguna.
SWIG dan Go
Memanggil Kode C ++ Dari Go With SWIG
Saat membandingkan bahasa, C ++ dan Go
GoForCPPProgrammers
sumber
Ada pembicaraan tentang interoperabilitas antara C dan Go saat menggunakan kompiler gcc Go, gccgo. Ada beberapa batasan untuk interoperabilitas dan set fitur Go yang diterapkan saat menggunakan gccgo, namun (misalnya, goroutine terbatas, tidak ada pengumpulan sampah).
sumber
Anda berjalan di wilayah yang belum dipetakan di sini. Berikut ini adalah contoh Go untuk memanggil kode C, mungkin Anda dapat melakukan sesuatu seperti itu setelah membaca tentang C ++ nama mangling dan konvensi pemanggilan, dan banyak trial and error.
Jika Anda masih merasa ingin mencobanya, semoga berhasil.
sumber
Masalahnya di sini adalah implementasi yang sesuai tidak perlu menempatkan kelas Anda dalam file .cpp kompilasi. Jika kompiler dapat mengoptimalkan keberadaan suatu kelas, selama program berperilaku dengan cara yang sama tanpanya, maka ia dapat dihilangkan dari output yang dapat dieksekusi.
C memiliki antarmuka biner standar. Karenanya, Anda dapat mengetahui bahwa fungsi Anda diekspor. Tetapi C ++ tidak memiliki standar seperti itu.
sumber
Anda mungkin perlu menambahkan
-lc++
keLDFlags
untuk Golang / CGo untuk mengenali kebutuhan untuk perpustakaan standar.sumber
Lucu berapa banyak masalah yang lebih luas yang pengumuman ini dikeruk. Dan Lyke melakukan diskusi yang sangat menghibur dan penuh pertimbangan di situs webnya, Flutterby, tentang mengembangkan Standar Prosesproses sebagai cara bootstrap bahasa baru (dan konsekuensi lainnya, tapi itulah yang berhubungan erat di sini).
sumber
Ini dapat dicapai dengan menggunakan perintah cgo.
Intinya 'Jika impor "C" segera didahului dengan komentar, komentar itu, yang disebut preamble, digunakan sebagai header ketika menyusun bagian-bagian C dari paket. Misalnya: '
sumber: https://golang.org/cmd/cgo/
sumber