본문 바로가기
linux

Make File 만들기

by 상레알 2011. 2. 17.

출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C/Documents/UsedMake

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

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

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

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

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

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

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

make는 크게 Target, DEpend, Command, Macro 로 구성되어 있다.
            <Target>: <Depend> ? ....   [[;] <Command>]
            <탭문자><Command>

여기서 Target은  생성하고자 하는 목적물을 지칭하며 Depend는 Target을 만들기 위해서 필요한
요소를 기술하게 됩니다.  그리고 Command는 일반 Shell 명령이 옵니다. 이때 Command는
Depend 의 파일생성시간 (또는 변경된 시간)을 Target과 비교하여 Target 보다 Depend의 파일이
시간이 보다 최근일 경우로 판단될때에만 실행된다. 물론 이것에 대한 예외적인 규칙은 있다.
Command는 반드시 앞에 <TAB> 문자가 와야한다.


다음은 Makefile의 간단한 형태이다.

001  CC = gcc
002  CXX = g++
003  CFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG
004  CXXFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG
005  INCPATH = -I/usr/local/include/mysql
006  LINK = g++
007  LIBS = -L/usr/local/lib/mysql -lmysqlclient -lcrypt
008 
009  # FILE
010  SOURCES = main.cc \
011      sql.cc
012 
013  OBJECTS = main.o \
014      sql.o
015 
016  TARGET = myprg
017 
018  # Implict rules
019  .SUFFIXES:.cc .c
020 
021  .cc.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
022  .c.o: $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
023 
024  # build rule
025 
026  all: $(TARGET)
027  $(TARGET): $(OBJECTS) $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
028 
029  clean: -rm -f $(OBJECTS) $(TARGET) \
030      -rm -f core
031 
032  # complie
033  main.o: main.cc
034  sql.o : sql.cc

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

                   매크로명 = 매크로값

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

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

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

21~22번째 줄은 .SUFFIXES에서 정의한 확장자를 위한 컴파일 규칙을 적용한 것이다. 21번째 줄은
.cc 에 대한 빌드 규칙은  ":"  이하의 규칙에 따라서 컴파일을 하고, 컴파일후 만들어지는 object 파일
은 확장자 " .o "를 붙여라는 뜻이다. 21번째 줄을 매크로 치환을 해서 완전한 명령어로 바꾸어 보면
(sql.cc 를 컴파일 한다고 가정하자)
                  
                 $ g++ -c  -pipe -Wall -W -02 -DNO_DEBUG -I/usr/local/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 ( mysql 연동 계속쓰는게 그래서 만들엇다..위 예제보다는 더 간단하다)

------------------------------------------------------
CC = cc
RM = rm -rf
CFLAGS = -I/usr/include/mysql/ -L/usr/lib/mysql -lmysqlclient -lpthread -ldl -lm

mysql: mysql.o
        $(CC) -o mysql  mysql.o $(CFLAGS)
mysql.o: mysql.c
        $(CC) -c  mysql.c
clean :
        $(RM) *.o mysql
------------------------------------------------------
여기서 Command 앞에 공백은 <TAB> 이 아니면 오류가 발생한다는것에 유의하자 .