CMake - add_library, target_link_libraries, set

markyang92·2024년 9월 3일

cmake

목록 보기
2/4

소스파일


add_library(): 라이브러리 생성

지정된 소스 파일을 사용하여 프로젝트에 라이브러리를 추가합니다.

add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)
<name>이라는 라이브러리 타겟을 생성합니다.
<type>은 라이브러리 종류를 지정합니다:
STATIC: 정적 라이브러리
SHARED: 동적 라이브러리
MODULE: 플러그인(다른 타겟에서 링크 불가, 런타임에 동적 로딩)
<type>을 지정하지 않으면 BUILD_SHARED_LIBS 변수에 따라 STATIC 또는 SHARED가 기본값입니다.
EXCLUDE_FROM_ALL 옵션을 주면 기본 빌드 대상에서 제외됩니다.

add_library(<name> OBJECT <sources>...)
오브젝트 라이브러리를 생성합니다. 소스 파일을 컴파일하지만 라이브러리로 묶지 않습니다.

add_library(... $<TARGET_OBJECTS:objlib> ...)
오브젝트 라이브러리의 오브젝트 파일을 다른 타겟에 포함시킬 때 사용합니다.

add_library(<name> INTERFACE)
인터페이스 라이브러리를 생성합니다. 소스 파일을 컴파일하지 않고, 사용 요구사항만 지정합니다.
주로 target_link_libraries, target_include_directories 등과 함께 사용합니다.

add_library(<name> INTERFACE [EXCLUDE_FROM_ALL] <sources>...)
(CMake 3.19 이상) 소스 파일이 포함된 인터페이스 라이브러리를 생성합니다.
소스 파일은 빌드 타겟에 포함되지만 컴파일되지는 않습니다.

add_library(<name> <type> IMPORTED [GLOBAL])
외부 라이브러리를 참조할 때 사용합니다. <type>은 STATIC, SHARED, MODULE, UNKNOWN, OBJECT, INTERFACE 중 하나입니다.
IMPORTED_LOCATION 등 속성으로 실제 파일 경로를 지정해야 합니다.
GLOBAL 옵션을 주면 전체 프로젝트에서 참조할 수 있습니다.

add_library(<name> ALIAS <target>)
<target>의 별칭을 생성합니다. <name>으로 <target>을 참조할 수 있습니다.

target_link_libraries(): 라이브러리 링크

지정된 대상 및/또는 해당 종속성을 연결할 경우 사용할 라이브러리 또는 플래그를 지정합니다. 연결된 라이브러리 대상의 사용 요구 사항이 전파됩니다. 대상 종속성의 사용 요구 사항은 자체 소스의 컴파일에 영향을 줍니다.

    target_link_libraries(<target> ... <item>... ...)
    target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>... [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
    target_link_libraries(<target> <item>...)
    target_link_libraries(<target> <LINK_PRIVATE|LINK_PUBLIC> <lib>... [<LINK_PRIVATE|LINK_PUBLIC> <lib>...]...)
    target_link_libraries(<target> LINK_INTERFACE_LIBRARIES <item>...)

에러

  • 만약 target_link_libraries()add_executable()보다 앞에온다면 에러

Library, Executable 만 빌드해보자

  • 위의 'Library'에 대해서만 빌드
$ cmake --build . --target Library

  • 위의 'Executable'에 대해서만 빌드
$ cmake --build . --target Executable

add_subdirectory(): 하위 디렉토리

  • 이제 위치가 다음과 같이 존재한다면
    최상위 1번 CMakeLists.txt에서 하위 디렉토리 셋팅이 필요하다.
  • add_subdirectory()
빌드에 하위 디렉터리를 추가합니다.

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
하위 디렉터리를 빌드에 추가합니다. ``source_dir``는 소스 ``CMakeLists.txt``와 코드
파일이 위치한 디렉터리를 지정합니다.
상대 경로인 경우 현재 디렉터리를 기준으로 평가되며(일반적인 사용법), 절대 경로도 사용할 수 있습니다. 
``binary_dir``는 출력 파일을 저장할 디렉터리를 지정합니다.
상대 경로인 경우 현재 출력 디렉터리를 기준으로 평가되며, 절대 경로도 사용할 수 있습니다.
``binary_dir``를 지정하지 않으면, 상대 경로를 확장하기 전의 ``source_dir`` 값이 사용됩니다(일반적인 사용법).
지정된 소스 디렉터리의 ``CMakeLists.txt`` 파일은 이 명령 이후 현재 입력 파일의 처리가 계속되기 전에
즉시 CMake에 의해 처리됩니다.
  • 최상위 1번 CMakeLists.txt에 아래와 같이 설정한다.
cmake_minimum_required(VERSION 3.22)

project(CppProjectTemplate VERSION 1.0.0 LANGUAGES CXX)

add_subdirectory(src)
add_subdirectory(app)
  • src(라이브러리), app(실행파일) 순서로.
    app이 src의 라이브러리를 사용해야하기 때문

app/CMakeLists.txt

  • appmain.cc가 있다.
    기존 CMakeLists.txt에서 해당 부분을 가져온다.
add_executable(Executable main.cc)
target_link_libraries(Executable PUBLIC Library)
  • 여기서, main.cc#include "my_lib.h" 위치를 못찾아서 에러가 날 것이다.

src/CMakeLists.txt

  • srcmy_lib.ccmy_lib.h가 존재하여 라이브러리 소스파일이 존재한다.
    기존 CMakeLists.txt에서 해당 부분을 가져온다.
add_library(Library STATIC my_lib.cc)

my_lib.h 에러

  • app/main.cc#include my_lib.h 하지만, my_lib.hsrc에 존재하므로,
    gcc -I../src 혹은 gcc -I${HOME}/cpp/src 같은 옵션이 필요하다.
    그 역할을 하는 것이 target_include_directoreis()이다.

target_include_directories(): -I<위치>

대상에 포함 디렉터리를 추가합니다.

target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_include_directories(mylib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib> $<INSTALL_INTERFACE:include/mylib>)
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
   <INTERFACE|PUBLIC|PRIVATE> [items1...]
   [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

지정된 타겟을 컴파일할 때 사용할 include 디렉토리를 지정합니다.
지정된 ``<target>``은 ``add_executable()`` 또는 ``add_library()``와 같은 명령어로 생성되어야 하며,
:ref:`ALIAS target <Alias Targets>`이어서는 안 됩니다.

명시적으로 ``AFTER`` 또는 ``BEFORE``를 사용하면 기본값과 상관없이 추가(append) 또는 앞에 삽입(prepend)을 선택할 수 있습니다.

``INTERFACE``, ``PUBLIC``, ``PRIVATE`` 키워드는 다음 인자의 :ref:`scope <Target Usage Requirements>`를 지정하기 위해 필요합니다.
``PRIVATE``와 ``PUBLIC`` 항목은 ``INCLUDE_DIRECTORIES``를 채웁니다.
  • target_include_directoreis()app/CMakeLists.txt, src/CMakeLists.txt 둘 중 하나에 둘 수 있다.
  • app/CMakeLists.txt에 둔다면..
add_executable(Executable main.cc)
target_link_libraries(Executable PUBLIC Library)
target_include_directories(Executable PRIVATE ../src)
-> Executable에서만 ../src 디렉토리를 include path로 사용한다.
   라이브러리 헤더가 외부에 노출될 필요가 없다.
  • src/CMakeLists.txt에 둔다면..
add_library(Library STATIC my_lib.cc)
target_include_directories(Library PUBLIC "./")
-> Library를 사용하는(링크하는) 모든 타겟도 자동으로 ./(src) 디렉토리를 include path로 사용한다.
   라이브러리의 헤더가 외부에서 사용되어야 할 때(, 라이브러리의 public API를 노출할 때) 주로 사용한다.

최종 구성


한단계 더 깊숙히

  • src/내 소스 파일들을 src/my_lib/ 디렉토리 이하로 옮긴다면,
    src/CMakeLists.txt에 아래와 같이 한다.

set(): 일반, 캐시 또는 환경 변수를 제공된 값으로 설정

set(<variable> <value>... [PARENT_SCOPE]) :target: normal
현재 함수 또는 디렉터리 범위에서 ``<variable>``을(를) 설정하거나 해제합니다:
* 하나 이상의 ``<value>...``이(가) 주어지면, 변수를 해당 값으로 설정합니다.
* 값이 주어지지 않으면, 변수를 해제합니다. 이는 :command:`unset(<variable>) <unset>`과 동일합니다.
``PARENT_SCOPE`` 옵션이 주어지면 변수는 현재 범위의 상위 범위에 설정됩니다. 각 새 디렉터리 또는 :command:`function` 명령은 새 범위를 생성합니다. :command:`block` 명령으로도 범위를 생성할 수 있습니다. ``set(PARENT_SCOPE)``는 변수 값을 상위 디렉터리, 호출 함수 또는 둘러싼 범위(해당되는 경우)에 설정합니다. 변수의 이전 값은 현재 범위에서 그대로 유지됩니다(예: 이전에 정의되지 않았다면 여전히 정의되지 않으며, 값이 있었다면 그대로 유지됨). :command:`block(PROPAGATE)` 및 :command:`return(PROPAGATE)` 명령은 :command:`set(PARENT_SCOPE)` 및 :command:`unset(PARENT_SCOPE)` 명령의 대체 방법으로 상위 범위의 변수를 갱신할 수 있습니다.

set(<variable> <value>... CACHE <type> <docstring> [FORCE]) :target: CACHE
지정된 캐시 ``<variable>``(캐시 항목)을 설정합니다. 캐시 항목은 사용자가 설정할 수 있는 값이므로 기본적으로 기존 캐시 항목을 덮어쓰지 않습니다. 기존 항목을 덮어쓰려면 ``FORCE`` 옵션을 사용하세요. ``<type>``은 다음 중 하나여야 합니다:
``BOOL`` 불리언 ``ON/OFF`` 값. :manual:`cmake-gui(1)`에서 체크박스 제공.
``FILEPATH`` 디스크의 파일 경로. :manual:`cmake-gui(1)`에서 파일 대화상자 제공.
``PATH`` 디스크의 디렉터리 경로. :manual:`cmake-gui(1)`에서 파일 대화상자 제공.
``STRING`` 한 줄의 텍스트. :manual:`cmake-gui(1)`에서 텍스트 필드 또는 드롭다운 제공(캐시 항목 속성 :prop_cache:`STRINGS`가 설정된 경우).
``INTERNAL`` 한 줄의 텍스트. :manual:`cmake-gui(1)`에서는 내부 항목을 표시하지 않음. 실행 간에 변수를 영구적으로 저장하는 데 사용할 수 있습니다. 이 타입은 ``FORCE``를 암시합니다.
``<docstring>``은 :manual:`cmake-gui(1)` 사용자에게 옵션 요약을 제공하는 한 줄의 텍스트여야 합니다.
호출 전 캐시 항목이 없거나 ``FORCE`` 옵션이 주어지면 캐시 항목이 해당 값으로 설정됩니다.

.. note:: 동일한 이름의 일반 변수가 이미 존재하면 캐시 변수의 내용에 직접 접근할 수 없습니다(자세한 내용은 :ref:`CMake Language Variables` 참고). 정책 :policy:`CMP0126`이 ``OLD``로 설정된 경우, 현재 범위의 일반 변수 바인딩이 제거됩니다. 캐시 항목이 이미 존재하지만 타입이 설정되지 않은 경우(예: :option:`-D<var>=<value> <cmake -D>` 옵션으로 명령줄에서 생성된 경우), ``set`` 명령이 타입을 추가합니다. 또한, ``<type>``이 ``PATH`` 또는 ``FILEPATH``이고 명령줄에서 제공된 ``<value>``가 상대 경로인 경우, ``set`` 명령은 해당 경로를 현재 작업 디렉터리를 기준으로 절대 경로로 변환합니다.

set(ENV{<variable>} [<value>]) :target: ENV
:manual:`환경 변수 <cmake-env-variables(7)>`를 지정된 값으로 설정합니다. 이후 ``$ENV{<variable>}`` 호출은 이 새 값을 반환합니다. 이 명령은 현재 CMake 프로세스에만 영향을 주며, CMake를 호출한 프로세스나 시스템 전체 환경, 이후 빌드 또는 테스트 프로세스의 환경에는 영향을 주지 않습니다. ``ENV{<variable>}`` 뒤에 인수가 없거나 ``<value>``가 빈 문자열이면, 해당 환경 변수의 기존 값을 지웁니다. ``<value>`` 뒤의 인수는 무시됩니다. 추가 인수가 있으면 경고가 표시됩니다.

일반, 캐시 또는 환경 변수를 지정된 값으로 설정합니다.
일반 변수와 캐시 항목의 범위 및 상호작용에 대한 자세한 내용은 :ref:`cmake-language(7) variables <CMake Language Variables>` 문서를 참고하세요.

이 명령의 ``<value>...`` 자리표시자는 0개 이상의 인수를 기대합니다. 여러 인수는 :ref:`세미콜론으로 구분된 리스트 <CMake Language Lists>`로 결합되어 실제 변수 값이 됩니다.

  • main CMakeLists.txtadd_subdirectory()src, inc, app 순 (라이브러리, App)
  • my_lib/CMakeLists.txt에서 target_include_directories(.. PUBLIC "./") 를 적용하여, 라이브러리를 사용(링크)하는 모든 타겟도 자동으로 ./(my_lib) 디렉토리를 include path로 노출

set 사용 및 종류

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_BUILD_TYPE Release)
  • CMAKE_C_STANDARD 11: c 컴파일러 -std=11
  • CMAKE_CXX_STANDARD 17: c++ 컴파일러 -std=17
  • CMAKE_CXX_STANDARD_REQUIRED ON:
    • c++ 표준 버전(위 17)이 반드시 적용되어야 함을 명시
    • 컴파일러가 C++17을 지원하지 않으면 빌드 실패
  • CMAKE_CXX_EXTENSIONS OFF
    • 컴파일러 확장 기능(예: GNU 확장)을 사용하지 않도록 설정
  • CMAKE_BUILD_TYPE Release
    • 빌드 유형을 지정
    • 일반적인 값에는 Debug, Release, RelWithDebInfo 및 MinSizeRel이 포함되지만 사용자 지정 빌드 유형도 정의할 수 있음

  • -g 옵션으로 디버그 모드로 빌드하려면?
set(CMAKE_BUILD_TYPE Debug)
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") <-- 혹시나 싶으면.. 기존 CMAKE_CXX_FLAGS_DEBUG에 -g추가
  • CMAKE_BUILD_TYPEDebug로 Set되어 있으면 디버그 심볼 들어감

컴파일러 설정

set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)

project(....)
  • C컴파일러와 CXX컴파일러 설정을 각각 clang, clang++로 설정
  • 컴파일러 설정은 project()이전에 설정할 것
profile
pllpokko@alumni.kaist.ac.kr

0개의 댓글