Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
19
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@Satachito

GO 1.5 と C++ を SWIG でブリッジさせる方法

わかってしまえば簡単なのだが、引っかかることが多いのでメモ。
(検証環境:OSX El Capitan, GO 1.5.1, SWIG 3.0.7)


1 まず引数をエコーさせる単純な例を考える。

ソースディレクトリに以下の3ファイルを作る。

sc1.h
#pragma once 

inline  int
EchoIntN( int p ) {
    return p;
}

inline  double
EchoDoubleN( double p ) {
    return p;
}
sc1.swigcxx
%module sc1
%{
#include    "sc1.h"
%}

%include    "sc1.h"
nop.go
package sc1

以下を実行すると

go install

*. swigcxx があれば自動的に swig が呼び出され、pkg 化されてインストールされる。(GO 1.5 から)
ファイル nop.go は go ファイルが一つもないと go install が失敗してしまうので、その対策用のダミー。他に go ファイルがあれば必要ない。

呼び出し側は実行ディレクトリに以下のファイルを用意して

main1.go
package main

import  "fmt"
import  "github.com/Satachito/sc1"

func
Dump( p interface{} ) {
    fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
    Dump( sc1.EchoIntN( 8 ) );
    Dump( sc1.EchoDoubleN( 9 ) );
}

実行

$ go run main1.go
8:int
9:float64


補足

もし nop.go ファイルを作るのが嫌だったら、sc1.swigcxx を別の名前(例えばsc1.i)に変えて、明示的に swig を呼び出してから go install すれば良い。

swig -go -c++ -cgo -intgosize 32 sc1.i
go install

sc1.go と sc1_wrap.cxx の2つのファイルが同一ディレクトリに作成される。


2 テンプレート化してみる。

sc2.h
#pragma once 

template    <typename T>    T
Echo( const T& p ) {
    return p;
}
sc2.swigcxx
%module sc2
%{
#include "sc2.h"
%}

%include "sc2.h"

%template(EchoIntT)     Echo<int>;
%template(EchoDoubleT)  Echo<double>;

最後の2行でテンプレートを実体化している。

nop.go
package sc2

として

go install

呼び出し側は

main2.go
package main

import  "fmt"
import  "github.com/Satachito/sc2"

func
Dump( p interface{} ) {
    fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
    Dump( sc2.EchoIntT( 8 ) );
    Dump( sc2.EchoDoubleT( 9 ) );
}

$ go run main2.go
8:int
9:float64


3 string を使ってみる。

関数とテンプレート両方用意した。

sc3.h
#pragma once 

template    <typename T>    T
Echo( const T& p ) {
    return p;
}

#include    <string>

inline  std::string
EchoStringN( std::string p ) {
    return p;
}
sc3.swigcxx
%module sc3
%{
#include "sc3.h"
%}


%include    "std_string.i"

%include    "sc3.h"

%template(EchoStringT)  Echo<std::string>;

std_string.i を include するのがポイント

nop.go
package sc3

として

go install

呼び出し側は

main3.go
package main

import  "fmt"
import  "github.com/Satachito/sc3"

func
Dump( p interface{} ) {
    fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
    Dump( sc3.EchoStringN( "Echo me N." ) );
    Dump( sc3.EchoStringT( "Echo me T." ) );
}

$ go run main3.go
Echo me N.:string
Echo me T.:string


4 vector を使ってみる。

sc4.h
#pragma once 

template    <typename T>    T
Echo( const T& p ) {
    return p;
}

#include    <string>
#include    <vector>

inline  std::vector<std::string>
EchoVSN( std::vector<std::string> p ) {
    return p;
}
sc4.swigcxx
%module sc4
%{
#include "sc4.h"
%}


%include    "std_string.i"
%include    "std_vector.i"

%include    "sc4.h"

namespace std {
    %template(StringVector) vector<string>;
}

%template(EchoVST)  Echo<std::vector<std::string>>;

std_vetor.i を include するのがポイント。

nop.go
package sc4

として

go install

呼び出し側は

main4.go
package main

import  "fmt"
import  "github.com/Satachito/sc4"

func
Dump( p interface{} ) {
    fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
    a := sc4.NewStringVector()
    defer sc4.DeleteStringVector( a )
    a.Add( "Echo me." );
    Dump( sc4.EchoVSN( a ).Get( 0 ) );
    Dump( sc4.EchoVST( a ).Get( 0 ) );
}

$ go run main4.go
Echo me.:string
Echo me.:string

NewStringVector, DeleteStringVector, Add, Get は自動的に生成されている。他にもvectorとして扱うために必要なものが生成される。どんなメソッドが生成されているかを見るには、swig を明示的に呼び出して生成された go ファイルの中を見てみる。


5 struct を使ってみる。

sc5.h
#pragma once 

template    <typename T>    T
Echo( const T& p ) {
    return p;
}

struct
IF {
    int     I;
    float   F;
    double  Total() {
        return I + F;
    }
};

IF
EchoIFN( const IF& p ) {
    return p;
}
sc5.swigcxx
%module sc5
%{
#include "sc5.h"
%}

%include    "sc5.h"

%template(EchoIFT)  Echo<IF>;
nop.go
package sc5

として

go install

呼び出し側は

main5.go
package main

import  "fmt"
import  "github.com/Satachito/sc5"

func
Dump( p interface{} ) {
    fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
    a := sc5.NewIF()
    defer sc5.DeleteIF( a )
    a.SetI( 1 )
    a.SetF( 2 )
    w1 := sc5.EchoIFN( a )
    Dump( w1.GetI() );
    Dump( w1.GetF() );
    Dump( w1.Total() );
    w2 := sc5.EchoIFT( a )
    Dump( w2.GetI() );
    Dump( w2.GetF() );
    Dump( w2.Total() );
}

$ go run main5.go
1:int
2:float32
3:float64
1:int
2:float32
3:float64

メンバーには直接アクセスできないので、setter, getter を使う。
忘れがちだけど、GO らしく C の構造体の方のメンバーの名前も最初大文字で。


Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
19
Help us understand the problem. What are the problem?