# 외부 라이브러리 및 종속성 관리

***

#### 외부 라이브러리 추가 방법

CMake에서 외부 라이브러리를 추가하는 방법은 크게 세 가지로 나눌 수 있다. 첫째는 `find_package()` 함수를 사용하는 방법, 둘째는 `add_subdirectory()`를 사용하는 방법, 셋째는 `ExternalProject_Add()`를 사용하는 방법이다. 이 방법들은 각각의 상황에 맞게 사용할 수 있으며, 외부 라이브러리의 소스 코드 위치와 빌드 방법에 따라 적절한 방법을 선택해야 한다.

**find\_package() 함수 사용**

`find_package()` 함수는 시스템에 설치된 패키지나 라이브러리를 검색하고, 그 정보를 CMake에 제공하는 방법이다. CMake는 다양한 패키지 구성 파일(CMake configuration files, `Config.cmake` 또는 `Find<Package>.cmake` 파일)을 통해 라이브러리의 위치, 헤더 파일 경로, 라이브러리 파일 등을 찾아낸다. 이 방법은 보통 외부 라이브러리가 이미 시스템에 설치되어 있을 때 사용된다.

예를 들어, `Eigen3` 라이브러리를 사용하는 경우, 다음과 같이 `find_package()` 함수를 사용할 수 있다:

```cmake
find_package(Eigen3 REQUIRED)
target_link_libraries(MyTarget PRIVATE Eigen3::Eigen)
```

이 코드에서 `REQUIRED`는 해당 패키지가 필수임을 의미하며, 찾지 못할 경우 CMake가 오류를 발생시킨다. `target_link_libraries()` 함수는 대상(`MyTarget`)에 라이브러리를 연결하는 역할을 한다.

**add\_subdirectory() 함수 사용**

`add_subdirectory()` 함수는 외부 라이브러리의 소스 코드를 직접 프로젝트에 포함시키는 방법이다. 이 방법은 외부 라이브러리가 CMake를 사용하여 빌드되는 경우에 유용하다. 라이브러리 소스 코드를 프로젝트 디렉토리에 포함시키고, CMakeLists.txt 파일에서 해당 디렉토리를 추가하면 된다.

예를 들어, 프로젝트에 `MyLibrary`라는 외부 라이브러리를 포함시키려면 다음과 같이 설정할 수 있다:

```cmake
add_subdirectory(external/MyLibrary)
target_link_libraries(MyTarget PRIVATE MyLibrary)
```

이렇게 하면 `MyLibrary`는 프로젝트의 일부로 빌드되며, `MyTarget`에 링크된다. 이 방법은 라이브러리를 소스 코드 레벨에서 제어할 수 있다는 장점이 있지만, 프로젝트의 크기와 빌드 시간을 증가시킬 수 있다.

**ExternalProject\_Add() 함수 사용**

`ExternalProject_Add()` 함수는 외부 라이브러리를 별도의 빌드 단계에서 가져오고 빌드하는 방법이다. 이 방법은 외부 라이브러리가 독립적으로 빌드될 필요가 있거나, 다양한 빌드 시스템을 사용할 때 유용하다. 이 함수는 외부 라이브러리를 다운로드, 구성, 빌드, 설치하는 작업을 CMake 스크립트 내에서 자동으로 수행한다.

예를 들어, 외부 프로젝트로 `MyExternalProject`를 추가하려면 다음과 같이 할 수 있다:

```cmake
include(ExternalProject)
ExternalProject_Add(
    MyExternalProject
    GIT_REPOSITORY https://github.com/user/MyExternalProject.git
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
)
```

이 코드는 Git 리포지토리에서 소스를 가져와서 별도의 빌드 디렉토리에서 빌드하고, 설치하는 과정까지 포함한다. `CMAKE_ARGS` 옵션을 통해 외부 프로젝트에 전달할 CMake 인자를 설정할 수 있다.

#### 타겟 종속성 관리

CMake에서는 `target_link_libraries()` 함수를 통해 타겟의 종속성을 관리한다. 이 함수는 대상 타겟에 필요한 라이브러리를 연결하며, 타겟 간의 종속성을 명확하게 정의하는 데 사용된다. 종속성은 `PUBLIC`, `PRIVATE`, `INTERFACE`의 세 가지 범위로 나눌 수 있다.

**PUBLIC, PRIVATE, INTERFACE**

* **PUBLIC**: 라이브러리를 사용하는 타겟과 그 타겟을 사용하는 다른 타겟 모두에 종속성을 전달한다.
* **PRIVATE**: 라이브러리를 사용하는 타겟에만 종속성을 전달한다.
* **INTERFACE**: 라이브러리를 사용하는 타겟에는 종속성을 전달하지 않고, 그 타겟을 사용하는 다른 타겟에만 전달한다.

예를 들어, 다음 코드는 `MyTarget`이 `MyLibrary`를 `PRIVATE`으로 링크하고, `MyInterfaceLib`를 `INTERFACE`로 링크하는 경우이다:

```cmake
target_link_libraries(MyTarget PRIVATE MyLibrary INTERFACE MyInterfaceLib)
```

이 설정에서 `MyLibrary`는 `MyTarget`에만 종속성이 적용되며, `MyInterfaceLib`는 `MyTarget`을 사용하는 타겟에 종속성이 전달된다.

#### 라이브러리 경로 및 헤더 경로 설정

CMake에서 외부 라이브러리의 경로를 설정할 때는 `include_directories()`와 `link_directories()` 함수를 사용할 수 있다. 그러나 현대적인 CMake에서는 `target_include_directories()`와 `target_link_directories()`를 사용하는 것이 권장된다.

**target\_include\_directories()**

`target_include_directories()` 함수는 특정 타겟에 대해 헤더 파일 경로를 설정한다. 이 함수도 `PUBLIC`, `PRIVATE`, `INTERFACE`의 범위를 가지며, 각 범위는 헤더 파일 경로가 어떻게 전달될지 결정한다.

예를 들어, 다음 코드는 `MyTarget`에 대해 `MyLibrary`의 헤더 파일 경로를 `PUBLIC`으로 설정하는 방법이다:

```cmake
target_include_directories(MyTarget PUBLIC ${MYLIBRARY_INCLUDE_DIR})
```

이 설정은 `MyTarget`과 그 타겟을 사용하는 모든 타겟에 `MYLIBRARY_INCLUDE_DIR` 경로를 포함시킨다.

**target\_link\_directories()**

`target_link_directories()` 함수는 특정 타겟에 대해 라이브러리 파일의 경로를 설정한다. 하지만, 이 함수는 보통 잘 사용되지 않으며, 대신 `target_link_libraries()` 함수에서 라이브러리의 절대 경로를 직접 지정하는 것이 일반적이다.

#### 패키지 구성 파일 생성

프로젝트가 설치될 때 다른 프로젝트에서 사용할 수 있도록 CMake 패키지 구성 파일(`Config.cmake` 파일)을 생성할 수 있다. 이를 통해 사용자는 `find_package()`를 사용하여 해당 라이브러리를 쉽게 사용할 수 있다.

**install() 함수와 export() 함수**

패키지 구성 파일을 생성하려면, `install()` 함수와 `export()` 함수를 사용한다. 이 함수들은 타겟과 관련된 파일들을 설치하고, 타겟을 내보내는 역할을 한다.

예를 들어, 다음과 같이 설정할 수 있다:

```cmake
install(TARGETS MyLibrary
    EXPORT MyLibraryTargets
    ARCHIVE DESTINATION lib
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

install(EXPORT MyLibraryTargets
    FILE MyLibraryConfig.cmake
    DESTINATION lib/cmake/MyLibrary
)
```

이 설정은 `MyLibrary` 타겟을 설치하고, `MyLibraryConfig.cmake` 파일을 생성하여 `lib/cmake/MyLibrary` 경로에 설치한다. 이렇게 하면 다른 프로젝트에서 `find_package(MyLibrary CONFIG REQUIRED)`를 사용하여 쉽게 `MyLibrary`를 가져올 수 있다.

***

관련 자료:

* CMake 공식 문서: <https://cmake.org/documentation/>
* Kitware CMake Tutorial: <https://cmake.org/cmake/help/latest/guide/tutorial/index.html>
