CMake - リンク

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

CMakeには、プロジェクトのターゲット間の依存関係を管理して、正しくリンクするためのいくつかのリンカ関連コマンドがある。

主要なコマンドには、ターゲットにリンクするライブラリを指定するtarget_link_librariesコマンド、ライブラリターゲットを追加するadd_libraryコマンド、
ライブラリディレクトリを追加するlink_directoriesコマンド等がある。

これらのコマンドを使用することにより、ライブラリや実行ファイルが必要な依存関係とともに正しくビルドされるようになる。


target_link_librariesコマンド

target_link_librariesコマンドは、CMakeでターゲットがリンクするライブラリを指定するために使用する。
このコマンドにより、ターゲットが他のライブラリとどのように関係するかを定義することができる。

target_link_librariesコマンドは、ターゲットがどのライブラリとリンクするかを定義して、ターゲット間の依存関係とビルド設定を管理するための重要なコマンドである。
修飾子を使用することで、ライブラリの可視性と依存関係の伝播を制御できる。

 # 基本構文
 target_link_libraries(<ターゲット名> <修飾子 (PRIVATE|PUBLIC|INTERFACE)>
    <ライブラリ名 1>
    <ライブラリ名 2>
    ...
 )


  • ターゲット名
    プロジェクトのターゲット名
  • 修飾子 (PRIVATE|PUBLIC|INTERFACE)
    ライブラリのリンクの可視性を制御する修飾子。
  • ライブラリ名
    リンクするライブラリ名


ターゲットのリンク

target_link_librariesコマンドを呼び出す時は、常に、PRIVATEPUBLICINTERFACEオプションを指定する。

例えば、ライブラリAがライブラリBを必要とする時、ライブラリ間に存在し得る依存関係には、いくつかの異なる種類がある。

  • PRIVATE
    プライベートな依存関係とは、ライブラリAが自身の内部実装でライブラリBを使用することを指定する。
    ライブラリAにリンクする他のものは、ライブラリBについて知る必要はない。なぜなら、ライブラリBはライブラリAの内部実装だからである。

    指定したライブラリは、ターゲット自身のみに適用され、他のターゲットには適用されない。
  • PUBLIC
    パブリックな依存関係とは、ライブラリAが内部でライブラリBを使用するだけでなく、そのインターフェイスでもライブラリBを使用することを指定する。
    例えば、ライブラリAで定義された関数が、ライブラリBで定義・実装された型のパラメータを少なくとも1つ持つ場合、
    ライブラリBの型を持つパラメータを提供しなければ、ライブラリAからその関数を呼び出すことができない。

    指定したライブラリは、ターゲット自身と、そのターゲットをリンクする他のターゲットの両方に適用される。
  • INTERFACE
    インターフェースな依存関係とは、ライブラリAを使用するために、ライブラリBの一部も使用しなければならないことを指定する。
    これは、ライブラリAが内部的にライブラリBを必要とせず、そのインターフェイスでライブラリBを使用するだけであるという点で、PUBLICとは異なる。

    指定したライブラリは、ターゲットをリンクする他のターゲットにのみ適用され、ターゲット自身には適用されない。

    add_libraryコマンドのINTERFACE形式を使用して定義されたライブラリターゲットを使用する場合に便利である。
    例えば、ヘッダファイルのみのライブラリの依存関係を表すためにターゲットを使用する場合等が挙げられる。


target_link_librariesコマンドを使用して、リンクだけではなく、依存関係を捉えることができる。

 target_link_libraries(
    <ターゲット名>
    <PRIVATE または PUBLIC または INTERFACE>
    item 1
    item 2
    # ...略
    [<PRIVATE または PUBLIC または INTERFACE>]
    item 3
    item 4
    # ...略
 )


これにより、あるライブラリが他のライブラリにどのように依存するかをプロジェクトで定義することができる。
CMakeは、この方法でリンクされたライブラリの連鎖を通して依存関係を管理する。

