他にも書かないかんかなーと思うとこはたくさんあるのですが、 気分的にこっち書いとこうということになりました。よろしく。
(2001/05/25追記: 途中でやめててもうしわけないっす。 書き足しました)
SDLはmulti-platformなライブラリです。 また、本家の冒頭で 「cross-platform」と書いている通り、 WindowsのライブラリをLinux上で作成する、といったことも可能です。
SDLの配布ファイル(ソースコードのarchive file)は、Windows用、Linux用、 といったように分かれておらず、すべて共通(例: SDL-1.2.0.tar.gz)です。 配布ファイルの中にはサポートしているすべての環境に対するコードが入っています。
それらのコードの多くの部分は、あなたが今使っている 環境(マシン、OS、インストールされているパッケージなど)と 違う環境向けに書かれたコードですので、コンパイルに失敗するかもしれませんし、 コンパイルが通ってもリンクでエラーが起きるかもしれません。 いずれにしても不要なコード、あるいは、別の環境では必要になるんだけど、 ここでは含まれてはいけないコードが 含まれています。
そのため、buildの前段階で、この環境(コンパイルする環境、 ターゲットとなる環境)で、どれが必要で、どれが不要かということを 調べる作業をする必要があります。
他の多くのソフトと同様に、 SDLは、この作業のためにautomake/autoconf/libtoolといったツールを 利用しています。それって何?という方は、 shimakiさんの ページや、 この本などを 読んでみてください。
SDLは、configureというスクリプトで、buildする環境に 関する情報、たとえば、どのようなOSなのか、 どんなパッケージがインストールされているか、などを調べます。 このconfigureスクリプトを手軽に生成するためのツールがautoconfです。
configureはその内容にしたがってMakefile.in からMakefileを生成します。 このMakefile.inを手軽に生成するためのツールがautomakeです。
libtoolはとりあえず略...
SDLソースのディレクトリ構造の図です。
手抜きでスマンクス(^^; これを見ますと、audio、cdrom、endian、events...
といった、SDL introで
見慣れた機能が並んでいて、その下に環境ごとにディレクトリが掘られている
様子が分かります。
今回はaudioを例にとって、
zinnia@iguchi:~/build/SDL/SDL-1.2.0/src/audio[10]% \ls -ARF Makefile.am SDL_sysaudio.h macrom/ Makefile.in SDL_wave.c nas/ SDL_audio.c SDL_wave.h nto/ SDL_audio_c.h alsa/ paudio/ SDL_audiocvt.c arts/ sun/ SDL_audiodev.c baudio/ ums/ SDL_audiodev_c.h dma/ windib/ SDL_audiomem.c dmedia/ windx5/ SDL_audiomem.h dsp/ SDL_mixer.c esd/ ./alsa: Makefile.am SDL_alsa_audio.c Makefile.in SDL_alsa_audio.h ./arts: Makefile.am SDL_artsaudio.c Makefile.in SDL_artsaudio.h ./baudio: Makefile.am Makefile.in SDL_beaudio.cc SDL_beaudio.h ./dma: Makefile.am Makefile.in SDL_dmaaudio.c SDL_dmaaudio.h ./dmedia: Makefile.am SDL_irixaudio.c Makefile.in SDL_irixaudio.h ./dsp: Makefile.am Makefile.in SDL_dspaudio.c SDL_dspaudio.h ./esd: Makefile.am Makefile.in SDL_esdaudio.c SDL_esdaudio.h ./macrom: Makefile.am Makefile.in SDL_romaudio.c SDL_romaudio.h ./nas: Makefile.am Makefile.in SDL_nasaudio.c SDL_nasaudio.h ./nto: Makefile.am SDL_nto_audio.c Makefile.in SDL_nto_audio.h ./paudio: Makefile.am Makefile.in SDL_paudio.c SDL_paudio.h ./sun: Makefile.am Makefile.in SDL_sunaudio.c SDL_sunaudio.h ./ums: Makefile.am Makefile.in SDL_umsaudio.c SDL_umsaudio.h ./windib: Makefile.am Makefile.in SDL_dibaudio.c SDL_dibaudio.h ./windx5: Makefile.am Makefile.in SDL_dx5audio.c SDL_dx5audio.h
src/audio以下のディレクトリは こんな感じになっています。 これ見て分かるのは
configureをしますと、各featureごとにその存在チェックを行います。 --disable-feature(または--enable-feature=no)することでこの チェックをスキップすることができます。
nas(Network Audio System)を例にとってconfigureの該当部分を眺めてみましょ う。
CheckNAS() { # Check whether --enable-nas or --disable-nas was given. if test "${enable_nas+set}" = set; then enableval="$enable_nas" : else enable_nas=yes fi if test x$enable_audio = xyes -a x$enable_nas = xyes; then echo $ac_n "checking for NAS audio support""... $ac_c" 1>&6 echo "configure:3788: checking for NAS audio support" >&5 have_nas=no if test -r /usr/X11R6/include/audio/audiolib.h ; then have_nas=yes fi echo "$ac_t""$have_nas" 1>&6 if test x$have_nas = xyes; then CFLAGS="$CFLAGS -DNAS_SUPPORT" SYSTEM_LIBS="$SYSTEM_LIBS -laudio -lXt" AUDIO_SUBDIRS="$AUDIO_SUBDIRS nas" AUDIO_DRIVERS="$AUDIO_DRIVERS nas/libaudio_nas.la" fi fi }おおざっぱに眺めてゆきますと
CFLAGSの方は、まあ、条件コンパイルのフラグっぽいということで よいのですが、AUDIO_{SUBDIRS,DRIVERS}は何者でしょうか? とりあえずこれを調べてみることにしましょう。
とりあえずgrepかけてみますか...
(zsh user only) zinnia@iguchi:~/build/SDL/SDL-1.2.0[44]% grep -l AUDIO_SUBDIRS **/* Makefile.in configure configure.in docs/Makefile.in docs/html/Makefile.in docs/man3/Makefile.in include/Makefile.in src/Makefile.in src/audio/Makefile.am src/audio/Makefile.in src/audio/alsa/Makefile.in src/audio/arts/Makefile.in src/audio/baudio/Makefile.in src/audio/dma/Makefile.in src/audio/dmedia/Makefile.in src/audio/dsp/Makefile.in src/audio/esd/Makefile.in src/audio/macrom/Makefile.in src/audio/nas/Makefile.in (中略) src/video/wincommon/Makefile.in src/video/windib/Makefile.in src/video/windx5/Makefile.in src/video/x11/Makefile.inうーん、かなりの量のファイルがヒットしました。が、ほぼすべてが Makefile関係のようですね。 Makefile.inはMakefile.amの生成物ですから...
zinnia@iguchi:~/build/SDL/SDL-1.2.0[46]% grep -l AUDIO_SUBDIRS **/* | grep -v Makefile.in$ configure configure.in src/audio/Makefile.amふむふむ。 src/audio/Makefile.amを見てみることにしましょう。
## Makefile.am for the SDL audio library noinst_LTLIBRARIES = libaudio.la # Define which subdirectories need to be built SUBDIRS = @AUDIO_SUBDIRS@ DIST_SUBDIRS = alsa arts baudio dma dmedia dsp esd macrom nas nto \ paudio sun ums windib windx5 DRIVERS = @AUDIO_DRIVERS@ # Include the architecture-independent sources COMMON_SRCS = \ SDL_audio.c \ SDL_audio_c.h \ SDL_audiocvt.c \ SDL_audiodev.c \ SDL_audiodev_c.h \ SDL_audiomem.c \ SDL_audiomem.h \ SDL_mixer.c \ SDL_sysaudio.h \ SDL_wave.c \ SDL_wave.h libaudio_la_SOURCES = $(COMMON_SRCS) libaudio_la_LIBADD = $(DRIVERS) libaudio_la_DEPENDENCIES = $(DRIVERS)automakeの細かいことはおいといて、意図を掴むように努力してみましょうか。
AUDIO_DRIVERS = dsp/libaudio_dsp.la dma/libaudio_dma.la arts/libaudio_arts.la esd/libaudio_esd.la nas/libaudio_nas.la AUDIO_SUBDIRS = dsp dma arts esd nasMakefileの動きとしては、SUBDIRSのそれぞれについてmakeをするというような 理解でよろしいかと思います。そんなこんなで、 AUDIO_{SUBDIRS,DRIVERS}に出てこないサブディレクトリは そもそもコンパイル/リンクの対象にならなさそうだということが 想像できましたでしょうか?
makeまでの手順はだいたい想像がつきました。 では実際にコードがどんなふうになっているのか、いよいよ見てみることに しましょう。configureのときに出てきた-DNAS_SUPPORTを手がかりにします。
zinnia@iguchi:~/build/SDL/SDL-1.2.0/src/audio[66]% grep NAS_SUPPORT **/* SDL_audio.c:#ifdef NAS_SUPPORT SDL_sysaudio.h:#ifdef NAS_SUPPORTおや、思ったより少ない。では該当部分を眺めてみます。
(SDL_audio.c) #ifdef NAS_SUPPORT &NAS_bootstrap, #endif (SDL_sysaudio.h) #ifdef NAS_SUPPORT extern AudioBootStrap NAS_bootstrap; #endif該当部分はこれだけでした。 どうもNAS_bootstrapというGlobal変数(AudioBootStrap構造体)が キーのようです。
AudioBootStrap構造体の定義は、 SDL_sysaudio.hの、 さきほど見た場所のすぐ上にあります。
typedef struct AudioBootStrap { const char *name; const char *desc; int (*available)(void); SDL_AudioDevice *(*create)(int devindex); } AudioBootStrap;2つのconst charへのポインタ、2つの関数へのポインタを持つ構造体の ようです。見た感じ、名前、説明、チェック用関数、???といった 気がします。 最後の関数createは、 SDL_AudioDeviceへのポインタを返す関数(引数はint1つ)へのポインタ ということになりそうです。 SDL_AudioDeviceの定義は、AudioBootStrapのすぐ上にあります(うーん楽な展開) ちょっとでかいので引用はひかえます。中身を見てみると、 OpenAudio、InitAudio、PlayAudioといった名前の(関数への)ポインタが あったり、enabled、paused、openedといったint変数があったりで、 どうもdeviceの内部状態へのアクセス手段を提供するもののように 見えます。
ここまでの話をまとめます。
さてさて。では実際にNAS_bootstrapというものは どういう中身を持つのか調べてみましょう。
zinnia@iguchi:~/build/SDL/SDL-1.2.0/src/audio[67]% grep -l NAS_bootstrap **/* SDL_audio.c SDL_sysaudio.h nas/SDL_nasaudio.c上の2つは先程見たものですからいいですね。というわけで nas/SDL_nasaudio.cを見ることにします。
AudioBootStrap NAS_bootstrap = { NAS_DRIVER_NAME, "Network Audio System", Audio_Available, Audio_CreateDevice };先程のAudioBootStrapの定義とてらしあわせてみますと、
static int Audio_Available(void) { AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); if (!aud) return 0; AuCloseServer(aud); return 1; }AuOpenServer/AuCloseServerというのはnasのAPIという理解でよいでしょう。 実際に起動できるかどうかのチェックをして、失敗したら0、 成功したら1を返す。というわけで、名前の通り利用可能かどうかの チェックをする関数のようです。
続いてAudio_CreateDeviceです。 中身を見てみると、おおざっぱに言ってSDL_AudioDeviceのセッティングを行い、 それを返す関数と言ってよいようですね。
/* Set the function pointers */ this->OpenAudio = NAS_OpenAudio; this->WaitAudio = NAS_WaitAudio; this->PlayAudio = NAS_PlayAudio; this->GetAudioBuf = NAS_GetAudioBuf; this->CloseAudio = NAS_CloseAudio; this->free = Audio_DeleteDevice; return this;最後の方だけ引用してみました。thisは(現在セットアップ中の) SDL_AudioDevice構造体へのポインタです。 しかしthisを変数名として使うのはいかがなものか...
こんなふうにして、SDL_AudioDeviceに、nas(src/audio/nas)向けのルーチンを 登録して上流(src/audio)に返してやるというのが、 個々のdeviceの仕事のすべてです。
ここで上でリンクした関数がいずれもstaticで宣言されていることに とりあえず注目しておきましょう。 これらの関数は外から直接呼ばれるのではなく、 SDL_AudioDevice構造体経由で呼ばれます。 構造体にアドレスを登録できればそれでいいわけで、外部に公開する 必要はないわけです。staticにすることで、 SDL_nasaudio_Audio_Availableみたいに 名前が衝突しないようにする気遣いも不要になり、コードの使いまわしが 楽になりそうーという利点もあります。
いろいろと眺めてみましたが、ここまでの結果をまとめておきましょう。 なお、ここでは「推測」や「想像」などがまじっていることを おことわりしておきます(ここまで読んできた方には先刻承知でしょうが)。 疑わしいと思ったらコードを確認するようにしてみてください。
これが各deviceに視点を向けて、コードを追いかけたときの様子です。 SDL本体としては、個々のdeviceに対して直接働きかけるのではなく、 かならずSDL_AudioDeviceのポインタ経由で触りにゆくのだ、ということも おわかりいただけたと思います。そのため、新しいdeviceのサポートを したいときは、SDL_AudioDeviceで要求されているmethodを実装してやれば、 全体としての構造をいじる必要はないということになります(SDL_audio.cに 定義を追加する必要はありますが)
では、そうやって作られたAudioBootStrap、SDL_AudioDeviceは 実際にどのように使われてゆくのでしょうか? というのが 次回のネタになる予定です。
いきなり息切れ中。感想とかいただけるととても喜びます。 変なところや説明が不十分なとこなども是非ご指摘ください。 わかりづらいとか無駄なことはやめろとかでも涙を飲みつつ 粛々と読ませていただきます。ではまた。