2010年4月5日月曜日

OpenCLマスターへの道 - ATI Stream SDK 編 第六話

今回は、サンプルソースを 64bit 版のWin32 コンソールアプリケーションとしてビルドしてみる。

参考にしたドキュメントは、”ATI Stream SDK OpenCL™ Programming Guide (v1.0) [PDF 900 KB]”
このファイルには、以下の手順で たどりつける。

「スタート」メニューから「すべてのプログラム」-「ATI Stream SDK v2」-「ATI Stream SDK Documentation」を選択すると、ブラウザで、「ATI Stream SDK v2.01 Documentation」のページが開く。開いたページのリスト中に上記ファイルがある。

Visual C++ 2008 Express Edition を起動する。

「ファイル」メニューから「新規作成」-「プロジェクト」を選択。


「プロジェクトの種類」から「Win32」を選択する。
「テンプレート」から「Win32 コンソール アプリケーション」を選択する。
「プロジェクト名」に”HelloCL”と入力し、「OK」ボタンを押す。


次に”HelloCL.cpp”ファイルを編集していく。


楽をするために、ATI Stream SDK のサンプルファイルの中身をコピーする作戦でいくことにする。
コピー元は、サンプルをインストールしたディレクトリ以 下”samples\opencl\cpp_cl\app\HelloCL\”の”HelloCL.cpp”と”HelloCL_Kernels.cl” とする。



”HelloCL_Kernels.cl” はそのまま、”HelloCL”プロジェクトのディレクトリにコピーして、既存の項目として「ソースファイル」に追加。

サ ンプルの”HelloCL.cpp”ファイルからインクルード行とmain関数の中身をコピーする。
main 関数の定義部分は、書き換えないことにする。

// HelloCLWin32.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sdkutil/sdkfile.hpp>
#include <sdkutil/sdkcommon.hpp>

#define __NO_STD_VECTOR
#define __NO_STD_STRING

#include <cl cl.hpp>
#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    cl_int err;

    // Platform info
    cl::vector<cl::platform> platforms;
    std::cout<<"HelloCL!\nGetting Platform Information\n";
    err = cl::Platform::get(&platforms);
    if(err != CL_SUCCESS)
    {

<中 略>

    err = queue.finish();
    if (err != CL_SUCCESS) {
        std::cerr << "Event::wait() failed (" << err << ")\n";
    }

    delete pProgram;

    std::cout<<"Done\nPassed!\n";
    return SDK_SUCCESS;
}


上記ソース中で”SDKUtil”を利用している ので、ドキュメントの手順をみると、インクルードファイルとライブラリ指定を追加するだけで大丈夫となっているが、”SDKUtil.lib”なんてどこ にもない。 しかたがないので、ドキュメントの手順は実行しない。


実行しない手順の代わりに、”SDKUtil”をサンプルからプロジェクトごと、新規作成し た”HelloCL”ソリューションの下にコピー。
既存のプロジェクトとして追加。
このままだと、とんでもね~ところにビル ド済みファイルを吐き出すので、以下のように設定を変更。


”SDKUtil”プロジェクトのプロパティを開く。
 「構成プロパティ」-「全般」を選 択。
「出力ディレクトリ」とし て”$(SolutionDir)$(PlatformName)\$(ConfigurationName)”を設定。
「中間ディレクト リ」として”$(PlatformName)\$(ConfigurationName)”を設定。



プロジェクトの依存関係を以下のように設定。
ソリューションのプロパティを開く。
「共 通プロパティ」-「プロジェクト依存関係」を選択。
「プロジェクト」には”HelloCL”を選択。
「依存先」 で”SDKUtil”をチェックして、「OK」ボタンを押す。


次に、OpenCL 本体のヘッダやライブラリに関する追加設定を、ドキュメントの手順で設定する。


”HelloCL”プロジェクトのプロパティを開く。
「構成プロパティ」-「C/C++」 -「全般」を選択。
「追加のインクルード ディレクトリ」に”"$(ATISTREAMSDKSAMPLESROOT)\include";"$(ATISTREAMSDKROOT)\include"” を設定。


「構成プロパティ」-「C/C++」-「プリプロセッサ」を選択。
「プリプロセッサの定 義」に”ATI_OS_WIN”を追加。


「構成プロパティ」-「リンカ」-「全般」を選択。
「追加のライブラリ ディレクトリ」に”$(ATISTREAMSDKROOT)/lib/x86”を追加。


