42 과제용 Makefile 템플릿?
42 과제 특징?
그래서 어떻게 해결할 것인가
Makefile 전체 코드
1. 42 과제 특징?
1) 꼭 필요한 파일만 제출
C 과제의 경우 Makefile, C 파일, 헤더 파일 정도만 제출할 수 있습니다.
기본적인 .gitignore나 .editorconfig조차 제출하면 안 됩니다.
당연히 .vscode같은 에디터 설정 파일도 제출할 수 없습니다.
.gitignore나 .editorconfig같은 파일들도 Git 저장소에 올리는 게 국룰입니다.
심지어 vscode가 유용한 프로젝트라면 .vscode조차요!
2) 굳이 수동으로 해야 하는 것
실제로 소스 폴더를 건드리는 것은 소스 파일을 건드리는 것과 다를 게 없지만,
Norm에서는 Makefile에 모든 소스 파일이 명시적으로 드러날 것을 요구하고 있습니다.
그래서 wildcard를 쓸 수 없습니다. ?????????????????
2. 그래서 어떻게 해결할 것인가
일단 문제 해결 전에 유틸 변수들을 만들어둘게요
Q := $(if $(filter 1,$(V) $(VERBOSE)),,@)
MAKE := make $(if $(filter 1,$(V) $(VERBOSE)),,--no-print-directory)
Makefile
복사
make 명령이 너무 많은 것을 출력하지 않도록 하기 위해 V와 MAKE 변수를 사용할 거에요.
make V=1 all처럼 V나 VERBOSE를 1로 설정하면 원래대로 전체 로그를 볼 수 있어요.
1) 제출 스크립트를 만들자
꼭 필요한 파일만 제출하라고 해서, 여러분의 개발환경을 망치지 마세요.
여러분의 생산성은 소중합니다.
소스 파일을 저장소 루트 디렉터리에 두면 제출하기가 힘들어집니다.
1.
다른 파일을 만들지 말거나 (내 개발환경 돌려내...)
2.
제출하기 직전에 제출하지 말아야 할 파일을 삭제하거나 (귀찮아...)
3.
제출용 git 저장소를 만들어서 제출하거나 (수동으로는 귀찮고, 자동화할 것!)
이 셋 중에 하나를 선택해야 하는데, 다 수동으로 하기에는 여간 귀찮은 게 아니죠.
소스 파일을 src 디렉터리에 두고 작업하는 경우를 예로 들어볼게요
# ... 중략
test:
$Q$(MAKE) -C test test
publish_without_test:
ifndef GIT_REMOTE_URL
$(error GIT_REMOTE_URL is undefined)
endif
$Qcp -r ./src ./tmp
$Q$(MAKE) -C tmp fclean
$Q(cd tmp && git init && git add . && git commit -m "Initial commit" && git push "$(GIT_REMOTE_URL)" HEAD:master)
$Qrm -rf tmp
$Qgit push "$(GIT_REMOTE_URL)" HEAD:source || echo "Failed to push HEAD to source"
publish: test publish_without_test
.PHONY: test publish_without_test publish
Makefile
복사
저장소 루트의 Makefile 일부입니다.
src에 제출할 파일이 있는 것처럼, test에 테스트용 파일이 있다고 가정합니다.
이제 제출하려면 make GIT_REMOTE_URL=(저장소 주소) publish를 입력하면 됩니다.
publish 명령어를 실행하면 대충 아래와 같은 일이 일어납니다.
1.
테스트 진행 후 src를 tmp로 복사하고, make fclean을 통해 임시 파일을 모두 삭제합니다.
2.
앞서 만든 tmp에서 git 저장소 초기화, 커밋 후 주어진 저장소의 master 브랜치에 push합니다.
3.
(선택적) 현재 저장소의 현재 브랜치(HEAD)를 주어진 저장소의 source 브랜치에 push합니다.
기계채점은 master에서 진행될 것이고, source는 동료평가에서 큰 도움이 될 것입니다.
이제 src가 아닌 저장소 루트 디렉터리에서 .gitignore, .editorconfig 등을 사용할 수 있습니다!
2) 소스 파일 목록을 제출 스크립트에서 만들자
publish_without_test:
ifndef GIT_REMOTE_URL
$(error GIT_REMOTE_URL is undefined)
endif
$Qcp -r ./src ./tmp
$Q$(MAKE) -C tmp fclean
$Qprintf "# script-generated file list\nSRCS := %s\n\n" "$$(cd src && find . -name "*.c" | cut -c 3- | xargs)" | cat - src/Makefile > tmp/Makefile
$Q(cd tmp && git init && git add . && git commit -m "Initial commit" && git push "$(GIT_REMOTE_URL)" HEAD:master
$Qrm -rf tmp
$Qgit push "$(GIT_REMOTE_URL)" HEAD:source || echo "Failed to push HEAD to source"
Makefile
복사
publish 스크립트에 한 줄을 추가했습니다.
printf "# script-generated file list\nSRCS := %s\n\n" "$(cd src && find . -name "*.c" | cut -c 3- | xargs)" | cat - src/Makefile > tmp/Makefile
Shell
복사
커밋하기 전에 제출할 Makefile의 첫 부분에 소스 파일의 목록을 넣는 스크립트입니다.
src/Makefile(제출할 Makefile)에서는 아래처럼 작성할 수 있습니다.
# This variable will be used only if source files are not hardcoded
SRCS ?= $(wildcard *.c)
# ... 또는 (저장소 루트가 아닌 다른 디렉터리에 소스 파일이 있는 경우)
SRCS ?= $(shell find . -name "*.c" | cut -c 3-)
Makefile
복사
제출한 파일에는 SRCS가 있기 때문에 제출한 파일에서는 wildcard가 사용되지 않습니다.
이렇게 하면 소스 파일을 이중 삼중으로 관리하는 끔찍한 노가다를 피할 수 있습니다.
3. Makefile 전체 코드
1) 제출할 Makefile (src/Makefile) - 프로젝트마다 다름 - 일부
Q := $(if $(filter 1,$(V) $(VERBOSE)),,@)
MAKE := make $(if $(filter 1,$(V) $(VERBOSE)),,--no-print-directory)
# This variable will be used only if source files are not hardcoded
SRCS ?= $(shell find . -name "*.c" | cut -c 3-)
# 주의! 프로젝트마다 바꿀 것
NAME := libft.a
all: $(NAME)
clean:
$Qfind -type f -a \( -name "*.o" -o -name "*.d" -delete \)
fclean: clean
$Qrm -f $(NAME)
re:
$Q$(MAKE) fclean
$Q$(MAKE) all
.PHONY: all clean fclean re
CC := clang
CFLAGS := -Wall -Wextra -Werror
DEPS := $(SRCS:.c=.d)
-include $(DEPS)
%.o: %.c
$Q$(CC) $(CFLAGS) -c $< -o $@ -MMD
# 프로젝트마다 필요한 것들. 그냥 예시
SRCS_BASIC := $(filter-out $(filter %_bonus.c,$(SRCS)), $(SRCS))
# ...후략
Makefile
복사
2) 저장소 루트 디렉터리의 Makefile
Q := $(if $(filter 1,$(V) $(VERBOSE)),,@)
MAKE := make $(if $(filter 1,$(V) $(VERBOSE)),,--no-print-directory)
all: test
clean:
$Qrm -rf ./tmp
$Q$(MAKE) -C src clean
$Q$(MAKE) -C test clean
fclean: clean
$Q$(MAKE) -C src fclean
$Q$(MAKE) -C test fclean
re:
$Q$(MAKE) -C src fclean
$Q$(MAKE) test
test:
$Q$(MAKE) -C test test
publish_without_test:
ifndef GIT_REMOTE_URL
$(error GIT_REMOTE_URL is undefined)
endif
$Qcp -r ./src ./tmp
$Q$(MAKE) -C tmp fclean
$Qprintf "# script-generated file list\nSRCS := %s\n\n" "$$(cd src && find . -name "*.c" | cut -c 3- | xargs)" | cat - src/Makefile > tmp/Makefile
$Q(cd tmp && git init && git add . && git commit -m "Initial commit" && git push "$(GIT_REMOTE_URL)" HEAD:master
$Qrm -rf tmp
$Qgit push "$(GIT_REMOTE_URL)" HEAD:source || echo "Failed to push HEAD to source"
publish: test publish_without_test
.PHONY: all clean fclean re test publish publish_without_test
Makefile
복사