53 . 변수

지금까지의 노력에도 불구하고, Makefile에는 여전히 중복된 콘텐트, 즉 countwords.py 스크립트 명칭과 스크립트를 실행하는데 동원된 프로그램 python이 존재한다. 해당 스크립트의 이름을 바꾸면, 여러 곳에서 Makefile을 갱신해야만 된다.

스크립트 명칭을 보관하는 Make 변수(variable) (Make 일부 버젼에서는 매크로(macro)라고도 불림)를 소개한다:

COUNT_SRC=countwords.py

변수 할당(assignment)하는 예제가 위에 나와 있다 - COUNT_SRC 변수에 countwords.py 값이 할당되었다.

countwords.py는 스크립트로, 파이썬(python)에 전달되어 호출된다. 또다른 변수를 도입해서 스크립트 실행을 표현한다:

LANGUAGE=python
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)

Make가 실행될 때, $(...)는 Make에게 변수를 해당 값으로 치환하도록 일러준다. 이것이 변수 참조(reference)다. 변수값을 사용하고자 하는 어떤 곳에서도, 이런 방식으로 작성하고 참조한다.

여기서는 COUNT_SRC 변수를 참조한다. Make로 하여금 COUNT_SRC 변수를 countwords.py 값으로 치환하게 한다. Make가 실행될 때, COUNT_EXE에 값으로 python countwords.py를 할당한다.

이런 방식으로 COUNT_EXE 변수를 정의하면 스크립트 실행방식을 쉽게 변경할 수 있게 된다 (예를 들어, 스크립트 구현 언어를 파이썬에서 R로 변경하게 되면).

변수 사용하기

Makefile를 갱신해서, %.dat 규칙이 COUNT_SRCCOUNT_EXE 변수를 참조하게 한다. 그리고 나서 ZIPF_SRCZIPF_EXE 변수명을 사용해서 testzipf.py 스크립트와 results.txt 규칙에 대해서도 동일하게 작업한다.

해답

LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)

# Generate summary table.
results.txt : $(ZIPF_SRC) isles.dat abyss.dat last.dat
  $(ZIPF_EXE) *.dat > $@

# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat

%.dat : books/%.txt $(COUNT_SRC)
  $(COUNT_EXE) $< $*.dat

.PHONY : clean
clean :
  rm -f *.dat
  rm -f results.txt

Makefile 상단에 변수를 위치시키게 되면, 찾고 변경하기 쉽게 한다는 의미가 된다. 대안으로, 변수 정보만 간직하는 Makefile을 새로 만들어 넣을 수 있다. config.mk 파일을 생성하자:

# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)

# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)

다음 명령어를 사용해서, config.mk 파일을 Makefile 내부로 Makefile을 가져올 수 있다:

include config.mk

Make를 재실행해서, 모든 것이 여전히 잘 동작하는지 살펴보자:

$ make clean
$ make dats
$ make results.txt

Makefile 구성정보와 작업을 수행하는 부분, 즉 규칙을 구분했다. 스크립트 명칭 혹은 실행방식을 변경하려면, Makefile에 있는 소스코드가 아니라, 단지 구성파일만 편집하면 된다. 이런 방식으로 코드를 구성과 결합시키지 않는 것이 좋은 프로그래밍 관례다. 더 모듈화 되고, 유연해지며, 재사용가능한 코드가 되기 때문이다.

현재까지 다룬 Makefile

include config.mk

# Generate summary table.
results.txt : $(ZIPF_SRC) isles.dat abyss.dat last.dat
    $(ZIPF_EXE) *.dat > $@

# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat

%.dat : books/%.txt $(COUNT_SRC)
    $(COUNT_EXE) $< $*.dat

.PHONY : clean
clean :
    rm -f *.dat
    rm -f results.txt

새로 추가된 config 파일

# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)

# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)