質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.32%
VC++

VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。

MSYS

MSYS(Minimal SYStem)は、Windows上で動くUnixシェル、テキスト操作ユーティリティなどをまとめたパッケージ。C言語やFortranのコンパイラであるMinGWをカバーする目的で作られています。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

Q&A

2回答

291閲覧

MSYS2(Mingw64)で作成したC++ staticメンバ関数をVisual Studioで使用する方法はあるのでしょうか?

jiro.kaihatsu

総合スコア16

VC++

VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。

MSYS

MSYS(Minimal SYStem)は、Windows上で動くUnixシェル、テキスト操作ユーティリティなどをまとめたパッケージ。C言語やFortranのコンパイラであるMinGWをカバーする目的で作られています。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

0グッド

0クリップ

投稿2025/03/30 09:35

実現したいこと

Visual StudioのC++から、MSYS2(Mingw64)でビルドされたDLL内のstatic関数を呼び出したいです。

前提

  • Windows 11 PCで開発しています
  • MSYS2はgcc version 14.2.0 (Rev2, Built by MSYS2 project)を使っています
  • Visual Studio 2022を使っています
  • 公開したいクラス及び関数は次です

cpp:公開したいクラス及びメンバ関数

1#if defined(WIN32) || defined(_WIN32) 2 #ifdef UTILITY_EXPORTS 3 #define DECLSPEC __declspec(dllexport) 4 #else 5 #define DECLSPEC __declspec(dllimport) 6 #endif 7#else 8 #define DECLSPEC 9#endif 10 11class /* DECLSPEC */ CoordinateUtil 12{ 13public: 14 DECLSPEC void showMessage(); 15 DECLSPEC static void latLonToUTM(double lat, double lon, double& utmX, double& utmY); 16};

発生している問題・エラーメッセージ

  • MSYS2側で__declspec(dllexport)を、Visual Studio側で__declspec(dllimport)をメソッド宣言に付与しても次のエラーになってしまいます。関数が公開されてもマングリングされてしまうことが原因と思われます。
    • 未解決の外部シンボル "__declspec(dllimport) public: void __cdecl CoordinateUtil::showMessage(void)" (_imp?showMessage@CoordinateUtil@@QEAAXXZ) が関数 main で参照されました
    • MSYS2側でnmしてシンボルを確認してみたところ、「_imp?showMessage@CoordinateUtil@@QEAAXXZ」とは別の名称でした。見つからないはずです
  • classとメソッド両宣言にDECLSPECを付与した場合、Visual Studio側で次のエラーになります
    • エラー「dll インターフェイス クラスのメンバーを dll インターフェイスと共に宣言するのは無効です。」
  • 次に示すウェブページを参考にして公開したいクラスを取得する関数を使うとCoordinateUtilのインスタンスは取得でき、showMessage()は呼び出せます

MSYS2(Mingw64)で作成したC++ staticメンバ関数をVisual Studioで使用する方法はあるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2025/03/30 14:30

extern "C"とした中継用の関数を作ってそれを公開する、という手法は考えられますが、それでは対応できない事情があるような状況なのでしょうか。
Manabu

2025/03/30 14:52

VidualStudioとgccでは通常互換性に乏しいのでVidualStudio側でライブラリをlib化した方が安全かと思います 尚静的メソッドは内部的にグローバルスコープへのポインタであり、通常のグローバル関数の型と可換なので、void*として取り回したアドレスを関数型へキャストする関数を用意すれば呼び出し自体は可能かと思います
jiro.kaihatsu

2025/03/31 20:27

maisumakunさん、コメントありがとうございます。 はい、その通りです。 クラスのstaticメンバ関数についてVisual Studio側で使用する方法が分かりません(見つけられていません)
jiro.kaihatsu

2025/03/31 20:30

Manabuさん、コメントありがとうございます。 MSYS2側で作成したライブラリは.cppソースコードを入手することが難しい状況です。アドレスを関数型ポインタ変数にキャストする方法は試してみます。
guest

回答2

0

マングルルールは処理系によって異なるべきであるとされてきました。 オブジェクトの構築方法や具体的なメモリのレイアウトなどが処理系によって異なるので関数の呼び出しだけ出来ても破綻するからです。 このことは GCC のドキュメントにも記載されています。 意図的にリンク出来なくするためにマングルルールは違わせてあるのです。

C では主要な実行環境では統一された ABI (Application Binary Interface) があって相互運用が出来ているので C と同程度の範囲に限って C++ でも相互運用が出来るようになっているに過ぎません。 C にないもので接続しようとするのはきちんとした仕組みが充分ではなく、処理系が保証したやり方というものは無いと考えて良いと思います。


質問を狭義に解釈して DLL の側では特別な事前準備をせずに static なメンバ関数を呼び出すのだとしたらマングルされた名前をそのまま GetProcAddress API に渡すということは出来ます。 コードで示すなら以下のような要領です。

cpp

1#include <libloaderapi.h> 2 3typedef void (*functype)(double, double, double&, double&); 4 5int main(void) { 6 auto lib = LoadLibraryA("sample.dll"); 7 // CoordinateUtil::latLonToUTM にマングルを適用した名前 ↓ 8 auto func = (functype)GetProcAddress(lib, "_ZN14CoordinateUtil11latLonToUTMEddRdS0_"); 9 double x, y; 10 func(1.0, 2.0, x, y); 11}

static なメンバ関数はクラスの名前空間にあるだけでバイナリレベルでは非メンバ関数とあまり違いがないはずなのでたぶん大丈夫でしょう。

投稿2025/03/31 02:46

SaitoAtsushi

総合スコア5714

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jiro.kaihatsu

2025/03/31 20:40

SaitoAtsushiさん、助言ありがとうございます。 マングルルールについても情報いただき勉強になりました。 初めて知りました。 解決コードまで示していただきありがとうございます。 試してみます。
guest

0

私だったらこういう場合、既にコメントもいただいているようにextern "C"なDLLエクスポート関数を経由させたりリンク時にDEFファイルを使うよう実装しそうですが、

次に示すウェブページを参考にして公開したいクラスを取得する関数を使うとCoordinateUtilのインスタンスは取得でき、showMessage()は呼び出せます
https://qiita.com/fan2tamo/items/8f110a22d47cb684f33d
が、ご存じの通りC++の文法上static関数は抽象クラスで宣言できないため、この方法では呼び出せません

抽象クラス、純粋仮想関数を使う、っていう部分とその理由が興味深いですね。
staticなメンバー関数で呼べないのなら、純粋仮想関数を経由してそのstaticメンバー関数を呼び出せば良さげな気がします。

不完全なコードですが、例として:

C++

1class CoordinateUtil : <純粋仮想関数を宣言したクラス> 2{ 3public: 4 static void STATIC_latLonToUTM(double lat, double lon, double& utmX, double& utmY); 5 DECLSPEC void latLonToUTM(double lat, double lon, double& utmX, double& utmY); 6}; 7 8... 9void CoordinateUtil::STATIC_latLonToUTM(double lat, double lon, double& utmX, double& utmY) 10{ 11 // 色々な処理 12} 13 14// 純粋仮想関数から呼び出されるメンバー関数 15DECLSPEC void CoordinateUtil::latLonToUTM(double lat, double lon, double& utmX, double& utmY) 16{ 17 // staticなメンバー関数を呼び出す 18 CoordinateUtil::STATIC_latLonToUTM(lat, lon, utmX, utmY); 19}

当方でも確認してから回答しようと思っていましたが、時間がかかりそうなので候補として投稿しておきます。NGだったらごめんなさい。

投稿2025/03/30 20:19

編集2025/03/30 20:26
dodox86

総合スコア9367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jiro.kaihatsu

2025/03/31 20:37

dodox86さん、助言ありがとうございます。 「純粋仮想関数から呼び出されるメンバー関数」から間接的に呼び出す方法だと確かに呼び出せると思うのですが、直接呼び出す方法があるなら知りたいと考えています。 最初に提示したサンプルはstatic関数が一つですが、関数が多いクラスのことを考えると、可能ならば直接呼び出す方法があればいいな、と考えています(もし無いなら間接的に呼び出す方法を選択するつもりです)。
dodox86

2025/04/01 00:19

ご質問の当初の記載内容からは私は読み取れませんでしたが、[2025/04/01 05:30]の質問コメントからするとmsys2/mingw側DLLのソースコードは修正できないのですね。 であれば、本回答の対応も無理ですね。マングリングのように少し踏み込んだ話まで出ていたのに // staticなメンバー関数を呼び出す CoordinateUtil::STATIC_latLonToUTM(lat, lon, utmX, utmY); のように単純な呼び出しでの解決策の話が出ていなかったので、妙な気はしていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.32%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問