centos_7_x86_x64,gcc_4.8.5linux
yum install -y pcre pcre-tools pcre-devel
yum install -y byacc
tar -xvzf swig-rel-3.0.12.tar.gz cd swig-rel-3.0.12 ./autogen.sh
./configure
make && make install
swig -version
這裏說一下爲何要編譯swig源碼來進行安裝,在yum上安裝swig的版本比較低,而較低版本的swig不支持-cgo參數,具體見官方文檔。ios
yum install -y go
go version
#ifndef _TEST_CPP_H_ #define _TEST_CPP_H_ #include <stdint.h> #include <string> /// 回調類 class ICallback { public: virtual void notify(const std::string& s) = 0; }; /// 測試類 class TestCall { public: static TestCall* Create() { return new TestCall(); } void SetCallback(ICallback* callback) { callback_ = callback; } int32_t Test(const std::string& s); private: TestCall() : callback_(NULL) {} ICallback* callback_; }; #endif
#include <iostream> #include "test_cpp.h" int32_t TestCall::Test(const std::string & s) { std::cout << "TestCall::Test(" << s << ")" << std::endl; if (callback_) { callback_->notify(s); } return 0; }
cmake_minimum_required(VERSION 2.8) project(test_cpp C CXX) set(SRC_LISTS test_cpp.cpp) add_library(test_cpp SHARED ${SRC_LISTS})
mkdir cmake cd cmake cmake .. make
因爲在golang中不能直接使用C++函數,因此咱們稍後會使用swig工具,生成C函數提供給golang使用。c++
/* Copyright 2011 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ /* An example of writing a C++ virtual function in Go. */ %module(directors="1") go_test_cpp %init %{ //printf("Initialization rms done.\n"); %} %typemap(gotype) (char **ppInstrumentID, int nCount) "[]string" %typemap(in) (char **ppInstrumentID, int nCount) %{ { int i; _gostring_* a; $2 = $input.len; a = (_gostring_*) $input.array; $1 = (char **) malloc (($2 + 1) * sizeof (char *)); for (i = 0; i < $2; i++) { /* Not work */ //_gostring_ *ps = &a[i]; //$1[i] = (char *) ps->p; //$1[i][ps->n] = '\0'; /*Work well*/ _gostring_ *ps = &a[i]; $1[i] = (char*) malloc(ps->n + 1); memcpy($1[i], ps->p, ps->n); $1[i][ps->n] = '\0'; } $1[i] = NULL; } %} %typemap(argout) (char **ppInstrumentID, int nCount) "" /* override char *[] default */ %typemap(freearg) (char **ppInstrumentID, int nCount) %{ { int i; for (i = 0; i < $2; i++) { free ($1[i]); } free($1); } %} /* 在複雜的企業環境中,可能有一些 C/C++ 頭文件定義了您但願向腳本框架公開的全局變量和常量。 * 在接口文件中使用 %include <header.h> 和 %{ #include <header.h> %},可解決在頭文件中重複全部元素的聲明的問題。 */ /* Includes the header files in the wrapper code */ %header %{ #if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(WIN32) #include "test_cpp.h" #else #include "test_cpp.h" #endif %} /* Parse the header files to generate wrappers */ %include "std_string.i" %feature("director") ICallback; #if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(WIN32) %include "./../cpp/test_cpp.h" #else %include "./../cpp/test_cpp.h" #endif
有幾個點咱們須要注意:git
%module(directors="1") go_test_cpp
%header %{ #if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(WIN32) #include "test_cpp.h" #else #include "test_cpp.h" #endif %}
%feature("director") ICallback;
#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(WIN32) %include "./../cpp/test_cpp.h" #else %include "./../cpp/test_cpp.h" #endif
swig -go -cgo -intgosize 64 -c++ ./go_test_cpp.swigcxx
總共生成了3個文件:go_test_cpp.go、go_test_cpp_wrap.h和go_test_cpp_wrap.cxxgithub
cmake_minimum_required(VERSION 2.8) project(go_test_cpp C CXX) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../cpp) set(SRC_LISTS go_test_cpp_wrap.cxx) add_library(go_test_cpp STATIC ${SRC_LISTS})
mkdir cmake cd cmake cmake .. make
最後編譯的靜態庫是給go使用的,大體調用流程是:go <=> libgo_test_cpp.a <=> libtest_cpp.sogolang
// Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package go_test_cpp //#cgo linux LDFLAGS: -fPIC -L${SRCDIR}/../../cpp/cmake -L${SRCDIR}/../../swig/cmake -Wl,-rpath=${SRCDIR}/../../cpp/cmake -ltest_cpp -lgo_test_cpp -lstdc++ //#cgo linux CPPFLAGS: -fPIC -I. import "C"
連接libtest_cpp.so和libgo_test_cpp.a模塊;應該將libgo_test_cpp.go文件保存在go_test_cpp目錄下,它和go_test_cpp.go都屬於同一個包。centos
package main import( "fmt" "unsafe" "time" "./go_test_cpp" ) type my_callback struct { go_test_cpp.ICallback } func (this my_callback) Notify(arg2 string) { fmt.Printf("c++ Notify:%s\n", arg2) } func main() { cb := go_test_cpp.NewDirectorICallback(my_callback{}) test := go_test_cpp.TestCallCreate() test.SetCallback(cb) res_ptr := test.Test("Hello World!").Swigcptr() res := *(*int32)(unsafe.Pointer(res_ptr)) if res == 0 { fmt.Println("Test success!") } else { fmt.Println("init failed[", res, "]!") } go_test_cpp.Swig_free(res_ptr) time.Sleep(time.Second*1) fmt.Println("end") }
go run main.go
資源下載連接: http://pan.baidu.com/s/1jIA5mXS 密碼: ksnqapp