これで解決!CMake target_link_options()のエラーとトラブルシューティング

2025-05-16

target_link_options() の基本的な説明

このコマンドは、コンパイラがリンカを呼び出す際に渡されるフラグやオプションを指定します。例えば、特定のライブラリをリンクする際に特別なオプションが必要な場合や、リンカの動作を制御したい場合などに使用します。

基本的な構文は以下の通りです。

target_link_options(<target> [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

各要素について詳しく説明します。

  • [items...]: 実際に追加したいリンカオプションを指定します。これらはリンカに直接渡されるフラグです。例えば、-Wl,--gc-sections (未使用セクションを削除) や -pthread (pthreadsライブラリをリンク) などです。

  • <INTERFACE|PUBLIC|PRIVATE>: これは、追加するオプションのスコープ(適用範囲)を定義する重要なキーワードです。

    • PRIVATE:
      • オプションは指定された <target> 自身がリンクされるときにのみ適用されます。
      • このターゲットに依存する他のターゲットには影響しません。
      • 内部的なリンク設定に主に使用されます。
    • PUBLIC:
      • オプションは指定された <target> 自身がリンクされるときに適用されます。
      • さらに、このターゲットに依存する他のターゲットがこのターゲットをリンクする際にも、そのオプションが「伝播」されます。
      • つまり、このターゲットを使用するすべてのターゲットにリンクオプションが伝わります。
    • INTERFACE:
      • オプションは指定された <target> 自身がリンクされるときには適用されません。
      • このターゲットに依存する他のターゲットがこのターゲットをリンクする際にのみ、そのオプションが「伝播」されます。
      • ヘッダーオンリーライブラリのように、自身はリンクステップを持たないが、それを使用するターゲットに特定のリンカオプションが必要な場合などに便利です。
  • [BEFORE]: このキーワードを指定すると、追加されるオプションが既存のオプションの先頭に追加されます。指定しない場合は末尾に追加されます。

  • <target>: オプションを追加したいターゲットの名前を指定します。このターゲットは、add_executable()add_library() などのコマンドで事前に作成されている必要があります。エイリアスターゲット (ALIAS target) には使用できません。

target_link_libraries() との違い

target_link_options()target_link_libraries() と混同されがちですが、役割が異なります。

  • target_link_options():

    • 主にリンカオプション(フラグ)を追加するために使用されます。例えば、-Wl,--as-needed のような、リンカの動作を制御するフラグを追加する場合に利用します。
    • ライブラリそのもののリンクではなく、リンクの方法を調整します。
  • target_link_libraries():

    • 主にライブラリそのものをリンクするために使用されます。例えば、target_link_libraries(my_app PRIVATE my_lib) は、my_appmy_lib に依存していることを示し、my_lib をリンクするように指示します。
    • これにより、コンパイラやリンカに my_lib のパスや名前が渡され、適切にライブラリが解決されます。

具体的な使用例

# 実行ファイルを作成
add_executable(my_program main.cpp)

# my_program のリンク時に、特定のリンカオプションを追加する
# PRIVATE スコープなので、my_program 自身にのみ適用される
target_link_options(my_program PRIVATE -Wl,--gc-sections -Wl,--as-needed)

# 共有ライブラリを作成
add_library(my_shared_lib SHARED shared_lib.cpp)

# my_shared_lib のリンク時に、-fPIC (Position Independent Code) を強制する
# これはコンパイラフラグのように見えますが、リンカが共有ライブラリを作成する際にも影響するため、
# target_link_options で指定することもあります。(通常は target_compile_options で十分な場合が多い)
target_link_options(my_shared_lib PRIVATE -fPIC)

# 別の実行ファイルを作成し、my_shared_lib に依存させる
add_executable(another_program another_main.cpp)
target_link_libraries(another_program PRIVATE my_shared_lib)

# もし my_shared_lib を PUBLIC スコープでオプションを追加した場合、
# another_program にもそのオプションが伝播します。
# 例: my_shared_lib をリンクするすべてのプログラムに特定のデバッグ情報を付与したい場合
add_library(my_public_lib SHARED public_lib.cpp)
target_link_options(my_public_lib PUBLIC -Wl,--version-script,version.map)
# another_program が my_public_lib に依存する場合、
# another_program のリンク時にも -Wl,--version-script,version.map が適用される
target_link_libraries(another_program PRIVATE my_public_lib)

# INTERFACE スコープの例
# ヘッダーオンリーライブラリなど、それ自体はリンクされないが、
# それを使用するターゲットに特定のリンカオプションが必要な場合
add_library(my_interface_lib INTERFACE)
target_link_options(my_interface_lib INTERFACE -Wl,-no-undefined) # 未定義シンボルを許可しない
# my_interface_lib を使用するターゲットは、自動的にこのリンカオプションを受け取る
add_executable(app_using_interface app.cpp)
target_link_libraries(app_using_interface PRIVATE my_interface_lib)

ジェネレータ式 (Generator Expressions)

target_link_options() は、$<...> の形式でジェネレータ式をサポートしています。これにより、ビルド設定(Debug/Releaseなど)やプラットフォームに応じて動的にリンカオプションを変更できます。

例:

target_link_options(my_program PRIVATE
    $<$<CONFIG:Debug>:-D_DEBUG>  # Debugビルドの場合に -D_DEBUG を追加
    $<$<LINK_LANG_AND_CONFIG:CXX,Release>:-O3> # C++でReleaseビルドの場合に -O3 を追加
)

LINKER: プレフィックス

リンカ固有のオプションをポータブルに指定するために、LINKER: プレフィックスを使用できます。これはCMakeが自動的に適切なコンパイラドライバのリンカオプション形式に変換してくれます。

# `-z defs` をリンカに渡す(未定義シンボルがあるとエラーにする)
# GNU GCC の場合は `-Wl,-z,defs` に、Clang の場合は `-Xlinker -z -Xlinker defs` に変換される
target_link_options(my_program PRIVATE "LINKER:-z,defs")

target_link_options() は、静的ライブラリのターゲットには直接適用できません。静的ライブラリは、それ自体がリンクステップを持たないためです。静的ライブラリのアーカイブツール(アーカイバ、ar など)にオプションを渡したい場合は、STATIC_LIBRARY_OPTIONS ターゲットプロパティを使用します。



target_link_options() の対象となるターゲットが存在しない

エラーメッセージの例

CMake Error at CMakeLists.txt:XX (target_link_options):
  Cannot specify link options for target "my_non_existent_target" which is
  not built by this project.

原因
target_link_options() は、add_executable()add_library() などで既に定義されているターゲットに対してのみ適用できます。コマンドを呼び出す前にターゲットが作成されていない場合、このエラーが発生します。また、タイプミスでターゲット名を間違えている場合も同様です。ALIAS ターゲットにも使用できません。

トラブルシューティング

  • ALIAS ターゲットではないことを確認してください。
  • ターゲット名のスペルミスがないか確認してください。
  • target_link_options() を呼び出す前に、指定されたターゲットがadd_executable() または add_library() で正しく定義されているか確認してください。

静的ライブラリに target_link_options() を適用しようとしている

原因
静的ライブラリ(add_library(my_static_lib STATIC ...) で作成されたもの)は、それ自体がリンクステップを持たないため、target_link_options() を直接適用することはできません。静的ライブラリは、それをリンクする他のターゲット(実行ファイルや共有ライブラリ)のリンク時に「アーカイブ」として扱われます。

トラブルシューティング

  • 静的ライブラリ自体にアーカイブ時に特別なフラグ(例えば、WindowsのMSVCでarに相当するツールに渡すフラグなど)が必要な場合は、set_target_properties() を使用して STATIC_LIBRARY_OPTIONS プロパティを設定することを検討してください。
    add_library(my_static_lib STATIC my_static_lib.cpp)
    set_target_properties(my_static_lib PROPERTIES
        STATIC_LIBRARY_OPTIONS "-my-ar-option"
    )
    
  • 静的ライブラリに対するリンカオプションが必要な場合、その静的ライブラリをリンクする実行ファイルまたは共有ライブラリのターゲットtarget_link_options() を適用してください。

オプションが期待通りにリンカに渡されない (特にプラットフォーム間での違い)

原因
リンカオプションの指定方法は、使用するコンパイラ(GCC、Clang、MSVCなど)やプラットフォーム(Linux、Windows、macOSなど)によって異なる場合があります。

  • LINKER: プレフィックスの誤用
    LINKER: プレフィックスは、CMakeがプラットフォーム固有のリンカオプション形式に自動的に変換してくれますが、その使用法を誤ると意図しない結果になることがあります。
  • コンパイラドライバによる変換
    gcc -Wl,--gc-sections のように、コンパイラドライバがリンカオプションをリンカに渡すために特定のプレフィックス(-Wl,-Xlinker など)を必要とする場合があります。
  • スペースを含むオプション
    オプションにスペースが含まれる場合、文字列として正しくクォートされていないと、リンカが単一のオプションとして認識しないことがあります。

トラブルシューティング

  • ビルドコマンドの確認
    実際に生成されたビルドシステム(MakefileやVisual Studioプロジェクトファイルなど)がどのようにリンカを呼び出しているかを確認します。これにより、オプションが正しく渡されているか、あるいは変換に問題があるかを確認できます。Verbose Makefiles (例: make VERBOSE=1) や Visual Studio のビルド出力を見ることで確認できます。
  • オプションのクォート
    スペースを含むオプションは、必ずダブルクォートで囲んでください。
    # 悪い例: -Wl,-version-script,version.map が分割される可能性
    # target_link_options(my_program PRIVATE -Wl,-version-script,version.map)
    # 良い例
    target_link_options(my_program PRIVATE "-Wl,--version-script,version.map")
    
  • LINKER: プレフィックスの使用
    可能な限り、LINKER: プレフィックスを使用して、リンカに直接渡したいオプションを指定します。これにより、CMakeが適切な変換を行ってくれます。
    # 例: 未使用セクションの除去 (クロスプラットフォーム対応)
    target_link_options(my_program PRIVATE "LINKER:--gc-sections")
    
    # 複数のオプションをカンマで区切って指定することも可能
    target_link_options(my_program PRIVATE "LINKER:--start-group,--end-group")
    

オプションのスコープ (PRIVATE, PUBLIC, INTERFACE) の誤解

原因
target_link_options() のスコープキーワード (PRIVATE, PUBLIC, INTERFACE) を誤解していると、オプションが期待通りに伝播しなかったり、逆に不要なオプションが伝播してビルドエラーや警告を引き起こすことがあります。

  • INTERFACE の誤用
    そのターゲット自身がリンクステップを持たない(例えばヘッダーオンリーライブラリ)場合にのみ INTERFACE を使用すべきですが、そうでないターゲットに使用するとオプションが適用されません。
  • PUBLIC の誤用
    そのターゲット自体にのみオプションが必要なのに PUBLIC を使うと、そのターゲットに依存するすべてのターゲットに不要なオプションが伝播し、リンクエラーやパフォーマンス低下を招く可能性があります。
  • PRIVATE の誤用
    依存するターゲットにもオプションを伝播させたいのに PRIVATE を使ってしまった場合、オプションが伝播されません。

トラブルシューティング

  • オプションの伝播を追跡するには、依存関係ツリーを想像し、各ターゲットのリンク行にオプションがどのように現れるかをシミュレートしてみてください。
  • 各スコープの定義を再確認し、意図する伝播動作と合致しているか確認してください。
    • PRIVATE
      そのターゲット自身のみ。
    • PUBLIC
      そのターゲット自身と、そのターゲットに依存するすべてのターゲット。
    • INTERFACE
      そのターゲット自身には適用されず、そのターゲットに依存するすべてのターゲットにのみ適用。

ジェネレータ式 (Generator Expressions) の構文エラー

原因
ジェネレータ式は強力ですが、構文が複雑になることがあります。特にドル記号 ($) や括弧の数が合わない、条件式の指定を間違えるなどのミスが起こりやすいです。

トラブルシューティング

  • エラーメッセージにジェネレータ式に関連する情報が含まれている場合は、そのヒントに従ってください。
  • 複雑なジェネレータ式は、一旦シンプルな形から段階的に構築し、動作を確認しながら進めてください。
  • ジェネレータ式の構文 ($<CONDITION:VALUE>) を厳密に確認してください。

リンク順序の問題と target_link_options() の関係

原因
target_link_options() はリンカオプションを追加しますが、ライブラリのリンク順序そのものを直接制御するわけではありません。しかし、特定のリンカオプション(例: --start-group, --end-group)は、ライブラリの解決順序に影響を与えることがあります。ライブラリ間のシンボル依存関係が複雑な場合、リンカオプションの適用順序が重要になることがあります。

トラブルシューティング

  • --start-group--end-group のようなオプションを使用している場合は、それらが正しくペアになっているか、そして適切なライブラリのグループを囲んでいるかを確認してください。
  • もしリンカオプションが原因で順序の問題が発生していると疑われる場合は、リンカのドキュメントを確認し、そのオプションがリンカの動作にどのように影響するかを理解してください。
  • ライブラリのリンク順序の問題は、通常 target_link_libraries() の問題であることが多いです。まずそちらを見直してください。

キャッシュの問題

原因
CMakeのビルド設定はキャッシュされます。CMakeLists.txt を変更しても、既存のキャッシュが古いために変更が反映されないことがあります。

  • または、CMake: Clean Cache (VS CodeなどのIDEの場合) や rm -rf build などでキャッシュをクリアしてください。
  • ビルドディレクトリを削除し、ゼロから再構成(cmake . または cmake -B build -S .)して再ビルドしてみてください。
  • CMakeの公式ドキュメント
    target_link_options() の詳細については、常にCMakeの公式ドキュメントを参照してください。最新の情報や、特定のバージョンでの変更点が記載されている場合があります。
  • 最小限の再現コード
    問題が複雑な場合は、最小限の CMakeLists.txt とソースファイルで問題を再現する試みを行ってください。これにより、問題の原因を絞り込みやすくなります。
  • message() コマンドの活用
    CMakeスクリプト内で message(STATUS "DEBUG: My option is ${MY_OPTION}") のように message() コマンドを使って、変数の値や条件式の評価結果を出力し、期待通りの値になっているか確認します。


基本的な使用法: PRIVATE スコープでのリンカオプション追加

この例では、実行ファイルが独自のリンカオプションを必要とする場合を示します。他のターゲットにこのオプションが伝播する必要はありません。

プロジェクト構成

.
├── CMakeLists.txt
└── main.cpp

main.cpp

#include <iostream>

int main() {
    std::cout << "Hello from target_link_options example!" << std::endl;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(MyProgram CXX)

add_executable(my_program main.cpp)

# my_program 自身のリンク時にのみ適用されるリンカオプションを追加
# -Wl,--gc-sections: 未使用のコードやデータを削除 (ELF形式のシステムでよく使われる)
# -Wl,--as-needed: ライブラリを本当に必要な場合のみリンク (Linuxでリンカが遅延解決する際に役立つ)
target_link_options(my_program PRIVATE
    "-Wl,--gc-sections"
    "-Wl,--as-needed"
)

# ビルドディレクトリで `make VERBOSE=1` を実行すると、
# 生成されるリンクコマンドに上記のオプションが含まれていることを確認できます。

解説

  • オプションの形式はリンカに直接渡されるものです。-Wl, はGCC/Clangでリンカオプションを渡すための一般的なプレフィックスです。
  • PRIVATE キーワードは、これらのオプションが my_program 自身のリンク時のみに適用され、my_program に依存する他のターゲットには伝播しないことを意味します。
  • target_link_options(my_program PRIVATE ...) は、my_program という名前のターゲットに対してリンカオプションを設定します。

PUBLIC スコープでのリンカオプション伝播

この例では、ライブラリが特定のリンカオプションを必要とし、そのライブラリを利用する他のターゲットにもそのオプションが伝播すべき場合を示します。

プロジェクト構成

.
├── CMakeLists.txt
├── my_lib.h
├── my_lib.cpp
└── main.cpp

my_lib.h

#pragma once
void print_lib_message();

my_lib.cpp

#include "my_lib.h"
#include <iostream>

void print_lib_message() {
    std::cout << "Message from MyLib!" << std::endl;
}

main.cpp

#include "my_lib.h" // MyLib に依存
#include <iostream>

int main() {
    std::cout << "Hello from main!" << std::endl;
    print_lib_message();
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(LinkOptionsPublicExample CXX)

# 共有ライブラリを作成
add_library(MyLib SHARED my_lib.cpp my_lib.h)

# MyLib に PUBLIC スコープでリンカオプションを追加
# この例では、-Wl,-no-undefined を使用します。これは、
# 未定義のシンボルがあるとリンク時にエラーとすることを強制します。
# MyLib を利用するすべてのターゲットにこの厳格なリンカ設定を適用したい場合に使えます。
target_link_options(MyLib PUBLIC
    "-Wl,-no-undefined"
)

# MyLib を使用する実行ファイルを作成
add_executable(my_app main.cpp)

# my_app が MyLib に依存することを宣言
target_link_libraries(my_app PRIVATE MyLib)

# my_app のリンク時、MyLib の PUBLIC リンカオプションである
# "-Wl,-no-undefined" が自動的に適用されます。
# これを確認するには、my_lib.cpp から print_lib_message の定義を削除してビルドすると、
# my_app のリンク時に未定義シンボルエラーが発生することを確認できます。

解説

  • この設定により、MyLib を利用するすべてのコンポーネントが、定義されていないシンボルがあるとリンクエラーになるという厳格なリンカチェックの恩恵(または制約)を受けます。
  • target_link_options(MyLib PUBLIC ...) は、MyLib 自身のリンク時にオプションが適用され、さらに MyLib に依存する my_app のリンク時にもそのオプションが伝播します。

INTERFACE スコープでのリンカオプション伝播

この例は、それ自体はビルドされない(リンクステップを持たない)インターフェースライブラリが、それを利用するターゲットにリンカオプションを強制する場合に便利です。

プロジェクト構成

.
├── CMakeLists.txt
├── my_interface_header.h
└── main.cpp

my_interface_header.h

#pragma once
// このヘッダーには、例えば特定のリンカフラグを必要とする外部ライブラリへの参照が含まれると仮定
void external_function_requiring_special_link_flag();

main.cpp

#include "my_interface_header.h"
#include <iostream>

int main() {
    std::cout << "Hello from main!" << std::endl;
    // external_function_requiring_special_link_flag(); // 実際にはリンクされないが、例示のため
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(LinkOptionsInterfaceExample CXX)

# インターフェースライブラリを作成
# INTERFACE ライブラリはソースファイルを持たず、プロパティや使用要件を定義するだけ
add_library(MyInterfaceLib INTERFACE)

# MyInterfaceLib に INTERFACE スコープでリンカオプションを追加
# 例えば、特定のシステムライブラリ(例: pthreads)が常に必要であることを示したい場合
# または、特殊なリンカスクリプトが必要な場合など
target_link_options(MyInterfaceLib INTERFACE
    "-pthread" # スレッドサポートが必要なことを示す
    "-Wl,--export-dynamic" # 共有ライブラリの場合、動的にエクスポート
)

# MyInterfaceLib を使用する実行ファイルを作成
add_executable(my_app main.cpp)

# my_app が MyInterfaceLib に依存することを宣言
target_link_libraries(my_app PRIVATE MyInterfaceLib)

# my_app のリンク時、MyInterfaceLib の INTERFACE リンカオプションである
# "-pthread" や "-Wl,--export-dynamic" が自動的に適用されます。
# my_app にスレッド関連のコードがない場合でも、このオプションは伝播します。

解説

  • これにより、ライブラリの利用者が明示的にリンカオプションを追加しなくても、必要な設定が自動的に適用されるようになります。
  • target_link_options(MyInterfaceLib INTERFACE ...) は、MyInterfaceLib 自身には適用されず、MyInterfaceLib に依存するすべてのターゲット(この場合は my_app)のリンク時にのみ、これらのオプションが伝播します。
  • add_library(MyInterfaceLib INTERFACE) は、実際のコードを持たない論理的なグループ(またはヘッダーオンリーライブラリの依存関係)を定義します。

ジェネレータ式 (Generator Expressions) との組み合わせ

ビルド設定(Debug/Releaseなど)やプラットフォームに応じてリンカオプションを動的に変更したい場合に非常に便利です。

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(GeneratorExpressionExample CXX)

add_executable(my_app main.cpp) # main.cpp は上記と同じものを使用

# ビルド設定に応じて異なるリンカオプションを適用
target_link_options(my_app PRIVATE
    # デバッグビルドの場合: デバッグシンボルを含める (-g)
    # リリースビルドの場合: コード最適化を有効にする (-s: シンボルを削除)
    $<$<CONFIG:Debug>:-g>
    $<$<CONFIG:Release>:-s>

    # 特定のプラットフォームでのみ適用されるオプション
    # Linuxの場合: 未定義シンボルを許可しない
    $<$<BOOL:${CMAKE_SYSTEM_NAME STREQUAL "Linux"}>:LINKER:-z,defs>

    # 特定のリンク言語(この場合はCXX=C++)でのみ適用されるオプション
    $<$<LINK_LANG:CXX>:"-Wl,--enable-new-dtags">
)

解説

  • $<$<LINK_LANG:CXX>:"-Wl,--enable-new-dtags">: リンク言語が C++ (CXX) の場合にオプションを追加します。
  • $<$<BOOL:${CMAKE_SYSTEM_NAME STREQUAL "Linux"}>:LINKER:-z,defs>: CMAKE_SYSTEM_NAME"Linux" と等しい場合に LINKER:-z,defs オプションを追加します。LINKER: プレフィックスはクロスプラットフォームでのリンカオプション指定に役立ちます。
  • $<$<CONFIG:Release>:-s>: CONFIGRelease の場合に -s オプションを追加します。
  • $<$<CONFIG:Debug>:-g>: CONFIGDebug の場合に -g オプションを追加します。

リンカに直接渡したいオプションをクロスプラットフォームでポータブルに指定する際に使用します。CMakeが適切なコンパイラドライバのオプション形式に変換してくれます。

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(LinkerPrefixExample CXX)

add_executable(my_app main.cpp) # main.cpp は上記と同じものを使用

# リンカに直接 --strip-all オプションを渡す
# GCC/Clang の場合は -Wl,--strip-all に、MSVC の場合は /LTCG など適切なオプションに変換される
target_link_options(my_app PRIVATE "LINKER:--strip-all")

# 複数のリンカオプションをカンマ区切りで指定する例
# LINKER: の後でカンマ区切りにすることで、それぞれの要素が個別のリンカ引数として扱われる
target_link_options(my_app PRIVATE "LINKER:-z,relro,-z,now")
  • LINKER: プレフィックスを使用すると、CMakeがバックエンドのビルドツール(Makefile、Ninja、Visual Studioなど)に応じて、正しいリンカオプションの形式に変換してくれます。これにより、OSやコンパイラに依存しないポータブルなリンカオプションの指定が可能になります。


set_target_properties() を使用する

target_link_options() は、内部的にターゲットプロパティを設定するショートカットのようなものです。リンカオプションを設定するための直接的なターゲットプロパティは LINK_OPTIONS です。

代替方法

add_executable(my_program main.cpp)

# target_link_options(my_program PRIVATE "-Wl,--gc-sections") と同じ
set_target_properties(my_program PROPERTIES
    LINK_OPTIONS "-Wl,--gc-sections"
)

# PUBLIC や INTERFACE のような伝播ルールを明示的に設定したい場合は、
# INTERFACE_LINK_OPTIONS または LINK_INTERFACE_LIBRARIES を使用し、
# 関連するターゲットプロパティを適切に設定する必要があります。
# これは `target_link_options(PUBLIC/INTERFACE ...)` よりも複雑になりがちです。
# そのため、通常は `target_link_options()` の方が推奨されます。

使い分け

  • INTERFACE_LINK_OPTIONS は、INTERFACE スコープのオプションを定義するために使用されますが、これは target_link_options(... INTERFACE ...) と同等です。
  • set_target_properties(LINK_OPTIONS ...) は、歴史的な理由や、非常に特定のプロパティ操作が必要な場合にのみ使用されます。
  • target_link_options() の方がモダンで推奨される方法です。スコープ(PRIVATE, PUBLIC, INTERFACE)の概念が明確で、オプションの伝播を簡潔に表現できます。

add_link_options() コマンドを使用する(CMake 3.13以降推奨されず)

add_link_options() は、現在のディレクトリおよびそれ以下で定義されるすべてのターゲットに対してリンカオプションを追加します。これはグローバルまたはディレクトリスコープのリンカオプション設定に使用できます。

代替方法

# CMake 3.13 以降では推奨されません
add_link_options("-Wl,--export-dynamic")

add_executable(my_program main.cpp) # my_program にも上記のオプションが適用される

使い分け

  • 推奨されない理由
    ターゲットごとに制御する方が柔軟で、依存関係の明確化にもつながるため、より粒度の高い target_link_options() が推奨されています。
  • グローバルな影響
    add_link_options() は、その呼び出し以降に定義されるすべてのターゲットに影響を与えるため、意図しない副作用を引き起こす可能性があります。特定のターゲットにのみオプションを適用したい場合は不適切です。
  • 非推奨
    CMake 3.13 以降、このコマンドは非推奨(deprecated)とされています。代わりに target_link_options() または cmake_push_check_state()/cmake_pop_check_state() と組み合わせて使用することを推奨されています。

link_options ディレクトリプロパティを使用する

link_options はディレクトリプロパティであり、set_property() コマンドを使用して設定できます。これも add_link_options() と同様に、現在のディレクトリとサブディレクトリのターゲットに影響を与えます。

代替方法

set_property(DIRECTORY APPEND PROPERTY LINK_OPTIONS "-Wl,--my-global-option")

add_executable(my_program main.cpp) # my_program にも上記のオプションが適用される

使い分け

  • 特定のリンカオプションをプロジェクト全体や特定のサブディレクトリ全体に適用したい場合にのみ検討されますが、通常は target_link_options() を各ターゲットで明示的に設定する方が管理しやすいです。
  • add_link_options() の代替として使用できますが、やはりターゲットごとの制御が失われます。
  • add_link_options() と同様に、ディレクトリ以下のすべてのターゲットに影響を与えます。

CMAKE_EXE_LINKER_FLAGS, CMAKE_SHARED_LINKER_FLAGS などを使用する

これらは CMake のグローバルな変数で、すべての実行ファイル、共有ライブラリなどに適用されるリンカフラグを定義します。

代替方法

# 全ての実行ファイルに適用されるリンカフラグ
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--verbose")

# 全ての共有ライブラリに適用されるリンカフラグ
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")

add_executable(my_program main.cpp) # 上記フラグが適用される
add_library(my_lib SHARED my_lib.cpp) # 上記フラグが適用される

使い分け

  • 上書きの可能性
    ユーザーがキャッシュ変数としてこれらの値を設定できるため、予期せぬ上書きが発生する可能性があります。
  • 柔軟性の欠如
    target_link_options() のようにターゲットごとの制御やスコープの概念がないため、特定のターゲットにのみ適用したい場合には不適切です。
  • グローバルな影響
    これらの変数はプロジェクト全体に影響を与えるため、非常に限定的な状況(例: デフォルトで全てのビルドに適用したい、あるいは特定のプラットフォームでのみ必要な非常に基本的なフラグ)でのみ使用すべきです。

target_link_libraries() でリンカオプションを渡す (非推奨)

過去のCMakeバージョンでは、target_link_libraries() にリンカオプションを直接渡すことが可能でした。これは非推奨であり、もはや行うべきではありません。

過去の非推奨な方法

# 非推奨: このようにリンカオプションを渡してはいけません
# target_link_libraries(my_program PRIVATE "-Wl,--my-option" my_lib)

使い分け

  • 使用すべきではありません。 target_link_options() がこの目的のために存在します。コマンドの役割を明確に分離することで、コードの可読性とメンテナンス性が向上します。

特定のCMakeポリシー(例: CMP0069)は、リンカオプションの処理方法に影響を与えることがあります。これらのポリシーは、古いCMakeの挙動との互換性を保つために存在します。


# CMakeポリシーを特定のバージョンに設定
cmake_policy(SET CMP0069 NEW) # New behavior: target_link_options() correctly handles duplicate options.

使い分け

  • 予期せぬリンカオプションの挙動に遭遇した場合は、関連するCMakeポリシーを確認してみる価値があります。
  • 通常、プロジェクトの先頭で cmake_minimum_required(VERSION ...) を適切に設定していれば、最新のポリシーが自動的に適用されるため、明示的にポリシーを設定する必要はあまりありません。
  • これは直接的な「代替方法」というよりは、target_link_options() の振る舞いを間接的に制御するものです。

現代のCMakeにおいては、ほとんどの場合において**target_link_options() コマンドを使用することが最も推奨される方法です。**

  • ジェネレータ式との組み合わせ
    ビルド設定やプラットフォームに応じた動的なオプション設定が容易です。
  • 可読性とメンテナンス性
    コマンド名がその意図を明確に示しており、コードの理解が容易になります。
  • ターゲットごとの制御
    特定のターゲットに対してのみオプションを設定できるため、グローバルな副作用を避けることができます。
  • 明確なスコープ
    PRIVATE, PUBLIC, INTERFACE を通じて、オプションの伝播ルールを明示的に定義できます。