금요일, 2월 06, 2015

make 유틸리티 강좌 (1/4)

make 유틸리티 강좌 (1/4)


Make Utility

Make 유틸리티는 유닉스 계열 운영체제에서 널리 사용되던 개발 도구 입니다. 윈도우즈 환경에서 수많은 GNU 도구들이 이식되어 있습니다. 특히 내장형 시스템 개발을 위한 크로스 컴파일러들이 대부분 GNU 컴파일러들입니다. 요즘 내장형 시스템에 가장 널리 사용되는 ARM 계열 컴파일러들은 전부 GNU 툴입니다. 통합 환경과 함께 상용화 된 것도 있긴 합니다만 기본적으로 컴파일러 자체는 GNU 컴파일러를 이식하여 통합한 경우가 많습니다.

GNU 도구의 가장큰 장점은 무료사용이라는 것이겠지요. 단점은 커맨드 라인에서 작업해야 하므로 불편하다는 겁니다. 이 불편을 덜어주는 도구가 바로 Make 유틸리티 입니다. ARM 기반 프로그램을 시작하지 전에 꼭 배워 두면 평생 잘한 일 중 하나가 될 것이라고 장담합니다.

MS-윈도우즈 버젼 GNU Make 다운받을 수 있는 곳
http://gnuwin32.sourceforge.net/packages/make.htm

아래 글은 아주 예전 HiTel 시절에 동호회에 임대영(RAXIS)씨에 의해 게시되었던 글입니다. 수십년이 지났습니다만 Make 유틸리티를 이렇게 쉽고 간단하게 정리해 놓은 글은 못봤습니다.

--------------------------------------------------------------------
번  호 : 180
게시자 : 임대영   (RAXIS   )
등록일 : 1995-10-15 22:31
제  목 : [강좌]  make  [1]                    
---------------------------------------------------------------------
                        make 유틸리티 강좌
                        작성 : RAXIS ( 임대영 )
---------------------------------------------------------------------

목차.
        1. make ( 만든다? )
           1.1  make 유틸리티.
           1.2  make 의 필요성.
        2. 간단한 Makefile
           2.1  Makefile 의 내부구성.
           2.2  Makefile 예제
           2.3  매크로의 사용
           2.4  레이블의 이용

---------------------------------------------------------------------
1. make ( 만든다 ? )
---------------------------------------------------------------------

1.1 make 유틸리티.

영어사전에서 make 란 뜻은 누구나 알듯이 '만들다'라는 뜻의 동사이다. 그럼 make 유틸리티는 왜 이름이 make인지 알 필요가 있을것 같다. man 으로 찾아보면 make 에 대해 다음과 같이 설명하고 있다.

   make - GNU make utility to maintain groups of programs

   The purpose of the make utility is to determine  automati-
   cally  which  pieces  of a large program need to be recom-
   piled, and issue the commands  to  recompile  them.

우리말로 하면 make 는 프로그램 그룹을 유지하는데 필요한 유틸리티이다. make 유틸리티의 목적은 프로그램 그룹중에서 어느 부분이 새롭게 컴파일 되어야 하는지를 자동적으로 판단해서 필요한 커맨드(gcc따위)을 이용해서 그들을 재컴파일 시킨다고 되어 있다.

make 는 일련의 프로그램 개발에만 쓰이지 않고, 컴파일러처럼 일종의 명령어 방식으로 처리되는 모든 곳에서 쓰일수가 있다. 가령 latex 와 같은 경우도 .tex 화일에서 .dvi 화일을 만들고 다시 .ps 화일로 만드는 과정을 make 를 사용해서 간단하게 만들수가 있다.

