MakefileとCMakeを使用したコードのコンパイルの違い


288

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


2
cmakeのは、使用忍者にファイルを生成することができます
BЈовић

回答:


403

Make(またはMakefile)はビルドシステムです-コンパイラやその他のビルドツールを駆動してコードをビルドします。

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

Visual Studioに慣れているWindows開発者と、GNU Makeで誓うUnix開発者がいる場合、CMakeは(その1つ)に進む方法です。

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

buildsystemジェネレーターを使用すると、プロジェクトの将来性が高まります。あなたが現在GNU-Makeのみである場合でも、後で他のプラットフォーム(Windowsや組み込みのものなど)に拡張することを決定した場合、または単にIDEを使用したい場合はどうなりますか?


5
@rishはい、それが要点です。ただし、Linuxでプログラムを作成するにはMakefileよりも多くの方法があることに注意してください。たとえば、QtCreator、KDEvelop、Ninjaを参照してください。これらのそれぞれについて、「プロジェクトを作成してMakefileと同期を保つ」か、「CMakeを再実行する」のいずれかです。そして、答えが言及するように、CMakeには、依存関係の発見(例:)find_package()やテスト/パッケージ化のサポートなど、他の機能もあります。
Angewは、SO

3
私は、CMakeが非再帰的なmakefileを作成できないことを読みました。それは本当ですか?
Maxim Egorushkin 2014

1
@Angew 非再帰は、完全なプロジェクト依存関係ツリーでmakeが1回呼び出される場合です。トップレベルのメイクファイルが特定の順序でサブプロジェクトのメイクファイルを呼び出すときの再帰とは対照です。
Maxim Egorushkin 2014

3
これはCMakeの重要な弱点です。GNUmakeにはしわがありますが、時間をかけて習得すると、非常に強力で用途が広く、膨大な数のプラットフォームで動作します。分析する完全な依存関係ツリーがないことは大きな欠陥であり、「再帰的に有害と見なされる」ことをググるだけです。
ErikAlapää15年

1
@ErikAlapää私は記事を詳細に読みますが、一見すると-再帰の深さがデータ駆動型である(つまり、ソースディレクトリの深さなどに依存する)再帰的なmakeについて話しているようです。これはCMakeの場合とは異なります。プロジェクトの構造に関係なく、make呼び出しの合計深度は常に3です。いくつかのビットがオールインワンではなく、サブメイクファイルに委任されているだけですが、プロジェクトの構造をまったく反映していませ。さらに、サブメイクファイルは実際には「自己完結型」ではないため、依存関係の過不足問題に悩まされることはありません。
Angewは2015

39

CMakeが「ビルドジェネレーター」であるという説明は、よくある誤解です。

技術的には問題ありません。それがどのように機能するかを説明するだけで、何が機能するかは説明しません。

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

では、実際の違いは何ですか?

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

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

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

  • 一度makeアーティファクトを構築し、それが構築された方法を忘れてしまいました。ビルド元のソース、コンパイラフラグ CMakeそれを追跡し、makeあなたに任せます。ライブラリー源の一つは、以前のバージョンのため、削除された場合はMakefilemakeそれを再構築しません。

  • モダンCMake(バージョン3.something以降)は、「ターゲット」間の依存関係に関して機能します。ターゲットは依然として単一の出力ファイルです(悲しいことに)が、推移的な(CMake用語では「パブリック」/「インターフェース」)依存関係を持つ可能性があります。これらの推移的な依存関係は、依存パッケージに対して公開または非表示にすることができます。CMakeディレクトリも管理します。ではmake、ファイルごとのレベルとディレクトリごとの管理のレベルで立ち往生しています。

makeフラグファイルを使用して最後の2つのギャップをカバーするようにコードを作成することもできますが、それは自分で行います。チューリング完全な言語(2つ、時には3つがガイルを数える)makeが含まれていて、それらすべてが恐ろしいです。

正直なところ、これは何CMakemakeあり、共通しています-彼らの言語はかなり恐ろしいです:

  • タイプはありません。
  • 配列ではなく、スペースで区切られた文字列のみであるため、地獄をエスケープします。
  • 通常、グローバル変数を設定して関数に引数を渡します。(これは最新のCMakeで取り組んでいます-変数は名前空間を持つことができます。ターゲットはそのプロパティの名前空間です)
  • 未定義の変数への参照は、デフォルトでは黙って無視されます。

で開始する。

しかし、CMakeあなたははるかに少ないコード行を書きます。


1
ここにいくつかの良い情報がありますが、1つの備考は完全に間違っています:cmakeはLISTタイプを持っています。これは、多くのビルドシステムタスクに重要な適切なLIST関数があるため、少し違います:cmake.org/cmake/help/git-master/command /list.html
solveJ

私はそれを「完全に」間違っているとは言いませんが、訂正してくれてありがとう。
ビクターSergienko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.