Recursive Make
make 에서 사용되는 rule 은 구조가 간단하여 읽고 해석하는데 어려움이 없지만 의존성을 가지고 서로 연결되기 시작하면 가독성이 떨어지고 추적하기가 어렵습니다. 따라서 프로젝트가 커지면 각 모듈 디렉토리별로 Makefile 을 두어서 독립적으로 빌드하게 됩니다. make 실행시 처음 실행되는 makefile 을 top makefile 이라고 하는데 여기서 전체적인 global 설정과 각 모듈별 의존관계를 설정한 후에 하나의 makefile 이 실행되는것 처럼 일괄 빌드하는데 이것을 recursive make 이라고 합니다.
recursive make 을 위해 기본적으로 사용되는 형식은 아래 예제와 같습니다.
여기서 recipe 에서 실행되는 make 을 sub-make 이라고 하는데
실행파일명으로는 $(MAKE)
변수를 사용해야 합니다.
왜냐하면 recipe 명령 라인에 $(MAKE)
이 존재하면 그 라인은 앞에 +
prefix 가 붙은 것과 같이 동작하기 때문입니다.
이것은 프롬프트 상에서 make 명령을 -t
(--touch), -n
(--just-print), -q
(--question)
옵션을 이용해 실행했을 때에도 sub-make 이 실행되게 합니다.
SUBDIRS := foo bar zoo
all clean : $(SUBDIRS)
$(SUBDIRS) :
$(MAKE) -C $@ $(MAKECMDGOALS)
foo : baz # ---- foo 보다 baz 를 먼저 실행 (1)
.PHONY: all clean $(SUBDIRS)
make 명령 실행시 -j
옵션을 이용해 병렬 실행을 하게 되면
prerequisites 에 해당하는 foo bar zoo 타겟들은 모두 동시에 실행되게 됩니다.
이때 만약에 특정 디렉토리가 먼저 빌드 되어야 할 경우에는 위의 (1) 번과 같이
의존 관계를 설정해 주면 됩니다.
sub-make 이 실행될 때는 자동으로 --print-directory
옵션이 설정되므로 makefile 실행 전, 후에
아래와 같은 메시지가 출력됩니다.
만약에 이와 같은 메시지 출력을 disable 하고 싶으면 --no-print-directory
옵션을 사용하면 됩니다.
[1]
안에 있는 숫자는 sub-make 의 depth 정도를 나타냅니다. top makefile 에서는 0 이 되고
첫 번째 sub-make 에서는 1 이 되는데 여기서 또 sub-make 이 실행되면 2 가 됩니다.
( MAKELEVEL
변수로 조회할 수 있습니다.)
make[1]: Entering directory '/home/mug896/tmp/foo'
. . .
make[2]: Entering directory '/home/mug896/tmp/foo/bar'
. . .
make[2]: Leaving directory '/home/mug896/tmp/foo/bar'
. . .
make[1]: Leaving directory '/home/mug896/tmp/foo'
병렬 실행 시에도 순서대로 실행하기
병렬 실행 시에도 특정 순서에 따라 serially 실행시키는 것이 필요할 경우에는 다음과 같이 recipe 에서 shell script 를 이용해 빌드하면 됩니다. 이때도 각각의 sub-make 내에서는 병렬로 실행됩니다.
all clean : serial
serial :
$(MAKE) -C foo $(MAKECMDGOALS)
$(MAKE) -C bar $(MAKECMDGOALS)
$(MAKE) -C zoo $(MAKECMDGOALS)
--------------------------------------
SUBDIRS := foo bar zoo
all clean : serial
serial :
@for dir in $(SUBDIRS); \
do \
$(MAKE) -C $$dir $(MAKECMDGOALS) || exit; \
done
recurive make 에서 변수의 사용
recursive make 은 새로 make 프로세스를 생성해 실행하는 것이므로 top makefile 에서 설정한 변수를 sub-make 에서도 사용하려면 export 지시자를 사용해야 합니다.
export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM STRIP OBJCOPY OBJDUMP PAHOLE KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS
export MAKE LEX YACC AWK INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE
. . . .
MAKEFLAGS, MAKEOVERRIDES 같은 builtin 변수들은 자동으로 export 되어 sub-make 에도 적용됩니다. make 명령 라인에서 설정한 변수값은 기본적으로 makefile 에서 설정한 변수값에 우선해서 사용되는데 MAKEOVERRIDES 변수는 이와 같은 기능이 sub-make 에도 적용되게 합니다. 다음은 실제 두 변수가 어떻게 적용되는지 테스트하는 예제입니다.
sh$ cat Makefile # top makefile
AA := 100
$(info top : MF : $(MAKEFLAGS))
$(info top : MO : $(MAKEOVERRIDES))
$(info top : AA : $(AA))
sub :
@$(MAKE) -C subdir
----------------------------------
sh$ cat subdir/Makefile # sub-make makefile
AA := 200
$(info sub : MF : $(MAKEFLAGS))
$(info sub : MO : $(MAKEOVERRIDES))
$(info sub : AA : $(AA))
0 :
########### 실행 결과 ############
sh$ make
top : MF :
top : MO :
top : AA : 100
make[1]: Entering directory '/home/mug896/subdir'
sub : MF : w # '-w' 옵션은 sub-make 실행시 자동으로 설정된다.
sub : MO :
sub : AA : 200 # 기본적으로 makefile 에서 설정한 변수값이 사용된다.
make[1]: Nothing to be done for '0'.
make[1]: Leaving directory '/home/mug896/subdir'
sh$ make -rR # 명령 라인에서 옵션 설정
top : MF : rR # MAKEFLAGS 변수값이 설정되고
top : MO :
top : AA : 100
make[1]: Entering directory '/home/mug896/subdir'
sub : MF : rRw # sub-make 에도 전달되어 사용된다.
sub : MO :
sub : AA : 200
make[1]: Nothing to be done for '0'.
make[1]: Leaving directory '/home/mug896/subdir'
sh$ make -rR AA=111 # 명령 라인에서 AA 변수값 설정
top : MF : rR
top : MO : AA=111 # MAKEOVERRIDES 변수값이 설정된다.
top : AA : 111
make[1]: Entering directory '/home/mug896/subdir'
sub : MF : rRw
sub : MO : AA=111 # MAKEOVERRIDES 변수값 설정에 따라
sub : AA : 111 # sub-make 에서도 override 된다.
make[1]: Nothing to be done for '0'.
make[1]: Leaving directory '/home/mug896/subdir'
다음은 top makefile 을 다음과 같이 변경한 후에 실행합니다.
AA := 100
MAKEOVERRIDES = # MAKEOVERRIDES 변수값을 empty 로 만듦
$(info top : MF : $(MAKEFLAGS))
$(info top : MO : $(MAKEOVERRIDES))
$(info top : AA : $(AA))
sub :
@$(MAKE) -C subdir MAKEFLAGS= # MAKEFLAGS 변수값도 empty 로 설정
########## 실행 결과 ###########
sh$ make
top : MF :
top : MO :
top : AA : 100
make[1]: Entering directory '/home/mug896/subdir'
sub : MF :
sub : MO : MAKEFLAGS=
sub : AA : 200
make[1]: Nothing to be done for '0'.
make[1]: Leaving directory '/home/mug896/subdir'
sh$ make -rR # 명령 라인에서 옵션 설정
top : MF : rR
top : MO :
top : AA : 100
make[1]: Entering directory '/home/mug896/subdir'
sub : MF : # MAKEFLAGS 값이 적용되지 않는다.
sub : MO : MAKEFLAGS=
sub : AA : 200
make[1]: Nothing to be done for '0'.
make[1]: Leaving directory '/home/mug896/subdir'
sh$ make -rR AA=111 # 명령 라인에서 AA 변수값을 설정하였지만
top : MF : rR
top : MO :
top : AA : 111
make[1]: Entering directory '/home/mug896/subdir'
sub : MF :
sub : MO : MAKEFLAGS= # MAKEOVERRIDES 값이 설정되지 않아
sub : AA : 200 # sub-make 에는 적용되지 않는다.
make[1]: Nothing to be done for '0'.
make[1]: Leaving directory '/home/mug896/subdir'