[ 참고 - 쉽게 말하면 다음과 같은 경우에 make 를 쓰면 유리합니다.
[
[      1. 입력화일이 바뀌면 자동적으로 결과화일을 바꿔줬음 좋을때.
[         기왕이면 좀 지능적으로 일을 수행하고 말입니다.
[      2. 위의 latex 화일처럼 자동적으로 프로그램이 수행이 되었으면
[         좋을때..( batch 의 개념이죠 )
[
[      make 는 위의 두가지 개념을 모두 포함하고 있다고 봅니다.
[
[      보통 리눅스 프로그램에서 make all 하면 자세한 내막은 모르지만
[      자기가 알아서 다하죠.. 그다음이 make install 이구요..히.

GNU make 는 보통 GNUmakefile , Makefile , makefile 중에서 하나가 있으면 그 화일을 읽게 된다. 하지만 일반적으로 Makefile을 추천을 하게 되는데 그 이유는 우선 GNUmakefile 은 기존의 make에서 인식을 못한다는 단점이 있고, makefile은 보통 소스화일에 묻혀서 잘 안보이게 되기 때문이다.

Makefile은 make가 이해할수 있도록 일종의 쉘 스크립트 언어 같이 되어있다. ( makefile database 라고도 한다 ) 이 화일에는 결과 화일을 생성 시키기 위한 화일들간의 관계, 명령어등을 기술하고 있는데 이 강좌의 주된 목적이 바로 Makefile 의 작성에 있다.

1.2 make의 필요성

우선은 make의 사용을 프로그램 개발과 유지쪽으로 국한시키기로 한다. 보통 라인수가 많이지면 여러개의 화일로 나누어(모듈로 나누어) 개발을 하게 된다. 이들은 알게모르게 서로 관계를 가지고 있는데, 어느 하나를 필요에 의해 바꾸게 되었을때 그 화일에 있는 함수를 이용하는 다른 화일도 새롭게 컴파일 되어야 한다.

하지만 화일수가 많은 경우 이를 일일이 컴파일을 하게 될때, 그 불편함과 함께 컴파일 하지 않아도 될 것도 컴파일을 하게 될수도 있구, 컴파일해야 할 것도 미처 못하게 되는 경우가 있다. (링크에러의 원인이 되기도 하는데 에러의 원인을 제대로 찾기가 힘이 든다. )

앞에서도 얘기했듯이 이런 상황에서 지능적으로 관게있는 것만 새롭게 갱신을 할 필요가 있을때 make 화일은 빛을 발하게 된다.

---------------------------------------------------------------------
2. 간단한 Makefile
---------------------------------------------------------------------

2.1 Makefile 의 내부구성

Makefile은 기본적으로 아래와 같이 목표(target), 의존관계(dependency), 명령(command)의 세개로 이루어진 기분적인 규칙(rule)들이 계속적으로 나열되어 있다고 봐도 무방하다. make가 지능적으로 화일을 갱신하는 것도 모두 이 간단한 규칙에 의하기 때문이다.

target ... : dependency ...
        command
        ...
        ...

여기서 목표(target) 부분은 명령(command)가 수행이 되어서 나온 결과화일을 지정한다. 당연히 목적화일(object file)이나 실행화일이 될것이다.

명령(command)부분에 정의된 명령들은 의존관계(depenency)부분에 정의된 화일의 내용이 바뀌었거나, 목표부분에 해당하는 화일이 없을때 이곳에 정의되 것들이 차례대로 실행이 된다. 일반적으로 쉘상에서 쓸수 있는 모든 명령어들을 사용하수가 있으며 bash 에 기반한 쉘 스크립트도 지원한다.

[ 참고 - 참고로 목표부분에는 결과화일만 올수 있는것이 아니고, 보통
[         make clean 에 서와 같이 간단한 레이블(label) 기능을 제공
[         하기도 한다.
[
[        명령 부분은 꼭 TAB 글자로 시작해야 한다. 그냥 스페이스등을
[        사용하면 make 실행중에 에러가 난다. 명심하세요. make 가
[        명령어인지 아닌지를 TAB 가지고 구별하기 때문이죠

2.2 Makefile 예제.

간단한 Makefile 을 만들어 본다. 우리가 만들려고 하는 프로그램은 main.c read.c write.c 로 구성되어 있고 모두 io.h 라는 헤더화일을 사용한다고 가정한다. ( 흐.. 구성을 간단화시킵시다. ) 이들을 각각 컴파일해서 test 라는 실행화일을 생성시킨다.

% gcc -c main.c
% gcc -c read.c
% gcc -c write.c

% gcc -o test main.o read.o write.o

위의 방식은 make 를 쓰지 않고 그냥 명령어를 주는 방식이다. 화일의 수가 작아서 오히려 더 간단하게 보일수 있으나, 화일이 100 개 정도 된다고 가정하면 .... 아찔...

그리고 아래는 위와 똑같은 일을 수행하는 Makefile 의 내용이다.

----Makefile [예제1]--------------------------

test   : main.o read.o write.o
        gcc -o test main.o read.o write.o

main.o : io.h  main.c
        gcc -c main.c
read.o : io.h  read.c
        gcc -c read.c
write.o: io.h  write.c
        gcc -c write.c
----------------------------------------------

( 대충 알아보시겠어요? , 참 TAB 문자 쓰는거 있지 마세요 )

make 는 Makefile 의 내용을 보고, 내부적으로 이떻게 화일들이 의존하고 있는지 조사한다. 위의 Makefile 을 바탕으로 의존관계를 그림으로 나타내보면 아래와 같다.

                       +---------------+
                       |     io.h      |
                       +------+--------+
                              |
                    +---------+----------+
                    |                    |
  +--------------+  |  +------+-------+  |  +--------------+
  |    main.c    |  |  |    read.c    |  |  |   write.c    |
  +------+-------+  |  +------+-------+  |  +------+-------+
         |          |         |          |         |
  +------+-------+  |  +------+-------+  |  +------+-------+
  |    main.o    +--+--|    read.o    |  +--+   write.o    |
  +------+-------+     +------+-------+     +------+-------+
         |                    |                    |
         +--------------------+--------------------+
                      +-------|-------+
                      |     test      |
                      +------+--------+

( 텍스트 기반이라서 그림그리기가 디게 어렵네요 )

위의 그림에서 보면 test 가 만들어지기 위해서는 main.o read.o write.o 가 필요하게 각각의 목적화일들은 모두 자신의 소스화일과 io.h 에 의존함을 알수가 있다.

가령 main.c 를 고쳤다고 생각한다면 main.o 가 컴파일되서 다시 생기고, test 도 다시 링크되어서 갱신된다. 만약 io.h 가 바뀌었다고 가정하면 모든 화일들이 컴파일되어서 목적화일이 생기고, 그것들이 링크가 되어 test가 생긴다.

위와 같이 화일들을 구성한다음 Makefile 을 실행시켜보자. Makefile 의 실행은 그냥 make 라고만 치면 된다.

% make
gcc -c main.c
gcc -c read.c
gcc -c write.c
gcc -o test main.o read.o write.o   <-- OK

[ 참고 - 그냥 테스트기 때문에 read.c write.c io.h 는 모두 내용없이
[        화일만 만들어두기로 하고, main.c 에 간단히 printf 함수만
[        적어봅시다. 정말 위와 같이 됨을 실감할꺼예요.. 신기하게.


2.3 매크로의 사용

간단한 메크로 기능을 사용해보자. main.o read.o write.o 라는것을 OBJECTS 라는 매크로로 바꾸는 것이 아래의 [예제2]에 나와있다.

----Makefile [예제2]--------------------------

OBJECTS = main.o read.o write.o

test   : $(OBJECTS)
        gcc -o $(OBJECTS)

main.o : io.h  main.c
        gcc -c main.c
read.o : io.h  read.c
        gcc -c read.c
write.o: io.h  write.c
        gcc -c write.c
----------------------------------------------

위에서 보다시피 매크로는 그냥 프로그램 짤때와 같이 사용해서 값을 대입한다. 대신 사용할때는 반드시 $(..) 안에 넣어서 사용한다. 매크로 치환을 위한 특수한 방법이 아닐까.. 히.. 매크로의 사용법은 위와같이 간단하므로 다양하게 정의해서 사용할수 있다.  매크로에 대한 자세한 설명은 다음 강좌에서 언급하기로 한다.

2.4 레이블의 사용

목표부분에 해당하는 부분이 그냥 레이블과 같이 사용될수도 있다고 이미 설명하였다. [예제2]에다가 목적화일들을 모두 삭제하는 명령어를 추가하기로 한다.

----Makefile [예제3]--------------------------

OBJECTS = main.o read.o write.o

test : $(OBJECTS)
        gcc -o $(OBJECTS)

main.o : io.h  main.c
        gcc -c main.c
read.o : io.h  read.c
        gcc -c read.c
write.o: io.h  write.c
        gcc -c write.c

clean :
        rm $(OBECTS)
----------------------------------------------

레이블로 사용될때는 당연히 의존관계 부분은 없어도 된다. 그리고 clean 을 실행시킬려면 아래와 같이 한다.

% make clean
rm main.o read.o write.o  <-- OK

---------------------------------------------------------------------


<다음편 예고 >
본편에서는 Makefile의 간단한 예제를 가지고 무엇을 할 수 있는지 대충 말해보았습니다. 예제를 많이 쓰다보니까 내용이 불어나게 됐군요. RCS 와 달리 make 는 한번 알고 있으면 정말 유용한 유틸리티 입니다.

다음편에서는 본격적으로 Makefile의 구성및 그 사용법을 자세히 알아 보고자 합니다. 그냥 일반적으로 Makefile 을 사용하실려면 오늘 한것에 몇가지만 더 알고 계시면 됩니다. 계속 예제 중심으로 이해가 잘되도록.. 그럼 계속 봐주시면 감사.~~

----------------------------------------------------------------------------------

댓글 없음:

댓글 쓰기