『리눅스 학당-리눅스 강좌 / 연재 (go LINUX)』 333번 제 목:GNUtic -- Autoconf/Automake <1> 올린이:onestep (류창균 ) 96/10/04 16:10 읽음:2542 관련자료 없음 ----------------------------------------------------------------------------- updated version.. 지난번 글은 부족함이 많다고 생각해서 개선한 글입니다. 지난번 글을 보신 분이라면 별 차이없는 내용이라 생각됩니다. GNUtic Programming -- Automake, Autoconf, Configure [주의] 이 글을 쓴 사람은 ID주인이 아님. ID주인에게 폐를 끼칠 수 없으므로 질문 메일은 사양함. 꼭 연락이 필요할때는 로 E-mail을 주시기를.. Prolog ****** GNU 프로그램을 컴파일해 본 사람이라면, 그 과정이 아주 간단한 것을 알 수 있다. 그리고 어떤 GNU 프로그램일지라도 인스톨하는 방법은 똑같다. 어떤 GNU program을 설치하고 싶다면, 일단 source code를 가져와서 컴파일하고자 하는 디렉토리에 푼다. automake를 설치하려고 한다고 가정해 보자. ---------------------------------------- coolie:~# ls -l total 872 drwxr-xr-x 2 root root 1024 Jan 29 1996 Mail drwxr-xr-x 2 root root 1024 Jan 3 1996 News -rw-r--r-- 1 root root 183160 Sep 29 20:17 automake-1.0.tar.gz coolie:~# tar zxvf automake-1.0.tar.gz . . . coolie:~# ls -l total 187 drwxr-xr-x 2 root root 1024 Jan 29 1996 Mail drwxr-xr-x 2 root root 1024 Jan 3 1996 News drwxr-xr-x 3 root root 2048 Jun 8 00:26 automake-1.0 -rw-r--r-- 1 root root 183160 Sep 29 20:17 automake-1.0.tar.gz coolie:~# cd automake-1.0 coolie:~/automake-1.0# ---------------------------------------. 다음 세번의 셸 명령으로 해결된다. .--------------------------------------- coolie:~/automake-1.0# configure .. oolie:~/automake-1.0# make ... coolie:~/automake-1.0# make install ---------------------------------------- 이것만 기억하면 GNU 프로그램을 설치방법은 다 알았다고 할 수 있다. `configure', `make', 그리고 `make install'이다. 이 세개만 기억하면 된다. (그렇지 않은 경우도 있다. GCC같은 경우는 한번 컴파일한 후에 자기 자신을 다시 컴파일하는 복잡한 과정을 거친다.) 자, 어떻게 이렇게 간단하게 해결되는지 궁금하지 않는가? 여러개의 서브디렉토리가 있고, C 소스화일 수십개, 그외의 매크로, 데이타 등등 갖가지 화일이 섞여 있는 패키지에서 어떻게 이렇게 간단하게 인스톨이 가능할까? 물론 make라는 필수적인 도구가 있기 때문에 가능한 일이다. 하지만, make만으로 이렇게 만들어진 것은 아니다. 수십개의 화일들간에 의존성이 커지면 커질수록 Makefile은 더욱 더 복잡해져만 간다. 그때마다 하나하나 손으로 Makefile을 고친다는 건 악몽이 아닐 수 없다. 이 글에서는 어떻게 이렇게 할 수 있는지 소개해 보고자 한다. 여기에서 사용된 도구는 Autoconf와 Automake이다. 물론 이 패키지에는 해당되는 매뉴얼이 있다. 매뉴얼은 Emacs에서 C-h i, 또는 `info' 명령을 실행시켜서 볼 수 있다.(물론 그 해당 패키지를 설치했을 경우) 들어가기 전에 필요한 것 *********************** Linux 시스템을 갖고 있다면 당연히 gcc, make와 같은 필수적인 개발도구는 설치되어 있을 것이다. 하지만, 널리 쓰이는 Slackware에는 포함되어 있지 않은 개발자에게는 매우 중요한 패키지가 있다. autoconf와 automake가 그것이다. 이 2개 패키지가 설치되어 있지 않다면 당장 설치하자. autoconf의 경우에는 m4 패키지가 먼저 설치되어 있어야 하고, automake는 perl이 설치되어 있어야 한다. 이 2개 패키지는 m4와 perl로 쓰여진 매크로들의 집합이기 때문에 설치하는 데 오래 걸리지도 않는다. 어떻게 설치하느냐는 위에도 나와 있다. `configure', `make' 그리고 `make install'. 이제 이 두 패키지의 힘을 사용해 보기 바란다. automake 패키지에는 데이타가 저장되어 있는 디렉토리가 있다. 직접 컴파일해서 설치했다면, /usr/local/share/automake가 될 것이다. 이 디렉토리에는 그 프로그램이 사용하는 매크로 화일들도 들어 있지만, 몇개는 개발자의 편의를 위해 필요할때마다 자기가 만들게 되는 패키지에 복사해서 쓸 수 있는 유용한 것들이 많다. 밑에서 어떤 화일이 필요하다고 할 때마다 이 디렉토리에서 찾아보자. 휴식 -- 표준이란 **************** 이 글의 의도는 결국, `좀더 편하게 프로그램을 개발할 수 있도록' 하는 것이다. 여기에서 소개된 도구를 잘 활용하면 분명 편하게 작업을 할 수 있다. 하지만 얻는 것이 있는 만큼 잃는 것도 있다. 당신의 프로그래밍 스타일을 바꿔야 할 것이다. 이 글에서 제시하고자 하는 것은 단지 개발도구의 사용만이 아니다. GNU의 개발도구를 잘 활용하기 위해서는 GNU 프로그램들이 제시하는 표준을 따라야 한다. 이 글을 읽어내려가 보면서 건방지다는 생각도 들 것이다. 나는 내 나름대로 프로그래밍을 잘 하고 있다고 생각하는데 뭣하러 이래라 저래라 하는 건가하는 생각도 들 것이다. 자, 이런 생각은 버리자. 당신이 만들고 있는 프로그램이 그냥 몇줄 끄적거린 심심풀이가 아니라면, 정말 널리 쓰이는 프로그램을 만들고 싶다면, 며칠 매달리다가 집어던질 프로그램이 아니라 오랫동안 계속 수정하고, 발전시켜야 할 프로그램이라면 보편적인 표준을 따름으로서 많은 이익을 얻을 수 있을 것이다. 현재 접할 수 있는 공식적인, 최근의 GNU 표준 문서는 역시 `GNU Coding Standards'이다. 글 쓰는 현재 GNU Coding Standards는 96년 6월 10일에 update된 것으로 되어 있다. 여기 쓰여 있는 내용을 철저히 준수해야 하는 것은 물론이다. 단, 유용한 내용이긴 하지만, 읽지 않아도 되는 부분이 있다. 바로 `Makefile Conventions'라는 부분으로, 이 글에서 다루게 될 부분이 바로 그것이다. 왜냐하면 automake라는 최근에 만들어진 유용한 도구가 있기 때문이다. 여러분은 직접 Makefile이나 Makefile.in을 손으로 작성할 일은 없을 것이다. Automake 매뉴얼에 언급된 바에 의하면 이 부분은 곧 바뀌게 될 것이라고 한다. 곧 `GNITS'라는 새로운 표준이 세워질 것이라고 한다. 이 내용은 아직은 덜 완성되었기 때문에 알 수 없지만, 최근에 만들어진 automake가 큰 역할을 하게 될 것이 분명하다. 본론 **** 이해를 돕기 위해 한개의 패키지를 만드는 과정을 살펴보자. 작성하게 될 패키지는 `first'라는 패키지로 처음으로 만들게 된 패키지라는 뜻이다. 이 프로그램은 stdin을 읽어서, 역순으로 stdout으로 내보내는 프로그램이다. 재미는 있지만 쓸모는 없다. 간단하지만, 일부러 2개의 화일로 나누고, GNU 라이브러리를 써 볼려고 쉬운 길을 돌아서 구현한 부분도 있다. 여기 나와 있는 대로 패키지를 만들어 나가면 어렵지 않게 패키지를 만들 수 있다. first는 곧 자료실에 올려질 것이다. 이 패키지는 받지 않아도 상관없다. 이 과정을 차근차근 따라하면 조그만 패키지라도 직접 만들 수 있을 것이다. "hello, world"같은 간단한 프로그램이라도 만들어서 패키지를 만들어 보자. (실제로 GNU hello 패키지가 있지만, 이 패키지는 automake를 사용하지 않았다.) 먼저 할일은 무엇일까? 작업할 디렉토리를 만드는 것이다. ---------------------------------------- coolie:~$ mkdir first coolie:~$ cd first coolie:~/first$ ls coolie:~/first$ ---------------------------------------- 여러분이 만들게 될 패키지 이름으로 디렉토리를 만들면 된다. 앞으로 이 디렉토리 안에서 관련된 모든 작업을 하게 될 것이다. 자, 이제 하나씩 하나씩 패키지를 만들 계획을 세워보자. issue -- 디렉토리의 모양 (depth) ******************************** 이제 생각해 볼 문제가 있다. `~/first'라는 디렉토리를 만들었는데 그 밑에 서브 디렉토리를 만들 것인가? 아니면 그냥 이 디렉토리 하나에 화일들을 넣어둘 것인가? 다른 GNU 프로그램들은 어떻게 해결했는지 살펴보자. 다음은 fileutils 패키지이다. ---------------------------------------- coolie:~/fileutils-3.13$ ls -CF ABOUT-NLS Makefile.am acconfig.h doc/ mkinstalldirs* AUTHORS Makefile.in aclocal.m4 install-sh* po/ COPYING NEWS config.h.in intl/ src/ ChangeLog README configure* lib/ stamp-h.in INSTALL TODO configure.in man/ coolie:~/fileutils-3.13$ ---------------------------------------- 참 깨끗한 구조로 되어 있다. 맨 윗 디렉토리에는 README, COPYING, INSTALL같은 간단한 문서 화일과 이 패키지를 설치하기 위한 화일들만이 들어 있다. src디렉토리에는 C 소스코드가 들어 있고, lib디렉토리에는 LGPL로 배포되는 GNU 라이브러리들의 소스코드가 들어 있다. doc디렉토리에는 TeXinfo로 쓰여진 이 패키지의 매뉴얼이 들어 있다. intl과 po디렉토리는 다국어 메세지를 지원하기 위한 도구들과 번역된 메세지를 담고 있다. (머지 않아 우리말로 메세지가 나오는 프로그램들이 나오게 될 것이다. GNU 번역 프로젝트의 한국어 팀에 성원을 보내 주시기를..) fileutils과는 다른 구조로 되어 있는 패키지도 있다. 다음은 bison 패키지이다. ---------------------------------------- coolie:~/bison-1.25$ ls -CF COPYING bison.hairy configure* gram.h reader.c ChangeLog bison.info configure.bat install-sh* reduce.c INSTALL bison.info-1 configure.in lalr.c state.h LR0.c bison.info-2 conflicts.c lex.c symtab.c Makefile.in bison.info-3 derives.c lex.h symtab.h NEWS bison.info-4 files.c machine.h system.h README bison.info-5 files.h main.c texinfo.tex REFERENCES bison.rnh getargs.c mkinstalldirs* types.h alloca.c bison.simple getopt.c new.h version.c allocate.c bison.texinfo getopt.h nullable.c vmsgetargs.c bison.1 build.com getopt1.c output.c vmshlp.mar bison.cld closure.c gram.c print.c warshall.c ---------------------------------------- 아니 이게 웬 일인가? 소스코드, 문서, 라이브러리(alloca와 getopt는 LGPL로 배포되는 라이브러리이다.) 할 것없이 전부 한 디렉토리에 들어 있다. 또 다른 형태가 있다. 다음은 make이다. ---------------------------------------- coolie:~/make-3.75$ ls -CF COPYING build.sh.in* getopt.c make.info-4 remote-cstms.c ChangeLog build_w32.bat* getopt.h make.info-5 remote-stub.c INSTALL commands.c getopt1.c make.info-6 rule.c Makefile.ami commands.h glob/ make.info-7 rule.h Makefile.in config.ami implicit.c make.info-8 signame.c NEWS config.h-vms install-sh* make.ky signame.h* NMakefile config.h.WIN32 job.c make.lnk subproc.bat* README config.h.in job.h make.man tags README.Amiga configh.dos main.c make.pg texinfo.tex README.WIN32* configure* make-stds.texi make.texinfo variable.c SCOPTIONS configure.bat make.aux make.toc variable.h SMakefile configure.in make.cp make.tp version.c TAGS default.c make.cps make.vr vmsdir.h acconfig.h dep.h make.fn makefile.com vmsfunctions.c aclocal.m4 dir.c make.fns makefile.vms vmsify.c alloca.c expand.c make.h misc.c vpath.c amiga.c file.c make.info mkinstalldirs* w32/ amiga.h filedef.h make.info-1 read.c ar.c function.c make.info-2 readme.vms arscan.c getloadavg.c make.info-3 reake.c ---------------------------------------- 앞에서와 마찬가지로 모든 화일이 한 디렉토리에 들어 있다. 소스코드, 라이브러리, 문서 모두 여기 들어 있다. 그런데 몇개의 디렉토리가 있다. glob와 w32라는 디렉토리가 있다. 특정 목적을 위한 코드를 위해 디렉토리를 새로 만들어서 그 안에 넣어 놓았다. 이러한 패키지의 디렉토리 모양을 그 패키지의 `depth'라고 한다. 첫번째 경우 fileutils와 같이 모든 소스 화일(문서를 포함해서)들이 서브 디렉토리에 들어가 있는 경우를 *deep package*라고 한다. 두번째 경우 bison과 같이 모든 화일이 하나의 디렉토리에 들어가 있는 경우 이것을 *flat package*라고 한다. 그리고 마지막으로 make와 같이 대부분이 한 디렉토리에 들어 있고, 일부의 화일이 서브 디렉토리에 들어가 있는 경우를 *shallow package*라고 한다. 선택은 그 패키지를 만드는 사람에게 달려 있다. 소스화일이 몇개밖에 되지 않는 작은 패키지의 경우에는 flat도 괜찮을 것이다. 그리고, 거기에서 특별히 소스화일이 아닌 라이브러리 같은걸 서브디렉토리에 넣는 shallow 형태가 될 수도 있다. 개인적으로는 deep을 선호한다. 너무 화일이 많아지면 어지럽기 짝이 없다. 또 각 디렉토리별로 그 작업에만 전념할 수 있어서 좋다. first 패키지도 deep으로 만들어졌다. (사실 deep이 할 일이 많다.) 요약 -- 패키지의 depth ====================== . deep -- 모든 소스, 문서 화일들이 서브 디렉토리에 들어가 있는 형태 . flat -- 모든 화일들이 한개의 디렉토리에 들어가 있는 형태 . shallow -- flat에서 특정 부분만 서브 디렉토리에 들어가 있는 형태 필요한 화일들 -- 문서 화일들 ****************************************************** 패키지를 만들때 가장 중요한 작업은 역시 소스코드를 작성하는 일이다. 그리고 이 패키지의 매뉴얼을 작성하는 것도 중요한 일이다. 우리가 이런 작업에 시간을 쏟고 있는 것은 관리에 신경을 덜 쓰고 중요한 작업에 좀더 매달릴 수 있도록 하기 위해서다. 대표적인 GNU 프로그램들을 살펴보면, 언제나 발견되는 화일들이 몇개 있다. 맨 위의 디렉토리를 살펴보자. 언제나 `README', `COPYING', `INSTALL', `NEWS' 따위의 화일들이 있는 것을 알 수 있다. 이 화일이 있고 없고는 중요한 것이 아니다. 하지만, 제목대로 `구색을 갖추기' 위해서 이 화일들이 필요하다. 먼저, 상위 디렉토리에 다음의 문서 화일이 필요하다. 공통점은 ChangeLog만 빼고 모두 대문자로만 이름이 구성되었다는 점이다. README COPYING INSTALL AUTHORS NEWS ChangeLog TODO README는 당연히 패키지 작성자가 작성해야 할 것이다. 이 프로그램에 대한 간단한 설명이 들어 있다. 자세한 사용법은 담지 않는다. 대부분의 GNU 프로그램의 경우는 이 화일에 `설치하는 방법은 INSTALL화일을 봐라.' `사용법은 first.texi에 문서화되어 있다.' 라는 식으로 다른 화일들을 가리키는 글을 담고 있다. INSTALL도 패키지 작성자가 작성해야 할 것이나, 대부분의 GNU 프로그램들이 동일한 방법(configure, make, make install)으로 설치되기 때문에 그냥 `generic install instruction'을 가져다 쓴다. 이 문서는 automake 디렉토리에서 찾아볼 수 있다. COPYING은 GNU 프로그램이라면, General Public License를 복사해서 쓰면 될 것이다. 이 화일 역시 automake 디렉토리에 있다. AUTHORS에는 이 패키지의 작성자를 쓴다. 자기 이름 석자를 써 넣자. 영어로 써야 한다. 이 화일은 자기 이름 자랑하려고 있는 게 아니다. 누가 어떤 작업을 했는가를 분명히 해서, 어떤 버그가 있는지를 알기 쉽도록 하기 위함이다. 훗날 이 패키지를 이어받는 사람이 있다면 그 사람의 이름이 당신의 이름 뒤에 쓰여질 것이다. NEWS는 이 패키지가 이전 패키지를 업그레이드한게 아니라면 필요없다. 이전 버전과 달라진 점을 써 넣는 화일이다. ChangeLog는 코드를 써 내려가면서 작성하는 것이기 때문에 이것도 필요없다. 하지만, 이 화일들이 없으면 automake에서 경고 메세지가 나오므로, `touch NEWS ChangeLog' 명령으로 이 화일들을 만들어 두자. TODO는 사실 필요없다. automake도 경고를 내지 않는다. 하지만, 개인적으로 이 화일은 아주 중요한 화일이라고 생각한다. 그때 그때 이 패키지의 발전방향을 적어 놓으면, 그 기능들을 하나하나 포함시켜 나가면서 프로그램을 발전시키는 것이다. 필요한 화일들(2) -- 여러가지 도구들 ***************************************** 이제 구색을 갖추기 위한 게 아닌 진짜 필요한 화일들을 작업 디렉토리에 복사해야 한다. 맨 위 디렉토리에 다음 스크립트가 필요하다. install-sh mkinstalldirs 이 스크립트의 기능을 몰라도 패키지를 만드는 데는 지장이 없다. install-sh은 install 명령과 같은 기능을 갖고 있다. 화일을 설치할 디렉토리로 복사할때 프로그램의 소유권을 결정한다든지 디버깅 정보를 strip한다든지 하는 기능을 갖고 있다. 물론 install이 설치되어 있는 Linux 시스템에서 설치할때는 이 화일은 필요가 없다. 하지만, 이 프로그램이 없는 시스템을 위해서 이 화일을 복사해둔다. mkinstalldirs는 mkdirhier와 같은 기능을 갖고 있다. 화일을 설치하기 전에 설치할 디렉토리를 만드는데 쓰인다. 이 역시 mkdirhier 명령이 없는 시스템을 위해서 복사해 둔다. 만약, 만드려고 하는 패키지가 deep이라면 doc디렉토리에, flat이나 shallow라면 맨 위 디렉토리에 필요한 매뉴얼을 위한 화일이 있다. texinfo.tex mdate-sh GNU의 문서는 texinfo로 작성된다. texinfo 패키지가 설치된 시스템도 있지만, 그렇지 않은 시스템도 있다. 컴파일되어 있는 dvi나, ps를 포함할 수도 있겠으나, 그건 낭비라고 생각했는지, TeX만 설치되어 있으면 hardcopy를 찍어낼 수 있도록 texinfo.tex을 포함하도록 `GNU Coding Standards'에서 정하고 있다. 문서화일이 있는 곳에 이 화일을 반드시 포함하자. 그렇지 않으면 역시 automake가 경고를 낼 것이다. `mdate-sh'라는 셸 스크립트는 그냥 날짜를 프린트해 주는 스크립트이다. 문서에 최종 변경일을 기록하는 데 사용한다. 이 스크립트를 실행해 보면 다음과 같이 날짜가 나오게 될 것이다. ---------------------------------------- coolie:~/first/doc$ mdate-sh 31 August 1996 coolie:~/first/doc$ ------------------------------------- 이 스크립트는 최종 변경일을 문서내에 기록하기 위해 사용된다. 뒤에 패키지의 버전을 어떻게 결정할 것인가의 문제에서 다시 언급된다. 그리고 소스코드가 들어 있는 디렉토리에 선택에 따라 포함할 수도 있고, 하지 않을 수도 있는 화일이 있다. ansi2knr.c ansi2knr.1 ansi2knr라는 프로그램의 소스코드와 그것의 man page 화일이다. `GNU Coding Standards'에서는 ANSI C style의 함수의 인수 표시 방식을 쓰지 말 것을 권하고 있다. 왜냐하면 아직도 ANSI C가 설치되어 있지 않은 시스템이 있기 때문이다. 다음 (1)과 같이 쓰면 안 되고 (2)와 같이 써야 한다. (1)------------------------------------- main (int argc, char **argv, char **env) { ... ---------------------------------------- (2)------------------------------------- main (argc, argv, env) int argc; char **argv, **env; { ... ---------------------------------------- 하지만, 요즘 대부분의 프로그래머는 (1)의 ANSI C방식을 사용하길 좋아하고 당연히 이렇게 써야 하는 것으로 생각한다. ANSI C를 사용하는 방법은 있다. 그것은 ansi2knr이라는 프로그램을 패키지에 포함시키는 것이다. 이 프로그램은 (1)과 같은 방식으로 되어 있는 C 소스코드를 (2)와 같이 고쳐준다. 나중에 이 옵션에 관한 언급이 있을 것이다. ANSI C를 쓰려면, automake 디렉토리에 있는 ansi2knr.c와 ansi2knr.1을 ANSI C 코드가 들어 있는 디렉토리에 복사한다. 어떤 디렉토리든지, ANSI C 코드가 들어 있는 경우는 이 2개의 화일이 꼭 필요하다. 마지막으로 또 하나의 화일을 맨 상위 디렉토리에 복사하자. aclocal.m4 이 화일은 앞으로 사용하게 될 automake에서 필요로 하는 매크로에 대한 정의를 담고 있어서 꼭 필요하다. 없으면 warning 정도가 아니라 아예 작동되지 않을 것이다. 『리눅스 학당-리눅스 강좌 / 연재 (go LINUX)』 334번 제 목:GNUtic -- Autoconf/Automake <2> 올린이:onestep (류창균 ) 96/10/05 05:26 읽음:1512 관련자료 없음 ----------------------------------------------------------------------------- 화일작성 ******** 드디어 화일을 손수 작성해야 할 때가 왔다. 우리가 만들고자 하는 패키지가 어떻게 관리되는지 설명한 후에 직접 작성해 보도록 하자. 다음은 autoconf 매뉴얼에서 가져와서 약간 고친 것이다. 다음은 우리가 패키지를 가져와서 컴파일하기까지의 과정을 나타낸 것이다. 화일이름 뒤에 *가 붙은 것은 그 프로그램을 실행한다는 뜻이고, []안에 들어 있는 화일은 없을 수도 있다는 뜻이다. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .-------------> config.cache configure* ------------+-------------> config.log | [config.h.in] -. v .-> [config.h] -. +--> config.status* -+ +--> make* Makefile.in ---' `-> Makefile ---' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ configure 스크립트를 실행하여 config.cache에 스크립트 실행시에 알게 된 정보를 담는다. 다시 configure를 실행할때 이 화일에 들어있는 정보를 사용해서 보다 빨리 수행할 수 있게 한다. config.log는 메세지를 기록하는 화일이다. config.h.in은 config.h에 무엇을 넣을 것인가에 대한 정보가 들어 있다. 실제로 들어다 보면, #undef 문으로 가득하다. 생성되는 config.h에는 그 해당 definition이 #define으로 바뀌어 나타난다. Makefile.in은 Makefile과 다를 것이 없다. 단지 `@어쩌구@'로 되어 있는 부분이 있다. configure 스크립트를 수행하고 나면, 이 부분이 다른 것으로 치환된다. configure를 실행시키면, 일단, 시스템의 정보를 알아낸 다음 config.status라는 또 다른 스크립트를 만든다. 이 스크립트를 실행시켰을때 미리 저장된 시스템 정보에 따라 config.h나 Makefile을 생성하게 된다. config.status는 다시 configure를 실행시키지 않고, Makefile이나 config.h를 만들어낼때 쓰인다. 그러면 만들어야 할 것이 configure스크립트와 config.h.in, Makefile.in이 될 것이다. configure와 config.h.in은 autoconf가 자동으로 만들어 준다. 다음을 보자. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ your source files --> [autoscan*] --> [configure.scan] --> configure.in configure.in --. .------> autoconf* -----> configure +---+ [aclocal.m4] --+ `---. [acsite.m4] ---' | +--> [autoheader*] -> [config.h.in] [acconfig.h] ----. | +-----' [config.h.top] --+ [config.h.bot] --' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ configure는 autoconf에 의해서, config.h.in은 autoheader(autoconf 패키지의 일부)에 의해 만들어지게 된다. config.h.in은 완전히 자동으로 만들어지고, configure.in은 autoheader를 돌린 후에 생성된 configure.scan을 약간 수정해야 한다. 문제는 Makefile.in인데 이것은 automake로 해결된다. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Makefile.am ---. +--> Makefile.in configure.in --' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 우리가 진짜 신경써서 작성해야 할 화일은 Makefile.am뿐이다. 이 화일을 작성하는 것은 아주 쉽다. 복잡해 보이는 위의 과정을 단순화하기 위해 만들어 낸 것인 만큼 정해진 규칙을 잘 따른다면, 아주 쉽게 패키지를 관리할 수 있다. Makefile.am의 작성 ****************** 먼저, 독자가 Makefile의 구조를 알고 있다고 가정한다. Makefile.am도 Makefile의 형식인데 변수이름을 정해진 이름을 사용함으로써 아주 간결하게 작성된다. Makefile.am은 디렉토리가 여러개인 경우, 그러니까 deep이나 shallow 형태일 경우에 각 디렉토리마다 한개씩 필요하다. 일단, 그 디렉토리에 서브 디렉토리가 있을 경우 다음과 같이 SUBDIRS 변수에 그 서브디렉토리의 이름을 서줘야 한다. 다음은 first 패키지의 맨 위 디렉토리의 Makefile.am이다. ---------------------------------------- SUBDIRS = lib src doc ---------------------------------------- deep 패키지의 경우 맨 위 디렉토리에서는 이것 하나로 모든게 해결된다. 실제 그 디렉토리에는 소스 화일이 없기 때문에 서브 디렉토리에서 할 일만 해 주면 되는 것이다. 단, 이 순서에 유의할 필요가 있다. 보통 라이브러리 디렉토리에 있는 화일들은 컴파일된 후에 ar 명령을 통해서 한개의 .a 화일로 만들어진다. 그 다음에 진짜 소스코드와 링크된다. 라이브러리가 언제나 소스코드보다 먼저 만들어져야 한다. 반드시 lib를 먼저 써 주고, src를 그 다음에 써 준다. 그리고 각 디렉토리마다 Makefile.am을 작성해야 한다. 자, 하나하나 살펴보자. 다음은 first의 src/Makefile.am이다. ---------------------------------------- AUTOMAKE_OPTIONS = ansi2knr bin_PROGRAMS = first first_SOURCES = first.c fileblock.c noinst_HEADERS = fileblock.h EXTRA_DIST = ansi2knr.c ansi2knr.1 LDADD = ../lib/libfirst.a $(bin_PROGRAMS): ../lib/libfirst.a ---------------------------------------- AUTOMAKE_OPTIONS 변수에는 이름 그대로 옵션을 써준다. 이 소스는 ANSI C로 되어 있으므로, ansi2knr옵션과 함께 ansi2knr의 소스 화일이 들어 있어야 한다. EXTRA_DIST에 써주지 않으면 이 화일들은 포함되지 않는다는 것에 유의하자. extra distribution을 뜻한다. bin_PROGRAMS 변수에는 최종적으로 링크될 실행화일의 이름을 적는다. 여러개일 경우는 여러개를 하나씩 적는다. 그리고 `first_SOURCES' first라는 실행화일을 컴파일하는데 필요한 소스화일들이다. (헤더 화일은 적지 않는다.) noinst_HEADERS, noinst는 install하지 않는다는 뜻이다. 그러니까 이 화일을 한번 컴파일한 후에는 필요없어진다는 뜻이다. 헤더 화일은 물론 그렇다. noinst_HEADERS에 그 디렉토리의 모든 헤더 화일을 다 써준다. make를 쓸 줄 아는 독자라면 한가지 의문이 생겼을 것이다. 헤더 화일 사이의 의존성(dependency)문제는 어떻게 해결되는 것일까? 예를 들어서 first에는 first.c에 `#include "fileblock.h"' 라는 부분이 있어서 fileblock.h가 변경되었을 경우 first.c는 다시 컴파일되어야 한다. automake는 실행될때 자동으로 해당 소스코드를 검색해서 #include 되어 있는 부분을 찾아내서 의존성을 써 준다. 이제 더 이상 헤더와 소스코드 사이의 의존성 문제에 신경슬 필요가 없다. 그러면 또 다시 의문이 생긴다. 그러면 도대체 noinst_HEADERS에 왜 써주는 것일까? 일단, 여기 쓰여 있지 않은 경우 automake는 의존성을 추가하지 않을 것이다. 그리고 나중에 우리가 직접 해 보겠지만, Makefile.am 안에서 언급되지 않은 화일들은 최종적인 소스 배포본에 포함되지 않는다. 우리는 first-0.1.tar.gz 과 같은 배포본을 만들기 위해 직접 tar와 gzip을 사용하지 않는다. `make dist'로 꼭 필요한 화일만 압축해서 배포본을 만든다. EXTRA_DIST에 ansi2knr을 써 주는 이유도 같다. 여기 쓰지 않으면 나중에 포함되지 않는다. 하지만, AUTOMAKE_OPTIONS에 ansi2knr을 써 주고 다시 서 줘야 한다는 건 문제가 있다고 생각한다. 다음 버전에서 개선되리라고 믿는다. 그 뒷부분은 deep이나 shallow 패키지 같은 경우에 필요한 것이다. 이 패키지에서 만들어진 라이브러리를 사용하기 위해서는 반드시 LDADD에 써줘야 한다. 그래야만 프로그램을 만들때 그 라이브러리가 링크가 된다. 그러면 실행화일이 여러개 있을때 a라는 프로그램에는 liba.a라는 라이브러리를 링크하고, b라는 프로그램에는 libb.a 라는 라이브러리를 링크해야 할 상황이라면 어떻게 할까? 눈치가 빠르다면, 이미 automake의 변수명명법을 알아챘을 것이다. 각각 ---------------------------------------- a_LDADD = ../lib/liba.a b_LDADD = ../lib/libb.a ---------------------------------------- 라고 써 주면 된다. 프로그램의 이름이 앞에 오고, 그 다음에 밑줄, 그 다음에는 그 프로그램에 해당되는 변수명을 쓰면 된다. 그러면 이 패키지에서 만들어진 라이브러리가 아닌, 시스템에 설치된 라이브러리를 링크할때는 어떻게 할 수 있을까? 그 때는 LDADD변수에 해당 라이브러리 옵션을 쓴다. c라는 프로그램에 -lX11 옵션을 붙여서 링크하고 싶다면, ---------------------------------------- c_LDADD = -lX11 ---------------------------------------- 이라고 써주면 된다. 위의 first의 예제에서 화일 의존성 설정이 하나 눈에 뜨인다. $(bin_PROGRAMS)보다 ../lib/libfirst.a가 먼저 만들어져야 한다는 것이다. 제대로 컴파일이 된다면, libfirst.a가 나중에 만들어질 일은 없다. 하지만, 예를 들어서 configure 스크립트를 실행한 다음에 lib 디렉토리 내의 라이브러리가 만들어지지 않은 상태에서 src 디렉토리에 직접 들어가서 make를 실행시키면 어떻게 되겠는가? 이 의존성 설정이 없다면, make는 ../lib/libfirst.a를 링크하려고 시도할 것이고, 링커로부터 `no such a file' 이라는 메세지가 나오게 될 것이다. 하지만, 이 의존성 설정때문에 make는 ../lib/libfirst.a가 없다는 것을 알고, make 프로그램상에서 `no such a rule..' 어쩌구 하는 메세지가 나올 것이다. 앞의 경우처럼 링커에서 애러가 나는 것보다 make에서 애러를 내보내는 편이 낫지 않은가? 별 차이 없다고 생각하면, 굳이 없어도 되는 부분이다. 이제 라이브러리가 들어 있는 디렉토리를 보자. 다음은 lib/Makefile.am이다. ---------------------------------------- noinst_LIBRARIES = first first_SOURCES = error.c getopt.c getopt1.c xmalloc.c noinst_HEADERS = getopt.h ---------------------------------------- noinst_LIBRARIES, 역시 컴파일시에만 사용되고, 설치되지는 않으므로 noinst 접두어가 붙는다. first라고 이름을 붙이면 만들어지는 라이브러리의 이름은 libfirst.a가 된다. first_SOURCES는 마찬가지로 생각하면 된다. first라는 라이브러리를 만들기 위해 사용되는 소스코드이다. 역시 라이브러리에 사용되는 헤더화일도 noinst_HEADERS에 써줘야 한다. 이 디렉토리에 있는 소스코드는 모두 K&R style로 코딩되었기 대문에 ansi2knr 옵션을 붙여줄 필요가 없다는 것에 주목하자. 자, 이제 성격이 좀 다른 doc/Makefile.am을 보자. ---------------------------------------- info_TEXINFOS = first.texi first_TEXINFOS = gpl.texi EXTRA_DIST = texinfo.tex ---------------------------------------- GNU의 문서는 TeXinfo로 만들어진다. ???.texi 화일은 makeinfo 프로그램을 통해서 ???.info라는 온라인 매뉴얼로 만들어지고, TeX을 통해서 ???.dvi라는 책으로 펴낼 수 있는 hardcopy가 만들어진다. GNU Coding Standards에는 ???.texi의 소스와 ???.info 화일만 배포본에 포함하도록 하고 있다. 그러니까 따로 지정하지 않는한 문서화일의 최종 출력물은 ???.info 화일이다. info_TEXINFOS에 해당 소스화일을 써 준다. 여러개일 경우 여러개를 써 준다. 각각의 화일은 각각 makeinfo를 통해서 각각의 ???.info 화일로 만들어질 것이다. 그렇지 않고, 한 화일에서 texinfo의 @include 명령으로 다른 texinfo 화일을 포함하고 있을 경우 first_TEXINFOS와 같이 써줘야 한다. first의 경우에는 GPL을 담고 있는 화일을 포함하는 부분이 있다. EXTRA_DIST 에 texinfo.tex을 써 주었다. 이것은 automake의 버그가 아닌가 생각된다. 반드시 포함해야 하는 이 화일을 이렇게라도 써 주지 않으면 최종 배포본에 포함되지 않는다. textutils의 doc/Makefile.am에도 ---------------------------------------- # FIXME: remove this when automake has been fixed to include this # file automatically EXTRA_DIST = texinfo.tex ---------------------------------------- 과 같이 쓰여져 있다. 앞으로 고쳐질 것이라고 생각한다. configure.in 작성하기 ********************* 자, 이제 configure.in을 쓰는 일이 남았다.. 이건 그리 간단치 않으니 좀 생각해 보고 작성해 보자. configure.in은 위의 Makefile.am과는 달리 프로그램 소스코드를 어떻게 작성하느냐에 따라서 써야 할 내용이 달라진다. 즉, 얼마나 코드가 호환성 있게 쓰여졌느냐, 아니냐에 따라서 configure.in에 써야 할 내용이 적어지느냐, 많아지느냐가 달려있다. 경험이 부족한 사람은 자기 코드가 얼마나 호환성이 좋고, 나쁜지 모르기 때문에 configure.in을 직접 작성할 수 없다. 하지만, 코드를 어떻게 작성했느냐의 문제는 자동으로 해결된다. 앞의 그림에도 보이듯이, `autoscan'을 실행하면, 자동으로 서브디렉토리를 뒤지면서 필요한 프로그램, 필요한 config switch를 검사하는 내용을 configure.scan에 써 준다. 하지만, autoscan은 완벽한 게 아니다. autoscan은 그냥 scan하는 순서대로 내용을 기입한다. 순서가 문제가 될 수도 있고, 더 필요한 내용이 있을 수도 있다.(하지만, 버릴 내용은 없다.) autoscan을 맨 위의 디렉토리에서 실행시키면 자동으로 서브디렉토리를 검색하면서 필요한 것들을 점검해 준다. 그래서 configure.scan이 만들어진다. 그렇게 만들어진 configure.scan을 configure.in으로 복사하고 그것을 편집한다. ---------------------------------------- dnl Process this file with autoconf to produce a configure script. AC_INIT(src/first.c) AC_PREREQ(2.10) --------------------------------------.. dnl 은 그 위치에서부터 newline까지를 comment로 처리한다. configure.scan에 위와 같은 메세지가 맨 첫 줄에 적혀 있을 것이다. 아마 configure.scan에는 AC_INIT안에 다른 화일 이름이 적혀 있을 것이다. AC_INIT에서 괄호 안의 화일이 있어야만 autoconf가 동작한다. 이건 단지, 패키지를 알아보기 위한 수단일뿐 그 이상은 아니다. 보통 main()함수가 들어 있는 C 소스 화일을 써 준다. AC_PREREQ의 괄호 안에는 필요로 하는 autoconf의 버전을 써 준다. 만약 이보다 버전이 낮을 경우 autoconf는 작동하지 않게 될 것이다. autoconf는 Unix의 표준 프로그램이 아니기 때문에 최신 버전을 써 주더라도 별 문제가 없다. ..-------------------------------------- AC_CONFIG_HEADER(config.h) --------------------------------------.. config switch가 필요한 경우(대부분의 경우 필요하다) 반드시 있어야 한다. ...------------------------------------------- AC_ARG_PROGRAM -------------------------------------------... 설치할때, 프로그램의 이름을 바꿀 수 있도록 한다. GNU make를 gmake라는 실행화일명으로 설치한다던가 하는 것을 configure옵션에서 결정할 수 있다. automake는 이걸 반드시 필요로 한다. ..-------------------------------------- PACKAGE=first VERSION=0.1 PACKAGE_VERSION="$PACKAGE-$VERSION" AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") AC_DEFINE_UNQUOTED(VERSION, "$VERSION") AC_DEFINE_UNQUOTED(PACKAGE_VERSION, "$PACKAGE_VERSION") AC_SUBST(PACKAGE) AC_SUBST(VERSION) AC_SUBST(PACKAGE_VERSION) --------------------------------------.. PACKAGE는 이 패키지의 이름이고, VERSION은 버전 번호이다. PACKAGE_VERSION은 패키지명과 버전을 함께 말할때 쓰는 말을 쓴다. $PACKAGE라고 쓰면, 위에서 정의한 PACKAGE변수를 슬 수 있다. $VERSION도 마찬가지이다. 이 변수를 따로 둠으로써 좋은 점도 있다. 예를 들어서 textutils의 경우 PACKAGE는 textutils, VERSION은 1.19, PACKAGE_VERSION은 "GNU $PACKAGE-$VERSION"으로 되어 있다. GNU라는 말을 앞에 붙일 수 있다. AC_DEFINE_UNQUOTED는 config.h에 ---------------------------------------- #define PACKAGE "first" #define VERSION "0.1" #define PACKAGE_VERSION "first-0.1" ---------------------------------------- 이라고 정의하도록 한다. AC_DEFINE_UNQUOTED(a, b)는 config.h에서 (혹은 AC_CONFIG_HEADER에서 정의한 어떤 화일이든 a를 b로 #define하게 한다. UNQUOTED가 없는 AC_DEFINE이라는 명령도 있는데 UNQUOTED를 붙여줌으로써 내부에 $로 시작되는 변수명이라든지, ``로 묶여진 셸 명령, escape문자 \(backslash)를 쓸 수 있다. AC_SUBST는 AC_DEFINE_UNQUOTED와 비슷한 일을 한다. 이 매크로는 Makefile.in의 내용을 바꾼다. 앞에서 언급했듯이 Makefile.in이 Makefile과 다른 점은 @어쩌구@와 같은 부분이 있다는 것이다. 위의 예에서는 각각 @PACKAGE@, @VERSION@, @PACKAGE_VERSION@이라고 되어 있는 부분을 해당 변수값으로 치환한다. ..-------------------------------------- dnl Checks for programs. AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_RANLIB AC_PROG_MAKE_SET ---------------------------------------.. AC_PROG_...는 특정 프로그램이 이 시스템에 존재하는지 검사하는 매크로이다. 예를 들어 AC_PROG_CC는 일단 gcc가 있는지 검사하고, 있으면 그걸 사용하고, 없으면 cc를 사용한다. configure.scan에서는 맨 위의 4가지밖에 없을 것이다. AC_PROG_MAKE_SET은 그 패키지에 서브디렉토리가 있을때, 즉 deep이나 shallow의 경우에 반드시 필요하다. 이 경우 recursive하게 make를 call해야 하는데, 그때 Makefile의 `MAKE'변수가 정의되지 않은 구버전의 make를 위해 존재한다. ..-------------------------------------- dnl This test must precede tests of compiler characteristics like dnl that for the inline keyword, since it may change the degree to dnl which the compiler supports such features. fp_C_PROTOTYPES --------------------------------------.. ANSI C를 사용하려면 이게 반드시 필요하다. 왜냐하면, 일단 configure 스크립트를 통해서 이 C 컴파일러가 ANSI C를 지원하는지 알아보고, ansi2knr을 사용할 것인지, 아닐지를 결정해야 하기 때문이다. 이 매크로는 이 컴파일러가 ANSI C의 prototype을 지원하는지 알아본다. 이 매크로는 fp_로 시작되는데 이것은 이 매크로를 만든 사람의 이름을 딴 것이다. autoconf에서 기본적으로 제공하는 매크로는 AC_가 붙는다. 이 매크로는 아까 복사한 aclocal.m4에 들어있는 매크로이다. 중간에 더 있어야 할 것이 있다면, 그것은 모두 autoscan에 의해서 자동으로 파악될 수 있는 것들이다. 라이브러리, 헤더 화일, 함수와 같은 테스트가 중간에 들어가게 될 것이다. 사실 이 부분이 호환성 보장을 위해서 중요한 부분이다. 중간생략... ...--------------------------------------------- AC_OUTPUT(Makefile src/Makefile lib/Makefile doc/Makefile) ------------------------------------------------ 자, 이제 끝이다. 패키지 안에서 만들어야 될 Makefile을 모두 써 주자. 그외에 작성할 것들 ****************** 자, 또 필요한 화일이 2개가 있다. 왜 이리 필요한 게 많은지... config.h.in이 필요하다. 하지만, 앞에서 봤듯이 이건 손으로 만들 필요가 없다. 그냥 간단히 `autoheader'를 실행하자. 잠시후에 config.h.in이 생겼을 것이다. 또 하나 수고를 해 줘야 할 화일이 acconfig.h이다. ------------------------------------------------ /* Define to the name of the distribution. */ #undef PACKAGE /* The concatenation of the strings PACKAGE, "-", and VERSION. */ #undef PACKAGE_VERSION /* Define to the version of the distribution. */ #undef VERSION /* Define to 1 if ANSI function prototypes are usable. */ #undef PROTOTYPES ------------------------------------------------ config.h.in과 acconfig.h는 그 기능이 똑같다. #undef <매크로>라고 써 주면, 나중에 configure스크립트가 알아서 #define <매크로> <어쩌구>라고 바꾸어 준다. 단지 config.h.in은 자동으로 만드는 것이니까 에디트하지 말고, acconfig.h만을 에디트한다. PACKAGE, PACKAGE_VERSION, VERSION, 그리고 PROTOTYPES라는 매크로를 정의해 준다. 위의 configure.in에서 이 부분을 해당 패키지 이름과 버전으로 대체하는 AC_DEFINE_UNQUOTED라는 부분이 있다. 그 매크로에 의해서 위에 쓰여진 #undef 부분은 #define문으로 바뀌어 config.h에 쓰여진다. VERSION은 "0.1"로, PACKAGE는 "first"로 정의될 것이다. 그리고 맨 마지막의 PROTOTYPES는 fp_C_PROTOTYPES 매크로에서 필요로 하는 것으로, ANSI 방식의 함수 prototype이 가능할 경우 1로 정의된다. 마지막으로 또 한개 화일을 작성해야 한다. stamp-h.in이다. .in이 붙은 것으로 짐작하겠지만, 이 화일에 의해 stamp-h가 만들어진다. 이 화일은 config.h가 언제 만들어졌느냐를 기록하는 수단일 뿐이다. 이 화일에 timestamp라는 9자를 써 넣는다. ---------------------------------------- echo "timestamp" >stamp-h.in ---------------------------------------- 이 화일의 변경날짜가 곧 config.h가 만들어진 시각이다. 『리눅스 학당-리눅스 강좌 / 연재 (go LINUX)』 335번 제 목:GNUtic -- Autoconf/Automake <3> 올린이:onestep (류창균 ) 96/10/05 05:27 읽음:1501 관련자료 없음 ----------------------------------------------------------------------------- 결과 맛보기 *********** 이제 automake를 실행해 보자. 제대로 위 과정을 거쳤다면 무난히 Makefile.in을 만들어낼 것이다. 그런데 본인의 시스템에서 automake를 locale 관련 경고 메세지가 나왔다. 다른 패키지의 경우에도 경고를 내는 것을 보면 automake의 문제는 아니고 이 시스템의 문제인 것 같았다. 데비안을 쓰고 있는데 슬랙웨어나 다른 배포본을 사용하고 계신 분은 어떤지 모르겠다. 앗, 그러고 보니, 이미 automake를 실행했다. 그러면 autoconf를 실행하자. 무슨 화일이 없다는 메세지가 나오면, configure.in에서 AC_INIT으로 설정한 화일이 없기 때문이다. 어떤 방법으로든 그 화일을 만들어 놓자. 그러면 문제 없이 autoconf가 끝날 것이다. 그러면.. 드디어 configure 스크립트를 만들어 내었다. configure를 실행해 보자. 여러가지 프로그램들을 검사하고, 곧, 각 서브디렉토리마다 Makefile을 만들어 낼 것이다. 그리고 `make'를 실행하면, 컴파일이 될 것이다. 그러나, 물론 그 전에 프로그램을 만들어야 한다. 이제 할일은 끝났다. C 프로그램을 직접 작성할 차례이다. first의 경우에는 first.c, fileblock.c 그리고 fileblock.h를 작성했다. 프로그램을 만들면 automake를 다시 실행하는 것이 좋다. 왜냐하면 first.c에서 fileblock.h를 #include 하는 부분이 존재하는데 automake가 이것을 알아채고 의존성을 Makefile.in에 추가하도록 해야 하기 때문이다. 실제로 만들어진 Makefile.in을 보면 의존성이 없는 것을 보고 의문을 가질지도 모르겠다. 직접 automake를 실행했을 때는 Makefile.in 내에 만들지 않는다. 왜냐하면, 개발중이기 때문에 의존성이 계속해서 것이기 때문이다. 대신에 src 디렉토리에 보면 .deps라는 디렉토리가 있고, 그 안에 정보가 있는 것을 알 수 있다. Makefile.in에 정보가 들어가도록 하려면 --include-deps 옵션을 붙인다. `make dist'로 소스 배포본을 만들때는 이 옵션을 붙여서 다시 automake가 실행된다. 최종적인 배포본에는 Makefile.in에 이 정보가 포함된다. `make dist'를 해 보자. 그러면 한참 후에 맨 상위 디렉토리에 first-0.1.tar.gz이라는 화일이 생길 것이다. 즉, 이 디렉토리에서 한참동안 작업한 후에 `make clean'하고 압축할 필요없이 바로 release할 수 있는 패키지를 만들어 낼 수 있는 것이다. 이것으로 일련의 과정은 끝났다. 쉬어가기 -- 편해지고 싶은 인간의 마음 ************************************* 처음에 GNU 프로그램들은 이런 편리한 설치도구가 없었다. 그냥 Makefile만 달랑 있었고, 다른 환경에 포팅하기 위해서 Makefile을 직접 에디트해야 했다. 그 대부분은 컴파일시에 -D 스위치를(define) 맞춰주는 것이었다. 따라서 컴파일할때 보면 엄청나게 많은 -D 스위치가 붙어 있었다. autoconf를 만든 사람은 그 당시에 fileutils를 maintain하고 있었는데 이런게 귀찮아서 몇가지 세팅을 자동으로 맞추어 주는 스크립트를 만들어서 fileutils 2.0과 함께 발표했다. 그것이 바로 configure 스크립트의 탄생이었다. Makefile.in을 틀로 해서 Makefile을 만들어내는 것이었다. configure 스크립트는 계속 발전했으나, 문제는 configure는 셸 스크립트였지만 너무 어려웠다는 점이다. 그래서 configure.in을 틀로 해서 configure스크립트를 자동으로 만들어 내는 도구를 만들었다. 그것이 autoconf이다. autoconf도 발전해서 이제 어떤 config switch가 필요한지 일일이 검사할 필요가 없이 거의 모든 과정을 자동으로 수행할 수 있었다. 하지만, autoconf는 config switch를 맞추어주는 수고를 덜었을 뿐이지 Makefile의 복잡함 자체를 덜어주지는 못했다. Makefile.in도 아직 어렵고, 작성하려면 한참을 고생해야 한다. 그리고, 패키지 구성이 조금만 달라져도 수정하는 데 어려움이 생겼다. 그래서 Makefile.in을 자동으로 만들어 주는 automake가 최근에 발표된 것이다. automake는 편리한 도구이긴 하지만, 편리한 만큼 철저하게 automake의 방식을 따라야 한다는 문제점이 있다. 다른 화일이름을 쓰고 싶거나, 설치 방식을 다르게 하고 싶으면 그건 개발자가 직접 만들어야 한다. 이 방식을 따르자. 그러기 싫다면 그것은 고생을 자초하는 길이다. 버전 문제의 해결 **************** 모든 GNU program은 다음 2가지 옵션을 가지고 있다. 첫번째가 --help이고, 또 하나가 --version이다. (그런데 왜 GCC는 --help가 안되지?) 이것도 하나의 규칙이다. 만들고 있는 프로그램은 반드시 이 두 옵션을 가지고 있어야 한다. 우리가 생각해 볼 문제는 --version의 경우이다. --version 옵션을 줘서 이 프로그램의 버전이 몇인가를 표시할 수 있다는 얘기는 어딘가 version과 관련된 string을 가지고 있다는 얘기가 된다. GNU program들은 이 version string 문제를 여러가지 방법으로 해결하고 있다. `hello'와 같은 프로그램은 version.c라는 화일이 있다. 그곳에서 `char version[] = "GNU Hello, version 1.3";'이라고 선언해 주고 있다. 반면, fileutils같은 경우는 오직 configure.in에서 `VERSION=3.13'이라는 라인이 있을 뿐이다. 그리고 configure 스크립트를 실행시키면 자동으로 생성되는 `config.h'라는 화일에 `#define PACKAGE_VERSION "GNU fileutils-3.13"'라고 되어 있어 직접 PACKAGE_VERSION이라는 매크로를 쓰도록 하고 있다. 어느쪽을 택해야 하겠는가? 이건 선택의 여지가 없다. 당연히 후자를 택해햐 한다. 후자는 전자에 비해 많은 장점을 가지고 있다. version을 높이고 낮추고의 문제는 프로그래밍의 차원이 아니라, 패키지 관리의 차원이다. 패키지 관리 업무에서 version.c라는 C 소스코드를 에디트해야 한다는 게 얼마나 웃긴 일인가? 또 fileutils의 경우는 config.h뿐만 아니라 doc/디렉토리에 version.texi라는 화일도 만들어 낸다. 역시 version이 쓰여 있는 단순한 매크로일 뿐이다. 이 화일은 그 패키지의 문서의 version에 관계된다. 한개의 configure.in 화일을 바꿈으로써 이런 효과를 거둘 수 있다. 자, 위에서 우리는 PACKAGE, VERSION, PACKAGE_VERSION이라는 세개의 매크로를 가지고, 많이 고생을 했었다. 그 고생의 결과 생성된 config.h에는 이 세개의 매크로에 대해서 #define한 라인이 들어 있을 것이다. 다음은 first.c의 --version 옵션에 대한 처리 부분이다. 물론 옵션 처리는 getopt 라이브러리를 사용했다. ----------------------------------------------- if (show_version) { printf ("%s\n", PACKAGE_VERSION); exit (0); } ----------------------------------------------- TeXinfo를 사용할 줄 아는 독자에게만 해당되는 얘기... 굳이 모르더라도 보고 넘어갈 수 있을 것이다. 매뉴얼에도 그 프로그램의 버전이 들어간다. 매번 버전이 바뀔 때마다 찾아가서 바꾸는 것도 귀찮은 일이고, 패키지 관리 차원에서 할 일이다. automake는 version.texi를 해당 .texi(위의 예에서는 first.texi)에서 @include 명령으로 `포함'하도록 하고 있다. version.texi에는 다음 세개의 매크로가 정의되어 있다. UPDATED EDITION VERSION UPDATED는 최종 변경된 날짜, VERSION은 해당 프로그램의 버전, EDITION은 이 매뉴얼의 버전을 말한다. 매뉴얼에서 @value{VERSION}과 같이 사용하면 된다. 다음은 first.texi의 표지에 쓰인 위의 매크로이다. ------------------------------------------------- @titlepage @title @code{first} @subtitle Example of autoconf/automake @subtitle for version @value{VERSION}, @value{UPDATED} @author Changwoo Ryu ------------------------------------------------- automake는 위와 같이 version.texi를 @include하는 부분이 없으면, version.texi를 만들지 않는다. 그러면 위에서 AC_SUBST로 Makefile.in의 내용을 수정했는데 그건 어디에 쓰일까? 먼저 `make dist'에서 만들어내야 할 화일이 `first-0.1.tar.gz'이라는 것을 알기 위해서이다. 또 GNU 프로그램이 실행화일 이외에 데이타를 필요로 할때 데이타를 찾는 디렉토리명이 되기도 한다. Emacs의 경우는 .../share/emacs 이고, automake의 경우는 .../share/automake이다. 데이타를 설치할때 해당 디렉토리로 복사할 수 있도록 한다. Portablility의 고려 ******************* 자, 너무 편한 것만 찾았나 보다. 이제 좀 골치아픈 문제인 포팅에 대해서 간단히 생각해 보자. autoconf를 사용하는 이유는 포팅을 원활히 할 수 있게 하기 위해서이다. 여러 시스템에 경험이 없다면, 일단, 코드를 써 내려 나가자. 그리고, autoscan으로 자신의 코드에 system-dependent한 부분이 어떤 것들이 있는지 알아본다. 그리고, 해당 부분을 고쳐 나간다. 프로그램이 커지면, 커질 수록 이 문제는 커진다. 특정 헤더 화일 하나 #include하는 데도, 이 화일이 있는지 없는지를 나타내는 매크로를 살펴보아야 한다. 특정 함수가 없는 경우도 검사해서 없을 경우는 다른 방법으로 구현할 줄도 알아야 한다. 이건 경험상의 문제인 것 같다. 다음은 fileutils의 ls.c의 일부분이다. ----------------------------------------------- #ifdef S_ISLNK if (S_ISLNK (files[files_index].stat.st_mode)) files[files_index].filetype = symbolic_link; else #endif ----------------------------------------------- 이상하게 생각할 지도 모르지만, 심볼릭 링크라는 게 존재하지도 않는 Unix 시스템이 있다. 그래서 S_ISLNK라는 심볼릭 링크인지를 검사하는 매크로가 존재하는지 아닌지도 검사해야 한다. 위의 예는 autoconf없이도 할 수 있는 부분이다. 하지만, 다음과 같은 경우는 어떤가? ----------------------------------------------- #if HAVE_LIMITS_H /* limits.h must come before system.h because limits.h on some systems undefs PATH_MAX, whereas system.h includes pathmax.h which sets PATH_MAX. */ # include #endif ----------------------------------------------- 위의 예도 fileutils의 ls.c이다. 특정 헤더화일이 있는지 없는지 컴파일할 때 알 수 있는 방법이 없다. HAVE_LIMITS_H는 configure 스크립트가 미리 검사한 내용을 config.h에 써 놓았기 때문에 미리 config.h를 #include한 ls.c가 HAVE_LIMITS_H의 값으로 limits.h가 있는지 없는지를 알아 볼 수 있는 것이다. 불행하게도 autoconf는 포팅을 자동으로 해 주는 것이 아니다. `자동으로 config를 해주는' 것 뿐이다. 그 config 결과를 어떻게 활용하는가는 코드를 작성할때 고려해야 한다. autoconf의 기능은 단지 이러한 #if.. preprocessor로 제어할 수 있는 스위치를 만들어 주는 역할 뿐이다. 예제로 만들어 놓은 first도 다른 시스템에서 동작할지는 알 수 없다. 각 스위치는 autoconf매뉴얼의 `Preprocessor Symbol Index'에 나와 있으니 참고하기 바란다. Epilog ****** 부족하지만, 이글로 대충 윤곽을 잡을 수는 있을 것이다. Emacs에서 C-h i를 눌러 autoconf와 automake의 매뉴얼을 계속 참조해 나가면서 익히기 바란다. [출처] Autoconf/Automake 강좌|작성자 PlayaHC