`cmake`から` pkg-config`を使用する適切な方法は何ですか?


87

ネットを見回すと、次のようなコードがたくさん見られます。

include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)

target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS}
target_link_libraries(app ${SDL2_LIBRARIES})

ただし、インクルードディレクトリとライブラリのみを使用し、定義、ライブラリパス、およびによって返される可能性のあるその他のフラグを無視するため、これは間違った方法のようpkg-configです。

これを行い、によって返されるすべてのコンパイルフラグとリンクフラグpkg-configがコンパイル済みで使用されるようにする正しい方法は何でしょうappか?そして、これを達成するための単一のコマンド、つまり次のようなものはありtarget_use(app SDL2)ますか?

参照:

回答:


33

cmakeとpkg-configをごく普通の方法で使用している場合、このソリューションは機能します。

ただし、開発ディレクトリ(/ home / me / hack / libなど)にライブラリが存在する場合は、ここに示す他の方法を使用しても、リンカーパスを構成できません。通常のインストール場所にライブラリが見つからない場合は、のようなリンカーエラーが発生します/usr/bin/ld: cannot find -lmy-hacking-library-1.0。このソリューションは、その場合のリンカーエラーを修正します。

別の問題は、pkg-configファイルが通常の場所にインストールされておらず、cmakeの実行中にPKG_CONFIG_PATH環境変数を使用してプロジェクトのpkg-configパスを追加する必要があることです(これに関する他のスタックオーバーフローの質問を参照してください)。正しいpkg-configパスが設定されていると仮定すると、このソリューションはその問題も修正します。

解決策は、動作するCMakeLists.txtのこの最終バージョンに要約されます。

cmake_minimum_required(VERSION 3.14)
project(ya-project C)

# the `pkg_check_modules` function is created with this call
find_package(PkgConfig REQUIRED) 

# these calls create special `PkgConfig::<MODULE>` variables
pkg_check_modules(MY_PKG REQUIRED IMPORTED_TARGET any-package)
pkg_check_modules(YOUR_PKG REQUIRED IMPORTED_TARGET ya-package)

add_executable(program-name file.c ya.c)

target_link_libraries(program-name PUBLIC
        PkgConfig::MY_PKG
        PkgConfig::YOUR_PKG)

target_link_librariesリンカコマンドを変更するだけではないことに注意してください。また、コンパイラフラグ、コンパイラ定義、インクルードパスなど、指定されたターゲットの他のPUBLICプロパティを伝播します。


5
IMPORTED_TARGETCMake3.6以降が必要です。
CrisLuengo20年

1
これに反対票を投じた場合は、回答を改善できるように、反対票を投じた理由を確認してコメントしてください。
activedecay

gitlab.kitware.com/cmake/cmake/-/issues/19387が原因で、これは失敗したと思います。
FlorianZwoch20年

63

まず、呼び出し:

include(FindPkgConfig)

次のように置き換える必要があります。

find_package(PkgConfig)

find_package()コールは、より柔軟であり、そのようななどのオプションができますREQUIRED1が使用して手動で行う必要があろうと、自動的に物事を行います、include()

第二に、手動で呼び出すことpkg-configは可能な限り避けるべきです。CMakeには、Linuxのの下にある豊富なパッケージ定義のセットが付属しています/usr/share/cmake-3.0/Modules/Find*cmake。これらは、への生の呼び出しよりも多くのオプションと選択肢をユーザーに提供しますpkg_search_module()

前述の架空のtarget_use()コマンドに関しては、CMakeにはすでにPUBLIC | PRIVATE | INTERFACEの方法で組み込みがあります。以下のようなコールは、target_include_directories(mytarget PUBLIC ...)ディレクトリが自動的に使用しているすべてのターゲットで使用されるように含ませます mytarget、例えばtarget_link_libraries(myapp mytarget)。ただし、このメカニズムはCMakeLists.txtファイル内で作成されたライブラリにのみ適用されるようで、で取得されたライブラリでは機能しませんpkg_search_module()。そのために電話add_library(bar SHARED IMPORTED)が使われるかもしれませんが、私はまだそれを調べていません。

主な質問に関しては、これはほとんどの場合ここで機能します:

find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
...
target_link_libraries(testapp ${SDL2_LIBRARIES})
target_include_directories(testapp PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(testapp PUBLIC ${SDL2_CFLAGS_OTHER})

SDL2_CFLAGS_OTHER定義し、成功したコンパイルに必要な他のフラグが含まれています。旗SDL2_LIBRARY_DIRSSDL2_LDFLAGS_OTHERしかし、まだ、それが問題になる頻度は考えて無視されていません。

その他のドキュメントはこちらhttp://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html


4
私はそれのpkg-config設定は避けるべき同意のIF検索* .cmakeが存在するが、それはまだ2016年にcmakeの最新バージョンのためのケースではありません
キュービック

3
ライブラリがデフォルトのディレクトリにない場合、これは機能しません。link_directories()は回避策になる可能性がありますが、グローバルです。
ヘンリーフー

このアプローチは、vcpkgでは機能しません。パスをハードコーディングせずにSDL2_imageを見つけることはできますか?
user2023370 2018

@HenryHuは、これがこの回答の構成の状況である場合、これがどのように行われるかを示すことができますか?
ティムVisée

2
CMakeのようなビルドツールにヒューリスティックをバンドルして世界中のすべてのライブラリをスニッフィングすることを要求することは意味がありません。それはその役割ではありません。Pkg-configは、ユーザーが利用できるようにするのはlib作成者またはpkg / distroメンテナーの責任であるように設計されています。そして、このスキームに従っている場合、libを使用する正しい方法は、常にpkg-configを呼び出すことです。
ヨハン・ブール

10

SDL2とリンクするだけでよいことはめったにありません。現在人気のある回答pkg_search_module()では、特定のモジュールをチェックし、最初に機能するモジュールを使用します。

SDL2、SDL2_Mixer、SDL2_TTFなどとリンクする可能性が高くなります...pkg_check_modules()指定されたすべてのモジュールをチェックします。

# sdl2 linking variables
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2 SDL2_ttf SDL2_mixer SDL2_image)

# your app
file(GLOB SRC "my_app/*.c")
add_executable(my_app ${SRC})
target_link_libraries(my_app ${SDL2_LIBRARIES})
target_include_directories(my_app PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(my_app PUBLIC ${SDL2_CFLAGS_OTHER})

免責事項:stackoverflowで十分なストリートクレジットがあれば、Grumbelの自己回答についてコメントしただけです。


2
ソースファイルをグロブすることは悪い習慣であり、お勧めできません。
liberforce 2018

1
私にとっては、target_link_libraries(my_app ${SDL2_LINK_LIBRARIES})うまくいきました。
ステファン・

2
@liberforceのグロブソースファイルは良い習慣です。バグがある場合はCMakeのせいです。
ヨハン・ブール

2
@JohanBoulé:いいえ、そうではありません。開発者に大量のファイルをローカルに追加してもらい、それらを自分のコンピューターで動作させ、必要なすべてのファイルをコミットしない場合があります。それから彼らは彼らの変更をプッシュし、それは他の人々のために壊れます。確かに、これは継続的インテグレーションによって捉えることができますが、これは最も明白な問題にすぎません。中間子のビルドシステムはglobingファイルを実装していないことを選んだ、とCMakeの開発者が明示的にグロブ落胆します。明示的は暗黙的よりも優れています。
liberforce

1
@liberforce私はその議論を、それが理論化する実際の問題よりもすでに何倍も多く見ました。Mesonは反対、build2は賛成です。タブ対スペースのように、誰もそれを持っていません。
ヨハン・ブール

6

利用可能な回答のほとんどは、pkg-configライブラリのヘッダーを構成できません。FindPkgConfigドキュメントについて瞑想した後、私はそれらも提供するソリューションを思いつきました。

include(FindPkgConfig)
if(NOT PKG_CONFIG_FOUND)
  message(FATAL_ERROR "pkg-config not found!" )
endif()
 
pkg_check_modules(<some-lib> REQUIRED IMPORTED_TARGET <some-lib>)
 
target_link_libraries(<my-target> PkgConfig::<some-lib>)

それに応じて、の代わりにターゲットを、代わりに<my-target>任意のライブラリを使用してください<some-lib>

このIMPORTED_TARGETオプションは重要なようで、PkgConfig::名前空間の下ですべてを利用できるようにします。これは必要とされたものをすべてだったし、また、すべてのことがなければならない必要になること。


ヒント:実行後にcmake変数を印刷pkg_check_modulesして、利用可能な変数を確認しますstackoverflow.com/a/9328525/1211174
オーク

0
  1. のようなコマンドはありませんtarget_use。しかし、私はそれらの内部使用のためにそのようなコマンドを書いたいくつかのプロジェクトを知っています。しかし、すべてのプロジェクトは追加のフラグまたは定義を渡したいので、一般的にCMakeを使用することは意味がありません。それを持たないもう1つの理由は、EigenのようなC ++テンプレートライブラリです。ライブラリはありませんが、インクルードファイルはたくさんあります。

  2. 説明されている方法はしばしば正しいです。ライブラリによっては異なる場合があります。その場合は、_LDFLAGSまたはを追加する必要があり_CFLAGSます。がないもう1つの理由target_use。それがうまくいかない場合は、SDL2または使用したいライブラリに固有の新しい質問をしてください。


-2

ライブラリから定義を追加することも検討している場合は、そのためのadd_definitions手順があります。ドキュメントはここにあります、コンパイラフラグを追加するその他の方法とともに、にあります。

次のコードスニペットは、この命令を使用してGTKGLをプロジェクトに追加します。

pkg_check_modules(GTKGL REQUIRED gtkglext-1.0)
include_directories(${GTKGL_INCLUDE_DIRS})
link_directories(${GTKGL_LIBRARY_DIRS})
add_definitions(${GTKGL_CFLAGS_OTHER})
set(LIBS ${LIBS} ${GTKGL_LIBRARIES})

target_link_libraries([insert name of program] ${LIBS})

3
include_directoriesグローバルスコープに感染するなど使用しないでください!使用target_include_directoriesなど
Dawid Drozd 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.