`cmake`에서`pkg-config`를 사용하는 적절한 방법은 무엇입니까?


86

인터넷을 둘러 보면 다음과 같은 많은 코드를 보았습니다.

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)있습니까?

심판 :

답변:


32

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_TARGETCMake 3.6 이상이 필요합니다.
Cris Luengo

이 항목에 대해 반대표를 던진 경우 답변을 개선 할 수 있도록 반대표를 작성한 이유를 확인하고 의견을 남겨주세요.
activedecay

나는 이것이 gitlab.kitware.com/cmake/cmake/-/issues/19387 때문에 실패했다고 생각합니다 .
Florian Zwoch

63

먼저, 전화 :

include(FindPkgConfig)

다음으로 교체해야합니다.

find_package(PkgConfig)

find_package()호출은 더 유연하며 REQUIRED수동으로해야하는 작업을 자동으로 수행하는 등의 옵션을 허용 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_DIRS와는 SDL2_LDFLAGS_OTHER하지만 여전히 그 문제가 될 것입니다 얼마나 자주 아무 생각을 무시하지 않습니다.

더 많은 문서는 http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html에 있습니다 .


4
그 PKG-설정은 피해야한다 동의 경우 찾기 '가 * .cmake가 존재하지만 여전히 2016 년에 cmake의 최신 버전의 경우에는 해당되지 않습니다
큐빅

3
라이브러리가 기본 디렉토리에 없으면 작동하지 않습니다. link_directories ()는 해결 방법이 될 수 있지만 전역 적입니다.
Henry Hu

이 접근 방식은 vcpkg 에서는 작동하지 않습니다 . 하드 코딩 경로없이 SDL2_image를 찾을 수 있습니까!?
user2023370

@HenryHu이 답변의 구성 상황이라면 이것이 어떻게 수행되는지 보여줄 수 있습니까?
Tim Visée

2
CMake와 같은 빌드 도구를 사용하여 휴리스틱을 번들로 사용하여 세계의 모든 라이브러리를 스니핑하는 것은 의미가 없으며 그 역할이 아닙니다. Pkg-config는 lib 작성자 또는 pkg / distro 유지 관리자가 사용자가 사용할 수 있도록 설계되었습니다. 그리고이 체계를 따르는 경우 lib를 사용하는 올바른 방법은 항상 pkg-config를 호출하는 것입니다.
Johan Boulé 2019 년

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

1
나를 target_link_libraries(my_app ${SDL2_LINK_LIBRARIES})위해 더 잘 작동했습니다.
스테판

2
@liberforce globbing 소스 파일은 좋은 습관이며 버그가 있으면 CMake의 잘못입니다.
Johan Boulé 2019 년

2
@ JohanBoulé : 아니에요. 개발자가 로컬에 여러 파일을 추가하고 필요한 모든 파일을 커밋하지 않고 컴퓨터에서 작동하도록 할 수 있습니다. 그런 다음 그들은 그들의 변화를 밀어 붙이고 다른 사람들을 위해 깨집니다. 물론 이것은 지속적인 통합에 의해 잡힐 수 있지만 가장 명백한 문제 일뿐입니다. 중간자 빌드 시스템은 globing 파일을 구현하지하기로 결정 하고, CMake 개발자는 명시 적으로 globbing을 억제 . 명시적인 것이 암시적인 것보다 낫습니다.
liberforce

1
@liberforce 나는 이론이 제시 한 실제 문제보다 이미 여러 번 그 주장을 보았습니다. Meson은 반대하고 build2는 반대입니다. 탭 대 공간처럼 아무도 그것을 가질 수 없습니다.
Johan Boulé

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 var를 인쇄 pkg_check_modules하여 사용 가능한 vars stackoverflow.com/a/9328525/1211174
oak

0
  1. 와 같은 명령은 없습니다 target_use. 그러나 내부 사용을 위해 그러한 명령을 작성한 여러 프로젝트를 알고 있습니다. 그러나 모든 프로젝트는 추가 플래그 또는 정의를 전달하기를 원하므로 일반 CMake에서이를 갖는 것은 의미가 없습니다. 그것을 가지지 않는 또 다른 이유는 Eigen과 같은 C ++ 템플릿 라이브러리입니다. 라이브러리는 없지만 포함 파일이 많이 있습니다.

  2. 설명 된 방법은 종종 정확합니다. 일부 라이브러리에서는 다를 수 있으므로 _LDFLAGS또는 을 추가해야합니다 _CFLAGS. 필요하지 않는 이유가 하나 더 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.