CMake를 이용한 C 언어 프로그래밍 #3: 라이브러리

반응형

    개요 

    본 글에서는 CMake를 이용한 C 라이브러리 작성법을 소개한다.

     

    본 글에서 사용된 환경은 다음과 같다

    • CMake 실행 및 빌드 환경 : 우분투 리눅스 16.04 (도커 컨테이너)

    • CMake 버전: 3.13.2

    참고로 리눅스 상에 CMake를 설치하는 방법은 다음 글에서 확인할 수 있다.

     

    hello 라이브러리 작성

    "Hello world"라는 문자열을 화면에 출력하는 (아주 간단한) API를 제공하는 라이브러리를 작성해 본다.

     

    다음과 같이 hello.c 파일과 hello.h 파일을 작성한다.

    hello.c 파일은 hello 라이브러리의 메인 구현 파일로써, "Hello world"라는 문자열을 출력하는 PrintHelloWorld()라는 API 함수를 구현한다. 해당 API 함수는 hello 라이브러리를 링크하는 어플리케이션에 의해 호출된다.

    /**
     * @file hello.c
     * @brief hello 라이브러리가 제공하는 API들을 구현한 파일
     */
    
    
    #include <stdio.h>
    
    
    /**
     * @brief Hello world 문자열을 출력한다.
     */
    void PrintHelloWorld(void)
    {
      printf("Hello world\n");
    }

     

    hello.h 파일은 hello 라이브러리의 API를 호출하는 어플리케이션이, 해당 API를 호출할 수 있도록 API의 원형을 선언한다. hello.h 파일은 hello 라이브러리의 API를 호출하는 어플리케이션에서 인클루드 된다.

    /**
     * @file hello.h
     * @brief hello 라이브러리가 제공하는 API들을 선언한 헤더 파일
     */
    
    void PrintHelloWorld(void);
    

     

     

    hello.c 파일과 동일한 디렉터리 내에 CMakeLists.txt 파일을 다음과 같이 작성한다.

     

    • add_library 명령은 라이브러리를 빌드하는 명령이다.

    • hello는 빌드 결과로 생성되는 라이브러리의 이름을 나타내며, 최종 라이브러리 파일은 라이브러리 이름 앞에 "lib" 라는 프리픽스가 추가된 파일명을 가진다. 

    • STATIC 인자는 정적 라이브러리로 빌드하라는 의미이며, 이 경우 라이브러리 파일은 *.a 파일로 생성된다. SHARED 인자를 사용할 경우에는 동적 라이브러리(공유 오브젝트)로 빌드되며, 라이브러리 파일은 *.so 파일로 생성된다.

    • hello.c는 빌드할 파일을 의미한다. 두 개 이상의 파일을 빌드할 경우 각 파일명을 연속적으로 추가한다. 각 파일명사이는 한칸씩 띄운다.

    add_library(hello STATIC hello.c)

     

    CMakeLists.txt 파일이 위치한 디렉토리에서 "cmake CMakeLists.txt" 명령(또는 "cmake .")을 수행한다.

    root@f3b504fd1ee8:/workspace/cmake-lib# cmake CMakeLists.txt
    -- The C compiler identification is GNU 5.4.0
    -- The CXX compiler identification is GNU 5.4.0
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /workspace/cmake-lib

     

    cmake 명령에 의해 Makefile이 생성되었으므로, "make" 명령으로 빌드한다. 빌드 결과로 libhello.a라는 이름의 라이브러리 파일이 생성된 것을 확인할 수 있다.

    root@f3b504fd1ee8:/workspace/cmake-lib# make
    [100%] Built target hello
    root@f3b504fd1ee8:/workspace/cmake-lib# ls
    CMakeCache.txt  CMakeFiles  CMakeLists.txt  Makefile  cmake_install.cmake  hello.c  hello.h  libhello.a

     

    이로써 hello 라이브러리의 생성은 완료 되었다.

     

     

    hello 라이브러리의 API를 사용하는 어플리케이션 작성

    이제, 위에서 만들어진 hello 라이브러리의 PrintHelloWorld() API 함수를 호출하는 어플리케이션을 작성한다.

     

    다음과 같이 app.c 파일을 작성한다.

    • hello 라이브러리의 API를 사용하기 위해 라이브러리 헤더 파일(hello.h)을 인클루드한다.

    • main() 함수 내에서 hello 라이브러리의 PrintHelloWorld() API를 호출한다.

    /**
     * @file app.c
     * @brief hello 라이브러리의 API를 호출하는 예제 어플리케이션
     */
    
    
    // hello 라이브러리 해더 파일 인클루드
    #include "hello.h"
    
    
    /**
     * @brief 메인 함수
     * @param[in] argc 실행 파라미터 개수
     * @param[in] argv 실행 파라미터(들)
     * @return 0
     */
    int main(int argc, char *argv[])
    {
      PrintHelloWorld();
    }

     

    app.c 파일과 동일한 디렉토리에 CMakeLists.txt 파일을 다음과 같이 작성한다.

    • cmake_minimum_required(): 필요한 CMake의 최소 버전을 명시한다. target_link_libraries() 등과 같은 일부 CMake 명령문은 오래된 버전의 CMake 문법에서는 지원하지 않을 수 있으므로, 사용한 명령문에 따라 필요한 CMake의 버전을 명시해야 한다.

    • add_executable(): app.c 파일을 빌드하여 app 라는 실행파일을 생성하도록 명령한다.

    • target_include_directories(): 어플리케이션이 인클루드하는 헤더 파일들이 위치한 경로를 지정한다. 본 예제에서는 hello 라이브러리의 헤더파일(hello.h)이 위치한 경로를 지정해야 하며, 본 예제 상으로는 모두 동일한 디렉토리를 사용하고 있어 현재 디렉토리를 의미하는 ${CMAKE_CURRENT_LIST}를 지정하였다. 

      • gcc 컴파일 명령문의 "-I" 옵션에 해당된다.

    • target_link_directories(): 어플리케이션이 링크하는 라이브러리 파일들이 위치한 경로를 지정한다. 본 예제에서는 hello 라이브러리 파일(libhello.a)이 위치한 경로를 지정해야 한다.

      • gcc 컴파일 명령문의 "-L" 옵션에 해당된다.

    • target_link_libraries(): 어플리케이션이 링크하는 라이브러의 이름을 지정한다. 본 예제에서는 hello 라이브러리를 링크하므로 hello를 작성한다.

      • gcc 컴파일 명령문의 "-l" 옵션에 해당된다.

    cmake_minimum_required(VERSION 3.13)
    set(TARGET_APP app)
    add_executable(${TARGET_APP} app.c)
    target_include_directories(${TARGET_APP} PRIVATE ${CMAKE_CURRENT_LIST})
    target_link_directories(${TARGET_APP} PRIVATE ${CMAKE_CURRENT_LIST})
    target_link_libraries(${TARGET_APP} PRIVATE hello)

     

     

    CMakeLists.txt 파일이 위치한 디렉토리에서 "cmake CMakeLists.txt" 명령(또는 "cmake . ")을 수행한다.

     

    cmake 명령에 의해 Makefile이 생성되었으므로, "make" 명령으로 빌드한다. 빌드 결과로 app 실행 파일이 생성된 것을 확인할 수 있다.

    root@f3b504fd1ee8:/workspace/cmake-lib# make
    [ 75%] Building C object CMakeFiles/app.dir/app.c.o
    [100%] Linking C executable app
    [100%] Built target app
    root@f3b504fd1ee8:/workspace/cmake-lib# ls
    CMakeCache.txt  CMakeFiles  CMakeLists.txt  Makefile  app  app.c  cmake_install.cmake  hello.c  hello.h  libhello.a
    root@f3b504fd1ee8:/workspace/cmake-lib#

     

    생성된 app 파일을 실행해 본다.

    hello 라이브러리에 정의된 대로 "Hello world" 문자열이 화면에 출력되는 것을 확인할 수 있다.

    root@f3b504fd1ee8:/workspace/cmake-lib# ./app
    Hello world

     

    기타

    위 예제에서는 hello 라이브러리와 샘플 어플리케이션의 CMakeLists.txt 파일을 별도로 작성하였으나, 다음과 같이 하나의 CMakeLists.txt 파일을 이용하여 빌드할 수도 있다. 이 경우, 한번의 cmake와 make 명령으로 라이브러리와 어플리케이션을 함께 빌드할 수 있다.

    cmake_minimum_required(VERSION 3.13)
    
    add_library(hello STATIC hello.c)
    
    set(TARGET_APP app)
    add_executable(${TARGET_APP} app.c)
    target_include_directories(${TARGET_APP} PRIVATE ${CMAKE_CURRENT_LIST})
    target_link_directories(${TARGET_APP} PRIVATE ${CMAKE_CURRENT_LIST})
    target_link_libraries(${TARGET_APP} PRIVATE hello)

     

    파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음

    댓글

    Designed by JB FACTORY