5 min read

cmake 시작부터 라이브러리까지

이 글은 리눅스/유닉스 환경으로 설정이 되어있습니다.

대부분의 오픈소스인 경우 cmake로 구성되어 있다.

그 이유는 플래폼마다 컴파일 방법 달라 솔루션을 동일하게 설치해야하는 문제가 발생한다.

그래서 위와 같은 모양이 나오게 된다.

하지만 이를 하나의 방법으로 통합시키기 위한툴이 cmake이다.

cmake는 다음과 같이 여러개의 플래폼에 맞는 탬플릿을 생성해준다.

이글을 큰 흐름을 설명한 글입니다. 자세한 글 은 다음 링크를 참조해보시기 바랍니다.

https://gist.github.com/luncliff/6e2d4eb7ca29a0afd5b592f72b80cb5c

step 1 : 일단 해보자

사전에 cmake가 설치되어 있어야 한다.

위와 같은 구조의 폴더를 생성한다.

.
├── CMakeLists.txt
└── main.cpp

각각의 파일의 내용은 아래와 같다.

main.cpp

#include <iostream>

int main(){
    std::cout<<"hello world"<<std::endl;
}

CMakeLists.txt

#cmake 최소 버전 요구 사양
cmake_minimum_required(VERSION 3.8)

#프로젝트명 버전
project(myproject VERSION 1.0.0)

#main.cpp의 파일을 가주고 main이라는 바이너리를 생성한다.
add_executable(main main.cpp)

이제 기본적인 작업은 끝났으니 cmake을 솔루션파일로 보자.

아래와 같은 커맨드를 입력하자.

mkdir build
cd build 
cmake ..
make

그러면 main 바이너리 파일이 만들어지게 된다.

step 2 : 라이브러리를 추가해보자.

라이브러리를 추가해 보자.

디렉토리 구조는 다음과 같다.

.
├── CMakeLists.txt
├── build
├── hello.cpp
├── hello.hpp
└── main.cpp

각각의 파일은 다음과 같다.

main.cpp

#include <iostream>
#include "hello.hpp"

int main(){
    hello::say();
}

hello.hpp


namespace hello{
    void say();
}

hello.cpp

#include <iostream>
#include "hello.hpp"

void hello::say(){
    std::cout<<"hello world"<<std::endl;

}

CMakeLists.txt

#cmake 최소 버전 요구 사양
cmake_minimum_required(VERSION 3.8)

#프로젝트명 버전
project(myproject VERSION 1.0.0)

#라이브러리를 추가한다.
add_library(
    hello
    hello.hpp
    hello.cpp
)

#main.cpp의 파일을 가주고 main이라는 바이너리를 생성한다.
add_executable(main main.cpp)

이렇게 하고 아까전과 같이 cmake을 돌려보자.

돌려보신분들은 아시겠지만 make단계 즉 컴파일 단계에서 에러가 발생한다.

add_library을 하여서 libhello.a라는 정적파일이 만들어지는데 main은 해당 libhello.a을 찾지 못해 발생하는 것이다.

이를 해결하기 위해서는 main 파일에 링킹이라는 작업을 해줘야하는데 이는 다음과 같이 CMakeLists.txt를 수정하면 된다.

#cmake 최소 버전 요구 사양
cmake_minimum_required(VERSION 3.8)

#프로젝트명 버전
project(myproject VERSION 1.0.0)

#라이브러리를 추가한다.
add_library(
    hello
    hello.hpp
    hello.cpp
)

#main.cpp의 파일을 가주고 main이라는 바이너리를 생성한다.
add_executable(main main.cpp)

#라이브러리 링킹
target_link_libraries(main PRIVATE hello)

하지만 이와 같은 디렉토리구조는 버전과 외부 라이브러리 관리등에 직관적이지 않고 불편을 초래한다.

이에 대해 다음섹션에서 이야기한다.

step 3 : 디렉토리 바꾸기

대부분의 경우 아래와 같이 프로젝트코드를 src 폴더에 넣고 작성한다.

우리도 이와 비슷하게 만들어보자.

src 라는 폴더에 프로젝트 소스를 관리한다.

.
├── CMakeLists.txt
├── hello
│   ├── CMakeLists.txt
│   └── src
│       ├── hello.cpp
│       └── hello.hpp
└── src
    ├── CMakeLists.txt
    ├── hello.cpp
    ├── hello.hpp
    └── main.cpp

일단 하나하나 살펴보자

./CMakeLists.txt

cmake_minimum_required(VERSION 3.8)

project(myproject VERSION 1.0.0)

add_subdirectory(hello)
add_subdirectory(src)

add_subdirectory는 서브 디렉토리를 의미하면 해당 풀더의 있는 camkeFiles을 실행시켜주는 역활을 한다.

이경우 hello와 src의 폴더에 있는 cmakeFiles을 실행해준다.

./hello/CMakeLists.txt


add_library(
    sayhello 
    src/hello.cpp
    src/hello.hpp
)
target_include_directories(sayhello PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

target_include_directories 키워드는 종속된 프로젝트를 include를 해줄수 있는 키워드이며

이 함수를 통해 sayhello 라이브러리를 사용하게 된 경우 해당 소스코드를 include를 해주는 역활을 한다.

마지막으로 가장중요한 src/CMakeLists.txt 을 확인하자

./src/CMakeLists.txt

add_executable(main main.cpp)

target_link_libraries(main PRIVATE sayhello)

여기서 중요하게 봐야할점은 target_link_libraries이 함수다.

이 함수를 사용하게 된경우 해당 타켓에 맞는 link을 해주고 또한 더불어서 sayhello에 속한 include 값을 자동으로 해당 프로젝트 값을 넣어준다.

target_link_libraries(main PRIVATE sayhello)을 지우고 추가했을때 VS기준 C/C++ include 의 설정을 확인해보면

추가했을때는 아래와 같이 뜨는 반면 없으면 빈 값은걸 확인 할수있다.

이 내용은 정말 기초적인 내용을 담은 내용이며 자세한 함수의 내용은 다음 링크를 읽어보는걸 권장한다.

https://gist.github.com/luncliff/6e2d4eb7ca29a0afd5b592f72b80cb5c

또한 cmakefiles의 대한 설정은 따른 오픈소스를 참조하여 자신만의 cmakefiles을 만들어보는게 가장 좋다.