「構成プロパティ」-「リンカ」-「入力」を選択。
「追加の依存ファイル」 に”OpenCL.lib”を追加。
「OK」ボタンを押す。


では、32bit版をビルドしてみる。「ビルド」メニューから「ソリューションのビルド」を選択。


error C2065: 'cl_int' : 定義されていない識別子です。
error C2146: 構文エラー : ';' が、識別子 'err' の前に必要です。
error C2065: 'err' : 定義されていない識別子です。
error C2653: 'cl' : 識別子がクラス名でも名前空間名でもありません。
error C2065: 'vector' : 定義されていない識別子です。
error C2653: 'cl' : 識別子がクラス名でも名前空間名でもありません。
error C2065: 'Platform' : 定義されていない識別子です。
error C2065: 'platforms' : 定義されていない識別子です。
error C2653: 'std' : 識別子がクラス名でも名前空間名でもありません。
error C2065: 'cout' : 定義されていない識別子です。
error C2065: 'err' : 定義されていない識別子です。

<中略>

error C2065: 'cerr' : 定義されていない識別子です。
error C2065: 'err' : 定義されていない識別子です。
error C2065: 'SDK_FAILURE' : 定義されていない識別子です。
error C2065: 'devices' : 定義されていない識別子です。
error C2228: '.size' の左側はクラス、構造体、共用体でなければなりません
        型は ''unknown-type'' です。
error C2653: 'std' : 識別子がクラス名でも名前空間名でもありません。
error C2065: 'cerr' : 定義されていない識別子です。
error C2065: 'SDK_FAILURE' : 定義されていない識別子です。
error C2653: 'std' : 識別子がクラス名でも名前空間名でもありません。
error C2065: 'cout' : 定義されていない識別子です。
fatal error C1003: プログラム内のエラーが 100 個を超えました。コンパイルは中断されます。
ビルドログは "file://e:\work\program\VisualStudio2008\CPProjects\HelloCL\HelloCL\Debug\BuildLog.htm" に保存されました。
HelloCL - エラー 102、警告 8
========== ビルド: 1 正常終了、1 失敗、0 更新不要、0 スキップ ==========


大量にエラーになった。何かが間違っているようだ。
どうやら、#include "stdafx.h" の記述位置が悪いらしい、最初に持ってきてみる。 (そもそもプリコンパイルヘッダについて無知なのでトンチンカンなことをやっているかもしれない)

再びビルド。今度は先ほどとは違うエラーでいっぱいだ・・・



msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string>char,struct std::char_traits>char<,class std::allocator>char< <::size(void)const " (?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ) は既に sdkutil.lib(SDKFile.obj) で定義されています。
msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: __thiscall std::basic_string>char,struct std::char_traits>char<,class std::allocator>char< <::basic_string>char,struct std::char_traits>char<,class std::allocator>char< <(char const *)" (??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z) は既に sdkutil.lib(SDKFile.obj) で定義されています。
msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: void __thiscall std::basic_ios>char,struct std::char_traits>char< <::setstate(int,bool)" (?setstate@?$basic_ios@DU?$char_traits@D@std@@@std@@QAEXH_N@Z) は既に sdkutil.lib(SDKFile.obj) で定義されています。
msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: static bool __cdecl std::char_traits>char<::eq_int_type(int const &,int const &)" (?eq_int_type@?$char_traits@D@std@@SA_NABH0@Z) は既に sdkutil.lib(SDKFile.obj) で定義されています。



とか


libcpmtd.lib(ios.obj) : error LNK2005: "private: static void __cdecl std::ios_base::_Ios_base_dtor(class std::ios_base *)" (?_Ios_base_dtor@ios_base@std@@CAXPAV12@@Z) は既に msvcprtd.lib(MSVCP90D.dll) で定義されています。
libcpmtd.lib(ios.obj) : error LNK2005: "public: static void __cdecl std::ios_base::_Addstd(class std::ios_base *)" (?_Addstd@ios_base@std@@SAXPAV12@@Z) は既に msvcprtd.lib(MSVCP90D.dll) で定義されています。
libcpmtd.lib(locale0.obj) : error LNK2005: "void __cdecl _AtModuleExit(void (__cdecl*)(void))" (?_AtModuleExit@@YAXP6AXXZ@Z) は既に msvcprtd.lib(locale0_implib.obj) で定義されています。
libcpmtd.lib(locale0.obj) : error LNK2005: __Fac_tidy は既に msvcprtd.lib(locale0_implib.obj) で定義されています。


