環境
- Windows10 64bit
- OPENCV3.2.0
- gcc(mingw)
OPENCVのプログラムがVSでしかビルドできないことはわかっています。
しかし、プログラムを改造することでgccでもコンパイルできると思うのですが、
どこをどのように改造すればよいかわかりません。
何かヒントを頂けないでしょうか?(それ以前に**ビルドなし**でプログラムを改造しただけでgccでコンパイルできるようにすること自体が可能なのかも方法とは別にお聞きしたいです。)
コンパイラgccをいじることでも以下のプログラムをコンパイルすることを可能にできる気もしますが、さすがにコンパイラをいじるのは至難の業なので、プログラムの方をいじってgccでもコンパイルできるようにしたいと考えました。
どうかよろしくお願いいたします。
gccでコンパイルできるように改造したいプログラムはこちらです。
#include <opencv2/opencv.hpp> #include <opencv2/opencv_lib.hpp> #include <opencv2/highgui/highgui.hpp> int main(void) { cv::Mat src_img; src_img = cv::imread("ファイルパス", 1); // 画像が読み込まれなかったらプログラム終了 if(src_img.empty()) return -1; // 結果画像表示 cv::namedWindow("Image", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO); cv::imshow("Image", src_img); cv::waitKey(0); }
<編集1>
cmake、ビルドなしでプログラムの改造のみでgccコンパイラは使えないでしょうか?
丸投げの質問で申し訳ありません。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
ベストアンサー
この質問を見て、「なぜVC++で作成されたC++のDLLをMinGWでは使用できないのか?」と疑問に思っている人もいると思いますので、解説します。読みたい人だけ読んでください。
DLLの仕組みはCの時代からあまり変わっていません。C++にはクラスがありますが、DLL自体に何々クラスというのが存在するわけではありません。また、C++にはオーバーロードがありますが、この関数はオーバーロードするという情報が存在するわけではありません。実体は全て、Cと同じようにただの関数です。いってしまえば、DLLは関数名とそのエントリーポイントだけが公開されており、呼び出し側は目的の関数のエントリーポイントを探して、呼び出すだけという仕組みです。
問題はこの関数名をどうするかと言うことになります。C++にはCにはなかったクラスやテンプレート、名前空間、オーバーロード等があり、C++上では一つの関数名が複数の実装になったりします。しかし、エントリーポイントは一つしかないため、これらは別々の関数として登録しなくてはなりません。そして、実際にDLL上では別々の関数として登録されています。
つまり、C++をDLL化した場合、クラスやテンプレート、名前空間、オーバーロードによって一意に決まる名前の関数として登録しているに過ぎません。問題はこの一意に決まる名前をどうやって決めるかですが、**この決め方はコンパイラによって異なります。**さらに、VC++ではバージョンによっても異なります。
VC++でDLLを作成した場合、VC++における規則でDLLに登録される名前が決定されます。同じVC++では同じ規則で変換するので、その関数を見に行く事が出来るという仕組みです。しかし、MinGW等の別のコンパイラでは異なる規則を用いています。そのため、DLLに登録されている関数が見つけられず、使用することが出来ないというのが真相になります。
参考: c++ - Linking to MSVC DLL from MinGW - Stack Overflow
なお、Cの関数(C++内ならexport "C"
された関数)はそのままの名前でDLLに登録されるため、上記のような問題は起きません。そのため、VC++側でCの関数で出来たラッパーを作るという手段もありますが、簡単にできるような方法は見つけられませんでした。
名前だけの問題であれば、エイリアスを用意することで無理矢理使用することは出来ます(実際の例は後述)。ただし、名前が異なるだけではなく、内部の構造もコンパイル依存の所が存在するため、必ずうまくいくとは限りません。手動でエイリアスを用意するなどの苦労するばかりか、うまくいかなくて徒労に終わる可能性が高いため、推奨は出来ません。
ついでに、この質問を読んで疑問に思った方への補足です。これまでの質問にあった皆さんの優れた回答を読んでいなかった人達もいるかと思いますので、参考にしてください。
- OpenCV 3.4.1の公式バイナリのWindows版はVisual Studio 2015とVisual Studio 2017のVC++用にコンパイルされています。DLLおよびLIBはその二つから使えるようになっていますが、MinGW GCC等のVisual Studio以外のコンパイラから使用できるようにはなっていません(理由は上で述べたとおりです)。MinGW GCC用のバイナリは公式にはありません。
- MSYS2にはOpenCVのバイナリパッケージ(mingw-w64-x86_64-opencvとmingw-w64-i686-opencv)が存在します。そちらを使えばMSYS2環境でのMinGW GCCでOpenCVを使ったプログラムをコンパイルすることは可能です。OpenCV自体をMSYS2上でコンパイルするためのパッチおよび手順もMSYS2のレポジトリに公開されています。
- OpenCVはCmakeを使うことを前提に設計されています。OpenCVをコンパイルする場合はCmakeを用いて依存関係を解決したMakefileやVisual Studioのプロジェクトファイルを作る必要があります。OpenCVを使うプログラムを作る場合も、Cmakeで依存関係を解決できるようにCmakeのファイルが用意されています。
- OpenCVの公式バイナリや上記のMSYS2パッケージはCUDAが有効になっていません。CUDAを使用したい場合は自分でコンパイルする必要があります。
- OpenCV 3からCのAPIは非推奨になり、C++のAPIを使うことが推奨されています。しかし、CのAPIを使用できないわけではありません。
- Cmakeは依存関係等を解決してMakefileやVisual Studioのプロジェクトファイルを作成するツールです。往年のautomakeに取って代わるツールですが、UNIX/Linux環境のみならず、WindowsでのVisual Studioにも対応しているなど、マルチプラットフォームなC/C++プログラムで特に使われるようになっているツールです。
OpenCVの公式バイナリをMinGW GCCから無理矢理使う方法
MSYS2+MINGW64環境で実施します。GCCおよびdlltool等はインストール済みとします。また、VS2017のランタイムもインストール済みとします。特に明記しませんが、Windows 10の64bit環境です。$
はシェルのプロンプトになります。
1, 作業フォルダーにソースコード"sample.c"を置き、次のように書き換えます。(画像のファイル名を設定し、不要なヘッダを削除しただけです)
sample.c
C
1#include <opencv2/opencv.hpp> 2 3int main(void) 4{ 5 cv::Mat src_img; 6 src_img = cv::imread("sample.jpg", 1); 7 // 画像が読み込まれなかったらプログラム終了 8 if (src_img.empty()) return -1; 9 10 // 結果画像表示 11 cv::namedWindow("Image", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); 12 cv::imshow("Image", src_img); 13 cv::waitKey(0); 14}
2, 適当なJPEGファイルを作業フォルダーにおいて、"sample.jpg"という名前にします。
3, OpenCVのWindows版公式バイナリopencv-3.4.1-vc14_vc15.exeを実行し、Cドライブ直下にインストールします。"C:\opencv\build\x64\vc15\bin\opencv_world341.dll"を作業フォルダーにコピーします。
$ cp /c/opencv/build/x64/vc15/bin/opencv_world341.dll .
4, 下記内容のDEFファイル"opencv_world341_gcc.def"を作成します。
opencv_world341_gcc.def
DEF
1LIBRARY "opencv_world341.dll" 2EXPORTS 3; cv::String::allocate(unsigned long long) 4?allocate@String@cv@@AEAAPEAD_K@Z 5_ZN2cv6String8allocateEy==?allocate@String@cv@@AEAAPEAD_K@Z 6; cv::Mat::deallocate() 7?deallocate@Mat@cv@@QEAAXXZ 8_ZN2cv3Mat10deallocateEv==?deallocate@Mat@cv@@QEAAXXZ 9; cv::fastFree(void*) 10?fastFree@cv@@YAXPEAX@Z 11_ZN2cv8fastFreeEPv==?fastFree@cv@@YAXPEAX@Z 12; cv::imread(cv::String const&, int) 13?imread@cv@@YA?AVMat@1@AEBVString@1@H@Z 14_ZN2cv6imreadERKNS_6StringEi==?imread@cv@@YA?AVMat@1@AEBVString@1@H@Z 15; cv::String::deallocate() 16?deallocate@String@cv@@AEAAXXZ 17_ZN2cv6String10deallocateEv==?deallocate@String@cv@@AEAAXXZ 18; cv::namedWindow(cv::String const&, int) 19?namedWindow@cv@@YAXAEBVString@1@H@Z 20_ZN2cv11namedWindowERKNS_6StringEi==?namedWindow@cv@@YAXAEBVString@1@H@Z 21; cv::imshow(cv::String const&, cv::_InputArray const&) 22?imshow@cv@@YAXAEBVString@1@AEBV_InputArray@1@@Z 23_ZN2cv6imshowERKNS_6StringERKNS_11_InputArrayE==?imshow@cv@@YAXAEBVString@1@AEBV_InputArray@1@@Z 24; cv::waitKey(int) 25?waitKey@cv@@YAHH@Z 26_ZN2cv7waitKeyEi==?waitKey@cv@@YAHH@Z
5, 下記コマンドを実行し、libopencv_world341.aを作成します。
$ dlltool -D opencv_world341.dll -d opencv_world341_gcc.def -l libopencv_world341_gcc.a
6, 作成したライブラリにリンクしてコンパイルします。
$ g++ -O2 -Wall -std=c++17 -I/c/opencv/build/include -L. sample.cpp -lopencv_world341_gcc -o sample.exe
7, MSYS2環境でsample.exeを実行できるか確認します。
$ ./sample.exe
8, エクスプローラー上でも実行できるように依存関係のDLLをコピーしておきます。
$ cp /mingw64/bin/libgcc_s_seh-1.dll . $ cp /mingw64/bin/libstdc++-6.dll . $ cp /mingw64/bin/libwinpthread-1.dll .
9, エクスプローラー上でsample.exeをダブルクリックすると画像が表示されます。
これで完了です。お疲れ様でした。シンボル名を調べるのは二度とやりたくないです。なお、この方法は必ずうまくいくとは限らず、今回はたまたまうまくいっただけに過ぎません。私もよくわかっていない(特にDEFファイルが未だによくわからない)ため、解説はありません。
投稿2018/05/03 23:41
編集2018/05/05 00:55総合スコア21735
0
※ 回答ではありませんごめんなさい
通常ライブラリ(ここではOpenCV)の作者はユーザに対し"環境が違ってもコード自体は変更不要(orほんのちょっと)"となるよう工夫するでしょうし、実際OpenCVもそうなっています。環境(OS/compiler)の違いをヘッダとライブラリで吸収してくれています。
それを踏まえて:
プログラムを改造することでgccでもコンパイルできると思うのですが、
そう考えた理由/根拠は?
あなたはこれまでに:
OpenCVのヘッダを #include せずにコンパイルしたい
OpenCVライブラリなしにコンパイルしたい
などなど、「なんでそんなことしたいの? / なぜフツーにコンパイル/リンクしないの?」
な質問を挙げています。
一体どんな意図があってこんな質問を続けるんです?
投稿2018/05/03 23:16
編集2018/05/04 05:25総合スコア16614
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/05/04 13:40 編集
2018/05/04 12:41 編集
2018/05/04 12:41 編集
2018/05/04 13:37 編集
2018/05/04 13:24
2018/05/04 13:38 編集
2018/05/04 14:08
2018/05/04 14:16 編集
2018/05/04 14:16 編集
2018/05/04 14:21
2018/05/04 14:21
2018/05/04 14:23
2018/05/04 14:30 編集
2018/05/04 14:54
2018/05/04 15:01 編集
2018/05/04 15:01
2018/05/04 15:06 編集
2018/05/04 15:07 編集
2018/05/04 15:07
2018/05/04 15:10
2018/05/04 15:14
2018/05/04 15:16 編集
2018/05/04 15:16
0
こんにちは。
OPENCVのプログラムがVSでしかビルドできないことはわかっています。
そんなことないです。OpenCVはMinGWでもビルドできるようです。MinGWでビルドしたOpenCVとリンクすればMinGWでOpenCVを使うプログラムもビルドできますよ。
mingwでopencvビルドしてみた
An Instllation of OpenCV 3.2.0 on Windows10 using msys2
cmake、ビルドなしでプログラムの改造のみでgccコンパイラは使えないでしょうか?
MinGWでビルドされたOpenCVを入手できれば使えますよ。
MinGWでOpenCVをビルドした人はそこそこいるようですから、探せばあるかも知れません。
30分くらい探して見つからなければビルドした方が速いような気もしますが。
投稿2018/05/03 18:03
総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/05/03 18:09 編集
2018/05/03 18:37
2018/05/03 18:43
2018/05/03 19:21
2018/05/03 19:37
2018/05/03 20:13
0
OPENCVのプログラムがVSでしかビルドできないことはわかっています。
適切にcmake(+必要に応じてMSYS)を用いればビルドはできますね。
しかし、プログラムを改造することでgccでもコンパイルできると思うのですが、
どこをどのように改造すればよいかわかりません。
何かヒントを頂けないでしょうか?(それ以前にビルドなしでプログラムを改造しただけでgccでコンパイルできるようにすること自体が可能なのかも方法とは別にお聞きしたいです。)
OpenCVの規模に対しては無謀ですね。
環境切り分けのために定義しているマクロの調査
cmakeの仮定で生成されるファイルの調査など大掛かりな作業が必要になります。
VCでビルドしたDLLのCインタフェースに対してダイナミックリンクするって方法はありますが
特段優位性があるわけでもないので
OpenCVライブラリ作成者の意図通りにcmakeしてビルドしてリンクした方が無難でしょう。
投稿2018/05/03 23:53
総合スコア15147
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こちらの記事は参考になりますか。
投稿2018/05/03 16:51
総合スコア1195
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/05/04 00:37