web-dev-qa-db-ja.com

MakefileとCMakeを使ってコードをコンパイルする方法の違い

私はC/C++でコーディングし、(GNU)Makefileを使ってコードをコンパイルします。 CMakeでも同じことができ、MakeFileを取得できます。しかし、MakefileとCMakeを使ってコードをコンパイルすることの違いは何ですか?

208
rish

Make(あるいはむしろMakefile)はビルドシステムです - それはあなたのコードをビルドするためにコンパイラと他のビルドツールを動かします。

CMakeはビルドシステムのジェネレータです。それはMakefileを生成することができます、それはNinjaビルドファイルを生成することができます、それはKDEvelopまたはXCodeプロジェクトを生成することができます、それはVisual Studioソリューションを生成することができます。同じ出発点から、同じCMakeLists.txtファイル。したがって、プラットフォームに依存しないプロジェクトがある場合は、CMakeを使用してシステムに依存しないプロジェクトを構築することもできます。

Windowsの開発者がGNU Makeで誓うVisual StudioやUnixの開発者に慣れているなら、CMakeは(のうちの)一つの方法です。

あなたがあなたのプロジェクトをマルチプラットフォームまたは広く使用できるようにするつもりならば、私は常にCMake(または他のbuildsystemジェネレータ、しかしCMakeが私の好みです)を使うことを勧めます。 CMake自体も、依存関係の検出、ライブラリのインターフェース管理、CTest、CDash、CPackとの統合など、いくつかの素晴らしい機能を提供しています。

ビルドシステムジェネレータを使用すると、プロジェクトの将来性が高まります。あなたが今GNU-Make-onlyであっても、後で他のプラットフォーム(Windowsかそれとも埋め込まれたものか)に拡張することを決心するか、あるいは単にIDEを使いたいのであればどうしますか?

307
Angew

CMakeが "ビルドジェネレータ"であることについての記述はよくある誤解です。

技術的には間違っていません。それはそれがどのように機能するかを説明するだけですが、それが何をするものではありません。

質問の文脈では、同じことをします。C/ C++ファイルの束を取り出して、それらをバイナリに変換します。

それで、本当の違いは何ですか?

  • CMakeははるかに高レベルです。これはC++をコンパイルするように作られていて、あなたが書くコードはずっと少ないですが、汎用ビルドにも使うことができます。 makeにはC/C++のルールも組み込まれていますが、ほとんど役に立ちません。

  • CMakeは2段階のビルドを行います。ninjamake、または他の多くのジェネレータで低レベルのビルドスクリプトを生成してから実行します。通常Makefileに積み重ねられるすべてのシェルスクリプトは、生成段階でのみ実行されます。したがって、CMakeのビルドは桁違いに速くなります。

  • CMakeの文法は外部ツールのサポートがはるかに簡単です makeのものより

  • makeがアーティファクトを構築すると、それがどのように構築されたのかを忘れます。どのソースからビルドされたのか、どのコンパイラがフラグを立てたのか? CMakeはそれを追跡し、makeはあなたに任せます。以前のバージョンのMakefile以降にライブラリソースの1つが削除された場合、makeはそれを再構築しません。

  • 現代のCMake(バージョン3.something以降)は "ターゲット"間の依存関係に関して機能します。ターゲットは(悲しいことに)まだ単一のotputファイルですが、推移的(CMake用語では "public"/"interface")の依存関係を持つことができます。これらの推移的な依存関係は、依存関係のあるパッケージに対して公開または非表示にすることができます。 CMakeもあなたのためにディレクトリを管理します。 makeを使用すると、ファイルごと、ディレクトリを手動で管理することができます。

最後の2つのギャップを埋めるために、フラグファイルを使用してmakeで何かをコーディングすることもできますが、それはあなた自身の責任です。 makeには チューリングの完全な言語 (2つ、場合によっては3つのカウント Guile )が含まれていますが、それらはすべてひどいものです。

正直に言うと、これがCMakemakeの共通点です。それらの言語はかなり恐ろしいものです。

  • それらには型がありません。
  • 配列はなく、スペースで区切られた文字列のみなので、地獄からの脱出。
  • 通常、グローバル変数を設定して関数に引数を渡します。 (これは現代のCMakeで取り組まれています - 変数は今名前空間を持つことができます;ターゲットはそのプロパティの名前空間です)
  • 未定義の変数を参照しても、デフォルトでは暗黙のうちに無視されます。

で開始する。

しかしCMakeでは、書く行数がはるかに少なくなります。

7