Ubuntu 8.10 64bit上ではすべてそのままコンパイルできていますが、Windows Vista 32bit上と、Ubuntu 8.10 32bitではいくつかのプラグインで問題が起こりました。今回はこれらの問題のあったプラグインをどのようにコンパイルしたかについて見ていこうと思います。
○Windows Vista 32bitでの問題
まず、Windowsの方です。ほとんどのプラグインは少し前の記事で書いたVisual C++ 2008 Express Editionでの手順で問題なくコンパイルできるのですが、circdots_rgb、fixnoiseという2つのプラグインではコンパイルエラーが起こります。

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


この状態で、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

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


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


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

この部分の数字がプラグインをコンパイルするときにバイナリファイルの「.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);ver.6
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);
LIBIMPORT float hnoise(float noisesize, float x, float y, float z);util.hの方は、こうなっています。
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);
ver.5
LIBEXPORT void *mallocN(int len, char *str);ver.6
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 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 WIN32ver.6
#ifdef PLUGIN_INTERN
#define LIBEXPORT __declspec(dllexport)
#else
#define LIBEXPORT extern __declspec(dllimport)
#endif
#elif !defined(WIN32)
#define LIBEXPORT extern
#endif
#ifdef WIN32ifdef文では、まずWindowsとそれ以外で処理内容を分けていて、さらに「PLUGIN_INTERN」という定数で処理内容を分けています。
#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
「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);ver.6
int plugin_seq_getversion(void);
void plugin_getinfo(PluginInfo *);
LIBEXPORT int plugin_tex_getversion(void);ここで、plugin_tex_get_version()、plugin_getinfo()は実際にプラグインで使用されていますが、使われていないplugin_seq_getversion()にまでLIBEXPORTを加えているのがエラーの原因のようです。
LIBEXPORT int plugin_seq_getversion(void);
LIBEXPORT void plugin_getinfo(PluginInfo *);
ということで、この部分はこんな感じに修正してみます。
plugin.h line:70-72
LIBEXPORT int plugin_tex_getversion(void);これでエラーが出ずに、コンパイルが完了しました。
int plugin_seq_getversion(void);
LIBEXPORT void plugin_getinfo(PluginInfo *);
Blenderにロードすることもできて、スレッド数:4でレンダリングしてもノイズが出ていないようです。


○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()関数をまるごとコメントアウトした状態でコンパイルすると、正常に動作するようになりました。