[Work/TechInfo/other]

MinGW+Code::BlocksでOpenCLのコンパイル / 2015-01-06 (火)

追記: その後MSYSのbashから以下のオプション順でgccを叩くことで,コンパイル可能なことを確認しました.これでCode::Blocksもいらなくなるぜヒャッハー!
そもそもWindowsの場合スタティックリンクが想定されていないだけでなく,OpenCLそのものもダイナミックリンクの運用を前提としているようで……なので.aファイルは作らないで,シェアードオブジェクトの形でコンパイルするようにしておいたほうがよさそう.
(Intel SDKの場合)

gcc Cのファイル名 \
-I"/c/Program Files (x86)/Intel/OpenCL SDK/4.6/include" \
-L"/c/Program Files (x86)/Intel/OpenCL SDK/4.6/lib/x86" \
-lOpenCL -static-libgcc -o 出力ファイル名

MinGWでコンパイルできない!

*.clという形でカーネルプログラムをただのテキストファイルとして配置しておいて実行時ビルドする形にしておくのと,C言語のコード側に,

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

を書いておけば,基本的にどのOS,どのプラットフォーム,どのSDKでも動作するコードができるはずなのだが,OSXやLinuxではgccコマンド一発やmakeでコンパイルできていたものが,cmd.exeからコマンドを叩いたMinGWではリンクエラーを起こしてしまう.
(cmd.exeだとLD_LIBRARY_PATHが通らないからか?)

なので,MinGW環境のみ,Code::Blocksをmakeの代わりとして用いてビルドする.

WindowsでのコンパイルにVisual Studioを使う方法なんて当然却下である.
俺はEmacsでコードを書いて(幸い今はOSX, Linux, Windowsすべてで同じEmacsが使える),
Linuxで計算を実行させたいのだ.
計算マシンがWindowsの場合のみ同じコードから実行バイナリを生成したいだけなのである.

Intel OpenCL SDKやAMD APP SDK(Ver.2.9.1まで)だと最初からCode::Blocks+MinGWの環境で使えるlib(OpenCL.lib)が存在するので,SDKとしてはそちらをお勧めする.(ただしAMD APP SDKは3.0.0-Betaからは存在しない模様)

*.dllのみしか存在しない場合には,mingw-utilsのdlltoolを使って作っておく.
dlltoolを使ってlibOpenCL.aを作っておくとスタティックリンクもできる.

このテキストは,OpenCL™ with Code::Blocks tutorialこちらのページを参考にしたものである.

OpenCL用の「Compilerセッティング」

Code::Blocksをインストールしたら,Settings→Compiler.

最初から存在する「GNU GCC Compiler」というCompilerセッティングを「Copy」して,「OpenCL」なり,「OpenCL_Intel_SDK」なり,「OpenCL_NVidia_SDK」なり,「OpenCL_AMD_APP_SDK」なりのCompilerセッティングを作る.

Toolchain executableタブの「Compiler’s installation directory」にMinGWをインストールしてあるパスを指定.

普通にMinGWをインストールするとC:\MinGWに配置されているので,デフォルト設定(もしくはAuto-detect)で問題はないが,ユーザのホームディレクトリの下などにMinGWを配置している場合は,ここで明示的に指定する必要がある.

Linker settingタブのOther linker options欄に,「-lOpenCL」と書き込む.

Search directionsタブのCompilerタブ,「Add」して,使っているOpenCL SDKのincludeディレクトリを入れる.

同じくSearch directionsタブのLinkerタブ,「Add」して,使っているOpenCL SDKのlibディレクトリを入れる.64bitWindows用のSDKを落とした場合,x86_64とx86の二つがあるので,MinGW32の場合はlibディレクトリの中のx86ディレクトリを指定.

プロジェクトを作って既存コードを取り込む

File→New→Projectで,新規プロジェクトを作り,

ここではConsoleアプリを選択して,Go.

Skipはしないで,Next.

CかC++の言語を選択,Next.

プロジェクトの名前と配置する場所を設定して,Next.

先ほど作ったOpenCL用のコンパイラセッティングを選択.

新規プロジェクトができたら,Sourcesの中にある空のmain.cは「Remove file from project」しておく.(プロジェクトから外したら,プロジェクトディレクトリの中から消しても良い)

プロジェクトを右クリック→Add files.

ファイル選択ダイアログが開くので,既に作ってあるOpenCLの「C言語」のファイル一式を選択して開く.
ここではtest6というOSXとLinuxで既に動作実績がある既存のOpenCLプログラムのディレクトリから選択した.

適当にOK.

そうすると,パスなどは適当に処理されて,ソースコードファイル本体もコピーされることなく参照扱いとなり,既存のソースコードファイルをプロジェクトとして扱える.

つまりこの方法では,Code::Blocksのプロジェクトディレクトリは,プロジェクト設定ファイルとBuildセッティングファイル(あとビルド後のexe)を格納する為だけに使われることになる.
(感覚的にはMakefileのターゲットが一つ増えるだけ?)
当然他のマシン,他のOS,他のエディタなどで元のファイルを修正したりすれば,それが反映される.

OSXやLinuxでは同じファイルをmakeやgccコマンドを直接叩いてコンパイルしているしているので,そちらに変更を加えないでよく,かつDropboxなどに放り込んでおけば完全に同期が取れていることになるので,複数のマシン,OSで開発している人間にとっては非常に美しい形となる.

ビルドの設定(Build options)とビルド

プロジェクトを右クリック→Build options.

なぜかここでも,「Compilerセッティング」をした時と同じ,includeとlibの場所,linker optionを指定してやる必要がある.

例によって,Search directionsタブのCompilerタブで「Add」して,SDKのincludeディレクトリを追加.ここでは相対パスで読まれるようだ.

同様にSearch directionタブのLinkerタブで,「Add」して,SDKのlibのディレクトリを指定.

さらに同様に,Linker settingsのOther linker options欄に「-lOpenCL」を追加.

この欄に「-static-libgcc」と「-staticlibstdc++」も加えておくと,MinGWで提供されるCとC++の基本ライブラリがスタティックリンクされるので,MinGWがインストールされていないコンピュータでも動作するようになる.
ただし,C++の基本ライブラリをスタティックリンクすると生成される実行exeファイルが非常に大きくなるので,C言語の機能のみしか使ってない場合は-static-libgccのみで問題ない.

(MinGW独自の.dllが必要な時代って……MinGWの思想に反するんじゃ……)

ここまでできたら,プロジェクトを右クリック→Build.

プロジェクトディレクトリ/bin/Debugの中に,MSYSで実行可能なexeファイルができている.

当然,cmd.exeでも実行可能である.

外部カーネルプログラムファイル*.clを使っているコードの場合は,Buildされたexeファイルを,カーネルプログラムファイルが存在するディレクトリにコピーして実行するか,逆にカーネルプログラムをこのディレクトリに持ってきて実行する.

まとめ

MSYSから,gccコマンド一発でコンパイルできないのは気にくわないが,これで一応,複数のマシン,複数のOSで,エディタを問わず開発できるので,よしとしよう.