英語フランス語スペイン語

Ad


OnWorksファビコン

makepp_cookbook - クラウドでオンライン

Ubuntu Online、Fedora Online、Windows オンライン エミュレーター、または MAC OS オンライン エミュレーター上の OnWorks 無料ホスティング プロバイダーで makepp_cookbook を実行します。

これは、Ubuntu Online、Fedora Online、Windows オンライン エミュレーター、MAC OS オンライン エミュレーターなどの複数の無料オンライン ワークステーションの XNUMX つを使用して、OnWorks 無料ホスティング プロバイダーで実行できるコマンド makepp_cookbook です。

プログラム:

NAME


makepp_cookbook -- さまざまな状況に合わせて Makefile をセットアップする最良の方法

DESCRIPTION


実際、Make ツールのマニュアルを読む人はほとんどいないことに気づきました。
メイクプロセス自体には誰も興味がありません。私たちは結果だけに興味があります。
そこで、この料理本は、人々が必要なものを手に入れることができることを願って作成されました。
マニュアルを読み込まなくても、例からすぐに理解できます。 これは入力方法を示しています
インストール手順や障害となる点については、
よくある質問。

建物 ライブラリ
Do 貴社 本当に 必要 a 図書館?

私は、それぞれが多数のモジュールで構成される大規模なプログラムを多数見てきました。
これは独自のディレクトリに存在します。 通常、各ディレクトリは独自のライブラリに配置されます。
そして最終的なプログラムはすべてのライブラリとリンクします。

多くの場合、ライブラリを使用するよりも、より良いアプローチがあると思います。 図書館
各モジュールが他のモジュールで再利用できない、または再利用されない場合、実際には正しいソリューションとは言えません。
プログラムを使用すると、ライブラリのすべての欠点が得られ、
利点。 ライブラリは次の場合に役立ちます。

1. 複数の異なるサブルーチンにリンクする必要があるサブルーチンが多数ある場合
実際にサブルーチンを 100% 使用するプログラムはありません。各プログラムは
異なるサブセット。 この場合、静的ライブラリ (
.a ファイル、またはアーカイブ ファイル)。

2. 複数の異なるプログラムにリンクする必要があるモジュールがあり、
各プログラムが個別のコピーを持つ必要がないように、動的にロードしたい
図書館。 動的ライブラリは、実行可能ファイルのスペースを節約し、場合によっては機能を拡張することができます。
すべてのシステムに対してロードされるライブラリのコピーが XNUMX つだけであるため、システム パフォーマンスが低下します。
それを使用するさまざまなプログラム。

3. リンク時間が法外に長い場合は、大規模なファイルに共有ライブラリを使用します。
このプログラムによりリンクが大幅に高速化されます。

静的ライブラリの使用には、主な欠点が XNUMX つあります。それは、一部のシステム (Linux など) では、
どのライブラリをリンクするかが非常に重要です。 リンカはライブラリを処理します
コマンドラインで指定された順序で。 必要だと思われるものはすべて取得します
各ライブラリにアクセスしてから、次のライブラリに進みます。 後続のライブラリが
以前のライブラリからまだ組み込まれていないシンボルの場合、リンカは
前のライブラリに戻ってそれを取得する必要があることを知っています。 その結果、必要になる可能性があります
リンカーのコマンドラインでライブラリを複数回リストします。 (私はあるプロジェクトに取り組みました
ここでは、ライブラリのリスト全体を XNUMX 回繰り返す必要がありました。 このプロジェクトが作ったのが、
私は、以下で提案する別のアプローチ、つまり増分リンクのアプローチを好みます。)

動的ライブラリの使用にはいくつかの欠点があります。 まず、プログラムは少し複雑になる可能性があります。
ライブラリが他のプログラムによってまだ使用されていない場合、起動が遅くなります。
それを見つけてロードする必要があります。 次に、すべての動的な情報を取得するのは非常に面倒な場合があります。
ライブラリが正しい場所にインストールされている。 プログラムの実行可能ファイルをコピーすることはできません。
また、すべてのライブラリを必ずコピーする必要があります。 第三に、一部のシステムでは、
デバッガーがサポートしていないため、共有ライブラリ内のコードをデバッグするのは困難です。
彼らは元気です。

モジュールが他のプログラムで決して使用されない場合、使用する理由はほとんどありません。
ライブラリ: ライブラリを使用すると、欠点はすべて得られますが、利点はまったく得られません。
私が好む手法は、インクリメンタル リンクが利用可能な場合はそれを使用することです。

Linux でこれを行う方法は次のとおりです。

my_module.o : $(filter_out my_module.o, $(wildcard *.o))
ld -r -o $(出力) $(入力)

これは別のものを作成することになります .o と呼ばれるファイル my_module.oで構成されます。
すべての .o このサブディレクトリ内のファイル。 リンカーは、次のような問題を解決します。
参照はできる限り参照し、残りの参照は解決されるようにします。
リンクの後続段階。 最終的にプログラムを構築するトップレベルでは、
とリンクする代わりに libmy_module.a or libmy_module.so、単にリンクするだけです
my_module.o。 リンクするとき .o ファイルの順序依存性の問題は発生しません。
リンカーのコマンドライン。

