CMake를 이용한 모듈형 프로젝트 빌드와 배포

1. 프로젝트 디렉토리 구조 설계

모듈화된 C 프로젝트를 CMake를 통해 효과적으로 빌드하고 설치하는 방법을 다룹니다. 예제 프로젝트는 덧셈, 뺄셈 기능을 제공하는 두 개의 라이브러리 모듈과 이들을 사용하는 테스트 실행 파일 모듈로 구성됩니다. 각 모듈은 자체적인 CMakeLists.txt 파일을 가지며, 최상위 CMakeLists.txt가 이들을 통합 관리합니다.

math_project/
├── add_module
│   ├── math_add.c
│   ├── math_add.h
│   └── CMakeLists.txt
├── build/
├── CMakeLists.txt
├── example_apps
│   ├── CMakeLists.txt
│   ├── app_test_add.c
│   └── app_test_sub.c
└── sub_module
    ├── CMakeLists.txt
    ├── math_sub.c
    └── math_sub.h
  • add_module: 덧셈 연산을 담당하는 모듈로, 동적 및 정적 라이브러리를 생성합니다.
  • sub_module: 뺄셈 연산을 담당하는 모듈로, 동적 및 정적 라이브러리를 생성합니다.
  • example_apps: add_modulesub_module 라이브러리를 사용하여 연산을 테스트하는 실행 파일을 생성합니다.
  • CMakeLists.txt: 최상위 디렉토리에 위치하며, 각 서브 모듈의 CMakeLists.txt를 호출하여 전체 프로젝트 빌드를 지시합니다.

2. 모듈별 코드 및 CMake 설정

2.1. 덧셈 모듈 (add_module)

math_add.h

#ifndef MATH_ADD_H
#define MATH_ADD_H

/**
 * @brief 두 정수를 더하는 함수입니다.
 * @param val1 첫 번째 정수
 * @param val2 두 번째 정수
 * @return 두 정수의 합
 */
int calculate_sum(const int val1, const int val2);

#endif // MATH_ADD_H

math_add.c

#include "math_add.h"

// 두 정수를 더하는 함수 구현
int calculate_sum(const int val1, const int val2)
{
    return val1 + val2;
}

CMakeLists.txt (add_module)