とか


libcpmtd.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::_Lockit(int)" (??0_Lockit@std@@QAE@H@Z) は既に msvcprtd.lib(MSVCP90D.dll) で定義されています。
libcpmtd.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::~_Lockit(void)" (??1_Lockit@std@@QAE@XZ) は既に msvcprtd.lib(MSVCP90D.dll) で定義されています。
LIBCMTD.lib(setlocal.obj) : error LNK2005: __configthreadlocale は既に MSVCRTD.lib(MSVCR90D.dll) で定義されています。
LIBCMTD.lib(dbgheap.obj) : error LNK2005: __CrtSetCheckCount は既に MSVCRTD.lib(MSVCR90D.dll) で定義されています。
LIBCMTD.lib(tidtable.obj) : error LNK2005: __encode_pointer は既に MSVCRTD.lib(MSVCR90D.dll) で定義されています。
LIBCMTD.lib(tidtable.obj) : error LNK2005: __decode_pointer は既に MSVCRTD.lib(MSVCR90D.dll) で定義されています。
LIBCMTD.lib(winxfltr.obj) : error LNK2005: __XcptFilter は既に MSVCRTD.lib(MSVCR90D.dll) で定義されています。



とか


LINK : warning LNK4098: defaultlib 'MSVCRTD' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
LINK : warning LNK4098: defaultlib 'LIBCMTD' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
LIBCMTD.lib(crt0.obj) : error LNK2019: 未解決の外部シンボル _main が関数 ___tmainCRTStartup で参照されました。

HelloCL - エラー 51、警告 2
========== すべてリビルド: 1 正常終了、1 失敗、0 スキップ ==========




まだ設定が足りないらしい、色々調べると以下の手順が足りてないようだ。
この手順は、ドキュメントには書いていない、でもサンプルプロジェクトでは、設定されている。

”HelloCL”プ ロジェクトのプロパティを開く。




「構成のプロパティ」-「C/C++」-「コード生成」を選択。
「ラ ンタイム ライブラリ」を”マルチスレッド デバッグ DLL (/MDd)” から ”マルチスレッド デバッグ (/MTd)”に変更して、「OK」ボタンを押す。(ここらへんについても無知なのでよくわからない)

再びビルドする。


今度はうまくいった。
では、実行してみる。

「デバッグ」メニューから「デバッグなしで開始」を選択



HelloCL!
Getting Platform Information
Platform::get() failed (-1001)
続行するには何かキーを押してください . . .




ありゃ?なんでじゃ?

サンプルプログラムを動かしても、同様の状態・・・なんかオレに恨みでもあんのか?
64bit 対応化騒動で、何か大切なものを無くしてしまったのか?

ATI Stream SDK をインストーラでリペアしてもだめだった。
しかたがないので、ATI Stream SDK をアンインストール後、再びインストールした。サンプルをコンパイルして動作確認。うまくいった。
ようやく、”HelloCL”に戻ってきた。
こっちもビルドして実行。成功!

では、本題の 64bit 版をビルドする。

その前に、”HelloCL”プロジェクトのプロパティを開く。


「構成プロパティ」-「リンカ」-「全般」を選択する。
「追加のライブラリ ディレクトリを”$(ATISTREAMSDKROOT)/lib/x86_64”に変更する。
「OK」ボタンを押す。


「ビルド」メニューの「構成マネージャ」を選択。


”HelloCL”プロジェクトの「プラットフォーム」から”<新規作成>”を選択する。


「新しいプラットフォーム」で”x64”を選択し、「OK」ボタンを押す。
もし”同じ名前のソリューション プラットフォームが既に存在するため、このプラットフォームを作成できませんでした。”と表示される場合は、「キャンセル」ボタンを押して、「構成マネージャ」の「アクティブ ソリューション プラットフォーム」で”<編集>”を選択し、”x64”を削除してから、再びこの手順を行う。

こんな画面になる。
「閉じる」ボタンを押す。

「ビルド」メニューから「ソリューションのビルド」を選択する。
ビルドが成功したら。

「デバッグ」メニューから「デバッグなしで開始」を選択。


HelloCL!
Getting Platform Information
Creating a context AMD platform
Getting device info
Loading and compiling CL source
Running CL program
Done
Passed!
続行するには何かキーを押してください . . .


よし!成功!

長かった・・・丸二日もかかってしまった。

能力不足を再認識・・・欝だ・・・もう寝よう。

というわけで、今回はここまで。