출처 : http://blog.daum.net/english_100/14
10. 암묵적 규칙 사용하기
C 소스파일을 C 컴파일러를 이용해 오브젝트 파일을 생성하는 이런 표준적인 작업은 자주 발생하는 일이다. 암묵적 규칙은 사용자가 구체적으로 명기하지 않은 사항에 대해 관례적으로 사용하는 기술을 말한다. 예를 들어 '.c'로 끝나는 파일을 만나면 make는 C 컴파일러를 통해 오브젝트 파일을 만드는 암묵적 규칙을 수행한다.
10.1 암묵적 규칙 사용하기
타깃 파일을 갱신하기 위해 make로 하여금 통상적 방식을 사용하기 위해서는 단지 recipe를 명기하지 않으면 그만이다. 즉 규칙에 recipe를 명시하지 말든지 아예 규칙을 명시핮 말던지 하면 되는 것이다. 예를 들어 :
foo : foo.o bar.o
cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
여 기서 foo.o를 언급했지만 이에 대한 규칙이 명기되지 않았으므로 make는 자동적으로 암시적 규칙을 찾아 이를 갱신할것이다. 암시적 규칙을 찾게되면 한개 이상의 prerequisite과 recipe가 제공되는데 만약 foo.o에 암시적 규칙이 적용되지 않는 헤더파일과 같은 추가적인 prerequisite을 명기하고 싶으면 recipe가 없는 규칙을 작성하면 된다.
모 든 암시적 규칙은 타깃 패턴과 prerequisite 패턴을 갖는데 많은 암시적 규칙들이 동일한 타깃 패턴을 갖는다. 예를 들어 많은 '.o' 파일을 만드는 규칙들이 '.c' 을 C 컴파일러로 컴파일해 만들어 지거나 '.p' 파일을 파스칼 컴파일러로 컴파일해 만들진다. 실제로 적용되는 규칙은 prerequisite이 존재하고 갱신이 될수 있으면 되는 것이다. 다시 말해 foo.c 파일이 있다면 C컴파일러를 사용하고 foo.p 파일이 있다면 파스칼 컴파일러를 사용하는 것이다.
물론 makefile을 작성할 때 어떤 prerequisite이 존재하게 될지 알기 때문에 make가 어떤 암시적 규칙을 선택해사용할 지를 안다.
어 떤 규칙이 필요한 prerequisite이 존재하고 이로부터 만들어질 수 있으면 그 규칙은 적용된다. 어떤 파일이 만들어질 수 있다는 것은 makefile내에 그 파일이 타깃이나 prerequisite으로 명기가 되어있고 이를 위한 암시적 규칙을 찾을 수 있으면 된다. 만약 어떤 암시적 prerequisite이 또다른 암시적 규칙의 산물이라면 이를 연쇄작용이 발생했다고 말한다.
일반적으로 make는 어떤 타깃이 recipe를 갖고 있지 않으면 암시적 규칙을 찾게 된다. prerequisite에서만 언급된 파일은 아무것도 명시되지 않은 하나의 타깃으로 간주됨으로써 결국 암시적 규칙을 적용하게 되는것이다.
우리가 주의해야 할 것은 prerequisite이 명기되었다고 해서 그것이 암시적 규칙을 찾는데 영향을 주지는 않는다는 것이다. 예를 들어 :
foo.o : foo.p
prerequisite foo.p가 꼭 파스칼 소스파일 .p로부터 오브젝트 파일 .o를 만드는 암시적 규칙을 따라야 하는 것을 의미하지는 않는다는 것이다. 예를 들어 foo.c라는 파일이 존재한다면 사전에 정의된 암시적 규칙 목록에 의해 파스칼 규칙을 따르는 대신에 C소스파일을 이용해 오브젝트 파일을 만들것이기 때문이다.
recipe가 없는 타깃에 암시적 규칙이 적용되는것을 원치 않는다면 그 타깃에 세미톨론을 표기함으로써 빈 recipe로 남겨놓으면 된다.
10.2 암시적 규칙 목록
makefile이 명시적으로 덮어씌우거나 지우지 않는 한 사용할 수 있는 암시적 규칙이 사전에 정의되어 있다. 하지만 '-r'이나 '--no-builtin-rules' 옵션을 사용하면 이들 사전 정의된 규칙을 제거할 수 있다.
여 기서는 POSIX-based 운영체계에 대해서만 언급을 하며 다른 운영체계는 정의된 암시적 규칙들이 달라질 수 있다. GNU make의 모든 디폴트 규칙들과 변수들을 보기위해서는 makefile이 없는 디렉토리에서 'make -p'라고 치면 된다.
'-r' 옵션이 없다고 해도 모든 규칙들이 항상 정의되는것이 아니며 상당수의 사전정의 암시적 규칙들은 첨자(suffix) 규칙으로 구현된다. 그래서 어떤것이 정의될것인가는 첨자 목록에 따라 달라진다 (특별 타깃 .SUFFIXES의 prerequisite 목록). 디폴트 첨자 목록은 : .out, .a, .ln, .o, .c, .cc, .C, .cpp, .p, .f, .F, .m, .r, .y, .l, .ym, .lm, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch, .web, .sh, .elc, .el 이다. 아래 기술한 암시적 규칙들중 이 첨자중 하나를 prerequisite으로 갖는 것은 실제 첨자 규칙이 된다. 만약 첨자 목록을 수정한다면 그 목록에 존재하는 첨자들 중 한 두개로 이름붙여진 첨자 규칙들만이 효력을 갖게 되고 그렇지 않은 첨자들은 사용할 수 없게 된다.
Compiling C programs
n.o는 n.c로 부터 '$(CC) $(CPPFLAGS) $(CFLAGS) -c'라는 형태의 recipe를 통해 자동적으로 생성된다.
Compiling C++ programs
n.o는 n.cc , n.cpp 또는 n.C로 부터 '$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c'라는 형태의 recipe를 통해 자동적으로 생성된다. '.cc'를 사용하길 권장한다.
Compiling Pascal programs
n.o는 n.p로 부터 '$(PC) $(PFLAGS) -c'라는 형태의 recipe를 통해 자동적으로 생성된다.
Compiling Fortran and Ratfor programs
n.o는 n.f , n.F 또는 n.r로 부터 포트란 컴파일러를 통해 자동적으로 생성된다.
'.f'
'$(FC) $(FFLAGS) -c'.
'.F'
'$(FC) $(FFLAGS) $(CPPFLAGS) -c'.
'.r'
'$(FC) $(FFLAGS) $(RFLAGS) -c'.
Preprocessing Fortran and Ratfor programs
Compiling Modula-2 programs
Assembling and preprocessing assembler programs
Linking a single object file
Yacc for C programs
Lex for C programs
Lex for Ratfor programs
Making Lint Libraries from C, Yacc, or Lex programs
Tex and Web
Texinfo and Info
RCS
SCCS
10.3 암시적 규칙에 사용되는 변수들
빌 트인된 암시적 규칙의 recipe는 사전 정의된 여러 변수들을 자유로이 사용할 수 있다. 이 변수들의 값은 makefile 내에서나, make의 인자를 통해, 또는 환경을 통해 변경할 수 있으며, 결국 규칙을 변화시키지 않고도 그 규칙의 행동을 바꿀 수 있게 된다. '-R'이나 '--no-builtin-variables' 옵션을 통해 암시적 규칙이 사용하는 모든 변수들을 무효로 만들 수 있다.
예를 들어 C 소스파일을 컴파일하기 위해 사용하는 recipe인 '$(CC) -c $(CFLAGS) $(CPPFLAGS)'를 보자. 여기서 사용하는 디폴트 값은 'cc' 밖에 없다. 즉 결과적으로 'cc -c'가 될것이다. 'CC'를 'ncc'로 재정의 하고 'CFLAGS'를 '-g'로 재정의 한다면 C프로그램을 캄파일하기 위해 ㅜcc를 사용하게 되고 이때 '-g' 옵션을 전달하게 되는 것이다.
암시적 규칙이 사용하는 변수는 두가지 부류로 나뉘는데 프로그램 이름인 것과 어떤 프로그램을 위한 옵션이 그것이다. 다음 테이블은 일반적으로 많이 쓰이는 변수들을 나열하고 있다. 이 목록이 아주 정확하다거나 기술된 디폴트 값이 실제 사용자 환경에서도 같다고는 할 수 없으며 내가 현재 사용하는 환경하의 정확한 변수 목록을 보고자 한다면 makefile이 없는 디렉토리에서 'make -p'를 실행시키면 된다.
프로그램 이름류
AR
Archive-maintaining program; default 'ar'.
AS
Program for compiling assembly files; default 'as'.
CC
Program for compiling C programs; default 'cc'.
CXX
Program for compiling C++ programs; default 'g++'.
CPP
Program for running the C preprocessor, with results to standard output; default '$(CC) -E'.
FC
Program for compiling or preprocessing Fortran and Ratfor programs; default 'f77'.
M2C
Program to use to compile Modula-2 source code; default 'm2c'.
PC
Program for compiling Pascal programs; default 'pc'.
CO
Program for extracting a file from RCS; default 'co'.
GET
Program for extracting a file from SCCS; default 'get'.
LEX
Program to use to turn Lex grammars into source code; default 'lex'.
YACC
Program to use to turn Yacc grammars into source code; default 'yacc'.
LINT
Program to use to run lint on source code; default 'lint'.
MAKEINFO
Program to convert a Texinfo source file into an Info file; default 'makeinfo'.
TEX
Program to make TeX dvi files from TeX source; default 'tex'.
TEXI2DVI
Program to make TeX dvi files from Texinfo source; default 'texi2dvi'.
WEAVE
Program to translate Web into TeX; default 'weave'.
CWEAVE
Program to translate C Web into TeX; default 'cweave'.
TANGLE
Program to translate Web into Pascal; default 'tangle'.
CTANGLE
Program to translate C Web into C; default 'ctangle'.
RM
Command to remove a file; default 'rm -f'.
프로그램 옵션류
ARFLAGS
Flags to give the archive-maintaining program; default 'rv'.
ASFLAGS
Extra flags to give to the assembler (when explicitly invoked on a '.s' or '.S' file).
CFLAGS
Extra flags to give to the C compiler.
CXXFLAGS
Extra flags to give to the C++ compiler.
COFLAGS
Extra flags to give to the RCS co
program.
CPPFLAGS
Extra flags to give to the C preprocessor and programs that use it (the C and Fortran compilers).
FFLAGS
Extra flags to give to the Fortran compiler.
GFLAGS
Extra flags to give to the SCCS
get
program.
LDFLAGS
Extra flags to give to compilers when they are supposed to invoke the linker, 'ld'.
LFLAGS
Extra flags to give to Lex.
YFLAGS
Extra flags to give to Yacc.
PFLAGS
Extra flags to give to the Pascal compiler.
RFLAGS
Extra flags to give to the Fortran compiler for Ratfor programs.
LINTFLAGS
Extra flags to give to lint.
10.4 암시적 규칙의 연쇄작용
종종 하나의 파일이 여러단계의 암시적 규칙을 거쳐 생성되기도 한다. 예를 들어, 파일 n.o이 n.y로 부터 생성되기도 하는데 이는 Yacc와 cc를 거쳐 이루어지는 것이다. 이들 이련의 과정을 연쇄작용이라 부른다.
만약 n.c가 존재하거나 makefile 내에 관련 사항이 언급되었다면 다른 특별한 검색은 이루어지지 않아도 된다. 먼저 make는 오브젝트 파일을 만들기 위해 먼저 n.c 파일을 찾아야 한다는 걸 알고 있고, 이 파일을 만들기 위해서는 다시 Yacc를 이용하게 된다.
하지만 n.c 파일이 존재하지도 않고 그에 관한 어떤 언급도 없다면 어떻게 될까? make는 n.o와 n.y 사이의 사라진 고리를 찾기 시작한다. 이때 n.c를 매개 파일이라 부른다. 일단 매개파일이 결정되면 마치 makefile 내에 언급되어있는양 데이터베이스를 참조해 암시적 규칙을 사용한다.
매개파일이 다른 파일들과 같이 갱신되지만 두가지 측면에서 다르게 처리된다.
첫번째 다른 점은 매개 파일이 없을 때 어떻게 되는가 하는점이다. 만약 일반 파일 b가 없는데 make는 그 파일에 의존하는 타깃을 처리해야 하는 경우, 어쩔수 없이 먼저 b를 생성한 수 이어서 타깃을 갱신하게 된다. 하지만 b가 매개파일 경우는 어떨까? b의 prerequisite이 타깃보다 새것이 아닌한, 또는 타깃을 갱신해야할 어떠한 이유가 없는 한은 b나 타깃을 갱신하지 않을 것이다.
두번째 차이는 만약 make가 무언가를 갱신하기위해 b를 생성했다면 그 이후 더이상 필요가 없을 때 지워버린다는 것이다. 그래서 make를 수행하기 전에 존재하지 않았던 매개 파일은 make를 수행하고 난 후에도 존재하지 않는다. 이때 make는 어떤 파일이 삭제되었는지를 'rm -f' 명령을 통해 보여준다.
일 반적으로 일단 파일이 makefile 내에서 타깃이나 prerequisite으로 기술되었다면 더이상 매개파일이 될 수 없다. 하지만 특별 타깃 .INTERMEDIATE 의 prerequisite으로 명시해 주면 그 파일이 파일 내의 다른 곳에 기술이되어 있다해도 매개 파일이 될 수 있다.
매개파일을 secondary 파일로 지정함으로써 자동 삭제되는 것을 방지할 수 있다. 이를 위해서는 특별 타깃 .SECONDARY 의 prerequisite으로 명시하면 된다. 파일이 secondary 라는 것은 바로 이 파일이 매개 파일이라는 의미이다.
암 시적 규칙의 타깃 패턴 ('%.o' 와 같은)을 특별 타깃 .PRECIOUS의 prerequisite으로 명기하면 그 패턴과 일치하는 파일명에 해당하는 암시적 규칙에 의해 생성된 매개 파일을 유지시킬 수 있다. 연쇄작용은 둘 이상의 암시적 규칙이 연관되는데, 예를 들면 foo라는 파일을 RCS/foo.y.v라는 파일로 부터 RCS, Yacc 그리고 cc를 통해 만들어 낸다. 그러면 foo.y 와 foo.c는 결국에 지워질 매개 파일인 것이다.
연 쇄작용에서 같은 암시적 규칙이 절대 두번 이상 출현할 수 없다. 이는 foo라는 파일을 foo.o.o라는 파일에서 링커를 두번 걸치는 멍청한 일을 통해 만들지 않는다는 것을 의미한다. 이는 또한 암시적 규칙의 연쇄작용이 무한 루프에 빠지는 것을 방지해 주기도 한다.
연쇄작용으로 처리될 어떤 경우를 최적화해주는 특별한 암시적 규칙이 있다. 예를 들어 foo를 foo.c 로부터 만들때 컴파일과 링크를 거쳐 생성하고 foo.o라는 매개 파일이 생성된다. 하지만 실제로는 특별 규칙에 의해 컴파일과 링킹이 cc라는 하나의 명령에 의해서 이루어진다.
10.5 패턴 규칙을 정의하고 재정의하기
패턴 규칙을 기술함으로써 암시적 규칙을 정의할 수 있다. 패턴규칙은 타깃이 '%' 문자를 포함하고 있다는 것만 빼고는 일반 규칙과 동일하다.