以下の例では、uiライブラリはPUBLICとしてcollectorライブラリとリンクされているため、myAppが直接collectorにリンクしているだけでも、そのPUBLIC関係からmyAppはuiにもリンクされる。
一方、algoライブラリとengineライブラリは、PRIVATEとしてcollectorにリンクされているため、myAppはそれらに直接リンクされるわけではない。
これらのコマンドにより、ターゲット間でtarget_link_librariesコマンドで接続された場合、コンパイラやリンカのフラグやヘッダ検索パスもターゲット間で伝達されるようになる。

 add_library(collector src1.cpp)
 add_library(algo src2.cpp)
 add_library(engine src3.cpp)
 add_library(ui src4.cpp)
 add_executable(myApp main.cpp)
 
 target_link_libraries(
   collector
   PUBLIC ui
   PRIVATE algo engine
 )
 
 target_link_libraries(myApp PRIVATE collector)


このような場合、target_link_librariesコマンドで使用するターゲット名は、
target_link_librariesコマンドが呼び出されている同じディレクトリにおいて、add_executableコマンドまたはadd_libraryコマンドにより定義されている必要がある。

非ターゲットのリンク

target_link_librariesコマンドは、CMakeのターゲット以外にも、以下に示すものを指定することが可能である。

  • ライブラリファイルへのフルパス
    CMakeはそのライブラリファイルをリンカコマンドに追加する。
    ライブラリファイルが変更された場合、CMakeはその変更を検出して、ターゲットを再リンクする。
    CMake 3.3以降では、リンカコマンドは指定されたフルパスを使用するが、CMake 3.2以前では、CMakeが代わりにライブラリを検索するようリンカに要求する場合がある。
    (例. /usr/lib/libfoo.soファイルを-lfooに置換する等)
  • 単純なライブラリ名
    パスなしでライブラリ名だけを指定する場合、リンカコマンドはそのライブラリを検索する。
    (例えば、プラットフォームによって、fooは-lfoo、または、foo.libになる)
  • リンクフラグ
    特殊なケースとして、-lや-framework以外のハイフンで始まる項目は、リンカコマンドに追加されるフラグとして扱われる。

    ただし、これらはPRIVATE項目にのみ使用するように警告している。
    PUBLICINTERFACEとして定義する場合は、他のターゲットに引き継がれてしまい、必ずしも安全とは言えないからである。


上記に加え、項目の前にdebugoptimizedgeneralのいずれかのオプションを付加することができる。
これらのオプションは、ビルドがデバッグビルドとして設定されているかどうかに基づいて、それに続く項目が含まれるべき時をさらに絞り込むことである。
ただし、これらのオプションは、同様の機能をより明確で柔軟かつ堅牢な方法が別に存在するため、現在は使用しない方がよい。

  • debugオプション
    項目の前にdebugオプションを付加する場合、そのビルドがデバッグビルドである場合にのみ追加される。
  • optimizedオプション
    項目の前にoptimizedオプションを付加する場合、ビルドがデバッグビルドでない場合のみ追加される。
  • generalオプション
    項目の前にgeneralオプションを付加する場合、全てのビルド構成に対して項目を追加するように指定する。



ライブラリの検索

find_libraryコマンドを使用して、特定の名前のライブラリを検索することができる。

  • NAMESオプション
    ライブラリ名を指定することにより、libプレフィックス無しでライブラリを検索する。
  • PATHSオプション
    任意
    ライブラリを検索する場所を指定する。
    必要に応じて、パスを調整する。
  • NO_DEFAULT_PATHオプション
    任意
    指定したパスのみを検索する。


