1. ホーム
  2. cmake

[解決済み] CMakeはどのように使われるのですか?[クローズド]。

2022-09-23 22:35:31

質問

<余談
クローズド . この質問はもっと必要です 集中的 . 現在、回答は受け付けておりません。

<パス

この質問を改善したいですか? 問題を更新して、1つの問題だけに焦点を当てるようにする。 本論文の編集 .

クローズド 4年前 .

CMakeについて、初心者が有用な情報を得るのはなかなか難しいものです。これまでのところ、いくつかの非常に基本的なプロジェクトのセットアップ方法に関するチュートリアルやその他のものを見てきました。しかし、これらのどれもが 何でも の背後にある理由を説明するものはなく、常に多くの穴を埋める必要があります。

CMake を呼び出すと、CMakeLists の というのは ? それはビルドツリーごとに一度だけ呼び出されることになっているのか、それとも何ですか?すべてのビルドが同じソースから同じCMakeLists.txtファイルを使用する場合、どのように私はそれぞれのビルドに異なる設定を使用するのですか? なぜ、各サブディレクトリは、独自のCMakeListsファイルが必要なのですか?プロジェクトのルートにあるもの以外のCMakeLists.txtでCMakeを使用することは意味がありますか?もしそうなら、どのようなケースで? すべてのソースのルートにあるCMakeListsファイルでそれを行う場合と、それらの独自のサブディレクトリ内のCMakeListsファイルから実行可能ファイルやライブラリを構築する方法を指定することの違いは何ですか? Eclipse 用のプロジェクトと Visual Studio 用のプロジェクトを作成する際に -G オプションを変更するだけで、Eclipse 用と Visual Studio 用のプロジェクトを作ることができますか?それはどのように使用されるのでしょうか?

私がこれまでに見たチュートリアル、ドキュメントページ、質問/回答のどれも、CMakeの使い方を理解するための有用な洞察を与えてくれません。例題が徹底していないだけです。どのチュートリアルを読んでも、何か重要なことを見逃しているような気がします。

私のような CMake 初心者が尋ねる多くの質問は、これを明確に尋ねていませんが、初心者として CMake をどのように扱うか、またはそれをどう作るかがわからないという事実を明白にしています。

どのように解決するのですか?

CMakeは何のためにあるのですか?

Wikipediaによると

CMakeは、[...]ソフトウェアのビルドプロセスを管理するためのソフトウェアである。 であり、コンパイラに依存しない方法でソフトウェアのビルドプロセスを管理するためのソフトウェアです。このソフトウェアは ディレクトリ階層と複数のライブラリに依存するアプリケーションをサポートするように設計されています。 ライブラリに依存するアプリケーションをサポートするように設計されています。makeやAppleのXperiaなど、ネイティブのビルド環境と組み合わせて使用します。 Microsoft Visual Studio などのネイティブビルド環境と組み合わせて使用します。

CMake を使用すると、コンパイラー/ビルド環境に固有の設定を個別に維持する必要がなくなります。あなたには 一つ の設定があり、それは 多くの 環境で動作します。

CMake は、Microsoft Visual Studio ソリューション、Eclipse プロジェクト、または Makefile の迷路から と同じ ファイルを何も変更することなく生成できます。

コードのあるディレクトリの束が与えられると、CMake は依存関係、ビルド順序、およびプロジェクトがコンパイルできるようになる前に行う必要があるその他のタスクをすべて管理します。実際に何かをコンパイルするわけではありません。CMake を使用するには、(CMakeLists.txt と呼ばれる設定ファイルを使用して)どの実行ファイルをコンパイルする必要があるか、どのライブラリにリンクするか、プロジェクトにどのディレクトリがありその中に何があるか、さらにフラグやその他の必要なものの詳細を伝える必要があります(CMake は非常に強力です)。

これが正しく設定されると、次に CMake を使用して、選択した "ネイティブ ビルド環境" がその仕事をするために必要とするすべてのファイルを作成します。Linux では、デフォルトで、これは Makefile を意味します。そのため、CMake を実行すると、CMake 自身が使用するファイルの束と、いくつかの Makefile s. それ以降は、コードの編集が終わるたびにルートフォルダからコンソールに "make" と入力するだけで、コンパイル・リンクされた実行形式ができあがります。

CMakeはどのように動作しますか?何をするのですか?

ここでは、全体を通して使用するプロジェクトのセットアップの例を示します。

simple/
  CMakeLists.txt
  src/
    tutorial.cxx
    CMakeLists.txt
  lib/
    TestLib.cxx
    TestLib.h
    CMakeLists.txt
  build/

各ファイルの内容については、後ほど表示・説明します。

CMakeはプロジェクトのセットアップを ルート CMakeLists.txt を実行すると、プロジェクトのどのディレクトリでもそうなります。 cmake を実行したディレクトリで実行されます。プロジェクトのルートでないフォルダからこれを実行すると、いわゆる アウトオブソース と呼ばれるビルドを生成します。つまり、コンパイル中に作成されたファイル (obj ファイル、lib ファイル、実行ファイル、など) は、実際のコードとは別に、このフォルダに置かれます。これは、混乱を減らすのに役立ち、また、他の理由からも好ましいことですが、ここでは説明しません。

を実行した場合に何が起こるかはわかりません。 cmake をルート以外の場所で実行するとどうなるかはわかりません。 CMakeLists.txt .

この例では、すべて build/ フォルダの中に置きたいので、まずそこに移動して、CMake にルート CMakeLists.txt が存在するディレクトリを指定します。

cd build
cmake ..

デフォルトでは、私が言ったように、Makefile を使ってすべてをセットアップします。ビルドフォルダは以下のようになっているはずです。

simple/build/
  CMakeCache.txt
  cmake_install.cmake
  Makefile
  CMakeFiles/
    (...)
  src/
    CMakeFiles/
      (...)
    cmake_install.cmake
    Makefile
  lib/
    CMakeFiles/
      (...)
    cmake_install.cmake
    Makefile

これらのファイルはすべて何ですか? あなたが気にしなければならないのは、Makefile とプロジェクトフォルダだけです。 .

注目すべきは src/lib/ フォルダーがあります。これらが作成されたのは simple/CMakeLists.txt がそれらを指しているからです。 add_subdirectory(<folder>) . このコマンドは、CMake に当該フォルダー内の別の CMakeLists.txt ファイルを探して その スクリプトを実行するので、この方法で追加されたすべてのサブディレクトリは を持つことになります。 CMakeLists.txt ファイルでなければなりません。このプロジェクトでは simple/src/CMakeLists.txt は実際の実行ファイルをどのように構築するかを記述しており simple/lib/CMakeLists.txt はライブラリの構築方法を記述しています。すべてのターゲットは CMakeLists.txt が記述しているターゲットは、デフォルトでビルドツリー内のそのサブディレクトリに配置されます。ですから

make

から行われたコンソールでの build/ で、いくつかのファイルが追加されています。

simple/build/
  (...)
  lib/
    libTestLib.a
    (...)
  src/
    Tutorial
    (...)

プロジェクトがビルドされ、実行ファイルが準備されました。 実行ファイルを特定のフォルダに置きたい場合はどうすればいいのでしょうか? 適切なCMake変数を設定するか、特定のターゲットのプロパティを変更します。 . CMake変数については後ほど詳しく説明します。

CMakeにプロジェクトのビルド方法を教えるには?

ここでは、ソースディレクトリ内の各ファイルの内容を説明します。

simple/CMakeLists.txt :

cmake_minimum_required(VERSION 2.6)

project(Tutorial)

# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)

必要最小限のバージョンは常に設定されるべきで、設定されていない場合に CMake が投げる警告に従います。CMakeのバージョンが何であれ、使用してください。

プロジェクトの名前は後で使用することができ、同じCMakeファイルから複数のプロジェクトを管理することができるという事実へのヒントとなります。しかし、私はそれについて掘り下げません。

前述したように add_subdirectory() はプロジェクトにフォルダーを追加します。つまり、CMake はプロジェクトに CMakeLists.txt があることを期待し、それを実行してから作業を続けます。ところで、もしCMakeの関数が定義されていれば、その関数を他の CMakeLists.txt を使用する前に定義する必要があります。 add_subdirectory() を使う前に定義しておかないと見つかりません。CMake はライブラリに関してよりスマートなので、この種の問題に遭遇するのはおそらくこの時だけでしょう。

simple/lib/CMakeLists.txt :

add_library(TestLib TestLib.cxx)

自分だけのライブラリを作るには、名前を付けて、そのライブラリの元になるファイルをすべて列挙します。簡単ですね。もし別のファイルが必要なら foo.cxx という別のファイルをコンパイルする必要がある場合は、代わりに次のように書きます。 add_library(TestLib TestLib.cxx foo.cxx) . これは他のディレクトリにあるファイルにも当てはまります。 add_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx) . CMAKE_SOURCE_DIR 変数については、後で詳しく説明します。

これでできるもう一つのことは、共有ライブラリが欲しいことを指定することです。例では add_library(TestLib SHARED TestLib.cxx) . 恐るべし、ここからがCMakeの腕の見せ所です。共有であろうとなかろうと、このようにして作られたライブラリを使うために必要な処理は、ここでつけた名前だけです。このライブラリの名前はTestLibとなり、このライブラリを どこでも を指定します。CMakeはそれを見つけます。

依存関係をリストする良い方法はありますか? 間違いなくそうです . これについては、下記をチェックしてください。

simple/lib/TestLib.cxx :

#include <stdio.h>

void test() {
  printf("testing...\n");
}

simple/lib/TestLib.h :

#ifndef TestLib
#define TestLib

void test();

#endif

simple/src/CMakeLists.txt :

# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)

# Link to needed libraries
target_link_libraries(Tutorial TestLib)

# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)

コマンドは add_executable() と全く同じ動作をします。 add_library() と同じように動作しますが、もちろん、代わりに実行ファイルを生成します。この実行ファイルをターゲットとして target_link_libraries() . tutorial.cxx は TestLib ライブラリにあるコードを使用しているので、このように CMake に指摘します。

同様に、.h ファイルはすべて add_executable() である ではない は何らかの方法で追加されなければなりません。もし target_include_directories() コマンドを使用します。 lib/TestLib.h はチュートリアルをコンパイルするときに見つからないので、全体の lib/ フォルダ全体がインクルードディレクトリに追加され、#includesが検索されるようになります。また、次のようなコマンドを目にすることもあるでしょう。 include_directories() というコマンドもありますが、これはターゲットを指定する必要がなく、すべての実行ファイルに対してグローバルに設定します。もう一度言いますが、CMAKE_SOURCE_DIR については後で説明します。

simple/src/tutorial.cxx :

#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
  test();
  fprintf(stdout, "Main\n");
  return 0;
}

どのように "TestLib.h" ファイルがインクルードされているかに注目してください。フルパスでインクルードする必要はありません。CMake が舞台裏ですべての面倒を見てくれるのは target_include_directories() .

技術的に言えば、このような単純なソースツリーでは CMakeLists.txt の下にある lib/src/ のようなものを追加するだけです。 add_executable(Tutorial src/tutorial.cxx)simple/CMakeLists.txt . それはあなたとあなたのプロジェクトのニーズ次第です。

CMake を適切に使用するために、他に知っておくべきことはありますか?

(あなたの理解に関連する別名トピック)

パッケージの検索と使用 : この質問に対する答え は、私よりもうまく説明しています。

変数や関数の宣言、コントロールフローの使用など。 : チェックアウト このチュートリアル は、CMakeが提供するものの基本を説明し、また一般的な導入としても良いものです。

CMakeの変数 : たくさんあるので、以下は正しい道を歩むためのクラッシュコースです。 CMake wikiは変数についてのより詳細な情報を得るのによい場所です。 と表向きは他の事と同様に。

ビルドツリーを再構築することなく、いくつかの変数を編集したい場合があります。これには ccmake を使ってください (これは CMakeCache.txt ファイルを編集します)。忘れずに c を設定し、その後に g を実行し、更新された設定で makefile を作成します。

を読んでください。 以前参照したチュートリアル を読んで、変数の使い方について学んでください。しかし、長い話です。 set(<variable name> value) で変数を変更したり作成したりすることができます。 ${<variable name>} で使用する。

  • CMAKE_SOURCE_DIR : ソースのルートディレクトリ。先ほどの例では、これは常に /simple
  • CMAKE_BINARY_DIR : ビルドのルートディレクトリ。先ほどの例では、これは simple/build/ となっていますが、もし cmake simple/ のようなフォルダから foo/bar/etc/ への参照はすべて CMAKE_BINARY_DIR へのすべての参照は、そのビルドツリーでは /foo/bar/etc .
  • CMAKE_CURRENT_SOURCE_DIR : 現在の CMakeLists.txt があるディレクトリ。これは、全体を通して変化することを意味します: これを印刷すると simple/CMakeLists.txt からこれを印刷すると /simple となり、それを simple/src/CMakeLists.txt/simple/src .
  • CMAKE_CURRENT_BINARY_DIR : イメージはつかめたでしょうか。このパスはビルドがあるフォルダーに依存するだけでなく、現在の CMakeLists.txt スクリプトの場所にも依存します。

なぜこれらが重要なのでしょうか?ソースファイルは当然ながらビルドツリーには存在しません。もしあなたが以下のようなことをしようとしたら target_include_directories(Tutorial PUBLIC ../lib) のようにしようとすると、そのパスはビルドツリーからの相対パスとなります。 ${CMAKE_BINARY_DIR}/lib と書くようなもので、その内部は simple/build/lib/ . この中には .h ファイルはなく、せいぜい libTestLib.a . あなたが欲しいのは ${CMAKE_SOURCE_DIR}/lib の代わりに

  • CMAKE_CXX_FLAGS : コンパイラ、この場合はC++コンパイラに渡すフラグです。また、注目すべきは CMAKE_CXX_FLAGS_DEBUG で、これはもし CMAKE_BUILD_TYPE がDEBUGに設定されている場合、代わりに使用されます。このようなものがもっとあります。 CMake wiki を参照してください。 .
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY : CMake に、ビルド時にすべての実行ファイルをどこに置くか指示します。これはグローバルな設定です。例えば、以下のように設定できます。 bin/ に設定すると、すべてがそこに整然と配置されます。 EXECUTABLE_OUTPUT_PATH は似ていますが、非推奨です。
  • CMAKE_LIBRARY_OUTPUT_DIRECTORY : 同様に、すべてのライブラリファイルをどこに置くかを CMake に伝えるためのグローバルな設定です。

ターゲットプロパティ 実行ファイルやライブラリ(またはアーカイブ)など、1つのターゲットにのみ影響するプロパティを設定することができます。 以下は良い例です。 の使い方の良い例です( set_target_properties() .

ターゲットにソースを自動的に追加する簡単な方法はありますか? GLOBを使う を使って、与えられたディレクトリのすべてを同じ変数の下にリストアップします。構文例は以下の通りです。 FILE(GLOB <variable name> <directory>/*.cxx) .

異なるビルドタイプを指定することはできますか? はい、しかしこれがどのように機能するか、またはこれの限界について私はよくわかりません。おそらくいくつかの if/then'ning が必要ですが、CMake は何も設定せずにいくつかの基本的なサポートを提供します。 CMAKE_CXX_FLAGS_DEBUG のデフォルトのように、何も設定しなくても基本的なサポートを提供しています。 ビルドタイプは CMakeLists.txt ファイルの中で set(CMAKE_BUILD_TYPE <type>) または、コンソールから適切なフラグを付けて CMake を呼び出すことで、例えば次のようになります。 cmake -DCMAKE_BUILD_TYPE=Debug .

CMakeを使用したプロジェクトの良い例があれば教えてください。 WikipediaにCMakeを使用したオープンソースプロジェクトのリストがありますので、もし調べたいのであれば。オンラインチュートリアルは、この点で私にこれまで失望以外の何ものでもありませんでした。 このStack Overflowの質問 には、かなりクールでわかりやすいCMakeのセットアップがあります。これは一見の価値があります。

CMakeの変数をコードで使用する : 以下は、簡単で汚い例です。 他のチュートリアル ):

simple/CMakeLists.txt :

project (Tutorial)

# Setting variables
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 1)

# Configure_file(<input> <output>)
# Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
# So you can pass some CMake variables to the source code (in this case version numbers)
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
)

simple/TutorialConfig.h.in :

// Configured options and settings
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

CMakeで生成された結果ファイルです。 simple/src/TutorialConfig.h :

// Configured options and settings
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 1

これらを巧みに利用することで、ライブラリの電源を切ったりするようなクールなことができるようになります。私は、以下のものを見てみることをお勧めします。 そのチュートリアル を見てみることをお勧めします。少し高度なものもあり、いずれは大きなプロジェクトでとても役立つはずです。

その他のことについては、Stack Overflow は具体的な質問と簡潔な回答であふれかえっており、不慣れな人以外のすべての人にとって素晴らしいものです。