edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
gcc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
gcc -c main.c
kbd.o : kbd.c defs.h command.h
gcc -c kbd.c
command.o : command.c defs.h command.h
gcc -c command.c
display.o : display.c defs.h buffer.h
gcc -c display.c
insert.o : insert.c defs.h buffer.h
gcc -c insert.c
search.o : search.c defs.h buffer.h
gcc -c search.c
files.o : files.c defs.h buffer.h command.h
gcc -c files.c
utils.o : utils.c defs.h
gcc -c utils.c
clean :
rm -f edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
make clean 과 같이 명령행 인자를 주면 그 인자에 맞는 규칙을 실행한다.
OBJ = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(OBJS) gcc -o $@ $(OBJS)
.PHONY : clean clean : rm -f edit $(OBJS)
SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) edit : $(OBJS) gcc -o $@ $(OBJS)또한 SRCS 를 정의할 필요가 없다면 OBJS 를 다음과 같이 정의하는 것도 가능하다.
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))그리고 미리 정의된 변수에 대한 패턴 치환은 다음과 같이 줄여 쓸 수 있으며,
SRCS = $(wildcard *.c) OBJS = $(SRCS:%.c=%.o)특히 확장자와 같은 접미사 치환은 다음과 같이 더욱 줄일 수 있다.
SRCS = $(wildcard *.c) OBJS = $(SRCS:.c=.o)wildcard, patsubst 이외의 다른 함수들에 대해서는 더 알아보고 싶다면 매뉴얼 8. Functions for Transforming Text 를 참조하라.
OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) edit : $(OBJS) gcc -o $@ $(OBJS) %.o : %.c gcc -c -o $@ $< clean: rm -f edit $(OBJS)
%.d: %.c @set -e; rm -f $@; \ gcc -M $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$make 는 기본적으로 명령을 실행하기 전에 명령을 출력한다. 하지만 @ 으로 시작하는 명령은 출력하지 않고 실행한다. 또한 쉘에서 -e 는 일반적으로 에러가 다음 명령을 받지 않고 즉시 쉘을 종료하는 옵션이다. sed 명령이 하는 일은 원래 gcc 에 -M 옵션을 주었을 때 목적 코드에 대해서만 의존관계를 나타내는 다음과 같은 출력을
main.o : main.c def.h ...생성된 의존규칙 파일 자체에도 의존성을 부여하는 규칙이 되도록 다음과 같이 변환하는 것이다.
main.o main.d : main.c def.h ...이렇게 하면 파일을 수정했을 때 전체 소스에 대해 의존규칙을 다시 생성할 필요 없이 어떤 특정 의존규칙 파일들만 새로 만들면 되는지 make 에 알려줄 수 있다.
make 를 실행하곤 했다. 하지만 매뉴얼 3.7 How Makefiles Are Remade 에 나오듯이, GNU make 는 Makefile 자신이 갱신되었을 때 똑똑하게 행동한다는 큰 장점을 있기 때문에 그러한 별도의 자동 의존관계 생성 루틴이 필요없다. GNU make 는 실행에 앞서 Makefile 자신 뿐 아니라 그 Makefile 이 include 하고 있는 모든 다른 Makefile 들을 갱신하는 규칙이 있는지 확인하고 그 규칙을 적용여여 하나라도 갱신되면 전체 Makefile 을 다시 읽어들인 후에 작업을 진행한다. 그렇기 때문에 다음과 같이 Makefile 을 작성하여 의존관계 파일들을 include 하기만 하면 별도로 의존관계를 생성하는 명령을 내리지 않아도 된다.
OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) DEPS = $(OBJS:.o=.d) edit : $(OBJS) gcc -o $@ $(OBJS) %.o : %.c gcc -c -o $@ $< clean: rm -f edit $(OBJS) $(DEPS) $(DEPS:.d=.d.*) include $(DEPS) %.d: %.c @set -e; rm -f $@; \ gcc -M $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$처음 make 를 실행하면 아직 확장자가 .d 인 의존관계 파일이 없어서 include 하지 못한다. include 에 성공하건 못하건, GNU make 는 이들을 생성할 규칙이 있나 일단 먼저 알아보며, 규칙이 있고 확장자 .d 인 파일들은 아예 존재하지 않기 때문에 최신 파일이 아니다. 따라서 make 는 확장자 .d 인 의존관계 파일들을 생성하는 명령들을 실행한다. 이제 include 되어야 할 대상인 의존관계 파일들이 갱신되었으므로 make 는 다시 Makefile 들을 불러들여 edit 라는 표적을 생성하는 규칙을 실행하게 되는 것이다.
SUBDIRS = foo bar baz .PHONY: subdirs $(SUBDIRS) subdirs: $(SUBDIRS) $(SUBDIRS): $(MAKE) -C $@ foo: baz
$ export CC=gcc; makeMakefile 내부에서도 똑같은 형식으로 export 명령을 쓰면 환경변수가 설정되어 하위 make 을 를 부를 때 변수가 넘어간다. 그리고 더 이상 하위 make 로 넘겨주고 싶지 않은 정의는 unexport 명령으로 환경에서 제거한다. 더 자세한 내용은 매뉴얼을 참고하라.