[MAKE] How to Use Variables

CS/Shell/Perl/Python 2011. 6. 8. 06:52
원문 : GNU make

6.1 Basics of Variable References


변수 이름에는 대문자를 사용하는 것이 관행이다.
하지만, makefile 안에서 internal purpose 을 수행하는 것은 소문자를 사용하고,  암묵적인 규칙을 제어하는 파라매터나 컴맨드 옵션에서 사용자가 오버라이드 해야만 하는 파라메터에 대해서는 대문자로 예약할 것을 것을 권장 한다.

$(foo) 나 ${foo} 와 같이 변수 이름을 () 나 {}로 감사고 $를 붙여서 참조할 수 있다.

6.2 The Two Flavors of Variables


GNU make 에서는 변수가 값을 갖도로 하는 네 가지 방법이 있다.
  1. recursive expanded variable 
    이 종류의 변수는 '='를 통해서 정의하거나(Section 6.5 [Setting Variables] 참고), define 지시자를 통해서 정의될 수 있다.
    만약 다른 변수에 대한 참조를 포함하고 있다면, 이 참조는 이 변수가 치환될 때마다 확장된다.

    foo = $(bar)
    bar = $(ugh)
    ugh = Huh?

    all:;echo $(foo)
    에서 $(foo)는 $(bar)로 확장되고, 이것은 다시 $(ugh)로  확장되어, 최종적으로 Huh? 로 확장될 것이다.


    이 종류의 변수는 모든 다른 make에서도 지원한다. 하지만

    CFLAGS = $(include_dirs) -O
    include_dirs = -Ifoo -Ibar

    CFLAGS = $(CFLAGS) -O 

    와 같이 한 경우, 변수 확장에 의해 무한 루프를 돌게 된다.

  2. expanded variable
    변수가 정의될 때 어떤 다른 변수나 함수에 대한 참조를 확장하여 한번만 스캔 되고 확장된다. 즉, 이 변수가 정의 되었을 때의 값을 가진다.

    x := foo
    y := $(x) bar
    x := later
    는,
    y := foo bar
    x := later 
    와 같다.  


  •  ?=를 이용해서 변수가 정의되어 있지 않을때만 정의할 수 있다.

    FOO ?= bar 는

    ifeq ($(origin FOO), undefined)
        FOO = bar
    endif

    와 동일하다. 


     만약 bar 가 정의되어 있지 않았을 때 FOO = bar 와 같이 한다면, FOO는 empty value로 정의된 상태가 된다.

  •  +=를 이용하여 이미 정의된 변수의 값에 추가로 문자를 더할 수 있다.

    objects = main.o foo.o bar.o utils.o
    objects += another.o


    +=를 사용하는 것은 :=를 다음과 같이 사용하는 것과 유사하다. 

    objects = main.o foo.o bar.o util.o
    objects := $(objects) another.o 

     
    만약 +=로 덧붙일 변수가 이전에 정의되어 있지 않았다면, +=는 =(recursively-expanded variable)과 동일하게 동작한다. 

6.3 Advanced Features for Reference to Variables


  • substitution reference
    지정한 대치값으로 변수의 값을 치환한다.  $(var:a=b) 혹은 ${var:a=b}와 같은 형식으로 사용되며, var 변수에 있는 a로 끝나는(다음에 whitespace가 나오는 a) 모든 a를 b로 치환한다.

    foo := a.o b.o c.o
    bar := $(foo:.o=.c)

    는 bar 를 a.c b.c c.c 로 치환한다.

    이는, 사실상 patsubst(Section 8.2 [Functions for String Substitution and Analysis] 참고) 함수 확장의 축약형이다. patsubst 함수의 모든 기능을 사용하기 위해서는 $(var:%a=%b)와 같이 %를 덧붙임 형태를 사용해야 한다. 

    foo := a.o b.o c.o
    bar := $(foo:%.o=%.c) 

    는 $(patsubst .o,.c,$(var))와 동일하다. 


  • computed variable name (nested variable reference)
     변수들은 변수의 안에 있는 이름으로 참조될 수 있다. 이를 computed variable name 혹은 nested variable reference라고 한다. 예를 들어

    x = y
    y = z
    a :=$($(x))

    에서 $($(x)는 $(y)가 되어, 결국 z가 된다.


    혹은 재귀적으로

    x = $(y)
    y = z
    z = Hello
    a := $($(x))

    에서 $($(x)) 는 $($(y))가 되고, 이것은 $(z) 가 되어, 결국 Hello가 된다. 


    Nested variable 참조는 변경된 참조나 함수 실행(Chapter 8 [Functions for Transforming Text] 참고) 등을 포함할 수 있다. 예를 들어 subst 함수를 사용하여

    x = variable1
    variable2 := Hello
    y = $(subst 1,2,$(x))
    z = y
    a := $($($(z))))

    $($($(z)))는 $($(y))가 되고, y는 variable2의 값을 가지게 되기 때문에,  $(variable2)가 되어, 결국 Hello를 정의하게 된다. 


    computed variable name은 하나의 변수 참조로 이루어질 필요는 없다. 예를 들어

    a_dirs := dira dirb
    1_dirs := dir1 dir2

    a_files :=filea fileb
    1_files :=file1 file2

    ifeq "$(use_a)" "yes"
        a1 := a
    else
        a1 := 1
    endif

    ifeq "$(use_dirs)" "yes"
        df := dirs
    else
        dif := files
    endif

    dirs := $($(a1)_$(df))

    $(a1) 이 a를 정의하고 $(df)가 dirs를 정의한다면, a_dirs가 되어 dirs 는 $(a_dirs)가 되어 결국,
    dirs := dira dirb
    를 정의하게 된다.

     
    computed variable name은 치환 참조에서도 사용될 수 있다.

    a_objects := a.o b.o c.o
    1_objects := 1.o 2.o c.o

    sources := $($(a1)_objects:.o=.c)
    는 a1이 어떤것을 가리키느냐에 따라

    sources := a.c b.c c.c
    혹은
    sources :=1.c 2.c 3.c
    가 될 수 있다. 


    또한, computed variable name을 변수 대입의 왼편이나 define 지시자에서 사용할 수 있다.

    dir = foo

    $(dir)_sources := $(wildcard $(dir)/*.c)

    define $(dir)_print = 
     
    lpr $($(dir)_sources)

    endef

    이는 foo_sources와 foo_print를 정의한다. 



: