본문 바로가기
Language & Framework & GIT/ROS2

CMakeLists.txt 작성 방법

by veganwithbacon 2023. 7. 5.
반응형

CMAKE를 계속 작성해야하는데, 매번 찾아보기도 번거롭고 아직 이해도 제대로 안돼서 긁어왔다.

습득할 지식이 산넘어 산이다..

 

 


 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 라이브러리를 제외하는 옵션을 지정. 

 

 

 

참고

https://www.tuwlab.com/27260

반응형

댓글