2009年03月28日

テクスチャプラグインのLCCでのコンパイル

前回、プラグインリポジトリのソースファイルを修正して、マルチスレッドレンダリングに対応するようにしてみました。
Ubuntu 8.10 64bit上ではすべてそのままコンパイルできていますが、Windows Vista 32bit上と、Ubuntu 8.10 32bitではいくつかのプラグインで問題が起こりました。今回はこれらの問題のあったプラグインをどのようにコンパイルしたかについて見ていこうと思います。

○Windows Vista 32bitでの問題
まず、Windowsの方です。ほとんどのプラグインは少し前の記事で書いたVisual C++ 2008 Express Editionでの手順で問題なくコンパイルできるのですが、circdots_rgb、fixnoiseという2つのプラグインではコンパイルエラーが起こります。
pic090327_01.jpg

circdots_rgb.c
   ライブラリ circdots_rgb.lib とオブジェクト circdots_rgb.exp を作成中
circdots_rgb.obj : error LNK2019: 未解決の外部シンボル _roundf が関数 _punkt_abstand で参照されました。
circdots_rgb.dll : fatal error LNK1120: 外部参照 1 が未解決です。

fixnoise.c
   ライブラリ fixnoise.lib とオブジェクト fixnoise.exp を作成中
fixnoise.obj : error LNK2019: 未解決の外部シンボル _srandom が関数 _plugin_initで参照されました。
fixnoise.dll : fatal error LNK1120: 外部参照 1 が未解決です。

エラーの内容はこんな感じです。それぞれソースコードの中で使われている「roundf()」「srandom()」という関数が問題になっているようです。これらのソースファイルは、roundf()またはsrand()が「math.h」の中で定義されていることが前提で書かれていますが、Visual C++ 2008でインクルードされるmath.hにはこれらの関数が見当たりません。

このような場合、他にも対応する方法があると思いますが、私は別のコンパイラでコンパイルすることで、とりあえずこの問題を回避しました。もともと、Blender.orgのプラグインの解説ページでは、LCCというコンパイラを使うようにすすめています。

このLCCというコンパイラを使ってテクスチャプラグインのコンパイルを行う場合、Blenderが用意しているhnoise()などの関数を使っていると、プラグインがうまく動作しません。(追記:以下の手順でコンパイルする場合、についての話です。リンクの仕方とかを工夫することでなんとかできるのかもしれません。)
また、古いBlenderに付属する「plugins」フォルダにあるインクルードファイルであればそのままでコンパイルできるのですが、最新版の「plugins」フォルダのものを使うとコンパイル時にエラーが出ます。

ちなみに、LCCコンパイラを使うためには、インストールを行った後でLCCの実行ファイルのある場所「C:\lcc\bin」をOSの環境変数「path」に追加する必要があります。
また、プラグインのDLLファイルがエクスポートするシンボル定義ファイル「tex.def」というファイルを用意する必要があります。こちらは上記のプラグインの解説ページにも書かれていますが、
EXPORTS
LibMain@12
plugin_but_changed
plugin_getinfo
plugin_init
plugin_tex_doit
plugin_tex_getversion
これだけの内容の普通のテキストファイルとなります。

ここから先は、以下のような状況を想定して話を進めていきます。
  1. Blender2.48aの「plugins」フォルダを「C:\blender」というフォルダにコピーします。
  2. 前回用意した修正済みの「circdots_rgb.c」「fixnoise.c」をその中の「texture」フォルダに入れます。
  3. 上記のtex.defファイルを「include」フォルダに置きます。
pic090327_06.jpg pic090327_04.jpg

この状態で、LCCを使用してプラグインをコンパイルするには、コマンドプロンプトから以下のようにコマンドを実行します。

cd \blender\plugins\texture
lcc -Ic:\blender\plugins\include circdots_rgb.c
lcclnk -dll -nounderscores circdots_rgb.obj c:\blender\plugins\include\tex.def

そうすると、いくつかのエラーが表示されます。
Specified export _callocN is not defined
Specified export _callocT is not defined
Specified export _freeN is not defined
Specified export _freeT is not defined
Specified export _mallocN is not defined
Specified export _mallocT is not defined
Specified export _plugin_seq_getversion is not defined

pic090327_05.jpg

この状態でも「circdots_rgb.dll」が作成されますが、Blenderにロードしようとするとエラーが出ます。
pic090327_07.jpg pic090327_08.jpg

同じことを古いバージョンのBlenderの「plugins」フォルダで行えば、エラーが出ずにDLLファイルができます。Blenderにも当然のように正常にロードできます。
pic090327_09.jpg pic090327_10.jpg

