Study: DeveloperTools(DevTool)/DevTool: CMake

[CMake] make package 패키지 (feat. cmake install)

DrawingProcess 2022. 7. 14. 12:19
반응형
본 문서는 CMake에 패키지 관련 내용을 나열한 문서로,
주로 설치한 패키지를 받아서 사용하기 위해 사용합니다.

Package


Package의 구성

보통 패키지라고 하면 Chocolaty, NuGet, RPM, Brew처럼 Package Manager 소프트웨어를 통해 다운로드/설치/업데이트해서 사용하는 프로그램들(+ 문서)을 말하는데, C++ 프로그래머들에게 패키지란 개발에 필요한 Library + Manifest에 가까운 것 같습니다.

  • 일반적인 패키지:
    • 실행 프로그램(executable)
    • 문서 파일(license, manual, readme 등)
  • 프로그래밍 패키지: 일반 패키지 + 개발에 필요한 요소들
    • 서브 프로그램(library)
    • 실행 프로그램(test tools, script 등)
    • 소스 코드(include, example 등)

C++ 프로젝트의 파일트리

지금은 많은 C++ 프로젝트들이 Unix Filesystem에서 표준 C 라이브러리를 배치할때 사용하던 파일트리 구조를 적용하고 있습니다. 
굳이 이런 배치에 어떤 의미가 부여되어있다기 보다는, "CMake의 초창기부터 Unix 시스템에 빌드 된 라이브러리을 설치하면서 관례를 따르던 것이 이어지고 있다"정도로 생각하면 될 것 같습니다.

  • bin : 실행 프로그램(executable)
  • lib : 미리 빌드된 라이브러리(so, lib 등)
  • include : 소스 코드(헤더)
  • share : 기타 필요한 파일들. 주로 빌드 지원 파일
    • docs : 문서가 (많이) 있는 경우 따로 두기도

 

CMake Package


CMake Package을 위한 CMake 구성

실행 파일 및 라이브러리 폴더 구성

실행 파일과 라이브러리 파일을 비롯하여 필요한 파일들의 위치를 /lib, /bin 폴더로 모아줍니다.

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir. (.lib / .a)")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir. (.so / .dylib)")
set(CMAKE_PDB_OUTPUT_DIRECTORY     "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir. (.exe / .dll)")

You can also specify the output directories on a per-target basis:

set_target_properties( targets...
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

CMake Package 파일 구성

CMakeLists.txt

set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "gmbdmr")

install(FILES 
    ${CMAKE_SOURCE_DIR}/etc/Conf.json
    ${CMAKE_SOURCE_DIR}/etc/Conf.so.conf
  DESTINATION conf
  COMPONENT Conf)

install(DIRECTORY 
    ${CMAKE_SOURCE_DIR}/db
  DESTINATION .
  COMPONENT Db)

install(TARGETS ${PROJECT_NAME} app.out 
    RUNTIME DESTINATION bin
    COMPONENT Project
)

include(package.cmake)
  • install: 빌드 완료된 실행 바이너리와 라이브러리 및 기타 부속물(헤더 파일, 리소스 등)들을 시스템의 적절한 위치로 복사하는 동작

package.cmake

SET(CMAKE_INSTALL_PREFIX  "/opt/project")

string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GIT_VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_FEATURE "${GIT_VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_RELEASE "${GIT_VERSION}")
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+" LIBRARY_VERSION "${GIT_VERSION}")

SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Project Server")
SET(CPACK_PACKAGE_VENDOR "DrawingProcess Inc.")
SET(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
SET(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
SET(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PROTO}.${VERSION_PATCH}")

# include(../cmake/GetGitRevisionDescription.cmake)
# git_describe(GIT_VERSION)

SET(CPACK_PACKAGING_INSTALL_PREFIX  "/opt/project")
SET(CPACK_PACKAGE_FILE_NAME "Project-${GIT_VERSION}")

SET(CPACK_ARCHIVE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}")
SET(CPACK_PACKAGE_NAME "Project")

SET(CPACK_GENERATOR "TGZ;ZIP")

SET(CPACK_ARCHIVE_COMPONENT_INSTALL ON)

MESSAGE( STATUS "CPACK_ARCHIVE_COMPONENT_INSTALL: " ${CPACK_ARCHIVE_COMPONENT_INSTALL} )

set(CPACK_COMPONENTS_ALL Conf Db Project)

include(CPack)
  • CMAKE_INSTALL_PREFIX: 설치 매크로(make install)에서 실행 바이너리와 라이브러리 등의 최종 생성물을 복사할 설치 디렉토리를 지정합니다. INSTALL() 명령에서 상대 경로를 사용한 경우, 이 변수에 지정한 디렉토리가 Base 디렉토리가 됩니다.
    • 이 변수를 별도로 지정하지 않으면 기본값은 /usr/local 입니다.
  • 하단에 지정해준 set(CPACK_COMPONENTS_ALL ...) 명령을 통해 해당 컴포넌트 별 tgz.gz 형식의 압축파일을 구성합니다.
  • 여기서 지정 가능한 컴포넌트는 ADD_SUBDIRECTORY로 지정해주어 해당 디렉토리에 정의된 컴포넌트, FetchContent로 불러와 해당 프로젝트에 정의된 컴포넌트 등 최상단의 CMakeLists.txt 파일이 읽어들인 모든 컴포넌트를 의미합니다.

CPACK_GENERATOR 옵션: 원하는 아카이브 형식으로 패키지를 생성

  • 7Z: 7-Zip 파일 형식 (아카이브)
  • IFW: Qt Installer 프레임 워크 (실행 파일)
  • NSIS: 널 소프트 설치 프로그램 (실행 가능)
  • NSIS64: 널 소프트 설치 프로그램 (64 비트, 실행 가능)
  • STGZ: Tar GZip 자동 압축 풀기 (압축 파일)
  • TBZ2: Tar BZip2 압축 (아카이브)
  • TGZ: Tar GZip 압축 (아카이브)
  • TXZ: Tar XZ 압축 (아카이브)
  • TZ: Tar 압축 압축 (아카이브)
  • WiX: 도구 (실행 가능한 아카이브)를 통한 WIX MSI 파일 형식
  • ZIP: ZIP 파일 형식 (아카이브)

 

CMake의 Package 찾기 (find_package)

* 참고: 사용하는 라이브러리가 CMake를 지원하는 경우, find_package가 매끄럽게 사용되지 않을 때는 add_subdirectory를 사용하는 것이 '정확한' 해결책이 될 수 있습니다. Package export에 문제가 있는 경우 이를 찾아내기에도, Import하는 쪽에서 수정하기에도 어렵기 때문입니다.

CMake에서 find_package를 호출하면, 해당 함수는 Package를 찾고, 그 안에 있는 Target들을 가져옵니다.

# optional import
find_package(OpenCV 3.3)
if(OpenCV_FOUND)
    # ...
    # target_source:  Add OpenCV related source codes ...
    # target_compile_options:  Enable RTTI for OpenCV ...
    # ...
endif()

# mandatory import
find_package(OpenCV 3.3 REQUIRED)
  • find_package:
    • find_package는 이름과 버전을 인자로 사용합니다.
    • 탐색에 성공하면 <name>_FOUND 변수가 생성되어, 패키지 탐색 여부는 _FOUND로 확인할 수 있습니다.
    • CONFIG를 통해 상세한 옵션(path...)으로 패키지를 탐색할 수 있습니다.

CMake의 Package 내 Target 사용하기 (target_link_libraries)

find_package(gRPC CONFIG REQUIRED)
# ...
target_link_libraries(main
PRIVATE
    gRPC::gpr gRPC::grpc gRPC::grpc++ gRPC::grpc_cronet
)
  • CMake에서 find_package를 호출하면, 해당 함수는 Package를 찾고, 그 안에 있는 Target들을 가져옵니다.
  • executable과 링킹을 하지는 않기 때문에, 가져온 Target들은 add_library(INTERFACE) 혹은 add_library(SHARED)로 만들어진 결과물들입니다. 따라서 이들을 사용하기 위해 링킹하는 함수는 target_link_libraries입니다.
  • 물론 여기에는 하나의 전제가 있습니다....
    • 해당 라이브러리가 CMake에서 Import할 수 있도록 적절하게 Manifest를 작성해 놓았거나, CMake의 export함수를 사용해 CMake를 위한 Manifest를 생성해놓은 것입니다.
      • *Manifest: 보통 Manifest이라고 하면 -config.cmake를 말하며, 이 문서 상에서만 "Package를 내보낸것과 같이 가져오기 위한 목록"이라는 의미로 사용하기에 웹에서 CMake관련 검색할 때 사용하면 오히려 방해가 될 수 있습니다.

 

참고

반응형