cmake로 공유 라이브러리를 만드는 방법은 무엇입니까?


141

자체 작성 Makefile을 사용하여 컴파일하는 데 사용한 라이브러리를 작성했지만 이제는 cmake로 전환하려고합니다. 나무는 다음과 같습니다 (관련없는 파일을 모두 제거했습니다).

.
├── include
   ├── animation.h
   ├── buffers.h
   ├── ...
   ├── vertex.h
   └── world.h
└── src
    ├── animation.cpp
    ├── buffers.cpp
    ├── ...
    ├── vertex.cpp
    └── world.cpp

그래서 내가하려는 것은 소스를 공유 라이브러리로 컴파일 한 다음 헤더 파일로 설치하는 것입니다.

내가 찾은 대부분의 예제는 일부 공유 라이브러리로 컴파일 실행 파일을 찾지 만 평범한 공유 라이브러리는 결코 없습니다. 누군가가 cmake를 사용하는 매우 간단한 라이브러리를 말해 줄 수 있다면 도움이 될 것이므로 이것을 예제로 사용할 수 있습니다.



같은 질문이지만 소스를 혼합하여 유지하는 방법 (같은 소스 디렉토리에 .h ans .cpp)을 유지하지만 Cmake가 포함 디렉토리를 생성하게하는 방법이 있습니까?
Sandburg

답변:


204

항상 최소 필수 버전을 지정하십시오. cmake

cmake_minimum_required(VERSION 3.9)

프로젝트를 선언해야합니다. cmake이 필수이며 편리 변수를 정의 것이라고 PROJECT_NAME, PROJECT_VERSION그리고 PROJECT_DESCRIPTION(3.9 cmake이 후자의 변수 필요로) :

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

새 라이브러리 대상을 선언하십시오. 의 사용을 피하십시오 file(GLOB ...). 이 기능은 컴파일 과정에 익숙하지 않습니다. 게으른 경우 다음의 복사-붙여 넣기 출력 ls -1 sources/*.cpp:

add_library(mylib SHARED
    sources/animation.cpp
    sources/buffers.cpp
    [...]
)

VERSION속성 설정 (선택 사항이지만 좋은 습관 임) :

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

SOVERSION의 주요 수를 설정할 수도 있습니다 VERSION. 에 libmylib.so.1대한 심볼릭 링크가됩니다 libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1)

라이브러리의 공개 API를 선언하십시오. 이 API는 타사 응용 프로그램 용으로 설치됩니다. include/디렉토리를 배치하는 것과 같이 프로젝트 트리에서 격리하는 것이 좋습니다 . 개인 헤더는 설치하지 않아야하며 소스 파일과 함께 배치하는 것이 좋습니다.

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

하위 디렉토리로 작업하는 경우와 같은 상대 경로를 포함하는 것이 매우 편리하지 않습니다 "../include/mylib.h". 따라서 포함 된 디렉토리에서 최상위 디렉토리를 전달하십시오.

target_include_directories(mylib PRIVATE .)

또는

target_include_directories(mylib PRIVATE include)
target_include_directories(mylib PRIVATE src)

라이브러리의 설치 규칙을 작성하십시오. CMAKE_INSTALL_*DIR다음에 정의 된 변수를 사용하는 것이 좋습니다 GNUInstallDirs.

include(GNUInstallDirs)

설치할 파일을 선언하십시오.

install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

pkg-config파일을 내보낼 수도 있습니다 . 이 파일을 사용하면 타사 응용 프로그램에서 라이브러리를 쉽게 가져올 수 있습니다.

이름이 지정된 템플릿 파일을 만듭니다 mylib.pc.in(자세한 내용은 pc (5) 맨 페이지 참조).

prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@

Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@

Requires:
Libs: -L${libdir} -lmylib
Cflags: -I${includedir}

에서 매크로 CMakeLists.txt를 확장하는 규칙을 추가 하십시오 @( @ONLYcmake에게 형식의 변수를 확장하지 않도록 요청하십시오 ${VAR}).

configure_file(mylib.pc.in mylib.pc @ONLY)

마지막으로 생성 된 파일을 설치하십시오.

install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)

cmake EXPORT기능을 사용할 수도 있습니다 . 그러나이 기능은 호환되며 cmake사용하기가 어렵습니다.

마지막으로 전체 CMakeLists.txt가 다음과 같아야합니다.

cmake_minimum_required(VERSION 3.9)
project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")
include(GNUInstallDirs)
add_library(mylib SHARED src/mylib.c)
set_target_properties(mylib PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1
    PUBLIC_HEADER api/mylib.h)
configure_file(mylib.pc.in mylib.pc @ONLY)
target_include_directories(mylib PRIVATE .)
install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${CMAKE_BINARY_DIR}/mylib.pc
    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)

10
@Jezz의 멋진 설명을 보완하기 만하면됩니다. 위의 모든 단계 후에 프로그래머는 라이브러리를 빌드하고 설치 mkdir build && cd build/ && cmake .. && sudo make install하거나 스트라이프 된 라이브러리 버전 sudo make install/strip을 설치할 수 있습니다.
silvioprog

1
라이브러리 종속성을 전달하는 기술이 있습니까? 예를 들어, mylib가 liblog4cxx에 의존한다면, mylib.pc로 전달하는 좋은 방법은 무엇입니까?
mpr

1
liblog4cxx가 제공하는 경우 @mpr .pc파일을 추가, Requires: liblog4cxx당신에 mylib.pc, 다른 사람, 당신은 단지 추가 할 수 있습니다 -llog4cxxLibs:.
Jérôme Pouiller

다른 프로젝트에서이 라이브러리를 어떻게 사용합니까? 당신의 모범을 확장시킬 수 있습니까?
Damir Porobic

그리고 모든 헤더를 PUBLIC_HEADER 또는 다른 사용자가 볼 수있는 헤더에만 추가합니까? 그렇지 않은 경우 다른 모든 헤더로 무엇을합니까?
Damir Porobic

84

이 최소 CMakeLists.txt파일은 간단한 공유 라이브러리를 컴파일합니다.

cmake_minimum_required(VERSION 2.8)

project (test)
set(CMAKE_BUILD_TYPE Release)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(test SHARED src/test.cpp)

그러나 CMake를 사용하여 다른 대상으로 파일을 복사 한 경험이 없습니다. COPY / INSTALL 서명이있는 파일 명령이 유용 할 것 같습니다.


34
CMAKE_BUILD_TYPE은 생략해야하므로 결정은 컴파일 한 사람에게 달려 있습니다.
ManuelSchneid3r

${CMAKE_CURRENT_SOURCE_DIR}/in을 지정 하는 include_directories것이 유용합니까?
Jérôme Pouiller

@Jezz 그렇게 생각하지 않습니다. 동일한 디렉토리가 접두사없이 포함됩니다. 그러나 서브 디렉토리에 있는지 여부는 중요합니다.
Arnav Borborah

소스와 헤더를 일반 "소스"디렉토리에 혼합하려면 어떻게해야합니까? 내 소스에서 "헤더"디렉토리를 만들 수있는 "포스트 생성"가능성이 있습니까? (아마도 설치 명령)
Sandburg

24

이 작업을 직접 수행하는 방법을 배우려고하는데 다음과 같이 라이브러리를 설치할 수 있습니다.

cmake_minimum_required(VERSION 2.4.0)

project(mycustomlib)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} SHARED ${SOURCES})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME})

12

첫째, 이것은 내가 사용하는 디렉토리 레이아웃입니다.

.
├── include
   ├── class1.hpp
   ├── ...
   └── class2.hpp
└── src
    ├── class1.cpp
    ├── ...
    └── class2.cpp

며칠 후에 이것을 살펴본 후에 이것은 현대 CMake 덕분에 이것을 좋아하는 가장 좋은 방법입니다.

cmake_minimum_required(VERSION 3.5)
project(mylib VERSION 1.0.0 LANGUAGES CXX)

set(DEFAULT_BUILD_TYPE "Release")

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
  set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

include(GNUInstallDirs)

set(SOURCE_FILES src/class1.cpp src/class2.cpp)

add_library(${PROJECT_NAME} ...)

target_include_directories(${PROJECT_NAME} PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
    PRIVATE src)

set_target_properties(${PROJECT_NAME} PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1)

install(TARGETS ${PROJECT_NAME} EXPORT MyLibConfig
    ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake)

export(TARGETS ${PROJECT_NAME} FILE MyLibConfig.cmake)

CMake를 실행하고 라이브러리를 설치 한 후 Find ***. cmake 파일을 사용할 필요가 없으며 다음과 같이 사용할 수 있습니다.

find_package(MyLib REQUIRED)

#No need to perform include_directories(...)
target_link_libraries(${TARGET} mylib)

그것이 표준 디렉토리에 설치되어 있으면 발견되며 다른 것을 할 필요가 없습니다. 비표준 경로에 설치되어 있으면 CMake에 MyLibConfig.cmake를 찾을 위치를 알려주십시오.

cmake -DMyLib_DIR=/non/standard/install/path ..

나는 이것이 나를 도와 준만큼 모두에게 도움이되기를 바랍니다. 이 작업을 수행하는 오래된 방법은 상당히 번거로 웠습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.