Thursday, November 12, 2009

gcc make 프로그램 한꺼번에 컴파일

조그마한 크기의 프로젝트가 아니라면, 하나의 프로젝트를 위해서 보통 4-6 개 혹은 수십개의 쏘쓰 파일로 이루어 진다. 이러한 중/대 규모의 프로젝트를 테스트하고 실행하기 위해서, 일일이 gcc 를 사용한 다는것은 상당한 노력과 신중함을 필요로하게 된다. 이러할때 Unix 에서 제공하는 "make" 를 사용하게 되면 프로젝트 관리를 좀더 수월하게 할수 있다. 이번 문서에스는 "make" 를 사용하는 방법에 대해서 알아보도록 하겠다.

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

이러한 일련의 작업을 자동화 시켜주는 프로그램이 있으면 좋을것이다라고 누군가 생각을 했고 그래서 나온게 make 라는 도구(프로그램) 이다. make 를 사용하면 위의 모든 일련의 컴파일을 자동적으로 관리 해줄뿐만 아니라, 최근에 바뀐 쏘쓰만 컴파일해서 링크시켜주는 일까지 알아서 처리한다. 예를 들어 1.c 를 수정했다면 2.c, 3.c 4.c, 5.c 는 그대로 두고 단지 1.c 만을 컴파일 해서 object 파일을 만들고, 나머지 기존에 만들어져 있던 object 파일과 링크를 시켜준다. 그러므로 시간을 크게 절약할수 있으며, 프로그래머는 "어떻게 컴파일 될 것인가" 라는 부수적인 것에 신경쓰지 않고 코딩에만 전념할수 있다.

object 파일을 만들고 이들을 link 시켜서 최종 실행 파일을 만들기 위해서, 프로그래머는 보통 어떤 source를 필요로 하고, 어떤 헤더파일이 필요로 하는지, 그리고 어떤 라이브러리가 필요로 하고 있는지, 최종적으로 만들어질 실행파일의 이름이 무엇인지를 알고 있어야 한다. 마찬가지로 make 역시 "컴파일 규칙"을 알아야 할필요가 있다. 이러한 규칙을 정한 설정파일을 참조해야 하는데 보통 "Makefile" 라는 이름의 파일을 참조한다. Makefile 에는 해당 쏘쓰를 컴파일 하기 위해서, 어떤 컴파일러를 사용해야 하는지, 컴파일후 어떤 실행파일(Target) 를 만들어야 하는지, 각 object 파일의 의존성관계는 어떠한지, 컴파일시 어떤 헤더파일디렉토리와, 라이브러리를 참조할지 등에 대한 규칙을 담고 있다. 다음은 Makefile 의 간단한 형태이다.

1 CC = gcc
2 CXX = g++
3 CFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG
4 CXXFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG
5 INCPATH = -I/usr/local/include/mysql
6 LINK = g++
7 LIBS = -L/usr/local/lib/mysql -lmysqlclient -lcrypt

8 # FILE
9 SOURCES = main.cc
10 sql.cc

11 OBJECTS = main.o
12 sql.o

13 TARGET = myprg

14 # Implict rules
15 .SUFFIXES: .cc .c

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

18 # build rule

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

22 clean:
23 -rm -f $(OBJECTS) $(TARGET)
24 -rm -f core

25 # complie
26 main.o: main.cc
27 sql.o : sql.cc


각줄의 번호는 설명의 편의를 위해서 붙인거다.
언뜻 보면 쉘스크립트 언어와 꿰유사한 분위기를 풍김을 알수 있을것이다. make 에서는 make 파일의 내용을 쉽고 간편하게 작성하도록 하기 위해서 "매크로" 를 제공한다. 매크로의 사용은 shell 에서의 변수사용과 매우 비슷하다. 매크로명 = 매크로값 사용방법은 $(매크로명) 식으로 필요할때 불러쓰면 된다.


1 번줄 부터 13 번줄까지는 각종 매크로를 지정했음을 알수 있다.
15 번줄의 .SUFFIXES 는 파일의 확장자에 따른 컴파일 규칙을 정의해 주기 위해서 make 에서 내부적으로 제공하는 키워드로, 컴파일 규칙을 정의할 파일의 확장자를 적어준다.
16 - 17 번째 줄은 .SUFFIXES 에서 정의한 확장자를 위한 컴파일 규칙을 적용한 것이다. 16 번째줄은 .cc 에 대한 빌드규칙은 ":" 이하의 규칙에 따라서 컴파일을 하고, 컴파일후 만들어지는 object 파일은 확장자".o"를 붙여라는 뜻이다. 16 번째 줄을 매크로 치환을 해서 완전한 명령어로 바꾸어 보면 (sql.cc 를 컴파일한다고 가정하자) $ g++ -c -pipe -Wall -W -O2 -DNO_DEBUG -I/usr/local/include/mysql -o sql.o sql.cc 이 된다. 17 번째 줄의 경우는 확장자가 .c 인 파일에 대한 빌드 규칙인데, 이때는 g++ 대신 gcc 를 사용하도록 규칙이 정해져 있다.
위에서 보면 $@ 가 사용되었는데, 이는 타켓의 전체이름을 나타내는 생략형이다. .cc.o 에서 타겟의 이름은 파일명.o 로 하라고 지정되어 있음으로 sql.cc 에 대해서 $@ 는 sql.o 로 치환된다. 눈치 챘겠지만 "$<" 는 원래 파일 명을 나타낸다.

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

