[C++] Make와 Makefile 작성법


Study/C , C++ , MFC  2020. 3. 9. 00:01

안녕하세요. 명월입니다.


이 글은 Make와 Makefile 작성법에 대한 글입니다.


Visual studio를 사용한다면 Make와 Makefile 작성법에 대해 알 필요는 없습니다.

그러나 서버가 Linux이고 Visual studio를 사용할 수 없는 환경이라면 Make와 Makefile를 통해 빌드하는 방법을 알아두어야 합니다. 요즘에 Visual studio를 사용할 수 없는 환경이 있을까 싶네요.


Make와 Makefile은 여러가지 소스 파일의 의존성을 정리하고 빌드 순서를 만들어서 최종적으로 실행하는 프로그램을 만드는 프로그램 빌드 도구입니다.


Linux환경에서 빌드할 때 다음과 같은 명령어를 사용합니다.

#include <stdio.h>
#include <iostream>

using namespace std;

void function();
#include "function.h"

void function()
{
  cout << "function" << endl;
}
#include <stdio.h>
#include <iostream>
#include "function.h"

using namespace std;

int main()
{
  cout << "hello world" << endl;
  function();
}

위의 세 소스파일이 있습니다. 여기서 참고로 헤더 파일(.h)과 소스 파일(.cpp)이 있습니다.

헤더 파일은 소스 파일의 선언 파일입니다. 즉, 소스 파일은 함수를 실행하는 로직이 작성되어 있는데, 헤더 파일은 그 소스 파일의 함수명을 정의하여 다른 소스 파일에서 참조할 수 있게 만드는 것이 헤더 파일입니다.

즉, main.cpp에서 function()함수를 사용하는 데, main.cpp 파일에서는 function()함수가 없습니다. function.cpp에 있는데 main.cpp위에 보면 「#include "function.h"」로 function.cpp의 function함수를 사용할 수 있게 연결하는 역할한 것입니다.


다시 make로 설명으로 돌아와서 위 내용을 빌드할려고 하면 먼저 function.cpp와 main.cpp파일을 오브젝트 파일(.o)로 만들어야 합니다.

오브젝트를 만든 후에 모든 소스를 합쳐서 하나의 실행 파일로 만들어야 합니다.

g++ -c -o function.o function.cpp
g++ -c -o main.o main.cpp

g++ -o main.exe function.o main.o

여기서 -c 옵션은 main함수를 찾지 않는 다는 옵션입니다.(main.cpp는 main함수가 있으니깐 -c를 사용 안해도 됩니다.)

-o 옵션은 output 파일을 만드는 것읍니다.

빌드의 순서는 cpp -> object 파일 -> 실행 파일(윈도우라면 .exe 파일)을 만드는 것입니다.

./main.exe 파일을 실행하면 hello world와 function 결과가 출력되었습니다.


위 경우는 두개의 소스 파일이니 간단하게 되었지만 소스 파일이 많아지면 이야기가 달라질 것입니다.

이걸 빌드 파일을 만들어서 한방에 빌드을 할 수 있습니다.

# <Target>: <Dependencies>
#   <Recipe>
# Target은 대상 : Dependencies는 파일이 있는 지 목록을 체크하는 것, 없으면 Target를 찾습니다.
# Recipe는 Target을 만들기 위한 명령어.
# main.exe를 만들기 위해서 main.o와 function.o를 체크한다.
main.exe: main.o function.o
  # main.exe를 만드는 명령어
  g++ -o main.exe main.o function.o
# main.o를 만들기 위해서 function.h와 main.cpp를 체크한다.
main.o: function.h main.cpp
  # main.o를 만드는 명령어
  g++ -c -o main.o main.cpp
# function.o를 만들기 위해서 function.h와 function.cpp를 체크한다.
function.o: function.h function.cpp
  # function.o를 만드는 명령어
  g++ -c -o function.o function.cpp

참고로 Makefile의 구분은 탭입니다.(스페이스 4칸은 허용되지 않습니다.)

Makefile를 실행하기 위해서는 make 명령어를 사용하면 됩니다.

위 예에서 -c -o의 옵션으로 오브젝트(*.o)를 만드는 명령어가 있는데, make파일에서 이 오브젝트 생성하는 명령어는 생략이 가능합니다.

# main.exe를 만들기 위해서 main.o와 function.o를 체크한다.
main.exe: main.o function.o
  # main.exe를 만드는 명령어
  g++ -o main.exe main.o function.o
# main.o를 만들기 위해서 function.h와 main.cpp를 체크한다. 오브젝트 생성은 명령어를 생략한다.
main.o: function.h main.cpp
# function.o를 만들기 위해서 function.h와 function.cpp를 체크한다. 오브젝트 생성은 명령어를 생략한다.
function.o: function.h function.cpp

조금은 간편해졌네요..

Make파일은 변수를 치환해서 사용할 수도 있습니다.

# 변수 선언
# 빌드 변수
CC=g++
# 옵션 변수
CFLAGS= -o
# 오브젝트 변수
OBJS=main.o function.o
# 타겟 변수
TARGET=main.exe

# 변수를 사용하려면 $를 사용한다.
$(TARGET): $(OBJS)
  # $@은 현재 Target 이름을 뜻한다.
  $(CC) $(CFLAGS) $@ $(OBJS)

# 오브젝트 생성
main.o: function.h main.cpp
function.o: function.h function.cpp

변수를 사용하면 조금 더 Makefile를 깔끔하게 작성이 가능합니다.


Makefile에 의사 타케팅을 지정할 수 있습니다.

# 변수 선언
CC=g++
CFLAGS= -o
OBJS=main.o function.o
TARGET=main.exe

# 실행 파일 만드는 타겟팅
all: $(TARGET)

# make clean의 명령어를 수행.
clean:
  rm -rf *.o
  rm -rf $(TARGET)

$(TARGET): $(OBJS)
  $(CC) $(CFLAGS) $@ $(OBJS)
# 의존성 오브젝트 생성
main.o: function.h main.cpp
function.o: function.h function.cpp

제가 프로그램을 처음 공부할 때 만에도 Make와 Makefile부터 공부했었는데, 지금은 워낙 좋은 빌드 툴이 많아서 Make나 Makefile를 사용할까 싶기도 합니다.


여기까지 Make와 Makefile에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.