Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

만약 5개의 쏘쓰로 이루어진 프로그램을 테스트 하기 위해서 컴파일을 한다면 다음과 같은 방식을 사용해야 할것이다.

$ gcc -c 1.c
$ gcc -c 2.c
$ gcc -c 3.c
$ gcc -c 4.c
$ gcc -c 5.c
$ gcc -o myprg 1.o 2.o 3.o 4.o 5.o

매번 myprg 라는 실행파일을 만들어 내기 위해서 위의 방식대로 컴파일(:12) 하는건 보통 일이 아니다. 그나마 위의 경우는 간단한 형태이고 각종 gcc 옵션, library 링크 include 파일이 패스지정등이 들어가게 되면, 코딩하는 시간보다 컴파일 하는 시간이 더걸리는 사태가 벌어질것이다.

이러한 일련의 작업을 자동화 시켜주는 프로그램이 있으면 좋을것이다라고 누군가 생각을 했고 그래서 나온게 make 라는 도구(프로그램) 이다. make(:12) 를 사용하면 위의 모든 일련의 컴파일을 자동적으로 관리 해줄뿐만 아니라, 최근에 바뀐 쏘쓰만 컴파일해서 링크시켜주는 일까지 알아서 처리한다.

예를 들어 1.c 를 수정했다면 2.c, 3.c 4.c, 5.c 는 그대로 두고 단지 1.c 만을 컴파일 해서 object 파일을 만들고, 나머지 기존에 만들어져 있던 object 파일과 링크를 시켜준다. 그러므로 시간을 크게 절약할수 있으며, 프로그래머는 "어떻게 컴파일 될 것인가" 라는 부수적인 것에 신경쓰지 않고 코딩에만 전념할수 있다.

object 파일을 만들고 이들을 link(:12) 시켜서 최종 실행 파일을 만들기 위해서, 프로그래머(:12_는 보통 어떤 source 를 필요로 하고, 어떤 헤더파일이 필요로 하는지, 그리고 어떤 라이브러리(:12)가 필요로 하고 있는지, 최종적으로 만들어질 실행파일의 이름이 무엇인지를 알고 있어야 한다. 마찬가지로 make 역시 컴파일 규칙 을 알아야 할필요가 있다.

이러한 규칙을 정한 설정파일을 참조해야 하는데 보통 Makefile 라는 이름의 파일을 참조한다. Makefile 에는 해당 쏘쓰를 컴파일 하기 위해서, 어떤 컴파일러를 사용해야 하는지, 컴파일후 어떤 실행파일(Target) 를 만들어야 하는지, 각 object 파일의 의존성관계는 어떠한지, 컴파일시 어떤 헤더파일디렉토리와, 라이브러리를 참조할지 등에 대한 규칙을 담고 있다. 다음은 Makefile 의 간단한 형태이다.

CC = gcc
CXX = g++
CFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG
CXXFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG
INCPATH = -I/usr/local/include/mysql
LINK = g++
LIBS = -L/usr/local/lib/mysql -lmysqlclient -lcrypt

# FILE
SOURCES = main.cc \
	sql.cc

OBJECTS = main.o \
	sql.o

TARGET = myprg

# Implict rules
.SUFFIXES:.cc .c

.cc.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.c.o: $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<

# build rule

all: $(TARGET)
$(TARGET): $(OBJECTS) $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)

clean: -rm -f $(OBJECTS) $(TARGET) \
	-rm -f core

# complie
main.o: main.cc
sql.o : sql.cc

언뜻 보면 쉘스크립트(:12) 언어와 유사한 함을 알수 있을것이다. make 에서는 make 파일의 내용을 쉽고 간편하게 작성하도록 하기 위해서 "매크로" 를 제공한다. 매크로의 사용은 shell 에서의 변수사용과 매우 비슷하다.

매크로명 = 매크로값
사용방법은 $(매크로명) 식으로 필요할때 불러쓰면 된다. 여러줄에 걸쳐서 매크로값을 정의해야 할 경우 역슬래쉬(\)로 다음줄로 계속됨을 명시해주어야 한다.

1 번줄 부터 16 번줄까지는 각종 매크로를 지정했음을 알수 있다.

19 번줄의 .SUFFIXES 는 파일의 확장자에 따른 컴파일 규칙을 정의해 주기 위해서 make 에서 내부적으로 제공하는 키워드로, 컴파일 규칙을 정의할 파일의 확장자를 적어준다.

21-22 번째 줄은 .SUFFIXES 에서 정의한 확장자를 위한 컴파일 규칙을 적용한 것이다. 21 번째줄은 .cc 에 대한 빌드규칙은 ":" 이하의 규칙에 따라서 컴파일을 하고, 컴파일후 만들어지는 object 파일은 확장자 ".o"를 붙여라는 뜻이다. 21 번째 줄을 매크로 치환을 해서 완전한 명령어로 바꾸어 보면 (sql.cc 를 컴파일한다고 가정하자)
$ g++ -c -pipe -Wall -W -O2 -DNO_DEBUG -I/usr/local/include/mysql -o sql.o sql.cc
이 된다. 22 번째 줄의 경우는 확장자가 .c 인 파일에 대한 빌드 규칙인데, 이때는 g++ 대신 gcc 를 사용하도록 규칙이 정해져 있다.

위에서 보면 $@ 가 사용되었는데, 이는 타켓의 전체이름을 나타내는 생략형 문자다. .cc.o 에서 타겟의 이름은 파일명.o 로 하라고 지정되어 있음으로 sql.cc 에 대해서 $@ 는 sql.o 로 치환된다. 눈치 챘겠지만 "$<" 는 원래 파일 명을 나타낸다.

26-29 는 build rule이 정의되어 있다. make 프로그램에 아규먼트를 주는 형식으로 시행되는데, 아래와 같은 방법으로 실행한다.
$ make all
$ make clean

make all 명령을 실행하면 g++ 일 이용해서 실행파일을 만들어내고, make clean 을 실행하면 그동안 생성되었던 모든 오브젝트 파일과 core 파일을 지우게 된다. 물론 이러한 build 룰 같은것은 사용자가 필요로 할경우 얼마든지 새로운 기능을 추가시킬수 있다.

지금까지 make 의 사용법을 간단하게 나마 알아 보았다. 지금까지의 설명은 make 파일의 가장 일반적이고 간단한 사용의 방법이다. 그렇다고 하더라도 위의 정도만 사용할줄 알아도 대부분의 프로젝트 프로그램을 관리하는데에는 문제는 없을것이다. 이 문서에서 제공하지 않는 더 고급의 기능은 스스로 조금씩 배워나가면 될것이다.

다음번에는 Makefile 를 자동적으로 만들어주는 tmake(:12) 란 도구에 대한 문서를 제공하도 록 하겠다.
  1. minz님의 make 강좌
  2. tmake를 이용한 Makefile 생성