$ make all
$ make clean


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

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

다음번에는 Makefile 를 자동적으로 만들어주는 tmake 란 도구에 대한 문서를 제공하도 록 하겠다.

이전의 문서 "make 를 이용한 프로젝트 관리(1)" 에서 우리는 간단하게 나마 make 도구의 유용성에 대해서 알아보았다. 그렇긴 하지만 make 를 사용하기 위해서 Makefile 를 만드는 데에는 꽤 많은 시간이 든다.
이러한 문제를 해결하기 위해서 Makefile 을 자동적으로 만들어주는 tmake 란 프로그램이 있는데, 이번에는 tmake 를 사용해서 Makefile 을 쉽게 생성하는 방법을 알아보도록 하겠다.

tmake 는 QT를 제작한 회사로 유명한 troll 이라는 회사에서 배포하는 프로그램이다. 원래 tmake 는
QT프로그램을 위한 Makefile 를 생성하지만, 약간만 수정하면 쉽게 자신의 프로젝트에 맞는 kefile 를 만들수 있다.

우선 프로그램을 다운로드받는다.
다운로드 받은 파일은 적당한 디렉토리에 옮겨서 압축을 풀면 bin 디렉토리가 생성되는데, 여기에 있는 파일들중 progen 과 tmake 2개의 실행파일을 적당한 실행 디렉토리로(/usr/local/bin 과 같은) 복사해 준다.
그다음에 lib 디렉토리 역시 적당한 디렉토리(/usr/local/tmake/lib) 로 복사해준다.
이로써 tmake 를 사용하기 위해서 필요한 모든 파일의 설치가 끝이 났다. 이제 tmake 를 사용하기 위한 환경설정을 해주어야 하는데, 만약에 bash 쉘이라면 .bash_profile 에 아래의 내용을 포함시키도록 한다.
TMAKEPATH=/usr/local/tmake/lib/linux-g++
expotr TMAKEPATH


c 쉘이라면 .cshrc 파일을 수정하면 된다.

setenv TMAKEPATH /usr/local/tmake/lib/linux-g++


이로써 tmake 를 사용하기 위한 모든 환경설정이 끝났다. 이제 직접 tmake 를 이용해서 Make 파일을 생성시켜보도록 하겠다.

우선 Makefile 를 생성할 프로그램 쏘스가 있는 디렉토리로 이동한다. 그후 progen 을 이용해서 project 파일을 생성한다.

[yundream @localhost test]$ progen -o test.pro


progen 을 실행하면 test.pro 란 파일이 생성되었음을 알수 있을것이다. test.pro 는 프로젝트 파일로, 현재 디렉토리에 어떤 쏘쓰파일(.c .cc) 이있는지 어떤 헤더파일이 있는지에 대한 정보를 가지고 있다. tmake 는 이 파일을 참조 하여 Makefile 을 만들어낸다.
이제 tmake 파일을 실행해서 Makefile 를 만들면 된다.

[yundream @localhost test]$ tmake -o Makefile test.pro


위의 명령을 실행하면 tmake 는 test.pro 파일을 참조해서 Makefile 를 생성하게 된다.

이렇게 해서 Makefile 를 매우 쉽게 만들긴 했지만 tmake 가 모든것을 알아서 해주는 만능은 아니다. 게다가 서문에서 미리 말했듯이 tmake 프로그램이 원래 QT 응용 프로그램에 최적화되어 있기 때문에 약간 손을 봐줄 필요가 있다.
tmake 를 이용해서 생성된 Makefile 에서 LIBS 라인을 자신의 프로그램에 맞게 수정하면 된다.
그리고 MOC 와 UIC 는 필요 없는 라인이므로 삭제하면 된다.

수정전 LIBS = $(SUBLIBS) -L$(QTDIR)/lib -L/usr/X11R6/lib -lqt -lXext -lX11 -lm
MOC = $(QTDIR)/bin/moc
UIC = $(QTDIR)/bin/uic


수정후 LIBS = -lcrypt -lm


물론 LIBS 부분은 사용자마다 달라진다.

이제 make 를 실행하기만 하면 test 라는 실행파일이 만들어진다. 이로써 tmake 의 사용방법을 알아보았다. tmake 가 완벽한 프로그램은 아니지만 프로젝트 관리를 위한 시간을 대폭 줄여줄것이다.

No comments: