$Id: imakeuse,v 2.1 2001-06-22 22:40:18+09 kabe Exp $ 弱点 cons 違うディレクトリにソースがある場合、デフォルトの Imake.rulesなどだけでは対応できない。 (Implict rulesがデフォルトのためか、$*.c 以外の コンパイルコマンドがない) WnnではWnnSpecialObjectRuleを定義していた。 (これはmakeの弱点) Makefile中のmakeマクロはMakefileの中でしかつかえない。 たとえば変換用のスクリプトなどにmakeマクロを渡そうとすると 大騒ぎになる。(setenvするのかな…) -DUseInstalled: すでにインストールされているXを使う。例えば、 depend:: を作る時、makedepend を作るかどうかを指定する。 (指定のないときは depend:: makedepend になる) われわれが imake を使う時はすでに makedepend は インストールされてるので、-DUseInstalled を指定する。 ほかにも -I フラグの中身が微妙に変化したりする。 (cf. Imake.rules) ================================================================= Imake.tmpl order tmpl デフォルトのImake.tmpl(R5)では、 *.cf の読み込み の読み込み (host.defがあればこれも) 機種別のMacroIncludeFileの判別(R6ではImake.cfに追いだしてある) HasVForkとかHasPutenv とかのソース内部での切替えに必要な定義 CcCmd,RmCmd などで*.cfやsite.defで定義されてなかったものの定義 $(CC) やら $(MV) やらのコマンド定義 $(CFLAGS)やら$(LDLIBS)などの定義 Project.tmpl,Imake.rulesの読み込み Imakefileの読み込み すべてのImakefileに追加したいターゲットの宣言 がある。 X11R6.3では BeforeVendorCF: AfterVendorCF: Has*,Need* , *Flags , *Cmd ... MANDIR, CC ... (ProjectRulesFile,LocalRulesFile) (ProjectTmplFile,LocalTmplFile) -><*Lib.tmpl> 共通ターゲット **** Project{Rules,Tmpl}FileはR6.3にしかない。 **** 自前のImake.tmplを書く時 #define XCOMM # #include #include INCLUDE_IMAKEFILE は最低必要であろう。 Imake.tmpl order tmpl 読み込みの順番(R6): Imake.tmpl Imake.cf site.def (-DBeforeVendorCF) MacroIncludeFile (のこと;Imake.cfで定義) (あれば) ほかの*.cf, *Lib.rules など site.def (-DAfterVendorCF) host.def (使うには要site.def書き換え) Imake.rules LocalRulesFile (未定義なら) Project.tmpl ShLibIncludeFile ( *Lib.tmpl; *Lib.rulesで設定 ) LocalTmplFile (未定義なら) INCLUDE_IMAKEFILE () Library.tmpl (ライブラリ構築の場合; -DLibName=...) (R5)上の方にも書いてあるが、 Imake.tmpl site.def (-DBeforeVendorCF) MacroIncludeFile (;Imake.tmplで定義) site.def (-DAfterVendorCF) Project.tmpl Imake.rules INCLUDE_IMAKEFILE ・R6ではImake.tmplを肥大化させていた機種ごとの MacroIncludeFile,MacroFile,*ArchitectureをImake.cfに分けてある。 ・R6ではImake.rulesをProject.tmplの前に読む。影響はないはず ・R6ではLocalRulesFile,LocalTmplFileが新設され、.rulesや.tmplの 追加ができるようになった。(→custom tmpl) ・R6.3ではProjectRulesFile,ProjectTmplFileが新設された。 ProjectRulesFile->LocalRulesFile->ProjectTmplFile->LocalTmplFile と読まれる。デフォルトではProjectRulesFile==X11.rules, ProjectTmplFile==X11.tmpl Project.tmplは廃止->X11.tmpl Imake.tmplとProject.tmpl 普通にimakeを使うとMakefileには大量のX関係の定義がされるが、 これらにはImake.tmplにはいっておらず、Project.tmplにある。 R6.0以降ではX関係はX11.tmplに分離された。 ユーザーによる全Imakefileに共通のLocal.tmpl custom tmpl 一番簡単なのは #include <../config/Local.tmpl> を 各Imakefileに書くことだが、階層が深くなるとカッコ悪くなるし、 ディレクトリを移動すると面倒。 1)全Imakefile で #include を有効にする方法: i) TOP/config/Local.tmpl として置くとする。 ii) Local.tmpl にて、IMAKE_CMDを -I TOP/config がつくように書き換える。 ここでのTOPとは最初にxmkmfを起動するディレクトリのことと思って良い。 この方法はIMAKE_CMDをvendor.cfで独自に書き換えているような OSではそのままでは使用できない(Win32,OS/2)。 下の例は -DUseInstalled の検出をしていない。検出が必要なら リストの長さは倍になる。 ==================== XCOMM XCOMM Local.tmpl XCOMM /* can be . */ LOCALCONFIGDIR = $(TOP)/config #if ProjectX > 5 #ifdef ClearmakeOSName /*R6.1 R6.3*/ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IMAKEPREFIX)$(LOCALCONFIGDIR) -I$(IRULESRC) $(IMAKE_DEFINES) #else /*R6.0 !R6.[13]*/ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$${imakeprefix}$(LOCALCONFIGDIR) -I$(IRULESRC) $(IMAKE_DEFINES) #endif #else /*R5*/ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$${imaketop}$(LOCALCONFIGDIR) -I$(IRULESRC) $(IMAKE_DEFINES) /*NEWS-OS[46]; also works for MIT*/ /*IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(NEWTOP)$(LOCALCONFIGDIR) -I$(IRULESRC) $(IMAKE_DEFINES) /*MIT R5*/ #endif ==================== * 6.1以降と6.0での違いは、6.0が子ディレクトリへcdしてから ImakeSubCmdHelper(==IMAKE_CMD)を直接駆動しているのにくらべ、 6.1では 親ディレクトリから $(MAKE) $$i/Makefile を行なうため。 (6.1では一旦makeを経由するため $(IMAKEFREFIX)なるmake変数が使える) * NEWS-OSのXはR5のはずだがMakeMakeSubdirsはR5とR6.0の中間の ようなコード(実際rcsidは最終のR5-fix03より後)であり、 NEWTOPが使えない。気持ち悪ければ #ifdef ImakeSubCmdHelper で切替える。(NEWSではdefined) 他に必要な定義もLocal.tmplに書き加える。 iii) bootstrapにはxmkmfが使えない。 % imake -DUseInstalled -I./config -I/usr/local/X11R6/lib/X11/config とする。ただし Local.tmpl が TOP/ 直下にある場合は xmkmf でも 初期化できる。(-I.は常につくため) TOP/Local.tmplとしておくなら上のLOCALCONFIGDIRも . に変更すること。 bootstrapを自動化したければ make World を作ることになるが、 /usr/local/X11R6/の部分はいづれにしてもインストール者に 記入してもらうことになる。 * ImakeSubCmdHelperの再定義でmake Makefilesの対策はできるが、 make Makefile (のみ)は IMAKE_CMD を直接使っているのでどのみち IMAKE_CMDの入れ換えは必要。 (BuildMakefileTarget()をImakeSubCmdHelperを使うよう 再定義してしまう手もある) 2) R6.0 以降なら LocalTmplRules, LocalTmplFile が使えるので これを活用する: (vendor.cfですでに使われているとちょっと面倒;IRIX) この方法なら個別のImakefileでの#includeは不要。 LocalTmpl*は本来 site.def で定義するもの?なので、 若干細工をして有効にする。 すでに site.def等でLocalTmpl* が活用されているのであれば この方法は使えない。I)site.def をまるごとコピーしてきてちょっといじる、 II) -Tオプションで Imake.tmpl を入れ換える、の二つがある。 I) site.def を使う: I.i) config/site.def に 既存のsite.defをコピーしてくる。 I.ii) 末尾に #define LocalTmplFile を追加。 (AfterVendorCFの中) I.iii) Local.tmpl, bootstrap は上と同じ。 ううむ、site.defに直接#includeを書くのとどう違うんだ? →IMAKE_CMDの定義が無効になる(Imake.tmplでのものが後に来るから) II) Imake.tmpl を置換: こちらの方がsite.defがいらない分 移植性があるが、 bootstrapが面倒。xmkmfはどうやっても使えない。 II.i) config/Top.tmplとして ======================= XCOMM XCOMM Top.tmpl XCOMM #define LocalTmplFile #include ======================= II.ii) Local.tmpl ではIMAKE_CMDに -T Top.tmpl を追加。 II.iii) bootstrapは % imake -DUseInstalled -T Top.tmpl -I./config -I/usr/local/X11R6/lib/X11/config -T Top.tmpl があるので、TOP/Local.tmplとしていてもxmkmfは使えない。 1)2)いづれでもbootstrap後は make Makefile でTOPのMakefileを更新できる。 簡単なチェックはmake Makefile; make MakefileでMakefileがちゃんと Local.tmplを読み込んでいるか確認する。 直接#include ではなく、LocalTmplFileを定義することにより、 Imake.tmplの後でImakefileの前というタイミングでLocal.tmplを 挿入することができる。R5にはこの機能がないので全Imakefileに 個別に#includeを書くか、Project.tmpl乗っとりの形をとる。 ================================================================= locallibsとsyslibs todo ……違いが良くわからない。 locallibs $(LDLIBS) syslibs という順番が重要なのか? DEFINES -D DEFINES= は個別のImakefileで設定してよい。のかな? →よい。R6.3のREADMEにある。 INSTALLFLAGS todo どこでいじるのが正解なのかよくわからない。 (site.def? Imakefile?) インストール時にへんなフラグを使いたい時は Install*Flagsを使う。 でもプロジェクトに共通するフラグはどこにいれるんだろう。(-o wnnとか) (~X11/lib/X11/config/*をいじらないとして。) 自前でProject.tmplを書けってか? あるいはCannaみたいに全部のImakefileに#include とか? (注) InstallMultipleDestはINSTDATFLAGSを自動的に使う。 でもここでのインストールにはINSTINCFLAGSを使いたい。 (正?)InstallMultipleFlags/InstallMultipleDestFlags にてINSTINCFLAGSを渡す。 (誤?)INSTALLFLAGS=INSTINCFLAGSとして InstallMultiple/InstallMultipleDestを使う。 まあ、mit/include/Imakefileが(誤)をやってるからなん でしょうかねぇ… SRCS OBJS ふつうにmakeするだけならSRCSはいらないはず。では何のために SRCSを指定するのか? 1.CenterProgramTargetで使用 (CodeCenterを持ってない人は関係ない) 2.DependTarget()(->make depend) の対象 3.LintTarget()の対象 だから、SRCSにはそのImakefileで管理する *.cすべて を代入しておく。 同じプログラムに属している必要はない(例:ComplexProgramTarget_1) 普通はmake dependでしか活用されない。 /*OBJSについても同様だが、依存関係と*/ OBJSには、依存関係と {Center,Sentinel,Purify,Proof}ProgramTargetで使用されているのみ。 複数のプログラムを作るような場合(ex.ComplexProgramTarget_1)では OBJS[1-9]を使うので、OBJS自体は定義されるだけで出番がない。 ================================================================= Subdirのしかた subdir recursive #define IHaveSubdirs #define PassCDebugFlags CDEBUGFLAGS="$(CDEBUGFLAGS)" SUBDIRS = .......... MakeSubdirs($(SUBDIRS)) --make allの伝達。これが先頭 DependSubdirs($(SUBDIRS)) --make depend Makefiles,install,install.man,clean,includesは デフォルトで追加される(→Imake.tmpl)。 CDEBUGFLAGSを伝搬させるのはコマンドラインから % make CDEBUGFLAGS='-g' と打つことを想定しているため。(cf. Imake.rules) サブディレクトリ以下にCプログラムがあるなら PassCDebugFlags の 定義は必須ともいえるが、全部が全部Cとは限らないので、 CDEBUGFLAGSを下に渡すかどうかは各Imakefileに任されている (と思われる)。 なお、直下にCがなくても、2階層下にあるなら渡さないといけない。 困ったことに SUBDIRS が空だと**Subdirs系のimake関数は軒並 エラーを出す。これは Imake.rules内で直接 for i in dirs; do などとやっているため。FORTRANのDOループのような細工はされていない。 空になる可能性があるならダミーのディレクトリを用意? ================================================================= R6とR5 R6のInstallNamedTargetはR5にはない。 一番近いのはInstallMultipleDestFlagsだが、 機能はちょっとちがう。(dstnameがない) 結局定義し直しか… ---R6--- #define InstallNamedTarget(step,srcname,flags,dest,dstname) @@\ step:: srcname @@\ MakeDir($(DESTDIR)dest) @@\ $(INSTALL) $(INSTALLFLAGS) flags srcname $(DESTDIR)dest/dstname ---R5--- #define InstallMultipleDestFlags(step,list,dest,flags) @@\ step:: list @@\ MakeDir($(DESTDIR)dest) @@\ @case '${MFLAGS}' in *[i]*) set +e;; esac; \ @@\ for i in list; do \ @@\ (set -x; $(INSTALL) -c flags $$i $(DESTDIR)dest); \ @@\ done ================================================================= ごく単純なプログラムのImakefile simple single compile program link build (ソース一つ、プログラム一つ、ソース名==プログラム名) SimpleProgramTarget(hello) これは、 1) 一つのImakefileに一つだけのプログラム 2) 単一のソースファイル 3) ソース名 == プログラム名.c の時(AND条件)に使える。 (必要ならCC=などを前に加える) 簡単なImakefileではあるが、内部的には ComplexProgramTargetを 使っているので、コンパイル、リンク、 install,depend,install.man,clean を備えている。 複数のプログラムを一本のImakefileで管理したいのなら ComplexProgramTarget_{123}を使う。 ライブラリを使うプログラムのImakefile library リンク時に LDOPTIONS,LOCAL_LIBRARIES,LDLIBS,EXTRA_LOAD_FLAGS が使われるが、Imakefileでは SYS_LIBRARIES=-lm LOCAL_LIBRARIES=-lX11 と指定する。 -L/usr/local/X11R5/lib に関しては自動的につくはず。 SYS_LIBRARIES は/lib,/usr/libのもの、 LOCAL_LIBRARIES は個々のアプリケーションに固有のものを 指すらしい。libX11などはこっち。 X関係以外のライブラリを使用するのならLOCAL_LIBRARIESに -Lを書くが、これがshared libraryである時は若干話がややこしくなる。 別掲。 LOCAL_LIBRARIESは上のように直接書いても動くが、X関係の ライブラリを使っていて移植性を高くしたいと思えば、 LOCAL_LIBRARIES=$(XLIB) なんて書きかたがかっこいい。 XLIBはProject.tmpl(R5)、X11.tmpl(R6.3)マクロ。 Athena Widgetを使う時は LOCAL_LIBRARIES=XawClientLibs が使える。これもProject.tmpl(R5)、X11.tmpl(R6.3)。 Motif(要開発環境)を使っている場合は LOCAL_LIBRARIES=XmClientLibs LOCAL_LIBRARIES=MrmClientLibs が使える。 LDOPTIONS,LDLIBS,EXTRA_LOAD_FLAGSはImake.tmplが指定しているので ユーザーのImakefileではいじらないほうがよい。 自前のImake.tmplであればどれをいじってもよいでしょう。 (Imake.tmplコメントより) STD_INCLUDES システム固有のinclude。普通は空。 TOP_INCLUDES /usr/include(デフォルト)への道もしくは構築時に 参照する同等の所。 -I/usr/local/X11R5/includeなどとなっていることがある。 EXTRA_INCLUDES プロジェクト固有のinclude。Project.tmplで 指定するらしい。(Xでは使われてない) INCLUDES Imakefileで指定するinclude。 これらはいづれも -Iパス名 である。 順番は INCLUDES EXTRA_INCLUDES TOP_INCLUDES STD_INCLUDES LOCAL_LDFLAGS Imakefileで指定するldフラグ。 複数のプログラムを一本のImakefileで指定(Low-level=not complex) multiple 単一のプログラムであっても、こちらの方が細かいコントロールはしやすい。 (LOCAL_LIBRARIESとかがいらない。) OBJS1 = hello.o NormalProgramTarget(hello,$(OBJS1),NullParameter,NullParameter,NullParameter) ^^deplibs ^^locallibs ^^syslibs これはコンパイルとリンク,cleanをするだけである。 コンパイル、リンク、インストールを同じプログラムに対して 行なうなら、ComplexProgramTargetを使おう。 もしくは、installはInstallMultiple(programlist,$(BINDIR))を使う。 あいにく複数ファイルに対応したInstallManPage()はない。 ================================================================= マニュアルをインストールする(Low-level) manual install (R5,R6双方で有効の模様) コマンド(セクション1)であれば、hello.man なるファイルを用意して MANPATH=/usr/local/man InstallManPage(hello,$(MANDIR)) /usr/local/man/man1/hello.1としてインストールされる。 コンパイル、リンク、インストールを同じプログラムに対して 行なうなら、ComplexProgramTargetを使おう。 複数のマニュアルに対応したimake関数はないので、この場合は InstallManPage{,Long,Aliases}をずらずらと並べる。 (cf.xc/doc/man/X11/Imakefile) MANDIR (デフォルト$(MANSOURCEPATH)1): * ComplexProgramTarget でのInstallManPage の引数。 ComplexProgramTarget でのmake install 先を指す。 OSによって man1だったりcat1(NetBSD)だったりする。 * Imakefileで指定する。 ライブラリに関するマニュアルなら$(LIBMANDIR)、 ファイルフォーマットについてなら$(FILEMANDIR)(R6のみ)を 代入する。 MANDIR = $(LIBMANDIR) * LIBMANDIR,FILEMANDIR以外の値が欲しいなら MANDIR = $(MANSOURCEPATH)8 * ただ、ComplexProgramTarget はプログラム用だから、 section 8はともかくComplexProgramTargetを使用している Imakefileにてライブラリのマニュアルを MANDIRを書き換えてインストールするということはあまりない。 * ComplexProgramTarget を経由せずにマニュアルを入れる場合は、 MANDIR をわざわざ再定義しなくても Imakefile中でInstallManPageに直接 $(LIBMANDIR) を渡す方が 理に叶っている (でもxc/doc/*/ではMANPATHを書き換えてから渡してんだよなぁ) (↑ここはComplexProgramTargetがないからこれでもいい?) MANPATH (ProjectRoot/man): * make man_keywords(R6.1)でここがcatman(1) -w される * ManSourcePath の種 * ImakefileもしくはProject.tmplで指定する。 MANSOURCEPATH ($(MANPATH)/man): * {,Lib,File}ManDirの種。通常は数字が直後について $(MANSOURCEPATH)1 といった使われ方になる。 roffのソースがあるからsource? MANSUFFIX (ManSuffix; 1,1x,1X): * インストール後のマニュアルファイルの拡張子。 OSによっては(NetBSD,ncr)使われないこともある。 * Imakefileで指定する。 ただのコマンドなら未定義のまま(デフォルトの1,1x,1X)、 ライブラリ(3)なら$(LIBMANSUFFIX)、 ファイルフォーマット(4)なら$(FILEMANSUFFIX)(R6のみ)を代入する。 (?? * これを定義しただけではMANDIRは man$(MANSUFFIX)/ に 切り替わらないこともある。(??-ManDir再定義時?) (R5では切り替わる-??R6でも切り替わりそうだし、ManDirを再定義していない限り再定義もいらなそうだけど?) MANDIRにも代入するのを忘れないこと。(??) MANSUFFIX = 8 MANDIR = $(MANSOURCEPATH)$(MANSUFFIX) ??たぶん無効。実験してないのでわからんが… !! Wnn4.2でProject.tmplがManPathでなくManDirを使っていたための勘違いかも) * LIBMANSUFFIX,FILEMANSUFFIX以外の値が欲しい時は 直接 MANSUFFIX=8 と書くことになるが、OSによっては 8x だったりするので完全に移植性のある設定方法はない。 OSによってはroff形式のままでは索けなかったり、特殊処理を施して インストールしたりする場合があり、そのようなOSはvendor.cfで InstallManPageLongを再定義している。 ライブラリのマニュアルのインストール manual install library ex.ライブラリのマニュアルは、Function1() のための Fnc1.manを用意して MANPATH = /usr/local/man MANDIR = $(LIBMANDIR) MANSUFFIX = $(LIBMANSUFFIX) InstallManPageLong(Fnc1,$(MANDIR),Function1) ... となる。man 3 Function1 で索く。 *.manの*は8文字以内に収めることになっている。(InstallManPageLong のコメントより) この制限はソースツリーの Fnc1.man に適用されるものなので、 インストールされる man3/Function1.3 は制限しなくてよい (はずなのだが、Xでも8文字のまま突っ込まれるものが若干残っている) とにかくマニュアルのインストール manual install (すべて ComplexProgramTargetを使って*いない* 場合) InstallManPageLong(cmd,$(MANDIR),cmd) cmd.man が /usr/local/X11R6/man/man1/cmd.1x としてインストールされる。 MANSUFFIX=n InstallManPageLong(cmd,$(MANDIR),cmd) cmd.man が /usr/local/X11R6/man/man1/cmd.n としてインストールされる。 MANSUFFIX=n InstallManPageLong(cmd,/usr/local/man/mann,cmd) cmd.man が /usr/local/man/mann/cmd.n としてインストールされる。 MANSUFFIX=n MANPATH=/usr/local/man InstallManPageLong(cmd,$(MANPATH)/man$(MANSUFFIX),cmd) cmd.man が /usr/local/man/mann/cmd.n としてインストールされる。 MANPATHを再定義したので、 make man_keywords で catmanが起動できる。 ================================================================= 複数のプログラムを一本のImakefileで指定(Complex.._1) multiple compile program PROGRAMS=hello1 hello2 <--忘れずに BINDIR=/usr/local/bin <--インストール先は全部同じになる MANPATH=/usr/local/man MANSUFFIX=1 SRCS1 = hello1.c OBJS1 = hello1.o ... ComplexProgramTarget_1(hello1,$(LOCAL_LIBRARIES),NullParameter) (引数名) ^^locallib ^^syslib ^^ここにすき間をあけてはいけない。 installなどでパス名が変になる。 .._1でSRCS,OBJS,all,depend,cleanの初期化が行なわれるので、必ず_1を 初めに使うこと。 4つ以上のプログラムを一本のImakefileに入れたい multiple compile program R6.1以前のImake.rulesには ComplexProgramTarget_3 までしかない。 定義は単純(ProgramTargetHelperだけ)なので、自分で定義するか、 直接ProgramTargetHelperを書く。 Motif環境下であれば MComplexProgramTarget_10 までが使える。 X11R6.3なら ComplexProgramTarget_10 までが使える。 一番いいのはNormalProgramTargetを連ねること。installやinstall.man はつかないが、プログラムが多い場合はこれらを一箇所に まとめたほうがすっきりする。 リンク時に実際に使われる引数について link arguments まずLinkRuleをばらしてみる。ComplexProgramTargetからたどる。 R5: $(CC) -o $@ $(OBJS) $(CDEBUGFLAGS) $(CCOPTIONS) $(LOCAL_LDFLAGS) -L$(USRLIBDIR) $(LOCAL_LIBRARIES) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) $(EXTRA_LOAD_FLAGS) R6.0,R6.1: LD_RUN_PATH=$(USRLIBDIR) $(CC) -o program $(CDEBUGFLAGS) $(CCOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_LDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIB) $(OBJS) $(LOCAL_LIBRARIES) $(LDPOSTLIB) $(THREADS_LIBS) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) R6.3:(LD_RUN_PATH有効時) LD_RUN_PATH=$(USRLIBDIRPATH) ... $(LDPOSTLIBS) ... 以下Project.tmplはR6.3ではX11.tmpl, vendor.cfはsun.cfなどに読み替える。 vendor.cfで定義されているものが気に入らなければsite.defのフラグで 切替えられるはずだが、vendor.cfのできが悪いとsite.def(BeforeVendorCF) でいじることになる。(特にコンパイラまわりの設定) CDEBUGFLAGS -g もしくは -O など。通常は-Oなどの最敵化オプションで、 必要に応じてmake CDEBUGFLAGS='-g' などとして使う。 デフォルト: DefaultCDebugFlags ? OptimizedCDebugFlags @vendor.cf ? @Imake.tmpl:"-O" CCOPTIONS 普段からつけているオプション。-f68881, -pipe など。 ANSIモードや浮動小数点プロセッサを指定しているvendor.cfが多い。 デフォルト: DefaultCCOptions @vendor.cf ? @Imake.tmpl:/**/ EXTRA_LDOPTIONS (R6) 例が少なく、使用法は不明。 R6.0ではhplib.rulesでのみ使われているが、これは勘違いであろう。 デフォルト: ExtraLoadOptions @vendor.cf ? @Imake.tmpl:/**/ THREADS_LDFLAGS (R6) マルチスレッドなアプリのリンクに固有のもの? デフォルト: @Threads.tmpl:ThreadsLoadFlags @vendor.cf ?@Threads.tmpl:ThreadsCompileFlags @vendor.cf ?@Threads.tmpl:/**/ LOCAL_LDFLAGS Imakefile で指定するldフラグ。 デフォルト: なし LDPRELIB (R6) 例が少なく、使用法は不明。 構築時は-L$(BUILDLIBDIR) (~xc/usrlib)になる。 LOCAL_LIBRARIESの前につけられることが重要? @Imake.tmpl: LdPreLib @vendor.cf ?@Imake.tmpl:-L$(USRLIBDIR) R6.3: OBJS Imakefileで定義。 {Simple,Normal}ProgramTargetを使う時以外は 全部の*.oを定義しておかないといけない。 LOCAL_LIBRARIES Imakefileで定義。 X11のライブラリを使用するのであれば-Lや-Rは入れない。 $(XLIB), XawClientLibs, XmClientLibs などを代入する。 LDPOSTLIB (R6) 例が少なく、使用法は不明。 LOCAL_LIBRARIESの後につけられることが重要? (R6.0)構築時は-L$(USRLIBDIR)になるが、#if の雰囲気から -R のつもりだったのかもしれない。 @Imake.tmpl:LdPostLib @vendor.cf ?@Imake.tmpl:/**/ (R6.3)ibmLib.rulesの雰囲気から、-Rが入る所のつもりだったらしい。 ただimakeではリンク時は-RでなくLD_RUN_PATHを採用しているので 一貫性がなくどちらのつもりだったのか不明。 R6.3ではLDPOSTLIBはconfig/では使われていない。 LDPOSTLIBS (R6.3) 複数形になっている通り、複数の-Lが入る。 今の所-Rが入る気配はない。 @Imake.tmpl:LdPostLibs @X11.rules:(LdPostLib XLdPostLibs @X11.rules:/**/) Imake.tmplによるデフォルトはないので必ずProject.tmplで定義する。 THREADS_LIBS (R6) スレッド関係のライブラリの指定。-lthread など。 @Threads.tmpl:ThreadsLibraries @vendor.cf ?@Threads.tmpl:/**/ SYS_LIBRARIES Imakefileで定義? -lm など。 /usr/lib/ にあるものを書くようである。 R6.0以降なら MathLibrary とすれば"-lm"になる。 デフォルト:なし EXTRA_LIBRARIES 常に使うライブラリ。BSD系では空だがSVR4ではソケット関係の ライブラリが入る。 @Imake.tmpl:ExtraLibraries @vendor.cf ?@Imake.tmpl:"-lsocket -lnsl -lw" Krb5Libraries @Imake.tmpl:/**/ USRLIBDIR (LD_RUN_PATHとして; R6.0,R6.1) 名前からしてその*プロジェクトの* /usr/lib 相当の所を 指すように設定されるようである。 ちなみに LIBDIR = $(USRLIBDIR)/X11 。 @Imake.tmpl:UsrLibDir @Project.tmpl @Imake.tmpl:/usr/local/X11R6/lib ImakefileでLD_RUN_PATHに複数のディレクトリを渡したいなら USRLIBDIRは書き換えないほうがいいのでCCENVSETUPをいじるか、 CCENVSETUPを空にして-RをLDPOSTLIBに仕込むことになりそう。 USRLIBDIRPATH (R6.3) path1:path2 といったコロン区切りのリスト。 明らかに-R相当のものに使われているが、LD_RUN_PATHが 使えるldではこれがLD_RUN_PATHに設定され、-Rはつかない。 一般のSVR4では*ライブラリの*構築時に-rpathとして供給される。 @Imake.tmpl:UsrLibDirPath @X11.rules:XUsrLibDirPath @X11.rules:$(USRLIBDIR) Imake.tmplでのデフォルトの定義がないので *必ず*Project.tmplで定義する。 Imakefileでいじる場合はUSRLIBDIRPATHをいじることになるが、 USRLIBDIRPATH=UsrLibDirPath:/usr/local/additional/lib と なるのだろうか? ComplexProgramTargetの使い方 compile program SRCS = ソース全部 OBJS = オブジェクト全部 (LOCAL_LIBRARIES = ...) (INCLUDES = ...) (DEPLIBS = ...) ComplexProgramTarget(プログラム名) ================================================================= ライブラリの構築方法 library build compile shared ライブラリはライブラリだけディレクトリを分けておくのが一般的。 (OBJSを占拠してしまうため) 下の例は R6 で、libXsample.so.1,libXsample.a を作る例。 #define DoNormalLib YES #define DoSharedLib YES #define DoDebugLib NO #define DoProfileLib NO /* これらにはデフォルトがない(!)ので、必ずImakefileで設定する。 * Xlibでは Project.tmpl (R6.3ではX11.tmpl) で NormalLibX11 などを * 設定しておき、個別のImakefileでこれらを読み込んでいる。 * * site.def の設定を尊重するなら * DoNormalLib (!HasSharedLibraries | ForceNormalLib) * DoSharedLib HasSharedLibraries */ SOXSAMPLEREV = 1.0 /* 二桁 */ #define LibName Xsample #define SoRev SOXSAMPLEREV /* $(SOXSAMPLEREV) ではない */ /* SoRev = SOXSAMPLEREV でもよい? */ #define HasSharedData YES /* .sa を作るか? */ SRCS = ... OBJS = ... #include Library.tmplでCCを再定義しているので、CCを変更する場合は どこかに CC = ... を追加する。cc→gcc といった場合は PICFLAGS = ... も加える。 LibraryCcCmd や SharedLibraryCcCmd はvendor.cfで いじるもの。Imakefileでは変更しないほうがよい。 LibName: 定義しておくと自動的にallターゲットが作られる。(R6) ライブラリ名はlibLibName.aとなる。 DoNormalLib: Boolean. lib*.aを作る。 DoSharedLib: Boolean. lib*.so.$(SoRev)を作る。 ./unshared/ を勝手に掘るので注意。R5ではshared/が掘られる。 sharedlib用のオブジェクトではSharedLibraryDef,SharedCodeDef がついてコンパイルされる。Sunでは-DSUNSHLIB -DSHAREDCODE. DoDebugLib,DoProfileLib: 一般にはNOでいいでしょう。 SoRev: $(SoRev)といった形で使われている。したがって SoRevは必ずmake変数名に#defineする。 X11ソースツリーでは一旦SO*REVをProject.tmplで指定してから 各ImakefileでSoRevに移す形をとっている。 HasSharedData: Boolean. SunOS,EWS専用。*.saを作る。 UNSHAREDOBJS = *.o を .saに固める。 関係ないOSでは無視されるだけ。 SRCS,OBJS: LibNameを定義しておけば、これらがすべて ライブラリとしてアーカイブされる。(R6) R5では自動的に構築用ターゲットが作られないので、 #if ProjectX < 6 LIBNAME = LibName LibraryObjectRule() #if DoNormalLib NormalLibraryTarget($(LIBNAME),$(OBJS)) InstallLibrary($(LIBNAME),$(LIBDIR)) #endif #if DoSharedLib SharedLibraryTarget($(LIBNAME),$(SoRev),$(OBJS),shared,..) InstallSharedLibrary($(LIBNAME),$(SoRev),$(LIBDIR)) #endif DependTarget() #endif を追加する。 R5ではshared libコンパイル時に./unshared/ではなく./shared/が掘られる。 Imakefile中で#if ProjectX < 6 とすればR5,R6両用のImakefileが書ける。 R6.3では ProjectX = 603 なので気をつける。 DependTarget() は、R6でも自動でつくわけではないので、 使うのなら自分でつける。 共有ライブラリが依存しているライブラリ shared library dependency (R6.3;?他バージョン) sharedで依存しているライブラリがある場合にはImakefileにて REQUIREDLIBS を指定する。ldの末尾にこれが追加される。 REQUIREDLIBS = SharedXtReqs など。 Shared**Reqsは、定義するなら *.tmpl で。 同時にmakeするライブラリを使用する場合 library DEPLIBS = 依存するライブラリ リンク時には使われず、単なる依存関係。 存在してなかった場合はmakeがエラーを出す(No rule for target ...)。 リンクするなら明示的にLOCAL_LIBRARIESにも書く。 DEPLIBSを機能させるにはComplexProgramTarget,SimpleProgramTarget を使用する。ComplexProgramTarget_[1-3]ではDEPLIBS[1-3]となるが、 Project.tmpl(R5),X11.tmpl(R6.3)を読み込んでいればDEPLIBSと同じになる。 /*なんかSharedLibReferences,UnsharedLibReferencesを使う?*/ DEPLIBSには依存ライブラリをパス名で書くが、移植性のある方法が なさそう。(staticかsharedかでも変わるし…) ライブラリ名からファイル名を作るimake関数は意外だがない。 R5ではDEPXAWLIBなどはlib*.sa、なければlib*.aを 指すようになっている。この切替えはvendorLib.tmplで行なわれている。 R6ではDEPXAWLIBは定義されていない。obsoleteか? ライブラリをインストールしない library install netpbm ローカルなlib*.aだけを作って物を作った場合にこういうことを したいことがある。 #define LibInstall NO /* #undef は LibInstall YES と同じ; cf.Library.tmpl */ $(DESTDIR)とは install XのINSTALL.TXTを見ると、「/usr/X11R6 以外にインストールしたい場合は DESTDIRは使*うな*」とある。 ではどういう時使うかというと、(ドキュメントされてないように思うが、) 他のマシンに NFS 経由でインストールする時。 # mount target:/usr/local /mnt/target # make install DESTDIR=/mnt/target/../../ とすれば、target機の/usr/local/X11R6に ProjectRoot=/usr/local/X11R6 のXがインストールできる。 $(DESTDIR)は密接パスなので、必ず末尾に"/"を追加する (インストールは大抵絶対パスで行なわれるのでなくても動きそうだが、一応) ということは、自前でインストールを行なうimake関数をこしらえたら $(DESTDIR)を忘れずに入れる必要があることを意味する。 ================================================================= 別のディレクトリのソースをコンパイルしたい directory import symlink その別ディレクトリに*.oファイルをおくようにするのであれば ちょっと難しい。(そういう場合は一旦ライブラリにしてから使う) カレントディレクトリからソースへリンクを張る 方法を代わりに使う。*.oはカレントディレクトリに置かれる。 LinkSourceFile(SOURCE.c,OTHERDIR) symlink,includes,depend,cleanあり。単一の同名ソース用。 つまり他のディレクトリのソースを(必要に応じて コンパイルオプションを変えて)コンパイルする。 作る際は make includes; make depend; make。 R5ではリンクのみ。したがって #if ProjectX < 6 includes:: SOURCE.c depend:: SOURCE.c #endif を手で追加する。 ObjectFromSpecialSource(dst,src,flags) dst.c->src.cとして flags を付けてコンパイル。 ディレクトリをまたいでいるのであれば LinkSourceFileを使う。 make depend段でリンクが張られる。 all,clean,dependターゲットを定義。 シンボリックリンクを張りたい symlink LinkFileList(includes,$(LINKSRCS),.,OTHERDIR) make includesで起動。 ただリンクを張るだけ。ディレクトリが同じ複数のファイル についてシンボリックリンクを張る。 make cleanでの掃除はしない。 stepは普通"install"なので、主にインストール用と思われる。 (X11R6.3では使われていない…) LinkFile(tofile,fromfile) fromfile:: tofile のターゲット生成。 fromfile -> tofile のリンクを張る。 make includes で他の場所から *.h を借りてくる場合に 使うものと思われる。 includes,dependで fromfileが作られるが、この際 tofileが依存関係になるので、tofileに make allで 作られるバイナリやライブラリは指定しないほうがよい (make includesで腐る) コンパイル(.c.o)の設定 compile todo (R6) コンパイル用imake関数 compile これらはターゲットを生成しない。ただのシェルコマンドを生成する。 (R6) CPPOnlyCompile(src,options) $(CC) -E $(CFLAGS) options src > $@ cppだけを走らせる。一般に-Eをつけると標準出力に 書き出されるので、リダイレクトも行なわれる。 ObjectCompile(options) $(CC) -c $(CFLAGS) options $*.c 一番implict ruleに近い。一発もののオプションの指定ができる。 でも普通はSpecialObjectRule()を使う。 NormalLibObjCompile(options) 通常はObjectCompileと同じ。 ライブラリのコンパイルはこちらで行なわれる。 NormalSharedLibObjCompile(options) $(CC) -c $(CFLAGS) options $(SHLIBDEF) $(SHAREDCODEDEF) $(PICFLAGS) $*.c シェアードライブラリ用オブジェクトのコンパイル。 SHLIBDEF: Imake.tmplで定義。 = SharedLibraryDef SHAREDCODEDEF: Imake.tmplで定義。 = SharedCodeDef PICFLAGS: Imake.tmplで定義。 = PositionIndependentCFlags SharedLibraryDef: vendorLib.rulesで定義。-DBSDSHLIBなど。 SharedCodeDef: vendorLib.rulesで定義。 -DSHAREDCODE PositionIndependentCFlags: vendorLib.rules。-fpic,-KPIC,+zなど。 コンパイラによって違う。 LibObjCompile(dir,options) $(CC) -c $(CCOPTIONS) $(ALLDEFINES) options $*.c $(MV) $@ dir/$@ unshared/profiled/debuggedといったオブジェクトを 別の所に退避するための関数。 SharedLibObjCompile(options) R6では使われていない。おそらく下位互換用。 (shared/を掘る。) R6ではデフォルトがsharedのため使われなくなった? ================================================================= インストール install プログラムはComplexProgramTargetなどを使っていれば 自動的にinstall,install.manターゲットはつく。 app-defaultsなどはImakefileに明示的に書かなければならない。 →(app-defaultsはInstallAppDefaultsてのがある。R5-) InstallNonExecFile(filename,dir) $(INSTDATFLAGS) (通常-m 0444) でインストール。 InstallScript(program,dest) $(INSTBINFLAGS) (通常-m 0755) でインストール。 InstallProgramWithFlags(program,dest,flags) $(INSTPGMFLAGS)(-s;stripする) + flags でインストール。バイナリ用。 InstallMultipleDest(step,list,dest) 複数のファイルをINSTDATFLAGSでインストール。 もちろん単一ファイルで使っても良い。 通常使いそうなものはこんなものだが、他のものもいろいろ定義 されているので、ありがちなインストールを行なう場合はImake.rules をチェックして適切な(短いともいう)関数を使おう。 それでもおっつかない場合は下の基本関数を使う。 InstallNamedTarget(step,srcname,flags,dest,dstname) (R6から) 単一ファイルインストール系の関数の基本。インストール先での 名前の変更に対応。 step: Makefileターゲット。普通は"install"を指定する srcname: インストールするファイル flags: INSTALLFLAGS (通常-c) にさらに追加するinstallフラグ。 これがINSTDATFLAGSだったりINSTBINFLAGSだったりする。 dest: インストール先ディレクトリ dstname: インストール先での名前。通常はsrcnameと同じ。 InstallMultipleDestFlags(step,list,dest,flags) 複数(単一で使っても良い)インストール系の関数の基本。 step: "install" list: インストールするファイル dest: インストール先ディレクトリ flags: INSTALLFLAGS (通常-c) にさらに追加するinstallフラグ。 Imakefile独自のフラグを渡したい時はLOCAL_INSTFLAGS を新設して渡すことが多い。INSTALLFLAGSはいじらない。 (X11R6.3)USRLIBDIRPATH = UsrLibDirPath と USRLIBDIR = UsrLibDir USRLIBDIRPATHは LD_RUN_PATH の値として使われる。つまり "path:path" UsrLibDirPath は 各プロジェクトの *.rules にて #define UsrLibDirPath XUsrLibDirPath などと使われる。 右辺はXUsrLibDirPath,MUsrLibDirPath,CUsrLibDirPathなど。 ===== app-defaults のインストール install app-defaults (R5) InstallAppDefaults(class) class.ad というファイルを通常のapp-defaultsディレクトリ (/usr/local/X11R6/lib/X11/app-defaults/ あたりが普通) に class (.adはつかない)として放り込む。 データファイルと同じく 0444 にchmodされる。 InstallAppDefaultsLong(file,class) file.ad (fileではない) を app-defaults/class として放り込む。 両方とも make install ターゲットとして仕込まれる。 これらは InstallAppDefFiles なるsite.defフラグをNOとすると R5, R6.0 : 何もしない R6.1, R6.3: 上書きしなくなる デフォルトではYESなので無条件上書きインストール。 従って、普通は Hello.ad というapp-defaultsファイルを用意して InstallAppDefaults(Hello) でインストールされるようにする。 ComplexProgramTarget系の関数にはこれは含まれていないので 明示的に書く必要あり。(理由:X特有だから) ================================================================= 複数のディレクトリのシェアードライブラリを使用する shared library link X11関係のライブラリだけを使用している分には特に設定は 必要ない。LOCAL_LIBRARIESに必要なライブラリを書くだけで良い。 問題はX11以外の場所への-Lや-Rが必要になった場合。 通常は LDPRELIB = -L/usr/local/X11R6/lib がリンク時につく。 SunOS4のようにリンク時の-Lパスを覚えるldでは問題はない。 HP-UXでは+b:オプションで似たようなことをする。 (hpLib.rulesでは+b$(USRLIBDIR)を採用) 問題はSVR4系のld。R5ではサポートされていなかったようであるが、 R6以降では使用できる。 imakeではLD_RUN_PATHで設定する方法を採用。EWS ldがこれしか サポートしていないのでしかたがない。 例: USRLIBDIR = /usr/local/X11R6/lib、 別のライブラリがインストール後に/usr/local/lib/libMagick.so、 *構築時は* magick/libMagick.so で使われるとする。 まず LOCAL_LIBRARIES=-Lmagick -lMagick $(XLIB) だと、リンクはうまくいくが実行時にlibMagickが見つからずに エラーになる。-Lを記録するOSでもpwdを変えるとエラーになるはず。 -Lを記録するもの(SunOS4)に関しては(R6) LOCAL_LIBRARIES = -Lmagick -lMagick $(XLIB) LDPOSTLIB = -L$(USRLIBDIR) -L/usr/local/lib でrpathを記録できる。しかしHPUXやSVR4では実行時エラー。 (HPUXではUseInstalledのときは+bオプションがつかない) LOCAL_LIBRARIES = -Lmagick -lMagick $(XLIB) LDPOSTLIB = -R$(USRLIBDIR) -R/usr/local/lib とすればSunOS5では動くが、UsrLibDirPathの設定(R6.3)が無視される (-RをつけるとLD_RUN_PATHは使われない)上、-Rを受け付けないldへの 移植性をそこねる。 折衷案として LOCAL_LIBRARIES = -Lmagick -lMagick $(XLIB) LDPOSTLIB = -L$(USRLIBDIR) -L/usr/local/lib CCENVSETUP = LD_RUN_PATH=$(USRLIBDIR):/usr/local/lib (R5ではLOCAL_LIBRARIESに-L/usr/local/libを追加する) UsrLibDirPath(R6.3)も無視されている。HPUXもだめ。 UsrLibDirPathはMotifやCDEでは複数のパスを持つので、 Imakefileで書き換えるのは何をやっているのか分かっている場合に限る。 UsrLibDirPathを活かすには(R6) LOCAL_LIBRARIES = -Lmagick -lMagick $(XLIB) #if AlternateUsrLibDir && HasLdRunPath #ifndef UsrLibDirPath /*!R6.3*/ #define UsrLibDirPath UsrLibDir /*単一ディレクトリ*/ #endif CCENVSETUP = LD_RUN_PATH=UsrLibDirPath:/usr/local/lib #else #ifdef LdPostLibs /*R6.3*/ LDPOSTLIBS = LdPostLibs -L/usr/local/lib /* -L記録型ld用 */ #else LDPOSTLIB = LdPostLib -L/usr/local/lib #endif #endif これでSunOS4/SVR4でうまく動く。問題はHPUXで、UseInstalledを 外さないと+bがつかない。この問題はHPUXだけのようである。 うーむおてあげか?HPArchitectureで逃げるか? ================================================================= 変数名 varname LOCAL_* 個別のImakefileで指定する。でもLOCAL_*以外でも Imakefileで指定する/できる変数は多い。 imake変数は基本的にProject.tmplやvendor.cfで設定する。 Imakefileが読み込まれる段階ではすでにmake変数にマッピング されたあとなのでImakefileで設定しても無効なのが普通。 Imakefileで各種設定をいじりたい場合はmake変数をいじる。 この際は洩れなく周辺の設定をチェック。特にコンパイラまわりの設定は 設定忘れをしやすい(ccとgccを混ぜてしまう、など)ので、 テストはもちろん、config/をみて移植性があり(できるのか?)、 十分な設定をしているかどうか検討する。 ================================================================= all:: all AllTarget(depends) はまさに all:: depends だけなのだが、 移植性(て何のだ?)のためには使った方がいいのか? ================================================================= R6.0,R6.1,R6.3のImakefile中での判別法 distinguish minor release version Imake.tmplだけではまっとうな方法がない。 R6.1,R6.3: ClearmakeOSName が定義されている(ぅげ R6.3: TopLevelProjectが定義されている X11.tmplに依存してよければ R6.3: ProjectX == 603 R6.[01]では == 6 6.1は特に判別の必要はない…のかもしれない。 =================== X11インストール時 OptimizedCDebugFlags と DefaultCDebugFlags、どっちを設定する? X11R6.3: @Imake.tmpl: CDEBUGFLAGS = {DefaultCDebugFlags := OptimizedCDebugFlags} CFLAGS = $(CDEBUGFLAGS) ... LDOPTIONS = $(CDEBUGFLAGS) ... vendor.cfによっては扱いが一貫していないが、普通はOptimizedCDebugFlags を設定し、最適化を切りたい時に明示的に DefaultCDebugFlags を 設定するようだ。 Sol2(sun.cf+svr4.cf)ではsite.def等で何もしければOptimizedCDebugFlags だけが設定される。 (sun.cfでOptimizedCDebugFlags, svr4.cfで i386 ならDefaultCDebugFlags) X11R6.3: SolarisでInstLibFlagsを設定したいが?(0444ではなく0555にしたい) 読み込み順が Imake.tmpl beforevcf: ShLibIncludeFile = aftervcf: ... #ifndef # define InstLibFlags -m 644 ... INSTLIBFLAGS = InstLibFlags ... = ShLibIncludeFile ... であるから、sun.cf で設定する必要あり。理屈の上からもそうなる。 HPUXでも同様の要請があるが、hp.cfで直接hpLib.rulesを呼び出し、 ここでセットしている。 ??? ================================================================= ディレクトリの指定 ==== ProjectTmplFile では何を定義しておくべきなのか ConfigDir LibDir ? * カレントディレクトリ指定のための変数群 TOP, TOPDIR CURDIR, CURRENT_DIR, ONECURDIR, ONESUBDIR IMAKEPREFIX make Makefiles の動作は、R6.0までは基本的に cd subdir imake make Makefiles cd .. だが、R6.1以降は make subdir/Makefile cd subdir imake cd subdir make Makefiles cd .. となり、引数を渡す境界が増える。このためディレクトリを 指定する変数が増えているが、使う分には全部の機能を知っている必要はない (はず)。標準的なものを知っていればOK。 ・「最上位」は、必ずディレクトリ構造上でも根のほうにあるとは 限らない。SUBDIRS=../../upperdir といったこともできる。 (SUBDIRS = ./subdir は、MakeMakeSubdirsが対応していないため腐る; ディレクトリ階層をさかのぼりすぎる) $(TOP) 離接パス。相対と絶対両方ありうる。 最上位Makefile で定義されている TOP までのパス。 相対の場合: 現在のMakefileのあるディレクトリから。 通常は"../../.." といった値が入る。 絶対の場合: 最上位で TOP が絶対パスで定義されていれば、 そのままの値。(そういうことってあるんかな) 一度Makefileが生成されれば、subdir側で make Makefile を 行なってもTOPは保存される。 相対と絶対の両方の可能性があるため、$(TOP)の加工は けっこうめんどくさい。MakeMakeSubdirs()の定義を参照。 $(CURRENT_DIR) 離接パス。(($CURRENT_DIR)/path として使う) 最上位の make Makefiles のあるMakefile から、 現在のディレクトリまでの 相対パス。 @Makefile: CURRENT_DIR = . @subdir/Makefile: CURRENT_DIR = subdir @subdir/sub2/Makefile: CURRENT_DIR = subdir/sub2 一度Makefileが生成されれば、subdir側で make Makefile を 行なってもCURRENT_DIRは保存される。 最上位からの相対パスであるため、使用上は必ず $(TOP)/$(CURRENT_DIR)など、左側に $(TOP) が 入っている要素が必要。 最上位dir (物理的に根にあるとは限らない) | ^ CURRENT_DIR | | TOP (絶対パスの場合もあり) v | Imakefileのあるdir 通常のImakefileで使用することはない変数: $(ONECURDIR) R6.1以降、前置可能パス、*.tmplには現れず、直接-Dで定義、 make subdir/Makefilesでのみ使用。 $(IMAKETOP) 離接パス make subdir/Makefilesでのみ使用。 subdirでのTOPDIR(ということはTOP)の値として使われる。 IMAKE_CMDを書き換えるようなprojectでも、デフォルトの Imake.rulesを活かしている限り使うことはないハズ (でもxf86.tmplでは使っている…$(TOP)でいいようなもんだが) $(IMAKEPREFIX) subdirから現dirまでの密接パス。 -UUseInstalledのmake subdir/Makefilesでのみ使用。 $(IMAKEPREFIX)$(IMAKE)の形式で使用。 ではなぜ IMAKETOP = 離接($(IMAKEPREFIX))/$(TOP) という 定義になっていないかというと、$(TOP)は絶対・相対 両方ありうるため。 $(TOP)が相対なら(.の場合は冗長になるが)上の定義とほぼ同じ。 TOPDIR,CURDIR imakeにて作成されるMakefileのTOP,CURRENT_DIRの右辺値。 離接パス。 一見make変数だが、実はmake Makefilesの度に imake -DTOPDIR=... の形で再定義されるcppマクロ。 Imake.tmplにて TOP = TOPDIR CURRENT_DIR = CURDIR として使われているが、-Dされることが前提のcppマクロであるため 出来上がったMakefileに現れることはなく、$(TOPDIR)の 形で使われることは絶対にない。 make Makefile では TOP,CURRENT_DIR の保存に使われる。 最上位では Imake.tmplにてデフォルトの"."になる。 密接パス・離接パス term ディレクトリパスを表すmake変数として、使用時に $(PATH1)filename $(PATH2)/filename となる2種類のものがある。 ここでは、前者のような使われ方をする変数を「密接パス」、 後者を「離接パス」ということにする。 密接パス: 空でも良い(その場合はカレントディレクトリを指す) 空でない場合は "config/" のように末尾に / がつく。 離接パス: 普通は空ではない ($(DESTDIR)は例外で、通常空) 末尾に "/" はつかない(ついていても害はないのだが) カレントディレクトリは "." で表す カレント 相対 ルート 使用方法 密接 (空) subdir/ / $(dir)path 離接 . subdir (空) $(dir)/path 空の離接パスはルートを指すので、空にして使うことはないと思っていい。 空の密接パスは良く使われる。 密接パス - 離接パス変換 prefixable path needpostslash path 離接 -> 密接 case "$(NEEDPOSTSLASH)" in .) PREFIXABLE=;; *) PREFIXABLE=$(NEEDPOSTSLASH)/;; esac CONFIGSRC, CONFIGDIR, IRULESRC ディレクトリを指す。いずれも離接パスらしい。 CONFIGSRC: xc/config を指し、主にその下の各種ツールを -UUseInstalled時に使う時に使用。 $(CONFIGSRC)/util/install.sh といった形で使われる。 下のIRULESRCの種としても使われるが、IRULESRCそのものでは ないことに注意。 Xと同時に構築するようなパッケージでなければ Imakefileで明示的に利用することはない。 CONFIGDIR: インストール後の *.cf, *.tmpl がある(べき)場所。 ConfigDir として Project.tmpl で定義される。 種のConfigDirはProject.tmpl必須定義のようなのだが、 CONFIGDIR自体はImake.rulesなどでは使われていない。 Xではxc/config/cf/やxmkmfコマンドのインストール時に使用。 IRULESRC: 利用可能な *.tmpl などがある場所。通常は $(CONFIGDIR)だが、 -UUseInstalled では $(CONFIGSRC)/cf になる。 いずれにしても通常のパッケージのImakefileに現われることはないハズ。 ================================================================= IMAKE_DEFINES 6.4のImake.tmplによると、IMAKE_DEFINESは「コマンドラインでの使用専用」 ということらしい。(xf86では定義しているが…) つまるところ、これをImakefileやtmplなどで変更する場合は コマンドラインから別の値にされてもクリティカルな動作の変更が おこらないようにしておくのがいいということになる。 (CDEBUGFLAGSと似たような感じ) imake変数 vs make変数 imake変数では #define直後の空白などが保存されるが、make変数では 空白は除かれる。 通常はどっちを使っても大差がないような気もするが、パス名 (ファイルやコマンド)がからむと、make変数にしないと処理できない ことが多い。 TopLevelProjectは有名無実! 特定のプラットフォーム(しかも良く使われている)では、 TopLevelProjectを定義しても ProjectTmplFile, ProjectRulesFile に反映*されない*。(site.def参照) おそらくConcat3が誤動作するためと思われる。 このため、IMAKE_CMDの細工は引数が余計につくことになる。 -DTopLevelProject=... -DProjectTmplFile="<...>" -DProjectRulesFile="<...>" gccなど、ANSIなcppではsite.defで行なわれている細工は不要なのだが、 site.defにはそれは(まだ)反映されていない。(R6.4) X11.tmplを切り離すと… ProjectTmplFile X11.tmpl R6.3以降ではX11.tmplが独立しており、本来ならX11.tmpl抜きで imakeを使用することが可能。 …だが (Imake.tmpl) /* ConfigDir comes from X11.tmpl */ CONFIGDIR = ConfigDir /* build configuration information */ の通り、ここだけ(?)独立していない。 独立していないというか、X11というプロジェクトのconfigファイルは ここに入れなさい(「インストール後の位置」)ということになる。 似たようなことは LIBDIR にも言える。ライブラリ系のインストールでは 注意しないといかん。 X11 が TopLevelProject だとすると、ConfigDir を ProjectTmplFile が 供給すべきことは当然といえば当然なので、 ProjectTmplFileの要件: ConfigDir を定義すること が言える。ニワトリとタマゴの関係なので (ProjectTmplFileは通常ConfigDirにあるから)ブートストラップ時は 外部から与えるとかTOPDIRからどうにかしないといけない。 本気で改造するなら複数のConfigDirが定義できた方がいいよねぇ IMAKE, IMAKE_CMD, ImakeSubCmdHelper IMAKE: 純粋にコマンド名のみ。ImakeCmdと同。 通常はimakeだが、-UUseInstalled時は当然ながら $(IMAKESRC)/imake IMAKE_CMD: コマンドだけでは役に立たない(完全なスタンドアローン プロジェクトを除く)ので、-DUseInstalled -I$(IRULESRC) をつけたもの。 通常はこっちを使うことになる。 再定義している vendor.cf (xf86,Win32) もあり。 (xf86のは -I$(TOP)の 追加) ImakeSubCmdHelper: MakeMakeSubdirsでしか使っていない。 通常は IMAKE_CMD と同じ。-UUseInstalled時には -Iなどの相対パス修正が入る。 常にIMAKE_CMDでもよさそうだが、ImakeSubCmdHelperはsubdirで 実行されるため、-UUseInstalled時は相対パス周辺の細工が必要となっている。 本来はImake.rulesのローカルマクロなので、外部からいじくるものではない。 (でも-Iを追加するxf86.tmplではいじっている) $(MAKE) は再定義されている 通常のMakefileでは、$(MAKE)はmakeコマンド自身が設定するのだが、 Imakeにおいては MakeCmd (通常は"make") に明示的に定義される。 別段不都合はないようだが、コマンドラインから/usr/ccs/bin/make ほげ などと打っていると、make != /usr/ccs/bin/make なんて場合には わかりにくいエラーが出る。 Concat() は失敗しやすい Concat(imake変数,imake変数) 例 #define TclIncludeDir /usr/local/tcl8.1/include INCLUDES = Concat(-I,TclIncludeDir) といった形で使うことで、置換後の文字列を空白なしでくっつける のが本来の機能 なのだが、TopLevelProject が有名無実化してしまっていることからも わかるように、実は Concat() はあまり移植性がない。 Concat()の定義を見ると苦悩がわかる。 gcc -E ではちゃんと動くようだが、そうでないcppを使うように 設定された imake ではなかなかそうはいかない。 (env IMAKECPP="gcc -E" は、argv[0]が"gcc -E"になってしまうので効かない) ので、空白を詰めたいような場合は、一旦 make変数に代入してから くっつけるという手段をとる。 #define TclIncludeDir /usr/local/tcl8.1/include TCL_INCDIR = TclIncludeDir INCLUDES = -I$(TCL_INCDIR) デフォルトのImake.tmpl等にはこれが原因で回りくどい定義を 行なっているものが結構多い。ていうかほとんどそうかも ================================================================= bookformat: 簡単な Imakefile コンパイル・リンク 単一のソース 複数のオブジェクト ライブラリ利用 インストール マニュアル周辺 SUBDIRの利用 ライブラリ構築 特殊なコンパイル make World の各段階 新規プロジェクト 用語集