ここで、ちょっとBlenderのプラグインのバージョンについての補足です。「plugins」-「include」フォルダの中の「plugin.h」の39行目を見ると、
#define B_PLUGIN_VERSION    6
と書かれています。
pic090327_13.jpg

この部分の数字がプラグインをコンパイルするときにバイナリファイルの「.so」「.dll」ファイルの中に保持されることで、Blenderはプラグインのバージョンを識別しているようです。
Blenderの過去のバージョンのplugin.hを調べてみると、プラグインのバージョンとBlenderのバージョンとの対応は、以下のようになります。

ver.3    2.40 - 2.42
ver.5    2.43 - 2.45
ver.6    2.46 - 2.48

エラーが出るようになったのは「ver.6」以降からのようで、Blender 2.46以降では「plugins」-「include」フォルダの中のヘッダファイルに、どこか問題がありそうな感じです。
エラーの内容を見ると、callcN()、freeN()など、プラグインから利用できるようにBlenderが用意している関数名が並んでいますが、hnoise()、turbulence()などの関数の名前はありません。「include」フォルダの中で、これらのエラーの出ている関数名が記述されているのは「util.h」、一方のhnoise()、turbulence()については「plugin.h」です。

plugin.hの中の記述は、こうなっています。
ver.5
LIBEXPORT float hnoise(float noisesize, float x, float y, float z);
LIBEXPORT float hnoisep(float noisesize, float x, float y, float z);
LIBEXPORT float turbulence(float noisesize, float x, float y, float z, int depth);
LIBEXPORT float turbulence1(float noisesize, float x, float y, float z, int depth);
ver.6
LIBIMPORT float hnoise(float noisesize, float x, float y, float z);
LIBIMPORT float hnoisep(float noisesize, float x, float y, float z);
LIBIMPORT float turbulence(float noisesize, float x, float y, float z, int depth);
LIBIMPORT float turbulence1(float noisesize, float x, float y, float z, int depth);
util.hの方は、こうなっています。
ver.5
LIBEXPORT          void *mallocN(int len, char *str);
LIBEXPORT          void *callocN(int len, char *str);
LIBEXPORT          short freeN(void *vmemh);  
LIBEXPORT          void *mallocT(int len, char *str);
LIBEXPORT          void *callocT(int len, char *str);
LIBEXPORT          void freeT(void *vmemh);  
ver.6
LIBEXPORT          void *mallocN(int len, char *str);
LIBEXPORT          void *callocN(int len, char *str);
LIBEXPORT          short freeN(void *vmemh);  
LIBEXPORT          void *mallocT(int len, char *str);
LIBEXPORT          void *callocT(int len, char *str);
LIBEXPORT          void freeT(void *vmemh);  
コメント、スペースなどを省略した上、行頭のマクロの部分を色分けして強調してみました。
LIBEXPORT、LIBIMPORTというのは「externdef.h」で定義されているマクロで、プラグインのver.5とver.6とで内容は以下のように変わっています。
ver.5
#ifdef WIN32
 #ifdef PLUGIN_INTERN
  #define LIBEXPORT    __declspec(dllexport)
 #else
  #define LIBEXPORT    extern __declspec(dllimport)
 #endif
#elif !defined(WIN32)
    #define LIBEXPORT extern
#endif
ver.6
#ifdef WIN32
 #ifdef PLUGIN_INTERN
  #define LIBEXPORT    __declspec(dllexport)
  #define LIBIMPORT    __declspec(dllexport)

 #else
  #define LIBEXPORT    __declspec(dllexport)
  #define LIBIMPORT    extern __declspec(dllimport)
 #endif
#elif !defined(WIN32)
    #define LIBEXPORT extern
    #define LIBIMPORT extern

#endif
ifdef文では、まずWindowsとそれ以外で処理内容を分けていて、さらに「PLUGIN_INTERN」という定数で処理内容を分けています。
「plugins」-「include」にあるヘッダファイルは、プラグインの作成時に使用していますが、Blender本体の方でプラグインを処理する部分でも同じ内容のものが使われています。
「PLUGIN_INTERN」はそのどちらかを区別するのに使われていますが、プラグイン作成時には「else」以下の方が有効となるようです。

これを見ると、ver.5ではLIBEXPORTのみだったものがLIBIMPORT、LIBEXPORTの2種類に分けて処理されるようになったようです。そして、マクロがどのように展開されるのかを見ると、

Blenderが公開している関数をプラグインが使うための記述:LIBIMPORT
プラグインが公開している関数をBlenderが使うための記述:LIBEXPORT

