공식 레퍼런스: https://www.gnu.org/software/make/manual/make.html

 

 

GNU에서 제공하는 make 유틸리티는 빌드 자동화를 위한 툴입니다. 레퍼런스를 보면 컴파일러를 가진 어떤 언어든 상관없이 쉘 스크립트를 통해 자동화가 가능하며, 프로그램 빌드뿐만 아니라 파일의 업데이트 여부와 같은 변화도 체크할 수 있다고 합니다. 하지만 일반적으로 C/C++ 언어의 빌드 자동화를 위한 툴로 많이 사용됩니다. make 유틸리티는 파일들 사이의 관계와 용도(헤더 파일을 어떻게 링크시키고 어떤 식으로 컴파일할지)를 makefile에 정의해두면 어떤 환경에서든 동일한 빌드가 가능하게 해줍니다. 즉, makefile을 작성하는 방법만 알면 GNU에서 제공해주는 유용한 빌드 자동화 툴인 make 유틸리티를 사용할 수 있습니다.

 

makefile의 형식은 다음과 같습니다.

target: prerequisites
    recipe

 

각 부분의 의미를 알아보겠습니다.

  • target - 뒷부분의 조건과 레시피에 따라 출력될 파일입니다.
  • prerequisites - 출력 파일을 만들기 위해 넣는 입력 파일입니다.
  • recipe - 입력 파일을 가지고 어떤 식으로 요리할지, 그러니까 어떤 식으로 컴파일하고 링크할지를 나타냅니다.

 

실제로 어떤 식으로 사용되는지 예를 들어보겠습니다. 다음과 같은 디렉터리 구조를 가지는 2개의 .c 소스파일과 .h 헤더파일이 있다고 가정해봅시다.

src/

   - main.c

   - source.c

include/

   - main.h

   - source.h

 

// main.c
#include "main.h"
#include "source.h"

int main(int argc, char* argv[]) {
    sayHello("Hello, World");
    return 0;
}

 

// main.h
#ifndef _MAIN_H
#define _MAIN_H
#include <stdio.h>
#endif

 

// source.c
#include "source.h"

void sayHello(const char* str) {
    printf("sayHello Function: %s\n", str);
}

 

// source.h
#ifndef _SOURCE_H
#define _SOURCE_H
#include "main.h"
#endif

 

위의 파일들을 빌드하기 위해선 다음과 같은 명령을 사용할 수 있습니다.

$ gcc src/*.c -o program -Iinclude

 

 

위와 같은 row한 방법으로 프로그램을 빌드할 경우 몇 가지 문제가 있습니다.

  1. 위와 같은 복잡한 컴파일 명령을 오타없이 쳐야합니다.
  2. 프로젝트를 배포할 경우, 제 3자 입장에선 프로젝트를 어떻게 빌드해야할지 난감합니다.

이러한 이유로 빌드를 자동화하는게 좋습니다. 단 한 번만 스크립트를 짜두면 make만 이용해서 빌드할 수 있습니다.

$ make

 

이제 위의 예제 파일들에 대한 makefile을 작성해보겠습니다.

CC = gcc
TARGET = program

SRC_DIR = src
INCLUDE_DIR = include
BINARY_DIR = bin

OBJECTS = $(patsubst %.c, %.o, $(wildcard $(SRC_DIR)/*.c))
HEADERS = $(wildcard $(INCLUDE_DIR)/*.h)

$(TARGET): $(OBJECTS)
    @echo "[+] Make Binary File"
    $(CC) -o $(BINARY_DIR)/$@ $(OBJECTS);

%.o: %.c $(HEADERS)
    @echo "[+] Compile $@ File" 
    $(CC) -g -c -o $@ $< -I$(INCLUDE_DIR)
    
clean:
    @rm -f $(SRC_DIR)/*.o
    @rm -f $(BINARY_DIR)/$(TARGET)
    @rmdir $(BINARY_DIR)