以下の例では、動的ライブラリであるlibsmbclient.soファイルを検索して使用している。
もし、ライブラリの検索に失敗した場合、エラーメッセージを表示してビルドを停止する。
ターゲット (実行可能ファイルまたはライブラリ) を定義する。
target_link_librariesコマンドを使用して、検索で発見したライブラリをターゲットにリンクする。

 # ライブラリの検索
 find_library(SMBCLIENT_LIBRARY
    NAMES sambclient
    PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib  # PATHオプションは任意
    NO_DEFAULT_PATH                                            # NO_DEFAULT_PATHオプションは任意
 )
 
 # ライブラリの検索に成功したかどうかを確認
 if(NOT SMBCLIENT_LIBRARY)
    message(FATAL_ERROR "libsmbclient.so library not found")
 endif()
 
 # ターゲット (実行可能ファイルまたはライブラリ) を定義
 # Qtの場合は、qt_add_executableコマンドを使用する
 add_executable(<ターゲット名>
    <ソースファイル 1>
    <ソースファイル 2>
    # ...略
 )
 
 # ターゲットにライブラリをリンク
 target_link_libraries(<ターゲット名>
    ${SMBCLIENT_LIBRARY}
    # ...略
 )



ライブラリパスの指定 (target_link_directoriesコマンド)

target_link_directoriesコマンドは、特定のターゲット (実行可能ファイルやライブラリ) に対して、リンカが追加のライブラリを検索する場所を指定する。

target_link_directoriesコマンドの特徴を以下に示す。

  • スコープの明確化
    target_link_directoriesコマンドは、特定のターゲットに対してのみリンクディレクトリを設定するため、影響範囲が明確である。
  • より細かい制御
    ターゲット単位で設定できるため、プロジェクト全体ではなく必要なターゲットにのみ適用できる。
  • ジェネレータ式の対応
    target_link_directoriesコマンドはジェネレータ式をサポートしており、より柔軟な設定が可能である。
    ${CMAKE_CURRENT_SOURCE_DIR}のようなCMake変数や、$<...>のようなジェネレータ式が使用できる。
  • 順序
    複数のディレクトリを指定する場合、最初に指定したディレクトリから検索する。


基本的な構文を以下に示す。

 target_link_directories(<ターゲット名>
    <INTERFACE|PUBLIC|PRIVATE> [items1...]         # INTERFACE, PUBLIC, PRIVATE: リンクディレクトリの適用スコープ
    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]   # INTERFACE, PUBLIC, PRIVATE: リンクディレクトリの適用スコープ
 )


スコープの意味を以下に示す。

  • PRIVATE
    指定したディレクトリは、このターゲットのみに適用される。
    このターゲットに依存する他のターゲットには伝播しない。

  • INTERFACE
    このターゲットには適用されず、このターゲットに依存する他のターゲットに伝播する。
    主にインターフェースライブラリで使用する。

  • PUBLIC
    PRIVATEとINTERFACEの組み合わせである。
    このターゲットとそれに依存する他のターゲットの両方に適用される。


以下の例では、ターゲット1 (mylib) は、/path/to/private/libsおよび/path/to/public/libsからライブラリを検索する。
ターゲット2 (myapp) は、/path/to/public/libsおよび/path/to/interface/libsからライブラリを検索する。 (mylibに依存しているため)

 add_library(mylib STATIC
    source1.cpp
    source2.cpp
 )
 
 target_link_directories(mylib
    PRIVATE    /path/to/private/libs
    PUBLIC     /path/to/public/libs
    INTERFACE  /path/to/interface/libs
 )
 
 add_executable(myapp
    main.cpp
 )
 
 target_link_libraries(myapp PRIVATE
    mylib
 )



ライブラリパスの指定 (link_directoriesコマンド)

link_directoriesコマンドの使用は非推奨である。
代わりに、target_link_directoriesコマンドを使用することが推奨されている。

ライブラリパスを指定する場合、link_directoriesコマンドを使用する。

 link_directories(/path/to/lib)


link_directoriesコマンドを複数使用する場合、デフォルトでは、指定したパスは最後尾となる。
ただし、link_directoriesコマンドにBEFOREオプションを付加した場合は最前となる。

以下の例では、"-I/path1/to/lib -I/path2/to/lib"となる。

 link_directories(/path1/to/lib)
 link_directories(/path2/to/lib)


以下の例では、"-I/path2/to/lib -I/path1/to/lib" となる。

 link_directories(/path1/to/lib)
 link_directories(BEFORE /path2/to/lib)