[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
Makefile
복사
include를 위한 코드가 대충 이렇게 됩니다. 보기만 해도 머리아프죠.
그리고 저 test/common/asan.mk는 이렇게 생겼어요.
ADDITIONAL_CC_LD_FLAGS := -g3 -fsanitize=address
include ../../../../common/sanitizer_common.mk
Makefile
복사
왜 여기에도 ../../../이 들어가냐면요...
상대경로가 그 파일을 include한 파일이 아닌, make 명령이 실행된 cwd가 기준이에요.
2) 해결 안 하면?
코드가 좀 안 예쁘더라도 동작만 하면 그만 아닌가? 생각할 수 있는데요,
test/case1/ft_putstr_fd__mock/write/builddir/asan/Makefile에서도 include한다면 어떨까요?
# 이번에는 "../"이 다섯 번
include ../../../../../common/asan.mk
Makefile
복사
그냥 이렇게 끝난다면 행복할 것 같아요. ...하지만 현실은 그렇지 않아요.
asan.mk에서도 include를 하는데, 그 경로가 상대경로이기 때문에 재미있는 일이 일어날 거에요.
2. 해결방법
사실 엄청 간단한 방법으로 해결이 가능합니다.
1) 초간단 해결법!
임의의 어떤 한 변수(예를 들어 BASE_PATH)에 프로젝트 루트 디렉터리의 상대경로를 저장해둬요.
BASE_PATH := ../../../../..
include $(BASE_PATH)/test/common/asan.mk
Makefile
복사
그러면 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
Makefile
복사
벌써 모든 문제가 말끔하게 해결됐습니다. 와!
여기에서 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 := .
Makefile
복사
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
복사
대신에 이 방법은 모든 Makefile에서 BASE_PATH를 설정해야 되는 것처럼,
include를 할 때마다 매번 CURR_PATH를 재설정해야 한다는 불편함이 따를 수 있는데,
프로젝트가 정말 거대해져버리면 그 불편함을 감수하는 게 훨씬 나은 선택일 수 있어요.