make와 cmake를 다루기 전에 gcc 빌드 과정을 간단히 알아보자
gcc 빌드 과정
빌드(build)란?
소스코드 => 실행 가능한 프로그램으로 변환하는 과정
아래의 과정을 거친다
전처리 (Preprocessing)
- 전처리기 지시어 (#include, #define 등)를 처리
- 헤더 파일을 포함하고 매크로를 확장하며 조건부 컴파일 수행
- 결과물은 전처리가 끝난 C언어 형태
컴파일 (Compilation)
- 전처리된 소스코드(.i 파일)을 기계어로 변환 가능한 중간 단계의 어셈블리 코드로 변환
- 이 과정에서 문법 오류나 타입 관련 오류 등이 발견
- 결과물은 어셈블리 코드 파일(.s)
어셈블링 (Assembling)
- 어셈블리 코드 (.s)를 목적파일(Objective File) (.o)로 변환
- 목적파일은 기계가 읽을 수 있는 이진코드 형태이지만 완전히 실행가능한 상태는 아님
링킹(Linking)
- 목적파일(.o)와 필요한 여러 라이브러리 파일을 연결하여 실행 파일 (.out 또는 .exe)을 생성
- 링커는 프로그램에서 사용하는 모든 함수와 변수가 정의된 위치를 찾아 연결
- 특정 함수나 변수가 정의되지 않았다면 링킹 오류 발생
크게 묶으면
하나의 소스코드를 Preprocessing, Compilation, Assembling을 거쳐서 Objective File을 만들고,
만들어진 Object files + 라이브러리들을 모아 Linking 하는 것이 빌드의 과정이다.
예시 진행
간단하게 예시로 진행하자.
폴더를 만들고 해당 폴더 안에 main.c, hyndrome.c, hyndrome.h 를 생성해보자
// main.c
#include <stdio.h>
#include "hyndrome.h"
int main()
{
printf("I'm main!\n");
Hyndrome();
return 0;
}
// hyndrome.h
void Hyndrome();
// hyndrome.c
#include <stdio.h>
void Hyndrome()
{
printf("I'm HYndrome!\n");
}
.c파일을 각각 컴파일, 어셈블링하자
gcc -c main.c
gcc -c hyndrome.c
ls
만들어진 .o 파일들과 라이브러리 함수들을 하나로 Linking하자
gcc main.o hyndrome.o -o go
ls
./go
GCC 는 똑똑해서 굳이 나눠서 작업하지 않아도 동작한다.
만들었던 .o 파일과 실행 파일을 지우고 다시 빌드해보자
rm -r *.o
rm -r ./go
ls
gcc ./*.c
ls
./a.out
빌드 자동화 시작
bash shell script (.sh)를 활용해서 위 과정을 다시 진행해보자
build.sh 파일을 생성하고 아래 코드를 작성한다.
#! /bin/bash
gcc -c ./main.c
gcc -c ./hyndrome.c
gcc ./main.o ./hyndrome.o -o ./go
rm -r ./*.o
source 로 .sh 파일을 실행할 수 있다.
source build.sh
./go
이렇게 shell script로 빌드를 자동화할 수는 있지만
중간에 파일 하나라도 변경점이 생긴다면 모든 파일을 다시 빌드해야하는 문제점이 있다!
make
소프트웨어 빌드를 자동화하는 데 사용되는 도구로, 주로 소스 코드를 컴파일하여 실행 가능한 프로그램으로 만드는 작업을 간소화하기 위해 사용된다
Makefile이라는 특별한 형식의 파일과 문법을 사용한다
make 설치
sudo apt install make -y
make 사용방법
- Makefile 스크립트 파일을 만든다
- make 명령어로 실행한다
예제 실습
파일 이름을 Makefile로 아래 코드를 작성한다.
go : main.o hyndrome.o
gcc main.o hyndrome.o -o go
main.o : main.c
gcc -c main.c
hyndrome.o : hyndrome.c
gcc -c hyndrome.c
clean :
rm -r ./*.o ./go
정상 작동 확인
다시 make를 사용하여 빌드를 하면 변경사항이 없어서 build가 되지 않는 것을 확인할 수 있다.
그러면 hyndrome.c 파일을 조금 수정해서 다시 빌드해보자.
// hyndrome.c
#include <stdio.h>
void Hyndrome()
{
printf("I'm updated HYndrome!\n");
}
처음 make를 사용해서 빌드했을 때 와 다르게 gcc -c main.c 는 컴파일 안된 것을 확인할 수 있다.
변동사항이 생긴 hyndrome.c, hyndrome.c 변동사항으로 인해 변화가 생긴 hyndrome.o에 연동된 빌드들만 다시 진행된 것을 확인할 수 있다!
make는 특정 키워드로 동작시킬 수 있다
make clean
make 장점
- build 자동화
- 기술된 순서대로 build 작업을 수행하는 자동화 스크립트 지원
- build 속도 최적화
- 파일간의 의존성을 추적하여 파일이 변경된 경우에만 컴파일한다!
CMake
Makefile을 자동으로 생성해주는 build system
크로스 플랫폼 빌드 자동화 도구
CMake 설치
sudo apt install g++ cmake -y
CMakeList.txt 파일을 작성한다
cmake_minimum_required(VERSION 3.5)
project(HYndromeProject)
# 빌드할 실행 파일(go)과 소스 파일들을 정의합니다.
add_executable(go main.c hyndrome.c)
# 헤더 파일이 있는 디렉토리를 포함시킵니다.
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# 실행 파일(go)이 사용하는 헤더 파일(hyndrome.h)을 명시합니다.
target_include_directories(go PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
cmake한다
cmake .
약 200 줄 정도의 Makefile이 생성된 것을 확인할 수 있다!
생성된 Makefile로 빌드해보자!
정상적으로 빌드된 것을 확인할 수 있다.
'C language' 카테고리의 다른 글
포인터와 문자열 char v[4] = "ABC" ; vs const char* v = "ABC";는 어떻게 다를까? (0) | 2024.12.12 |
---|---|
c언어로 shell script 실행하기 (0) | 2024.12.12 |
make 문법, makedepend (0) | 2024.12.11 |
메모리 주소 공간과 포인터 개념 (2) | 2024.12.09 |
VSCode C / C++ 개발 환경 셋팅하기 (window) (1) | 2024.01.07 |