[c언어] make, Makefile 이해하기

업데이트:

[c언어] make, Makefile 이해하기

참고 링크

make를 사용하는 이유

간단한 소스코드 파일 한두개라면 몰라도 컴파일 해야할 코드 갯수가 굉장히 많아지면 gcc 방식으로 하나하나 입력하는 것은 매우 번거로운 일입니다. 따라서 이러한 불편함을 해결하고 쉽게 컴파일하기 위해 사용하기 위한 방법이 make 입니다.

make? Makefile?

make는 유틸리티 이름입니다. make 유틸리티는 Makefile이라는 파일의 내용을 읽어서 목표 파일(target)을 만듭니다.

실습 파일 만들기

main.c 만들기

#include "introduce.h"

int main(void)
{
  job();
  hobby();
  
  return 0;
}

위 코드가 메인 소스 코드 입니다. 위 코드를 보면 introduce.h라는 헤더파일이 사용된 것을 알 수 있고, job(), hobby() 함수가 사용된 것을 알 수 있습니다. 따라서 우리가 할 일은 introduce.h라는 헤더파일을 만들고, job(), hobby() 함수를 정의하는 것입니다.

introduce.h 헤더 파일 만들기

void job();
void hobby();

먼저 헤더 파일 introduce.h 파일을 만들어보겠습니다. 위 헤더 파일 내부에는 job(), hobby() 함수가 정의되어 있습니다.

job.c 파일 만들기

#include <stdio.h>

void job(){
  printf("I am a student. \n");
}

job.c 파일은 job 함수를 구현한 코드입니다. 코드 내용은 간단히 자신의 직업을 출력하는 코드입니다.

hobby.c 파일 만들기

# include <stdio.h>

void hobby(){
  printf("I enjoy playing soccer. \n");
}

job.c 파일과 비슷하게 이번에는 취미를 출력하는 hobby.c 파일을 생성해줍니다.

만든 파일 확인하기

$ ls
hobby.c introduce.h job.c main.c

gcc로 컴파일 하기

오브젝트 파일 생성하기

$ gcc -c -o job.o job.c
$ gcc -c -o hobby.o hobby.c
$ gcc -c -o main.o main.c

각각의 소스코드 별로 오브젝트 파일을 생성해줍니다. gcc 명령에서 -c 옵션은 오브젝트 파일을 생성하는 옵션이며, -o는 생성된 아웃풋 파일의 이름을 지정하는 옵션입니다. 예를 들어 첫번째 문장의 경우, job.c 파일을 이용해 만든 job.o 오브젝트 파일을 떨군다는 뜻입니다.

$ ls
hobby.c hobby.o introduce.h job.c job.o main.c main.o

결과를 보면 오브젝트 파일이 잘 생성된 것을 볼 수 있습니다.

오브젝트 파일로 컴파일 하기

$ gcc -o intro_exe main.o job.o hobby.o
$ ./intro_exe
I am a student.
I enjoy playing soccer.

위 코드를 보면 잘 실행되는 것을 볼 수 있습니다.

make를 이용해 컴파일 하기

Makefile의 구성 요소

  • 목적파일(target): 명령어 수행 후 나온 결과를 저장할 파일
  • 의존성(dependency): 목적 파일을 만들기 위한 재료 파일
  • 명령어(command): 실행 되어야 할 명령어들
  • 매크로(macro): 코드를 단순화 시킴

Makefile 구조

CC = gcc
target1 : dependency1 dependency2
  command1
  command2
  
target2 : dependency3 dependency4
  command3
  command4

Makefile 만들기

intro_exe : job.o hobby.o main.o
  gcc -o intro_exe job.o hobby.o main.o

job.o : job.c
  gcc -c -o job.o job.c
  
hobby.o : hobby.c
  gcc -c -o hobby.o hobby.c
  
main.o : main.c
  gcc -c -o main.o main.c
  
clean : 
  rm *.o intro_exe

make 실행!

$ make clean
rm *.o intro_exe

먼저 make clean 명령어로 위에서 만든 오브젝트 파일과 실행파일 intro_exe을 삭제해 줍니다.

$ make
gcc -c -o job.o job.c
gcc -c -o hobby.o hobby.c
gcc -c -o main.o main.c
gcc -o intro_exe job.o hobby.o main.o

그리고 make를 실행하면 잘 컴파일 되는 것을 알 수 있습니다.

$ ./intro_exe
I am a student.
I enjoy playing soccer.

그리고 실행하면 잘 실행되는 것을 볼 수 있습니다.

매크로 사용(1)

이번에는 매크로를 사용해서 Makefile 을 만들어보겠습니다.

CC = gcc
TARGET = intro_exe

$(TARGET) : job.o hobby.o main.o
  $(CC) -o $(TARGET) job.o hobby.o main.o

job.o : job.c
  $(CC) -c -o job.o job.c
  
hobby.o : hobby.c
  $(CC) -c -o hobby.o hobby.c
  
main.o : main.c
  $(CC) -c -o main.o main.c
  
clean : 
  rm *.o intro_exe

실행해보겠습니다.

$ make
$ ./intro_exe
I am a student.
I enjoy playing soccer.

매크로 사용(2)

이번에는 위에 사용한 매크로를 좀 더 간결히 표현해보겠습니다.

CC = gcc
TARGET = intro_exe
OBJECTS = job.o hobby.o main.o

all : $(TARGET)

$(TARGET) : $(OBJECTS)
  $(CC) -o $@ $^
  
clean : 
  rm *.o intro_exe

위 코드에서 $@는 현재 타겟의 이름을 의미하며, $^는 현재 타겟의 종속 항목 리스트를 의미합니다. 그리고 위 코드에서 $(CC) -o $@ $^ 구문을 실행할 때 오브젝트 파일이 없으면 오브젝트 파일과 동일한 이름의 c파일을 찾아 오브젝트 파일을 자동으로 생성합니다.