[make] include ../../../.. 지옥에서 벗어나기

1. ../../../../.. 지옥

수십, 수백개의 Makefile을 관리하다 보면 include path가 꼬이는 문제가 생길 수 있습니다.

1) 그게 뭔데?

test/case1/ft_atoi/builddir/asan/Makefile에서 test/common/asan.mk를 include하는 경우

# 현재 디렉터리는 test/case1/ft_atoi/builddir/asan이므로 "../"이 네 번
include ../../../../common/asan.mk

include를 위한 코드가 대충 이렇게 됩니다. 보기만 해도 머리아프죠.

그리고 저 test/common/asan.mk는 이렇게 생겼어요.

ADDITIONAL_CC_LD_FLAGS := -g3 -fsanitize=address
include ../../../../common/sanitizer_common.mk

왜 여기에도 ../../../이 들어가냐면요...

상대경로가 그 파일을 include한 파일이 아닌, make 명령이 실행된 cwd가 기준이에요.

2) 해결 안 하면?

코드가 좀 안 예쁘더라도 동작만 하면 그만 아닌가? 생각할 수 있는데요,

test/case1/ft_putstr_fd__mock/write/builddir/asan/Makefile에서도 include한다면 어떨까요?

# 이번에는 "../"이 다섯 번
include ../../../../../common/asan.mk

그냥 이렇게 끝난다면 행복할 것 같아요. ...하지만 현실은 그렇지 않아요.

2. 해결방법

사실 엄청 간단한 방법으로 해결이 가능합니다.

1) 초간단 해결법!

임의의 어떤 한 변수(예를 들어 BASE_PATH)에 프로젝트 루트 디렉터리의 상대경로를 저장해둬요.

BASE_PATH := ../../../../..
include $(BASE_PATH)/test/common/asan.mk

그러면 test/case1/ft_atoi/builddir/asan/Makefile 의 첫 줄이 이렇게 시작하겠죠.

그리고 include에 이 BASE_PATH를 사용하는 거에요.

ADDITIONAL_CC_LD_FLAGS := -g3 -fsanitize=address
include $(BASE_PATH)/test/common/sanitizer_common.mk

벌써 모든 문제가 말끔하게 해결됐습니다. 와!

여기에서 BASE_PATH를 다른 파일에서 가져온다면 디렉터리 구조 변경에 더 유연해질 거에요.

# 어딘가의 Makefile
include base_path.mk
# 후략

# 어딘가의 base_path.mk
include ../base_path.mk
BASE_PATH := $(BASE_PATH)/..

# 어딘가의 상위 디렉터리의 base_path.mk
include ../base_path.mk
BASE_PATH := $(BASE_PATH)/..

# ... 반복하다가 프로젝트 루트의 상위 디렉터리의 base_path.mk
BASE_PATH := .

2) 더 좋은 해결법?

사실 아직 완벽한 방법은 아니에요.

test/common의 파일에서 test/common의 파일을 include하려면 test/common 써 쭤야 해요.

위 예시에서는 BASE_PATH 변수에 프로젝트 루트 디렉터리를 저장하는 방법을 썼는데요,

다른 변수(예를 들어 CURR_PATH)에 include 될 파일 기준 상대경로를 저장해도 돼요.

# test/case1/ft_atoi/builddir/asan/Makefile
include base_path.mk
CURR_PATH := $(BASE_PATH)/test/common
include $(CURR_PATH)/asan.mk

# test/common/asan.mk
ADDITIONAL_CC_LD_FLAGS := -g3 -fsanitize=address
include $(CURR_PATH)/sanitizer_common.mk

# test/common/sanitizer_common.mk
CURR_PATH := $(CURR_PATH)/../../common
include $(CURR_PATH)/basic_common.mk

대신에 이 방법은 모든 Makefile에서 BASE_PATH를 설정해야 되는 것처럼, include를 할 때마다 매번 CURR_PATH를 재설정해야 한다는 불편함이 따를 수 있는데,

프로젝트가 정말 거대해져버리면 그 불편함을 감수하는 게 훨씬 나은 선택일 수 있어요.