TL;DR
- 재귀 레시피에서
make를 직접 호출하면 병렬 작업 서버(jobserver)가 자식 프로세스에 전달되지 않을 수 있으며, GNU Make 3.81~4.3의 동작은 호출 방식과-j조합에 따라 달라짐. - 레시피 앞에
+를 붙이거나make를$(MAKE)로 바꾸면 작업 서버 전달과 호출한make바이너리 사용 문제를 해결할 수 있음. - 자식 레시피에 별도의
-jN을 지정하면 경고와 함께 작업 서버 모드가 비활성화되거나 재설정되는 경우가 있음. - 자식 레시피에서
-j만 지정한 행은 GNU Make 4.2.1·4.3에서 상위-j설정과 무관하게 무제한 병렬 실행으로 바뀜. - 상위와 하위의 병렬성 제한을 기대한 방식으로 조합하는 이상적인 동작은 제시된 버전에서 구현되지 않아, 호출 방식별 절충이 필요함.
재귀적 `make`와 병렬 실행
- 재귀적
make는 Makefile 레시피가 다시make를 실행하는 방식임. - GNU Make 공식 문서는 관련 내용을 잘 설명하지만, 여러 버전과 함께 작업하면서 GNU Make 3.81~4.3 사이의 동작 변화를 살펴봄.
- 다음과 같이 레시피에서
make를 직접 실행하고make -j4 ser를 호출하면, 최근 버전에서jobserver unavailable: using -j1경고가 나타날 수 있음. ser레시피는make -C subdir을 실행함.- 작업 서버, 즉
-j설정이 자식make에 전달되지 않아 의도한 병렬성이 사라짐. - 호출한 것과 같은
make바이너리를 사용한다는 보장도 없으며,PATH에서 발견되는make가 실행됨. - 레시피 줄 앞에
+를 붙이거나make를$(MAKE)로 바꾸면 작업 서버 전달, 병렬 실행, 호출한make바이너리 사용 문제를 해결할 수 있음. +를 붙이는 방식은 특별한 동작을 하는 기호라 마법처럼 느껴질 수 있으며,$(MAKE)를 쓰는 방식도 내부적으로는 마찬가지로 특별한 처리에 의존함.
실험 구성
- 상위 Makefile에는 다음 호출 형태를 비교하는 타깃을 둠.
ser:make -C subdirpar2:make -j2 -C subdirpar4:make -j4 -C subdirpar:make -j -C subdir- 위 네 타깃의
+make버전인serplus,par2plus,par4plus,parplus. - 위 네 타깃의
$(MAKE)버전인sermake,par2make,par4make,parmake. - 하위 Makefile은
all타깃에서one부터five까지 다섯 개의 작업을 실행하며, 각 작업은 이름을 출력하고 1초 대기한 뒤 대문자 이름을 출력함. - 여러 GNU Make 버전에서
make ser,make -j2 ser등의 명령을 실행하고 동시에 수행되는 레시피 수를 비교함. - 표의
b는 하위make가-jN을 강제하면서 작업 서버 모드를 비활성화한다는 경고를 뜻함. - 예:
make -j2 par2실행 시-jN forced in submake: disabling jobserver mode경고. - 표의
a는 하위make가 작업 서버를 사용할 수 없어-j1로 동작한다는 경고를 뜻함. - 예:
make -j2 ser실행 시jobserver unavailable: using -j1. Add '+' to parent make rule.경고.
GNU Make 3.81
- 각 값은 동시에 실행되는 레시피 수이며,
∞는 무제한 병렬 실행을 나타냄. ser†,par†,parplus†,parmake†는 테스트한 Make 버전 간 차이가 나타난 비이식적 방식임.ser†: 상위 명령의-j설정에 따라1,2,4,∞.serplus,sermake:1,2,4,∞.par2,par2plus,par2make:2,2b,2b,2.par4,par4plus,par4make:4,4b,4b,4.par†,parplus†,parmake†:∞,2,4,∞.- †로 표시된 비이식적 관용구는 실무에서 피하는 편이 좋다는 의견임.
GNU Make 4.0
- 테스트 환경은 Debian 8.11임.
ser†: 상위 명령의-j설정에 따라1,1a,1a,∞.serplus,sermake:1,2,4,∞.par2,par2plus,par2make:2,2b,2b,2.par4,par4plus,par4make:4,4b,4b,4.par†:∞,1a,1a,∞.parplus†,parmake†:∞,2,4,∞.a경고는 부모 레시피 앞에+를 추가하라고 안내하며,b경고는 하위-jN지정으로 작업 서버 모드가 비활성화됨을 알림.
GNU Make 4.2.1과 4.3
- 테스트 환경은 Rocky 8.10의 GNU Make 4.2.1, Red Hat 9 또는 Ubuntu 22.04의 GNU Make 4.3임.
-jN forced in submake경고 문구에 지정된N값이 포함되도록 바뀜.make -j2 par에서는-j0 forced in submake: resetting jobserver mode경고.make -j2 par2에서는-j2 forced in submake: resetting jobserver mode경고.ser†:1,1a,1a,∞.serplus,sermake:1,2,4,∞.par2,par2plus,par2make:2,2b,2b,2.par4,par4plus,par4make:4,4b,4b,4.par†,parplus†,parmake†는 모두∞,∞b,∞b,∞로 동작함.- 마지막 세 행은 GNU Make 3.81·4.0과 비교해 상위 명령이
-j2또는-j4여도 무제한 병렬 실행이 되는 변화임.
재귀 호출 방식의 절충
ser의a경고는 레시피 줄 앞에+를 붙이면 사라짐.- 예:
serplus에서+make -C subdir을 실행함. +방식은@나-접두사처럼 특별한 의미를 가진 기호에 의존한다는 점에서 마법처럼 느껴지는 해결책임.- 레시피 앞의 마법 같은
-보다 줄 끝의|| true를 선호한다는 견해임. $(MAKE)를 사용하는 방식도 내부적으로는 특별 처리에 의존하지만, 겉보기에는 덜 마법적인 대안임.- 예:
sermake에서$(MAKE) -C subdir을 실행함. +와$(MAKE)어느 쪽도resetting jobserver mode관련b경고를 없애지 못함.- 기대하는 이상적인 동작은 상위 명령이
-j2이면 병렬 작업 수가 2,-j4이면 4,-j이면 무제한이 되는 방식임. - 현재는 표에 인용된 호출 방식 중 선호하는 절충안을 선택해야 하는 상황임.
- 게시일은 2026-09-30이며, 분류는
concurrency,makefiles,sre임.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요