させる マケップ でる which ライブラリ モジュール   必要とされる

たとえ本物のライブラリがあり、特定のプログラムがそのライブラリから数個のファイルだけを必要とする場合でも、
(個々のモジュールではなく) makepp は、どのモジュールがどのモジュールであるかを把握できる可能性があります。
ライブラリから必要なものだけをビルドに含めます。 これによりコンパイルを保存できます
プログラムと一緒にライブラリを開発している場合は、わざわざ時間を費やす必要がないため、
作業中の特定のプログラムに必要のないライブラリ モジュールをコンパイルします。

ライブラリが、すべての関数またはクラスが宣言されている規則を厳密に遵守している場合は、
ファイル xyz.h コンパイルされるソース ファイルに完全に実装されています。 xyzo (つまり、あなた
実装を分割しないでください xyz1.o & xyz2.o)、その後、を使用できます
「$(infer_objects)」関数は、makepp に関連するモジュールのみを
図書館。 これは、たとえ数十のインクルード ファイルを含むライブラリでも驚くほどうまく機能します。
基本的に、「$(infer_objects)」は次のリストを調べます。 .h 含まれるファイルと外観
対応するための .o ファイル。 ライブラリとプログラムを急速に開発している場合
一緒に使用すると、モジュールをコンパイルする手間がなくなるため、コンパイル時間を節約できます。
プログラムが使用しないライブラリ。

これは私がそれを使用する方法の例です:

my_program: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(入力) -o $(出力) $(SYSTEM_LIBRARIES)

"$(infer_objects )" 関数は、(ワイルドカードを実行した後) 最初の引数を返します。
展開)、XNUMX 番目の引数のファイルのリストも調べます。
他のファイルの名前と同じ名前のファイル .h 任意のファイルに最初に含まれるファイル
口論。 そのようなファイルが見つかった場合は、リストに追加されます。

建物 a 静的な ライブラリ

実際にライブラリが必要であるが、インクリメンタル リンクが利用できない場合、または
それはあなたがやりたいことではありません。それを行うにはいくつかの方法があります。 まず、ここに例があります
ここでは、すべてのファイルが明示的にリストされています。

LIBRARY_FILES = abcde

libmine.a: $(LIBRARY_FILES).o
&rm -f $(出力)
$(AR) cr $(出力) $(入力)
ranlib $(output) # OSによっては不要な場合があります。

&rm は、makepp の組み込みの「rm」コマンドです。 Makefile の作成に慣れている場合は、次のように思うかもしれません。
このコマンドには少し驚きました。 あなたは次のようなことに慣れているかもしれません:

libmine.a: $(LIBRARY_FILES).o
$(AR) る $@ $? #お勧めしません!!!!!!
ranlib $(出力)

どこに$? (「$(changed_inputs)」とも呼ばれます) は、任意のファイルを意味する自動変数です。
これらはライブラリが最後に構築されてから変更されており、$@ はほぼ同じです
「$(出力)」として。

このアプローチは、次のような理由から推奨されません。

· 現在のディレクトリからソース ファイルを削除するとします。 それはまだです
ライブラリを最初から再構築していないためです。 結果的には何でも
このライブラリとのリンクには古いものがあります .o ファイルが壊れる可能性があります
構築します。 (私はかつて、デッドコードを削除しようとしていたときにこれで完全に混乱しました
プロジェクトから: ファイルを削除し続けてもリンクされたままだったので、コードは
死んだ。 ただし、他の人がプロジェクトを最初から再構築したときは、何もリンクされませんでした。
もっと! 問題は、古い .o ファイルはまだアーカイブにありました。)

また、「ar」のオプションと「ar」の実装に応じて(たとえば、
"r" の代わりに "q" オプションを使用してください)、複数のバージョンの
同じ .o 内部 .a ファイル。 異なるバージョンが異なるグローバルを定義する場合、
リンカーは両方を取り込もうとする可能性があります。 これはおそらく悪いことです。

このため、最初にライブラリ ファイルを削除し、最初から作成します。 この意志
ライブラリ内のモジュールを更新するよりも若干時間がかかりますが、それほど長くはかかりません。 の上
最新のコンピュータでは、 ar プログラムは比較すると非常に小さい
一般的なビルドで C コンパイラが処理するものと同じなので、心配する必要はありません。
約。

· makepp が正しいビルドを保証しようとする方法の XNUMX つは、
特定のターゲットをビルドするコマンド ラインが変更された場合、自動的にリビルドします。 しかし
$を使用して? 変数はライブラリが更新されるたびに問題を引き起こす可能性があります。
ビルドコマンドが違います。 (これを抑制するには、
":build_check 無視_アクション"; 詳細については、makepp_build_check を参照してください。)

· アーカイブを再構築するのではなく更新すると、makepp が実行できなくなります。
ファイルをビルド キャッシュに適切に配置します (詳細については、makepp_build_cache を参照してください)。

場合によっては、すべてのファイルをリストするのが少し面倒だと感じるかもしれません。特に、
プロジェクトは急速に開発されており、ファイルのリストは常に変更されています。 それ
次のようにワイルドカードを使用してライブラリを構築する方が簡単かもしれません。

libmine.a: $(only_targets *.o)
&rm $(出力)
$(AR) cr $(出力) $(入力)

これにより、すべての .o 現在のディレクトリ内のファイルをライブラリにコピーします。 ワイルドカード
いずれかに一致します .o ファイルが存在するかビルドできるため、ファイルが存在しない場合でも機能します
まだ存在します。

「only_targets」関数は、 .o 対応するファイルがない場合
ソースファイルはもう必要ありません。 というファイルがあるとします。 xyz.c あなたが使っていたもの
図書館。 これは、 xyzo ファイルが転がっています。 今、あなたは削除します xyz.c
古いものですが、削除するのを忘れているためです xyzo。 「only_targets」を使用しない場合
機能、 xyzo まだリストに含まれるだろう .o ライブラリに含まれるファイル。

建物 a ダイナミック ライブラリ

動的ライブラリを構築するプロセスは完全にシステムに依存します。 ぜひ
libtool を使用して動的ライブラリを構築することをお勧めします (「
<http://www.gnu.org/software/libtool/>)、そのため、それを行う方法を理解する必要はありません
プラットフォームに切り替えてもメイクファイルは引き続き機能します。
異なるOS。 詳細については、libtool のドキュメントを参照してください。 Makefile のサンプルを次に示します。

LIBTOOL := リブツール

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(入力) -o $(出力)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

建物 on いくつかの 異なります or ネットワーク
Makefile に関する最も厄介な問題の XNUMX つは、次の場合には Makefile がほとんど機能しないことです。
別のマシンまたは別のネットワークに切り替えてください。 Makefile を動作させる必要がある場合
地球上にあるすべてのマシンの場合、おそらく何らかの設定が必要になるでしょう。
脚本。 ただし、数台の異なるマシンでのみ作業する必要がある場合は、いくつかの方法があります。
この問題には次のようにアプローチできます。

  a 異なります include file in   環境

各 Makefile の先頭に、次のような行を含めることができます。

system_defs.mk をインクルードする

ファイル system_defs.mk 通常はそれぞれ異なる場所に配置されます
環境。 ビルド ディレクトリをすべてのマシンで同一にしたい場合は、次のようにします。
system_defs.mk ビルド ディレクトリの上のディレクトリに配置するか、インクルード パスを指定します。
「-I」コマンド ライン オプションを使用して makepp に実行します。

通常、これを行うのは少々面倒ですが、膨大な数がある場合にはうまく機能します。
違い。

  if

これは最も醜い方法ですが、通常はうまくいきます。

ifsys i386
CC := gcc
他に ifsys sun4u
CC := CC
それ以外の場合は ifsys hpux11
CC = c89
ENDIF

いくつかのプログラムやライブラリを見つけるか、別の場所にファイルをインクルードするだけの場合は、
場合によっては、もっと良い方法があるかもしれません (下記を参照)。

検索プログラム、 最初に利用可能、 ファイルを見つける

これらの関数は、システム内のさまざまなディレクトリを検索して、
適切なファイル。 もちろん、これはconfigureスクリプトほど強力ではありませんが、私はそれを見つけました
役に立つ。 たとえば、私は次のことを行います。

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# PATH で利用可能な最初の C++ コンパイラを選択します。
# (ちなみに、CXX をまったく定義しない場合、これは
# は定義方法です。)
TCL_INCLUDE ;= -I$(dir_noslash $(findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) は、指定されたそれぞれのファイルで tcl.h を検索します。
# ディレクトリを検索し、フルパスを返します。 それならこれです
# を削除してコンパイルオプションに変換
# ファイル名 (ディレクトリを離れる) に接頭辞として -I を付けます。
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(入力) -o $(出力)

TCL_LIB ;= $((first_available
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Tcl ライブラリの場所を検索します。 これは明示的に
# リンクコマンドにリストされます:
私のプログラム: *.o
$(CXX) $(CXXFLAGS) $(入力) -o $(出力) $(TCL_LIB)

取る 利点 of Perlの 設定 情報

に関する追加情報が必要な場合、上記のテクニックでは不十分な場合があります。
使用しているシステム (long double が存在するかどうか、バイト順序が何であるかなど)。 しかし、
perl はこれらのことをすでに計算しているので、その答えをそのまま使用できます。

Perl の自動構成スクリプトは、すべての構成情報を次の方法で利用できるようにします。
%Config ハッシュ。 makepp には Perl ハッシュに直接アクセスするための構文はありませんが、アクセスすることはできます。
Perl にドロップして、makepp から直接アクセスできるスカラー変数を設定します。

perl_begin
# 設定ハッシュから値を取得します。
Configを使用します。
$CC = $Config{'cc'}; # Perl が使用する C コンパイラ;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_dependent = $Config{'d_longdbl'} eq '定義';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

また、「use Config」を実行したら、次のように「$(perl )」ステートメントを使用できます。
この:

SHARED_LIB_EXTENSION := $(perl $Config{'dlext'})

「perldoc Config」と入力して、%Config ハッシュを通じてどのような情報が入手できるかを確認します。

Perl の設定は、整数型やバイトに関する情報などを取得するのに適しています。
順序、および通常は検索するために別の構成スクリプトが必要なその他のもの。 いくつかの
ファイル システム内のものの存在に関連する情報は、そうでない可能性があります。
有効。 たとえば、$Config{'cc'} は、perl が構築された C コンパイラを指します。
これは、使用したい C コンパイラと同じではない可能性があります。 実際には存在すらしないかもしれない
おそらくバイナリ パッケージを介して Perl をインストールしたためです。

ヒント for ワイルドカード
マッチング ファイル 以下は除く a 一定 サブセット

Makepp のワイルドカードには、現時点ではすべてのファイルを照合する方法がありません。 以下は除く 一定
を設定しますが、関数を組み合わせて行うこともできます。

たとえば、ライブラリ内の各モジュールのテスト プログラムがあるとします。
テストプログラムをライブラリに含めたい。 すべてのテスト プログラムが次で始まる場合、
test場合は、次のようにしてそれらを除外できます。

libproduction.a: $(filter_out テスト*, $(ワイルドカード *.o))

「$(filter )」および「$(filter_out )」関数は、次のことを行うための非常に強力なフィルターのセットです。
あらゆる種類の集合交差および差分演算。 例えば、

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(shell find . -type d -print))
# 存在しないすべてのサブディレクトリを返します。
# その中の「test」または $(ARCH)。

$(フィルター $(patsubst test_dir/test_%.o, %.o, $(wildcard test_dir/*.o)), \
$(ワイルドカード *.o))
# 現在の .o ファイルのリストを返します。
# 対応するディレクトリがある
# test_dir サブディレクトリ内の test_*.o ファイル。
$(filter_out $(patsubst man/man3/%.3, %.o, $(ワイルドカード man/man3/*.3)), \
$(ワイルドカード *.o))
# 現在の .o ファイルのリストを返します。
# マニュアルページが存在しないディレクトリ
# man/man3 サブディレクトリに同じファイル名を付けます。

使い方   "$(only_targets )" function 〜へ 排除する 失効した .o ファイル

次のようなビルド コマンドを使用してプログラムまたはライブラリをビルドしているとします。

プログラム: *.o
$(CC) $(入力) -o $(出力)

ここでソース ファイルを削除するとします。 該当する項目を削除し忘れた場合 .o ファイル、
これ以上ビルドする方法がない場合でも、リンクされたままになります。 の中に
将来的には、makepp はおそらくこの状況を自動的に認識し、対象から除外するでしょう。
ワイルドカード リストですが、現時点では、手動で除外するように指示する必要があります。

プログラム: $(only_targets *.o)
$(CC) $(入力) -o $(出力)

Makepp は古いものを構築する方法を知りません .o ソース ファイルは次のとおりです。
なくなったため、「$(only_targets )」関数によって依存関係リストから除外されます。

ヒント for の試合に ディレクトリ
makepp を作成した主な理由の XNUMX つは、複数の処理を簡素化することでした。
ディレクトリ。 Makepp は複数の Makefile からのビルド コマンドを組み合わせることができるため、
によって構築されたファイルに依存する XNUMX つのメイクファイル内のルールを適切に処理する
別のメイクファイル。

この試験は 〜へ do in 場所 of 再帰的な make

Makepp は下位互換性のために再帰的 make をサポートしていますが、強くお勧めします。
あなたはその これを使って。 それが何であるか分からない場合でも、大丈夫です。

階層ビルドを望まない理由の詳細については、makepp の「階層ビルドのためのより良いシステム」を参照してください。
再帰的 make を使用するか、Web で「再帰的 make は有害であると考えられる」を検索してください。

再帰的な make を実行してすべての Makefile で「すべて」のターゲットを作成するのではなく、
通常、どのターゲットを実際にビルドする必要があるかを makepp に判断させる方が簡単です。
さらに、あなたのすべてを入れると、 .o およびライブラリ ファイルは、
makefile を作成すると、makepp はどの Makefile が必要かを自動的に判断します。
必要なのは、トップレベルの make リストに必要なファイルを作成することだけです
最後のリンク手順に進みます。 以下の例を参照してください。

1 メイクファイル for ディレクトリ:   暗黙 ローディング

複数のディレクトリを処理する最も一般的な方法は、各ディレクトリにメイクファイルを置くことです。
これは、そのディレクトリ内で、またはそのディレクトリからすべてをビルドする方法を説明しています。 置いたら .o ファイル内の
ソース ファイルと同じディレクトリに配置し、暗黙的にロードします (「暗黙的ロード」を参照)。
makepp_build_algorithm) は、すべての makefile を自動的に検索します。 あなたがあなたの .o
ファイルを別のディレクトリ (アーキテクチャに依存するサブディレクトリなど) に置くと、
おそらく、「load_makefile」ステートメントを使用して、関連するすべての Makefile をロードする必要があります。

以下は、暗黙的なロードを使用するディレクトリ階層のトップレベルの Makefile のサンプルです。
多くの共有ライブラリで構成されるプログラムを構築するには (ただし、「本当に必要ですか?」を参照してください)
makepp_cookbook のライブラリ?」は、多数の共有ライブラリからプログラムを作成するためです。
必ずしも良いアイデアではありません):

# トップレベルのメイクファイル:
Program : main.o **/*.la # すべてのサブディレクトリから共有ライブラリにリンクします。
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(入力) -o $(出力) $(LIBS)

最上位の Makefile に必要なのはこれだけです。 各サブディレクトリでは、
おそらく次のようなことを行うでしょう:

# 各サブディレクトリ内の Makefile:
include standard_defs.mk # .、..、.. を検索します。/ ..、など、それまで
# 指定されたインクルード ファイルを検索します。
# ここでいくつかの変数定義をオーバーライドします
SPECIAL_FLAGS := -do_something_ Different

ターゲットをビルドするコマンドが同じであれば、各メイクファイルはおそらくほぼ同じになる可能性があります。
かなり似ています。

最後に、以下を standard_defs.mk ファイル (おそらく
最上位ディレクトリに配置されます):

# すべてのディレクトリに共通の変数設定とビルド ルール。
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards にはインクルードが含まれます)
# 検索 .、..、../ ..、ファイルの場合など、または
# というディレクトリにincludesがあるので、
# そこにすべてのインクルードファイルがある場合、これは
# それらを見つけます。
インクルード := -I$(INCLUDE_DIR)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(出力) $(入力)
# $(relative_to ., ..) は現在の名前を返します。
# 上位レベルからの相対的なサブディレクトリ
# サブディレクトリ。 したがって、この Makefile が xyz/Makefile である場合、
# このルールは xyz/libxyz.la をビルドします。

# パブリック インクルード ファイルを最上位のインクルード ディレクトリにパブリッシュします。
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symlnk
&ln -fr $(入力) $(出力)

1 メイクファイル for ディレクトリ: 明白な ローディング

すべてを入れたい場合は、 .o ファイルをアーキテクチャに依存するサブディレクトリにコピーし、その後
上記の例は次のように変更する必要があります。

# トップレベルのメイクファイル:
MAKEFILES := $(wildcard **/Makeppfile) # コピーするすべてのサブディレクトリのリスト
# からメイクファイルを取得します。

load_makefile $(MAKEFILES) # それらをすべてロードします。

include standard_defs.mk # main.o のコンパイル コマンドを取得します。

プログラム : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(入力) -o $(出力) $(LIBS)
# */**/$(ARCH) はサブディレクトリを除外します
# $(ARCH)、ビルドしたくない場所
# 共有ライブラリ。

各メイクファイルは以前とまったく同じになります。

# 各サブディレクトリ内の Makefile:
standard_defs.mk をインクルードする
# ...変数はここでオーバーライドされます

そして最後に、 standard_defs.mk 次のようなものが含まれます。

# すべてのディレクトリに共通の変数設定とビルド ルール。
ARCH ;= $(shell uname -s)-$(shell uname -m)-$(shell uname -r)
# $(shell uname -m) のみを使用する人もいますが、
# これは FreeBSD と Linux でも同じです
#x86。 -r は Linux ではあまり役に立ちません。
# ただし、他の OS にとっても重要です: のバイナリ
# SunOS 5.8 は通常、SunOS 5.7 上では動作しません。
&mkdir -p $(ARCH) # 出力ディレクトリが存在することを確認してください。
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards にはインクルードが含まれます)
# 検索 .、..、../ ..、ファイルの場合など、または
# というディレクトリにincludesがあるので、
# そこにすべてのインクルードファイルがある場合、これは
# それらを見つけます。
インクルード := -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

$(ARCH)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(出力) $(入力)
# $(relative_to ., ..) は現在の名前を返します。
# 上位レベルからの相対的なサブディレクトリ
# サブディレクトリ。 したがって、この Makefile が xyz/Makefile である場合、
# このルールは xyz/$(ARCH)/libxyz.la をビルドします。

# パブリック インクルード ファイルを最上位のインクルード ディレクトリにコピーします。
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(入力) $(出力)

自動的に メイキング   メイクファイル

Makefile がすべて非常に似ている場合 (上記の例のように)、Makepp に次のように伝えることができます。
存在しない場合は自動的に構築します。 以下をトップレベルに追加するだけです
メイクファイル:

SUBDIRS := $(filter_out 不要な_dir1 不要な_dir2, $(ワイルドカード */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "standard_defs.mk を含める" -o $(出力)
&echo "_includeAdditional_defs.mk" -o >>$(出力)
# ファイル added_defs.mk が存在する場合、
# 含まれますが、存在しない場合は、
# _include ステートメントは無視されます。

これで、メイクファイル自体が自動的にビルドされます。

1 メイクファイル at   top レベル

すべての Makefile が同一である場合、なぜそれぞれに Makefile を用意する必要があるのか​​と疑問に思うかもしれません。
レベル? それをすべてトップレベルの Makefile に入れてみてはいかがでしょうか?

はい、これは可能です。 主な欠点は、特定が難しくなることです
サブディレクトリごとに異なるビルド オプション。 XNUMX 番目の欠点は、
makefile はおそらく少し読みにくくなるでしょう。

これを行う例を次に示します。

# ディレクトリ階層のトップレベルの makefile。 プログラムをビルドします
# 例として、共有ライブラリのセットから抜粋します。 (上記の注意事項を参照してください
# インクリメンタル リンクやその他の方法を使用する理由については、
# 共有ライブラリではなくアプローチです。)
makepp_percent_subdirs := 1 # % が複数のディレクトリと一致することを許可します。
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(wildcard **))
CFLAGS := -g -O2
インクルード := -Iインクルード

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(CFLAGS) -c $(input) -o $(output)

$(foreach)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(出力) $(入力)
# すべてのライブラリを作成するルール。

プログラム: main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(出力) $(入力)

include/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(入力) $(出力)
# パブリックにコピーするためのサンプルルール
# アクセス可能な .h ファイルを適切な場所に配置します。

A ターゲット

従来のメイクファイルにはクリーンなターゲットが含まれており、これにより、以前のすべてのものを削除できます。
建てられた。 makepp でこれを実行すべきではない理由が XNUMX つあります。

1. Makepp は、正しいビルドを保証するためにあらゆる努力を払っています。 それで絶望的に「私はそうではない」
何が間違っているのかわかっている」と言って、ゼロから始めたくなるのは過去のことです。

2. 人々は、時間を節約しようとして、次の XNUMX つの相反することを同時に実行することがあります。
「すべてをきれいにする」。 これにより、makepp のスマート ワイルドカード システムが混乱する可能性があります。
何かをする前にまず事実を把握してください。 次にクリーンアクションが来ます。
makepp にそれが何をするのかを伝えないでください (実際、何かを元に戻すので、それはできません --
ビルドツールの目的とは異なります)。 次に「すべて」ですが、最新のファイル、
そこにあるものは、不思議なことに消えてしまいます。

3. 同じことをより効率的に実行する「makeppclean」コマンドがあります。

それにも関わらず、この歴史的セクションは、
makepp の仕組み: 「clean」と呼ばれる偽のターゲットは、次のコマンドのセットの名前にすぎません。
make プロセスで生成されたすべてのファイルを削除します。 通常、ターゲットはきれいに見えます
このようなもの:

$(偽のクリーン):
&rm -fm $(ワイルドカード *.o .makepp_log)
# -m と .makepp_log は、makepp のジャンクをすべて削除します。

削除したいファイルを明示的にリストする代わりに、makepp に次のように指示することもできます。
次のように、構築方法がわかっているものをすべて削除します。

$(偽のクリーン):
&rm -fm .makepp_log $(only_targets *)

これには、ソース ファイルのいずれかを他のファイルからビルドできる場合に、
それらも削除されます。 一方で、古くなった .o ファイル (以前は
ビルド可能ですが、そのソース ファイルは削除されています) は削除されません。

いくつかの異なるディレクトリにある Makefile を含むビルドがある場合、最上位は
レベルの makefile は、別のレベルの「クリーン」ターゲット (またはその他の偽のターゲット) を参照する可能性があります。
メイクファイル:

# トップレベルのメイクファイル
SUBDIRS := サブ1 サブ2

# ここでルールを構築

# ビルド後にクリーンアップします:
$(偽のクリーン): $(SUBDIRS)/クリーン
&rm -fm .makepp_log $(only_targets *)

あるいは、「クリーンな」ターゲットをトップレベルのメイクファイルにのみ入れて、それを持たせることもできます。
次のように、すべてのディレクトリを処理します。

$(偽のクリーン):
&rm -fm $(only_targets **/*)

使い方 Qtの パワー プリプロセッサ
この例は、Nokia の Qt GUI ライブラリを使用するユーティリティの Makefile を示しています (「
<http://qt.nokia.com>)。 これについて少しだけ珍しいのは、あなたが
ウィジェット定義を含むほとんどの「.h」ファイルに対して「moc」と呼ばれるプリプロセッサを実行する必要があります。
ただし、「Q_OBJECT」マクロを使用しない「.h」ファイルに対して「moc」を実行する必要はありません。

自動的に 決定 which ファイル 必要 パワー ファイル

もちろん、「moc」を実行する必要がある「.h」ファイルをすべてリストすることもできます。
ただし、新しいウィジェットを急速に開発している場合は、面倒なことになるかもしれません。
メイクファイル内のリストを更新し続けます。 moc をリストする必要性を回避できます
次のようなモジュールを明示的に追加します。

MOC := $(QTDIR)/bin/moc
MODULES := プログラム内にたまたま存在するモジュール
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# すべての .h ファイルをスキャンして Q_OBJECT マクロを探します。

my_program: $(MODULES).o $(MOC_MODULES).o
$(CXX)$(入力)-o $(出力)

moc_%.cxx: %.h # .h ファイルから moc ファイルを作成します。
$(MOC) $(入力) -o $(出力)

%.o: %.cxx
$(CXX)$(CXXFLAGS)-c $(入力)-o $(出力)

このアプローチでは、 .h makepp が実行されるたびにファイルを探します。
「Q_OBJECT」マクロ。 これは高価に思えますが、おそらくそれほど時間はかかりません。 ( .h
いずれにせよ、ファイルはすべてコンパイルプロセスによってディスクからロードされる必要があるため、
キャッシュされます。)

#include   .moc file

別のアプローチは、ウィジェット内の「moc」プリプロセッサからの出力を「#include」することです。
実装ファイル。 これは、「#include」を忘れずに記述する必要があることを意味しますが、
コンパイルするモジュールが少なくなるため、コンパイルが高速になるという利点があります。
(ほとんどの C++ コンパイルでは、時間の大部分はヘッダー ファイルの読み取りに費やされます。
プリプロセッサからの出力には、ウィジェットとほぼ同じ数のファイルを含める必要があります
とにかく。) たとえば:

// my_widget.h
クラス MyWidget : public QWidget {
Q_OBJECT
//..。
}

// my_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc は、
// moc プリプロセッサ。
// その他の実装についてはこちら。
MyWidget::MyWidget(QWidget * 親, const char * 名前) :
QWidget(親、名前)
{
//..。
}

次に、すべての「.moc」ファイルを作成するためのルールをメイクファイルに含める必要があります。次のようになります。

MOC := $(QTDIR)/bin/moc
# .moc ファイルを作成するルール:
%.moc: %.h
$(MOC) $(入力) -o $(出力)

Makepp は、「my_widget.moc」を作成しない場合は作成する必要があることを理解できるほど賢いです。
すでに存在するか、古い場合。

この XNUMX 番目のアプローチは、コンパイルを高速化するため、私が通常使用するアプローチです。

リプレイスメント for 非推奨の make イディオム
MakeCMDGOALS

時々、ビルドするターゲットに応じてメイクファイルにルールを設定する人がいます。
特殊変数「MAKECMDGOALS」を使用します。 たとえば、次のようなものを時々目にします。
この:

ifneq ($(フィルター生成, $(MAKECMDGOALS)),)
CFLAGS := -O2
ほかに
CFLAGS := -g
ENDIF

これはmakeppでうまく動作します。 ただし、そのような目的には「MAKECMDGOALS」を使用しないことをお勧めします。
(GNU 作成マニュアルも同様です)。 最適化されたものと
デバッグコンパイル済み .o ファイルを別のディレクトリに置くか、異なるプレフィックスを与えるか、
サフィックスを使用するか、リポジトリを使用してそれらを分離します。

おそらく、実際に「MAKECMDGOALS」を参照する必要があるのは、次の場合だけです。
メイクファイルのロードには長い時間がかかりますが、「クリーンな」ターゲットにはその必要はありません
(ただし、クリーンなターゲットは必要ありません)。 例えば、

ifneq ($(MAKECMDGOALS),clean)
load_makefile $(ワイルドカード **/Makeppfile)
ほかに
no_implicit_load 。 # 他のメイクファイルの自動ロードを防ぎます。
ENDIF

$(偽のクリーン):
&rm -f $(ワイルドカード **/*.o)

再帰的 make 〜へ ビルド in 異なります ディレクトリ

makepp_cookbook の「複数のディレクトリに関するヒント」を参照してください。

再帰的 make 〜へ 変化する of a 変数

一部のメイクファイルは、変数の異なる値を使用して自身を再呼び出しします。例: デバッグ
次のメイクファイルフラグメント内のターゲット

.PHONY: すべてのデバッグ

最適化:
$(MAKE) プログラム CFLAGS=-O2

デバッグ:
$(MAKE) プログラム CFLAGS=-g

番組:アオボー
$(CC) $(CFLAGS) $^ -o $@

%.o:%。c
$(CC) $(CFLAGS) -c $< -o $@

ユーザーが「make debug」と入力すると、デバッグが有効なデフォルト モードでプログラムがビルドされます。
最適化の代わりに。

これを行うより良い方法は、XNUMX つの異なるセットを使用して XNUMX つの異なるプログラムを構築することです。
オブジェクト ファイルは次のようになります。

CFLAGS := -O2
DEBUG_FLAGS := -g
モジュール := ab

プログラム: $(MODULES).o
$(CC) $(CFLAGS) $(入力) -o $(出力)

デバッグ/プログラム: debug/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(入力) -o $(出力)

%.o:%。c
$(CC) $(CFLAGS) -c $(入力) -o $(出力)

デバッグ/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(入力) -o $(出力)

$(偽のデバッグ): デバッグ/プログラム

この方法で行う利点は、(a) 次の場合にすべてを再構築する必要がないことです。
デバッグから最適化に切り替え、再びデバッグに戻ります。 (b)

上記は、リポジトリを使用すると、もう少し簡潔に記述することができます。 次の
makefile はまったく同等です:

リポジトリのデバッグ=。 # デバッグサブディレクトリを次のコピーのようにします。
# 現在のサブディレクトリ。
load_makefile デバッグ CFLAGS=-g
# デバッグサブディレクトリで呼び出されたときに CFLAGS をオーバーライドします
CFLAGS := -O2 # このサブディレクトリで呼び出されたときの CFLAGS の値

番組:アオボー
$(CC) $(CFLAGS) $^ -o $@

%.o:%。c
$(CC) $(CFLAGS) -c $< -o $@

$(偽のデバッグ): デバッグ/プログラム
# ユーザーが「makepp debug」と入力すると、ビルドします
# プログラムの代わりにデバッグ/プログラム。

その他 ヒント
認定条件 do I ビルド XNUMXつ 異なって ただ 一度?

Makepp は結果がルールと矛盾しているため、これを行うのを難しくしています。
ただし、これが必要になる状況もあります。たとえば、次のモジュールを XNUMX つだけコンパイルする場合などです。
大量のデバッグ情報。 これは XNUMX つのステップで実現できます。まず、
依存関係を個別に抽出し、リンクフェーズから除外します。

makepp DEBUG=3 buggy.o # 他のオプションでビルドします。
makepp --dont-build=buggy.o buggy # 「間違った」ビルド オプションにもかかわらず、それを使用します。

認定条件 do I make 確か my 出力 ディレクトリ 存在する?

出力ディレクトリを構築するルールを指定して、出力ディレクトリを作成する各ファイルが
出力ディレクトリに入るのはそれに依存します。 しかし、通常は次のようなことを行う方が簡単です
この:

# 古典的な方法
ダミー := $(シェルテスト -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# これは通常、すべてのファイルを依存させるよりも簡単です
# $(OUTPUT_DIRECTORY) とそれを作成するためのルールがあります。
# 強制するには = の代わりに := を使用する必要があることに注意してください
# すぐに実行します。
# 別のアプローチ: Perl コード、OUTPUT_DIRECTORY ローカル変数を使用する
perl_begin
-d $OUTPUT_DIRECTORY または mkdir $OUTPUT_DIRECTORY;
perl_end
# 最新の方法では、既存のディレクトリには何も行いません
&mkdir -p $(OUTPUT_DIRECTORY)

これらのステートメントの XNUMX つは、メイクファイルの先頭近くにある必要があり、実行されます。
ディレクトリが必要になる可能性があるものの前に。

認定条件 do I a command 〜へ 実行します on あらゆる 建てる?

最も簡単な方法は、ルールメカニズムをまったく使用せず、単に実行することです。
この:

ダミー := $(シェルの日付 > last_build_timestamp)

または、次のように Perl ブロッ​​クに入れます。

perl_begin
system("実行するコマンド");
perl_end

このアプローチには、無関係なターゲットが存在する場合でも実行されるという欠点があります。
実行されている。

XNUMX 番目のアプローチは、たとえそれが本物のファイルであっても、そのファイルを偽のターゲットとして宣言することです。
これにより、makepp はビルドするコマンドを毎回再実行することになりますが、それは
何らかのルールの依存関係リストに表示されます。

認定条件 do I 短くする   表示される ビルド コマンド?

多くの場合、コンパイル コマンドには非常に多くのオプションがあり、
画面が読めない。 の表示を抑制することで、表示内容を変更できます。
コマンド全体を表示し、コマンドの興味深い部分を明示的に出力します。 その
次のように、「$(filter_out )」を使用してコマンドの関連部分のみを簡単に出力できます。
この:

ALL_CFLAGS = $(CFLAGS) $(INCLUDES) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o:%。c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(入力)
@$(CC) $(ALL_CFLAGS) -c $(入力) -o $(出力)

(コマンドの前の「@」はコマンドの出力を抑制します。)

これにより、興味深いオプションのほとんどが表示されますが、すべてが表示されるわけではありません。
include ディレクトリ (非常に多くのディレクトリが存在することがよくあります)。 気になる部分があれば
コマンド内で in が連続している場合は、「print」関数を使用することもできます(これにより、
改行なので、いくつかは必要ありません):

目標:
@... $(興味深い部分を印刷) ...

認定条件 do I 変換 a file 依存関係?

一部の不明瞭なファイル形式の場合、スキャナーを実装する価値はありません。 あるプロジェクトで
XML ファイルがあるとします。 foob​​ar.xml の依存関係が含まれています foob​​ar.out:


ある
b
c


XML を解析する必要がないように、この単純なレイアウトに従うことにしました。 とともに
組み込み &sed では、XNUMX 種類の
行:

%.d: %.xml
&sed さん! !$(ステム).out: \\! || す! (.+) !$$1 \\! || す! !# 空の!' \
$(入力) -o $(出力)

foob​​ar.d を含める

これを含めようとすると、最初に「foobar.d」が生成されます。

foob​​ar.out: \
NS \
b \
NS \
# 空の

空の (単なるコメントまたは実際に空の) 行は、末尾の行を気にする必要がなくなります。
バックスラッシュ。 複数行のリストを作成する別の方法は次のとおりです。

%.d: %.xml
&sed さん! !$(ステム).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(入力) -o $(出力)

foob​​ar.d を含める

これにより、同等のものが生成されます。

foob​​ar.out: $((
a
b
c
))

より複雑な書き換えを行う場合は、makefile 内または
インクルードするモジュール。 たとえば、$_ の定義を解除すると、入力行がスキップされます。

サブマイフィルター {
/ の場合は undef $_ を返します
私の $stem = f_stem;
す! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed さん! !$(ステム).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(入力) -o $(出力)

foob​​ar.d を含める

onworks.net サービスを使用してオンラインで makepp_cookbook を使用する


無料のサーバーとワークステーション

Windows と Linux のアプリをダウンロード

Linuxコマンド

Ad