Skip to content

Instantly share code, notes, and snippets.

@kuc-arc-f
Last active June 13, 2026 05:12
Show Gist options
  • Select an option

  • Save kuc-arc-f/b6df48e804989401ea09d9f0fb24198b to your computer and use it in GitHub Desktop.

Select an option

Save kuc-arc-f/b6df48e804989401ea09d9f0fb24198b to your computer and use it in GitHub Desktop.
GoLang call C++ , plugin package
module go-cpp-plugin-demo
go 1.26.1
// Go の plugin パッケージを使用して C++ .so プラグインをロードし、
// 文字列を C++ に送信して、処理結果を受け取るデモプログラム。
package main
import (
"fmt"
"os"
"plugin"
"strings"
)
const pluginPath = "./myplugin/myplugin.so"
func main() {
fmt.Println(strings.Repeat("=", 60))
fmt.Println(" Go ⇄ C++ プラグイン通信デモ")
fmt.Println(" (plugin パッケージ使用)")
fmt.Println(strings.Repeat("=", 60))
// ── プラグインのロード ──
fmt.Printf("\n📦 プラグインをロード中: %s\n", pluginPath)
p, err := plugin.Open(pluginPath)
if err != nil {
fmt.Fprintf(os.Stderr, "❌ プラグインのロードに失敗: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ プラグインのロード成功")
// ── 関数のルックアップ ──
processStringSym, err := p.Lookup("ProcessString")
if err != nil {
fmt.Fprintf(os.Stderr, "❌ ProcessString のルックアップに失敗: %v\n", err)
os.Exit(1)
}
processString, ok := processStringSym.(func(string) string)
if !ok {
fmt.Fprintf(os.Stderr, "❌ ProcessString の型が不正\n")
os.Exit(1)
}
toUpperSym, err := p.Lookup("ToUpper")
if err != nil {
fmt.Fprintf(os.Stderr, "❌ ToUpper のルックアップに失敗: %v\n", err)
os.Exit(1)
}
toUpper, ok := toUpperSym.(func(string) string)
if !ok {
fmt.Fprintf(os.Stderr, "❌ ToUpper の型が不正\n")
os.Exit(1)
}
stringInfoSym, err := p.Lookup("StringInfo")
if err != nil {
fmt.Fprintf(os.Stderr, "❌ StringInfo のルックアップに失敗: %v\n", err)
os.Exit(1)
}
stringInfo, ok := stringInfoSym.(func(string) string)
if !ok {
fmt.Fprintf(os.Stderr, "❌ StringInfo の型が不正\n")
os.Exit(1)
}
// ── テストメッセージの送受信 ──
messages := []string{
"Hello, C++!",
"こんにちは世界",
"Go から C++ へ文字列送信テスト",
"ABCDE 12345",
}
// 1. ProcessString(文字列反転)
fmt.Println("\n" + strings.Repeat("-", 60))
fmt.Println("📝 テスト1: 文字列処理 (ProcessString)")
fmt.Println(strings.Repeat("-", 60))
for _, msg := range messages {
fmt.Printf("\n Go → C++: \"%s\"\n", msg)
result := processString(msg)
fmt.Printf(" C++ → Go: %s\n", result)
}
// 2. ToUpper(大文字変換)
fmt.Println("\n" + strings.Repeat("-", 60))
fmt.Println("📝 テスト2: 大文字変換 (ToUpper)")
fmt.Println(strings.Repeat("-", 60))
for _, msg := range messages {
fmt.Printf("\n Go → C++: \"%s\"\n", msg)
result := toUpper(msg)
fmt.Printf(" C++ → Go: %s\n", result)
}
// 3. StringInfo(文字列情報)
fmt.Println("\n" + strings.Repeat("-", 60))
fmt.Println("📝 テスト3: 文字列情報 (StringInfo)")
fmt.Println(strings.Repeat("-", 60))
for _, msg := range messages {
fmt.Printf("\n Go → C++: \"%s\"\n", msg)
result := stringInfo(msg)
fmt.Printf(" C++ → Go: %s\n", result)
}
fmt.Println("\n" + strings.Repeat("=", 60))
fmt.Println(" ✅ すべてのテスト完了")
fmt.Println(strings.Repeat("=", 60))
}
.PHONY: all plugin main run clean
# デフォルト: プラグインとメインプログラムの両方をビルド
all: plugin main
# Go プラグイン (.so) のビルド
# C++ ソースコードは cgo によって自動的にコンパイルされる
plugin:
@echo "🔨 プラグインをビルド中..."
cd myplugin && go build -buildmode=plugin -o myplugin.so .
@echo "✅ myplugin/myplugin.so を生成しました"
# メインプログラムのビルド
main:
@echo "🔨 メインプログラムをビルド中..."
go build -o app main.go
@echo "✅ app を生成しました"
# ビルドして実行
run: all
@echo ""
@echo "🚀 実行中..."
@echo ""
./app
# クリーンアップ
clean:
@echo "🧹 クリーンアップ中..."
rm -f app myplugin/myplugin.so
@echo "✅ 完了"
// Package main は Go plugin として C++ の文字列処理関数をエクスポートする。
// go build -buildmode=plugin でビルドし、メインプログラムから plugin パッケージで読み込む。
package main
/*
#cgo CXXFLAGS: -std=c++17 -O2
#cgo LDFLAGS: -lstdc++
#include "processor.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"
// ProcessString は Go の文字列を C++ に送信し、処理結果を受け取って返す。
// C++ 側で文字列の反転処理が行われる。
func ProcessString(msg string) string {
cMsg := C.CString(msg)
defer C.free(unsafe.Pointer(cMsg))
cResult := C.process_string(cMsg)
defer C.free_string(cResult)
return C.GoString(cResult)
}
// ToUpper は Go の文字列を C++ に送信し、大文字変換結果を受け取って返す。
func ToUpper(msg string) string {
cMsg := C.CString(msg)
defer C.free(unsafe.Pointer(cMsg))
cResult := C.to_upper(cMsg)
defer C.free_string(cResult)
return C.GoString(cResult)
}
// StringInfo は Go の文字列を C++ に送信し、文字列情報を受け取って返す。
func StringInfo(msg string) string {
cMsg := C.CString(msg)
defer C.free(unsafe.Pointer(cMsg))
cResult := C.string_info(cMsg)
defer C.free_string(cResult)
return C.GoString(cResult)
}
#include "processor.h"
#include <cstring>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <sstream>
#include <cctype>
extern "C" {
// Go から受け取った文字列を処理し、反転した結果と合わせて返す
char* process_string(const char* input) {
std::string str(input);
// 文字列を反転(UTF-8 バイト単位)
std::string reversed(str.rbegin(), str.rend());
// 結果を組み立て
std::string result = "[C++ 処理結果] 受信: \"" + str + "\" → 反転: \"" + reversed + "\"";
// malloc で確保して返す(Go 側で free_string を呼ぶ)
char* output = (char*)malloc(result.length() + 1);
std::strcpy(output, result.c_str());
return output;
}
// 文字列を大文字に変換して返す(ASCII 部分のみ)
char* to_upper(const char* input) {
std::string str(input);
std::string upper_str;
upper_str.reserve(str.size());
for (char c : str) {
upper_str += static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
}
std::string result = "[C++ 大文字変換] \"" + std::string(input) + "\" → \"" + upper_str + "\"";
char* output = (char*)malloc(result.length() + 1);
std::strcpy(output, result.c_str());
return output;
}
// 文字列の情報(バイト数、ASCII 文字数)を返す
char* string_info(const char* input) {
std::string str(input);
size_t byte_count = str.size();
size_t ascii_count = 0;
size_t non_ascii_count = 0;
for (unsigned char c : str) {
if (c < 128) {
ascii_count++;
} else {
non_ascii_count++;
}
}
std::ostringstream oss;
oss << "[C++ 文字列情報] \"" << str << "\""
<< " | バイト数: " << byte_count
<< " | ASCII文字数: " << ascii_count
<< " | 非ASCII バイト数: " << non_ascii_count;
std::string result = oss.str();
char* output = (char*)malloc(result.length() + 1);
std::strcpy(output, result.c_str());
return output;
}
// malloc で確保したメモリを解放する
void free_string(char* str) {
if (str != nullptr) {
free(str);
}
}
} // extern "C"
#ifndef PROCESSOR_H
#define PROCESSOR_H
#ifdef __cplusplus
extern "C" {
#endif
// Go から受け取った文字列を処理し、結果を返す
char* process_string(const char* input);
// 文字列を大文字に変換して返す
char* to_upper(const char* input);
// 文字列の情報(長さ、バイト数など)を返す
char* string_info(const char* input);
// 返却された文字列のメモリを解放する
void free_string(char* str);
#ifdef __cplusplus
}
#endif
#endif // PROCESSOR_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment