SW 설계/make

makefile 기초: 변수, 패턴 규칙, 자동 변수

yztech 2021. 10. 19. 04:25
반응형

앞서 소개한 makefile은 실행 파일 program을 빌드하는데 잘 사용될 수 있다.

# Link
program: main.o function.o
    c++ main.o function.o -o program

# Compilation
main.o: main.c
    c++ -c main.c -o main.o

function.o: function.c
    c++ -c function.c -o function.o

만약, 컴파일러 옵션을 변경한다거나, 다른 컴파일러를 사용한다고 가정해보자. 또는, 컴파일할 소스 파일을 추가한다고 생각해보자.

컴파일러 옵션을 변경할 경우, (5,9) 의 action들을 모두 수정해야 하고, 이는 소스 파일의 개수만큼 수정해야 한다. 다른 컴파일러를 사용할 경우에도 마찬가지다. 만약 컴파일 소스 파일이 수십개 가된다면, makefile에서 수정할 내용도 수십개가 된다.

makefile은 이러한 반복된 부분을 필요할 때마다 사용할 수 있게 변수에 지정할 수 있다.

CXX := c++
CXXFLAGS := -g

OBJECTS := main.o function.o

# Link
program: $(OBJECTS)
    $(CXX) main.o function.o -o program

# Compilation
main.o: main.c
    $(CXX) $(CXXFLAGS) -c main.c -o main.o

function.o: function.c
    $(CXX) $(CXXFLAGS) -c function.c -o function.o

$(CXX)는 컴파일러 c++ 를 저장하고, $(CXXFLAGS)는 컴파일 옵션을 설정하고, $(OBJECTS)에는 object 파일의 이름들을 설정하면, 필요할 때마다 어디서든지 사용할 수 있게 된다.

만약, 컴파일 옵션을 -g -O2와 같이 변경할 경우, (2) CXXFLAG := -g -O2로만 변경하면 된다.

주의할 점은 makefile에서 변수 이름은 대소문자를 구분한다. 하지만, makefile에서 변수이름은 보통 대문자를 사용한다.

그리고, 다른 makefile에서 같은 이름으로 보통 사용되는 변수들도 있다. $CC는 C 컴파일러로 보통 사용되고, $CXX는 C++ 컴파일러로 보통 사용되며, $F77은 Fortran 컴파일러로 사용된다.

CC := cc
CXX := c++
CXXFLAGS := -g

F77 := f77
FFLAGS := 

 

패턴 규칙

소스 파일이 몇개 없을 때는, 각각의 소스파일 마다 컴파일 규칙을 만들어도 별로 문제가 있다고 느껴지지 않는다. 하지만, 소스 파일수가 많아져서 수십개가 된다면, 각 소스 파일마다 같은 규칙을 makefile에 추가하고, 변경하는 것은 매우 번거로운 작업이 될 수 있다. 패턴 규칙 (pattern rule) 은 반복되는 패턴을 하나의 규칙으로 단순화시킬 때 사용된다.

패턴 규칙에서는 wildcard (%)가 사용된다. % 은 어떤 것과도 매치된다.

패턴 규칙을 사용하면 위의 makefile은 다음과 같이 간략화될 수 있다.

CXX := c++
CXXFLAGS := -g

OBJECTS := main.o function.o

# Link
program: $(OBJECTS)
    $(CXX) main.o function.o -o program

# Compilation
%.o: %.c
    $(CXX) $(CXXFLAGS) -c $(input) -o $(output)

makepp는 자동 변수 (automatic variable)을 사용한다. 위 예에서 사용된 $(input)과 $(output)은 가장 많이 사용되는 자동 변수들이다.

  • $(input): dependencies의 첫 번째 입력 파일 이름이다. 예전 makefile들에서는 $<으로 사용되었다.
  • $(output): target의 첫 번째 출력 파일 이름이다. 예전에는 $@으로 사용되었다.
  • $(inputs): 모든 dependencies의 파일 이름들이고, $^과 동일하다.
  • $(outputs): target의 모든 파일 이름들이다.

기존에 makefile에서 사용된 자동 변수 심볼들을 사용하면, 위 코드는 다음과 동일하다.

CXX := c++
CXXFLAGS := -g

OBJECTS := main.o function.o

# Link
program: $(OBJECTS)
    $(CXX) main.o function.o -o program

# Compilation
%.o: %.c
    $(CXX) $(CXXFLAGS) -c $< -o $@

 

참고: 많이 사용되는 자동변수들

구분 설명
$@ 현재의 목표 파일이다.
$* 확장자가 없는 현재의 목표 파일이다.
예를 들어, 목표 파일명이 `foo.c`라면, `$*`는 `foo`가 된다. 
$% 목표 파일이 archive member일 때, 목표 파일명이다.
예를 들어, 목표 파일명이 `foo.a(bar.o)`라면, `$@`은  `foo.a`이고, `$%`는 `bar.o`이다.
$< 첫번째 dependencies의 이름이다.
예를 들어, `all: library.cpp main.cpp` 라면, 
`$@`은 `all`이고,
`$<`은 `library.cpp`이며,
`$^`은 `library.cpp main.cpp`이다.
$^ 모든 dependencies의 이름들이다.
$? 현재의 목표 파일보다, 최근에 갱신된 dependencies의 이름들이다. 

$*: 확장자가 없는 현재의 목표 파일 (target) 이다.

$@: 현재의 목표 파일이다.

$<: 현재의 목표 파일보다 더 최근에 갱신된 파일 이름이다.

$?: 현재의 목표 파일보다 더 최근에 갱신된 파일 이름이다.

 

반응형

'SW 설계 > make' 카테고리의 다른 글

makefile 기초: 소개 및 실행 과정  (0) 2021.10.19
makefile 사용시 유용한 팁들!  (0) 2021.10.12