-
[CMake] CMakeLists.txt 작성하기Computer Programs 2021. 6. 28. 15:03
l Make
- 항상 유지/보수를 신경써야한다. ( 소스 코드를 수정해서 의존성이 바뀔 때 마다 Makefile에 업데이트 해야한다. )
- 프로젝트 규모가 거대해 질수록 관리해야할 소스 파일이 많아지고, 의존성 관계가 복잡해 진다.
- Makefile 자체적으로 의존성을 파악해 주지만, Makefile에 기술된 의존성 (dependencies) 정보가 소스코드의 내용에 부합되게 관리되 있음이 전재 되어야 한다.
- 소스코드-결과물 사이를 깔끔하게 추상화 할 수 있다.
l CMake
: Kitware 사에서 만든 프로그램을 build하기 위한 meta build system으로 다양한 빌드환경을 위한 빌드 파일을 생성하는 유틸리티로, Qt의 qmake와 비슷한 역할을 수행한다.
- autoconfig / automake 에 비해 사용이 편리하다.
- 다양한 빌드 환경을 지원한다 ( Makefile, Visual Studio, Xcode)
- 의존성 정보를 일일히 기술해 주지 않아도 되므로 빌드 스크립트 관리에 효율적이다.
- Make와 다른 점은 소스 파일 내부까지 들여다보고 분석하여 의존성 정보를 스스로 파악한다.
-> 소스파일에 헤더 파일을 추가 하면, 직후 빌드부터 의존성 관계 변화가 자동으로 추적되어 헤더 파일의 변화 까지 추적한다.
l CMake 간단 사용
CMakeLists.txt 파일을 만들고, 빌드 규칙을 기술한 후에 cmake를 구동하면 타겟 프로그램에대한 빌드 스크립트 (실행파일)이 생성된다. CMakeLists.txt에서는 최종 빌드 결과물과 이를 빌드하기 위한 소스파일들만 명시하면 끝이 난다.
[Example]
cmake_minimum_required (VERSION 2.8 ) #cmake 최소 필요 버전
project(test) #프로젝트명, test
set(CMAKE_BUILD_TYPE Release)
add_definitions(-D__MY_DEFIEND__) #-D로 전달할 pre defined macro가 있을 경우 사용
- make 명령으로 ccmake로 생성한 Makefile을 실행하면, 가장 먼저 CMakeLists.txt 파일이 변경됬는지 여부를 검사하고, 변경된 경우 MakeFile을 다시 생성하여 실행한다.
- MakeFile에 정의된 각 Traget별로 빌드를 수행한다. 이 때 내부 Build Step에 따라 cmake명령으로 각 Target을 빌드하는데 필요한 Sub-makefile을 생성한다. 이 때 생성되는 Sub-make file도 cmakefiles 디렉토리 내부에 저장된다.
l CMake 주요 명령 & 변수
(1) SET() – 변수정의
: cmake 빌드 스크립드 작성시, 상단에 설정 변수를 정의하는 명령을 몰아 놓고, 이 설정에 따라 빌드 절차를 결정하도록 구성.
#변수정의
set ( <변수명> <값> )
#목록 변수 정의 -> 자동으로 적절하게 직렬화
set( <목록 변수 명> <항목> <항목> <항목> … )
#변수 참조
$변수명 $(<변수명>)
SET( SRC_FILES main.c foo.c bar.c ) -> 빌드 대상의 소스 목록을 SRC_FILE변수로 지정,
ADD_EXECUTETABLE( app.out ${SRC_FILE}) -> 이들로 app.out 실행파일을 생성함
(2) CMAKE_MINIMUM_REQUIRED() – 필요 CMake 최소 버전 명시
: CMake 빌드 스크립트를 실행하기 위한 최소 버전 명시. 최상단에 위치. 명시한 버전보다 낮은 CMake가 해당 빌드 스크립트를 해석하려 하면, 오류를 출력하고 종료함.
CMAKE_MINIMUM_REQUIRED( VERSION <버전> )
CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
(3) PROJECT() – 프로젝트 이름 설정
: 프로젝트 이름을 설정. 프로젝트 이름에 고백이 포함되면 큰따옴표로 둘러준다.
PROJECT(<프로젝트 명>)
(4) CMAKE_PROJECT_NAME – 프로젝트 이름
: PROJECT() 명령으로 설정한 프로젝트 이름이 변수에 저장됨.
MESSAGE( ${CMAKE_PROJECT_NAME) } #콘솔창에 프로젝트 이름 출력
(5) CMAKE_BUILD_TYPE – 빌드 형상 ( Configuration )
: 빌드 목적 ( 디버깅, 배포 ) 에 따라 서로 다른 옵션을 지정해서 빌드하는 것.
- Debug : 디버깅 목적
- Release : 배포 목적
- RelWithDebInfo : 배포 목적 이지만 디버깅 정보 포함
- MinSizeRel : 최소 크기로 최적화한 배포 목적 빌드
(6) MESSAGE() – 콘솔에 메시지 출력
: 콘솔에 메시지나 변수 출력. 빌드 스크립트 디버깅시 사용.
MESSAGE( [Type] <메시지> )
- STATUS : 상태 메시지 출력
- WARNING : 경고 메시지 출력 후 계속 진행
- AUTHOR_WARNING : 프로젝트 개발자용 경고 메시지, 계속 진행
- SEND_ERROR : 오류 메시지 출력, 계속 진행, Make_file 생성 하지 않음.
- FATAL_ERROR : 오류 메시지 출력, 작업 즉시 중단.
MESSAGE ( FATAL_ERROR “Fatal error occureed!”)
(7) CMAKE_VERBOSE_MAKEFILE – Verbose Makefile 작성 여부
: Switch 벼수, true 값으로 지정하면 빌드 상세과정을 모두 출ㄹ력하는 Makefile을 생성한다.
SET ( CMAKE_VERBOSE_MAKEFILE true )
-> 빌드 스크립트 작성시에 이 옵션을 켜 놓는 것이 좋다.
(8) ADD_EXECUTABLE() – 빌드 대상 바이너리 추가
: 빌드 최종 결과물로 생성할 실행파일을 추가한다. 이 명령을 반복하여 생성할 실행 파일을 계속 추가할 수 있다.
ADD_EXECUTABLE ( <실행파일명> <소스파일> <소스파일> … )
ADD_EXECUTABLE( app.out main.c foo.c bar.c )
(9) ADD_LIBRARY() – 빌드대상 라이브러리 추가
: 빌드 최종 결과물로 생성할 라이브러리를 추가한다. 이 명령을 반복하여 생성할 라이브러리를 계속 추가할 수 있다.
ADD_LIBRARY( <라이브러리 이름> [STATIC|SHARED|MODULE] <소스파일> <소스파일> … )
ADD_LIBRARY( app STATIC foo.c bar.c )
(10) ADD_DEPENDENCIES() – Target간 의존성 정의
: ADD_EXECUTABLE, ADD_LIBRARY, ADD_CUSTOM_TARGET 명령으로 정의한 Target간의 의존성을 지정.
Target을 빌드할 때 이 명령으로 정의한 의존 대상들이 Outdated인 경우 이들에 대한 빌드를 먼저 수행.
ADD_DEPENDENCIES( <Target 이름> <의존 대상> <의존 대상> … )
ADD_DEPENDENCIES ( flash app.out ) -> flash가 app.out에 의존적임을 명시.
(11) INSTALL() – 설치 매크로 정의
Makefile에서 관용적으로 설치용 Target으로 사용되는 install target의 동작 방식을 정의, 즉 make install 명령을 실행했을 때 어떤 동작을 수행할지를 결정.
Linux 에서 install은 build완료된 실행 바이너리와 라이브러리 및 기타 부속물 ( 헤더 파일, 리소스 )등을 시스템의 적절한 위치로 복사하는 동작임.
INSTALL( TARGETS <TARGETS 목록>
RUNTIME DESTINATION < 바이너리 설치 경로 >
LIBRARY DESTINATION < 라이브러리 설치 경로 >
ARCHIVE DESTINATION < 아카이브 설치 경로 >
)
설치 경로가 모두 같은 경우 축약 형태
INSTALL ( TARGETS < TARGET 목록> DESTINATION <설치 경로> )
INSTALL( TARGETS app.out app
RUNTIM_DESTINATION /usr/local/bin
ARCHIVE_DESTINATION /usr/local/lib
)
(12) CMAKE_INSTALL_PREFIX – 설치 디렉토리
: 설치 매크로에서 실행 바이너리와 라이브러리 등의 최종 생성물을 복사할 설치 디렉토리를 지정.
SET ( CMAKE_INSTALL_PREFIX /usr/bin )
(13) ADD_COMPILE_OPTIONS() – 컴파일 옵션 추가
: 소스파일을 컴파일 하여 Object 파일을 생성할 때 컴파일러에 전달할 옵션을 추가
ADD_COMPIE_OPTIONS( <옵션> <옵션> … )
ADD_COMPILE_OPTIONS( -g -Wall ) -> 디버깅 목적 심벌 테이블 포함, 모든 경고 메시지를 표시.
(14) ADD_DEFINITIONS() – 전처리기 매크로 추가(-D)
: 전처리기에 전달할 매크로 정의. 컴파일러 옵션중 -D
ADD_DEFINITIONS( -D<매크로> -D<매크로> -D<매크로>=값 …)
ADD_DEFINITIONS( -DICACHE_FLASH -DMY_DEBUG=1 ) -> ICACHE_FLASH매크로 변수를 정의하고, MY_DEBUG라는 이름의 전처리 매크로값을 1로 정의한다.
(15) INCLUDE_DIRECTORIES() – 헤더 디렉토리 추가(-I)
: 각 소스 파일에서 #include 구문으로 포함시킨 헤더파일을 찾을 디렉토리 목록을 추가. 컴파일러 옵션중 -I
INCLUDE_DIRECTORIES ( <디렉토리> <디렉토리> …)
INCLUDE_DIRECTORIES( include driver/include) -> include 디렉토리와 driver/include 디렉토리에서 헤더 파일을 찾도록 한다.
(16) LINK_DIRECTORIES() – 라이브러리 디렉토리 지정 (-L)
: 링크과정에서 필요한 라이브러리 파일들을 찾을 디렉토리 목록을 지정한다. 컴파일러 옵션중 -L
LINK_DIRECTORIES( <디렉토리> <디렉토리> … )
LINK_DIRECTOREIS ( lib /var/lib ) -> lib 및 /var/lib 디렉토리에서 라이브러리 파일을 찾는다.
(17) LINK_LIBRARIES() – 링크 옵션 추가
: 링크시 포함할 라이브러리 목록을 지정. 이때 라이브러리 파일명의 Prefix 및 Postfix는 제외하고 라이브러리 이름만 입력. ( libxxx.a 에서 xxx 만 ) 컴파일러 옵션 중 -l
LINK_LIBRARIES ( <라이브러리> <라이브러리> … )
** 링크옵션도 함께 지정. <라이브러리>값이 하이픈 – 으로 시작하는 경우 링크 명령에 그대로 포함, 그렇지 않은 경우 앞에 -l이 자동으로 추가됨.
LINK_LIBRARIES ( uart wifi -static) -> 링크 라이브러리로 libuart.a(.so), libwifi.a(.s0) 추가하고, Shared 라이브러리를 제외하는 옵션 -static을 추가.
(18) CMAKE_EXE_LINKER_FLAGS_<빌드 형상> - 빌드 형상별 링크 옵션
: 특정 빌드 형상에서만 사용할 링크 옵셩( flag ) 지정.
SET ( CMAKE_EXE_LINKER_FLAGS_DEBUG “-DCONFIG_DEBUG -Wl, -whole-archive”) -> debug빌드 시만 config_debug 매크로를 정의하고 모든 symbol을 포함하도록 링크 옵션을 지정.
(19) RUNTIME_OUTPUT_DIRECOTYR -실행 바이너리 출력 디렉토리
: 빌드 완료한 실행 바이너리를 저장할 디렉토리 지정.
SET ( RUNTIME_OUTPUT_DIRECTORY output/bin ) -> 실행 바이너리를 프로젝트 디렉토리 내 output/bin에 저장한다.
(20) LIBRARY_OUTPUT_DIRECTORY – 라이브러리 출력 디렉토리
: 빌드 완료한 라이브러리를 저장할 디렉토리를 지정
SET( LIBRARY_OUTPUT_DIRECTORY output/lib ) -> 빌드한 라이브러리를 프로젝트 디렉토리 내의 output/lib에 저장하도록 한다.
(21) ARCHIVE_OUTPUT_DRICETOR – 라이브러리 출력 디렉토리
: 빌드 완료한 아카이브(static 라이브러리)를 저장할 디렉토리 지정
SET( ARCHIVE_OUTPUT_DIRECTORY output/lib/static )
(22) TARGET_COMPILE_OPTIONS() – Target 컴파일 옵션 추가
: Target 소스 파일을 컴파일 할 때 전달할 옵션(플래그)를 추가.
TRAGET_COMPILE_OPTIONS ( <Target 이름> PUBLIC <옵션> <옵션> … )
TARGET_COMILE_OPTIONS ( app.out PUBLIC -g -Wall ) -> app.out을 컴파일 할 때 디버깅 목적의 심벌 테이블을 -g 포함하고, 모든 경고 메시지를 표시한다.
(23) TARGET_COMPILE_DEFINITIONS() – Target 전처리기 매크로 정의 ( -D )
: Target의 소스 파일을 컴파일 하여 Object 파일을 생성할 때 전처리기에 전달할 매크로를 정의.
TARGET_COMPILE_DEFINITIONS( <Target 이름> PUBLIC <매크로> <매크로> <매크로=값> … )
TARGET_COMPILE_DEFINITIONS (app.out PUBLIC UART_BUFFERED -DICACHE DEBUG = 1 ) -> app.out을 컴파일 할 때UART_BUFFERED, ICAHCE 매크로 변수를 정의, DEBUG이름의 전처리 매크로 값 1 로 정의.
(24) TARGET_INCLUDE_DIRECTORIES() – Target 헤더 디렉토리 추가 ( -I ) (대문자 아이)
: Target에 포함된소스파일에서 #include 구문으로 포함시킨 헤더 팡리을 찾을 디렉토리 목록 추가. 컴팡리러 옵션 중 -I에 해당.
TARGET_INCLUDE_DIRECTORIES ( <Target 이름> PUBLIC <디렉토리> <디렉토리> … )
TARGET_INCLUDE_DIRECTORIES(include driver/include) -> app.out을 빌드할 때 Include 디렉토리와 driver.include 디렉토리에서 헤더 파일을 찾도록 한다.
(25) TARGET_LINK_LIBRARIES() – Target 링크 옵션 및 라이브러리 지정 (-l) (소문자 엘)
: Target 링크 시 포함할 라이브러리 목록을 지정. 라이브러리 파일명의 Prefix밑 Postfix는 제외하고 라이브러리 이름만 입력. (libxxxx.a 에서 xxxx) 컴파일러 옵션 중 -l
TARGET)LINK_LIBRARIE( <Target_이름> <라이브러리> <라이브러리> … )
TARGET_LINK_LIBRARIES( app.out uart wifi -static ) -> app.out을 빌드할 때 libuart,a와 libwifi를 포함하고 Shared 라이브러리를 제외하는 옵션을 지정.
참고
'Computer Programs' 카테고리의 다른 글
[Capnp] Cap'n Proto 란 (0) 2022.11.07 [Protocol Buffer] google protobuf 란 (0) 2021.06.29 [ZeroMQ] Socket 생성 및 동작 확인 및 구현 (0) 2021.06.29 [ZeroMQ] Mac Os BigSur & Linux Ubuntun 18.04 에서 설치 및 helloworld 테스트 (0) 2021.06.28