ということだと思います。
以上のことから、「util.h」のLIBEXPORTをLIBIMPORTに修正してみます。
util.h line:94-101
LIBIMPORT          void *mallocN(int len, char *str);
LIBIMPORT          void *callocN(int len, char *str);
LIBIMPORT          short freeN(void *vmemh);  

LIBIMPORT          void *mallocT(int len, char *str);
LIBIMPORT          void *callocT(int len, char *str);
LIBIMPORT          void freeT(void *vmemh);  

コンパイル時に表示されたエラーの最後には、plugin_seq_getversion()関数についてのエラーも表示されていました。この関数については、plugin.hの70行目あたりに記述があります。
ver.5
int plugin_tex_getversion(void);
int plugin_seq_getversion(void);
void plugin_getinfo(PluginInfo *);
ver.6
LIBEXPORT int plugin_tex_getversion(void);
LIBEXPORT int plugin_seq_getversion(void);
LIBEXPORT void plugin_getinfo(PluginInfo *);
ここで、plugin_tex_get_version()、plugin_getinfo()は実際にプラグインで使用されていますが、使われていないplugin_seq_getversion()にまでLIBEXPORTを加えているのがエラーの原因のようです。

ということで、この部分はこんな感じに修正してみます。
plugin.h line:70-72
LIBEXPORT int plugin_tex_getversion(void);
int plugin_seq_getversion(void);
LIBEXPORT void plugin_getinfo(PluginInfo *);
これでエラーが出ずに、コンパイルが完了しました。
Blenderにロードすることもできて、スレッド数:4でレンダリングしてもノイズが出ていないようです。
pic090327_11.jpg pic090327_12.jpg


○Ubuntu 8.10 32bitでの問題

Ubuntu 8.10 32bitで問題があったプラグインですが、こちらはsarah0というプラグインです。普通にコンパイルできたのですが、Blenderにロードすることができませんでした。マルチスレッドレンダリング対応に修正していないものでも同じようにBlenderにロードできない「.so」ファイルができてしまいます。
ldコマンドで調べてみると、
mato@ubuntu:~/programing/pr_245/texture$ ld sarah0.so
ld: warning: cannot find entry symbol _start; not setting start address
sarah0.so: undefined reference to `__stack_chk_fail_local'
sarah0.so: undefined reference to `sqrt'
sarah0.so: undefined reference to `__fprintf_chk'
sarah0.so: undefined reference to `fflush'
sarah0.so: undefined reference to `turbulence'
sarah0.so: undefined reference to `__strncat_chk'
sarah0.so: undefined reference to `turbulence1'
sarah0.so: undefined reference to `hnoise'
sarah0.so: undefined reference to `fopen'
sarah0.so: undefined reference to `fclose'
sarah0.so: undefined reference to `fputc'
sarah0.so: undefined reference to `fwrite'
sarah0.so: undefined reference to `floorf'
sarah0.so: undefined reference to `hnoisep'

というように表示されました。
プラグインリポジトリからダウンロードしたバイナリファイルでは、
mato@ubuntu:~/Download/blender/plugin$ ld sarah0.Linux.so
ld: warning: cannot find entry symbol _start; not setting start address
sarah0.Linux.so: undefined reference to `sqrt'
sarah0.Linux.so: undefined reference to `floor'
sarah0.Linux.so: undefined reference to `fflush'
sarah0.Linux.so: undefined reference to `turbulence'
sarah0.Linux.so: undefined reference to `turbulence1'
sarah0.Linux.so: undefined reference to `fprintf'
sarah0.Linux.so: undefined reference to `hnoise'
sarah0.Linux.so: undefined reference to `strncat'
sarah0.Linux.so: undefined reference to `fopen'
sarah0.Linux.so: undefined reference to `memset'
sarah0.Linux.so: undefined reference to `fclose'
sarah0.Linux.so: undefined reference to `fputc'
sarah0.Linux.so: undefined reference to `fwrite'
sarah0.Linux.so: undefined reference to `hnoisep'

このように表示されます。
fprintf()、strncat()などの関数で問題が起こっているようですが、そもそもテクスチャプラグインではテキスト処理の関数は必要なさそうです。sarah0プラグインではsarah0.c以外に、2つのヘッダファイルsarahplugins.h、sarahutil.hが使われています。このうち、sarahutil.hの中にプラグインの動作をデバッグするための関数debug_log_inputs()があり、fprintf()、strncat()はそこでだけ使われているようです。
デバッグ用の関数はとりあえずなくてもOKということで、debug_log_inputs()関数をまるごとコメントアウトした状態でコンパイルすると、正常に動作するようになりました。
posted by mato at 00:37| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。