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_module과sub_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 파일에는 지정된 권한을 부여합니다.