# 현재 디렉토리의 C 소스 파일 찾기
file(GLOB add_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
# 현재 디렉토리의 헤더 파일 찾기
file(GLOB add_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h")

# 동적 라이브러리 생성: 이름은 'math_ops_add'
add_library(math_ops_add_dynamic SHARED ${add_sources})
# 정적 라이브러리 생성: 이름은 'math_ops_add'
add_library(math_ops_add_static STATIC ${add_sources})

# 생성될 라이브러리의 파일명 설정 (lib 접두사 및 확장자 제외)
set_target_properties(math_ops_add_dynamic PROPERTIES OUTPUT_NAME "math_ops_add")
set_target_properties(math_ops_add_static PROPERTIES OUTPUT_NAME "math_ops_add")

# 동적 라이브러리 버전 설정
set_target_properties(math_ops_add_dynamic PROPERTIES VERSION 2.0 SOVERSION 2)

# 라이브러리 설치 규칙 정의
INSTALL(TARGETS math_ops_add_dynamic math_ops_add_static
        LIBRARY DESTINATION lib        # 동적 라이브러리는 'lib' 디렉토리에
        ARCHIVE DESTINATION lib)       # 정적 라이브러리는 'lib' 디렉토리에

# 헤더 파일 설치 규칙 정의
INSTALL(FILES ${add_headers} DESTINATION include/math_module_headers)

2.2. 뺄셈 모듈 (sub_module)

math_sub.h

#ifndef MATH_SUB_H
#define MATH_SUB_H

/**
 * @brief 두 정수를 빼는 함수입니다.
 * @param operand1 첫 번째 정수
 * @param operand2 두 번째 정수
 * @return 두 정수의 차
 */
int calculate_difference(const int operand1, const int operand2);

#endif // MATH_SUB_H

math_sub.c

#include "math_sub.h"

// 두 정수를 빼는 함수 구현
int calculate_difference(const int operand1, const int operand2)
{
    return operand1 - operand2;
}

CMakeLists.txt (sub_module)

# 현재 디렉토리의 C 소스 파일 찾기
file(GLOB sub_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
# 현재 디렉토리의 헤더 파일 찾기
file(GLOB sub_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h")

# 동적 라이브러리 생성: 이름은 'math_ops_sub'
add_library(math_ops_sub_dynamic SHARED ${sub_sources})
# 정적 라이브러리 생성: 이름은 'math_ops_sub'
add_library(math_ops_sub_static STATIC ${sub_sources})

# 생성될 라이브러리의 파일명 설정
set_target_properties(math_ops_sub_dynamic PROPERTIES OUTPUT_NAME "math_ops_sub")
set_target_properties(math_ops_sub_static PROPERTIES OUTPUT_NAME "math_ops_sub")

# 동적 라이브러리 버전 설정
set_target_properties(math_ops_sub_dynamic PROPERTIES VERSION 2.0 SOVERSION 2)

# 라이브러리 설치 규칙 정의
INSTALL(TARGETS math_ops_sub_dynamic math_ops_sub_static
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib)

# 헤더 파일 설치 규칙 정의
INSTALL(FILES ${sub_headers} DESTINATION include/math_module_headers)

2.3. 테스트 애플리케이션 모듈 (example_apps)

app_test_add.c

#include "math_add.h" // 덧셈 모듈 헤더
#include 

int main()
{
    int num1 = 40;
    int num2 = 15;
    printf("Add Test: %d + %d = %d\n", num1, num2, calculate_sum(num1, num2));
    return 0;
}

app_test_sub.c

#include "math_sub.h" // 뺄셈 모듈 헤더
#include 

int main()
{
    int val_a = 70;
    int val_b = 25;
    printf("Sub Test: %d - %d = %d\n", val_a, val_b, calculate_difference(val_a, val_b));
    return 0;
}

CMakeLists.txt (example_apps)

# 덧셈 및 뺄셈 모듈의 헤더 파일 경로 추가 (빌드 시 찾을 수 있도록)
include_directories(${PROJECT_SOURCE_DIR}/add_module)
include_directories(${PROJECT_SOURCE_DIR}/sub_module)

# 라이브러리 검색 경로 추가 (빌드 시 생성된 라이브러리를 찾기 위함)
# CMAKE_BINARY_DIR는 빌드 디렉토리의 절대 경로를 나타냅니다.
link_directories(${CMAKE_BINARY_DIR}/lib)

# 덧셈 테스트 실행 파일 생성
add_executable(app_test_math_add app_test_add.c)
# 뺄셈 테스트 실행 파일 생성
add_executable(app_test_math_sub app_test_sub.c)

# 각 실행 파일에 필요한 라이브러리 링크
target_link_libraries(app_test_math_add math_ops_add) # 덧셈 라이브러리 링크
target_link_libraries(app_test_math_sub math_ops_sub) # 뺄셈 라이브러리 링크

# 실행 파일 설치 규칙 정의
INSTALL(TARGETS app_test_math_add app_test_math_sub
        RUNTIME DESTINATION bin) # 실행 파일은 'bin' 디렉토리에

2.4. 최상위 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(ModularMathProject C)

# 빌드된 라이브러리 파일이 생성될 디렉토리 설정
# CMAKE_BINARY_DIR는 빌드 디렉토리 (예: build/)를 가리킵니다.
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# 빌드된 실행 파일이 생성될 디렉토리 설정
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 서브디렉토리들을 프로젝트에 포함
add_subdirectory(add_module)
add_subdirectory(sub_module)
add_subdirectory(example_apps)

3. 프로젝트 빌드 및 설치 과정

프로젝트를 구성한 후, 다음 단계에 따라 빌드하고 설치할 수 있습니다.

$ cd math_project
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/home/user/my_math_install ..
$ make
$ make install
$ cd ..
$ tree my_math_install

설치 결과 확인:

my_math_install/
├── bin
│   ├── app_test_math_add
│   └── app_test_math_sub
├── include
│   └── math_module_headers
│       ├── math_add.h
│       └── math_sub.h
└── lib
    ├── libmath_ops_add.a
    ├── libmath_ops_add.so -> libmath_ops_add.so.2
    ├── libmath_ops_add.so.2 -> libmath_ops_add.so.2.0
    ├── libmath_ops_add.so.2.0
    ├── libmath_ops_sub.a
    ├── libmath_ops_sub.so -> libmath_ops_sub.so.2
    ├── libmath_ops_sub.so.2 -> libmath_ops_sub.so.2.0
    └── libmath_ops_sub.so.2.0

설명:

  • -DCMAKE_INSTALL_PREFIX: 최종 설치될 디렉토리의 절대 경로를 지정합니다. 모든 INSTALL 명령의 DESTINATION 경로는 이 CMAKE_INSTALL_PREFIX를 기준으로 합니다.

4. CMake 설치 명령어 (INSTALL) 상세 설명

4.1. 타겟 (Target) 설치: INSTALL(TARGETS ...)

빌드된 라이브러리(정적, 동적)나 실행 파일을 설치할 때 사용합니다.

INSTALL(TARGETS targets...
        [[ARCHIVE|LIBRARY|RUNTIME]
        [DESTINATION <dir>]
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [OPTIONAL]
        ] [...])
  • targets: 설치할 CMake 타겟의 이름 (예: 실행 파일, 동적/정적 라이브러리).
  • ARCHIVE: 정적 라이브러리 (.a).
  • LIBRARY: 동적 라이브러리 (.so, .dylib).
  • RUNTIME: 실행 파일 (실행 가능한 프로그램).
  • DESTINATION <dir>: CMAKE_INSTALL_PREFIX를 기준으로 하는 상대 경로입니다. 만약 <dir>/로 시작하면 절대 경로로 간주되어 CMAKE_INSTALL_PREFIX를 무시합니다.

예시:

# 덧셈 모듈 라이브러리 설치
INSTALL(TARGETS math_ops_add_dynamic math_ops_add_static
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib)

# 테스트 실행 파일 설치
INSTALL(TARGETS app_test_math_add app_test_math_sub
        RUNTIME DESTINATION bin)

4.2. 일반 파일 설치: INSTALL(FILES ...)

헤더 파일, 설정 파일 등 특정 파일들을 설치할 때 사용합니다.

INSTALL(FILES files... DESTINATION <dir>
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [RENAME <name>] [OPTIONAL])
  • files: 설치할 파일들의 목록.
  • DESTINATION <dir>: 위와 동일하게 설치 경로를 지정합니다.

예시:

# 헤더 파일 설치
INSTALL(FILES ${add_headers} DESTINATION include/math_module_headers)
INSTALL(FILES ${sub_headers} DESTINATION include/math_module_headers)

4.3. 디렉토리 및 스크립트 설치: INSTALL(DIRECTORY ...)

전체 디렉토리나 스크립트 파일들을 설치할 때 사용합니다.

INSTALL(DIRECTORY dirs... DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [[PATTERN <pattern> | REGEX <regex>]
        [EXCLUDE] [PERMISSIONS permissions...]] [...])
  • dirs: 설치할 디렉토리 목록. 디렉토리 이름이 /로 끝나지 않으면 디렉토리 자체가 대상 경로 아래에 생성됩니다. /로 끝나면 디렉토리 안의 내용만 대상 경로로 복사됩니다.
  • PATTERN <pattern> | REGEX <regex>: 특정 파일이나 디렉토리를 포함하거나 제외하기 위한 패턴/정규 표현식.
  • EXCLUDE: 패턴에 일치하는 항목을 설치에서 제외합니다.

예시:

# icons 디렉토리와 scripts/ 내의 내용을 설치
INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
        PATTERN "CVS" EXCLUDE             # CVS 디렉토리는 제외
        PATTERN "*.sh"                    # .sh 스크립트 파일에 대해
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
                    GROUP_EXECUTE GROUP_READ)

이 예시는 icons 디렉토리를 <prefix>/share/myproj/icons에 설치하고, scripts/ 디렉토리 안의 모든 내용(CVS 디렉토리 제외)을 <prefix>/share/myproj에 설치하며, 모든 .sh 파일에는 지정된 권한을 부여합니다.

태그: cmake C언어 라이브러리 모듈화 빌드시스템

9월 21일 10:24에 게시됨