|
CS/Shell/Perl/Python 2011. 6. 8. 16:43
원문 : GNU make
8.4 Functions for Conditionals
조건 표현을 제공하는 세 가지 함수가 있다. 모든 인자가 초기에 확장되지 않는다는 것이 이 세 함수의 중요한 면이다. 인자 중 확장되기를 원하는 인자만이 확장된다.
- $(if condition, then-part [,else-part])
if함수는 함수적 문맥에서 조건적 확장에 대한 지원을 제공한다.
첫 번째 인자인 condition은 먼저 모든 시작과 끝의 공백 문자를 제거하고, 그 이후에 확장된다. 만약 확장이 non-empty 문자열이라면 그 조건은 참으로 간주되며, 그렇지 않은 경우 거짓으로 간주된다.
만약 조건이 참이라면 두 번째 인자인 then-part가 평가되고, 이것이 if 함수 전체 평가의 결과로 사용된다.
만약 조건이 거짓이라면 세 번째 인자인 else-part가 평가되고, 이것이 If 함수 전체 평가의 결과로 사용된다. 만약 세 번째 인자가 없다면, if 함수는 아무것도 평가하지 않는다.
주의할 것은 오직 the-part나 else-part만 평가되고, 두 부분이 모두 평가되지 않는다는 것이다. 따라서 side-effect가 발생할 수 있다.
- $(or condition1 [, condition2 [, condition3 ...]])
or 함수는 "short-circuiting" OR 연산을 제공한다. 각 인자는 순서대로 확장된다. 만약 인자가 non-empty 문자열로 확장된다면 처리는 멈추고 그 확장의 결과가 결과 문자열이 된다. 만약 모든 인자가 확장되었고 모두가 거짓(empty)이라면, 확장의 결과는 빈 문자열이다.
- $(and condition1 [, condition2 [, condition3 ...]])
or 함수는 "short-circuiting" AND 연산을 제공한다. 각 인자는 순서대로 확장된다. 만약 인자가 empty 문자열로 확장된다면 처리는 멈추고 그 확장의 결과가 결과 문자열이 된다. 만약 모든 인자가 non-empty string으로 확장되었다면, 확장의 결과는 마지막 인자의 확장이 된다.
.
CS/Shell/Perl/Python 2011. 6. 8. 15:18
원문 GNU make
7.1 Example of a Conditional
다음 예제는 CC변수가 gcc인 경우에 make가 라이브러리들 중 하나의 셋을 사용하게 하고, gcc가 아닌 경우에는 다른 라이브러리 셋을 사용하게 한다.
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
혹은, 다음과 같이 변수를 조건부로 할당하고, 변수를 명시적으로 사용할 수도 있다
libs_for_gcc = -lgnu
normal_libs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
foo: $(objects)
$(CC) -o foo $(objects) $(libs)
7.2 Syntax of Conditionals
syntax는 else가 없는 다음의 가장 간단한 형태부터 else를 포함한 두가지 형태가 있다.
conditional-directive
text-if-true
endif
conditional-directive
text-if-true
else
text-if-false
endif
conditional-directive
text-if-true
else
text-if-false
else
text-if-false
endif
조건을 테스트하는데는 다음의 4가지 지시자가 있다
- ifeq
- iffeq (qrg1, arg2)
- ifeq 'arg1' 'arg2'
- ifeq "arg1" "arg2"
- ifeq "arg1" 'arg2
- 'ifeq 'arg1' "arg2"
arg1과 arg2에 있는 변수의 참조를 모두 확장하여 그들을 비교한다. 만약 일치한다면 text-if-true 가 적용된다.
- ifneq
- ifneq (qrg1, arg2)
- ifneq 'arg1' 'arg2'
- ifneq "arg1" "arg2"
- ifneq "arg1" 'arg2'
- ifneq 'arg1' "arg2"
arg1과 arg2에 있는 변수의 참조를 모두 확장하여 그들을 비교한다. 만약 일치하지 않는다면 text-if-true 가 적용된다.
- ifdef variable-name
name은 변수에 대한 레퍼런스가 아니라 변수의 이름을 나타낸다.
bar = true
foo = bar
ifdef $(foo)
frobozz = yes
endif
$(foo)는 확장되어 bar가 되고, bar는 참조가 아니라 이름으로 간주된다.
만약 variable-name이 non-empty 값이 아니라면 text-if-true 가 적용된다.
ifdef는 변수를 확장하여 그 값이 비어있는지는 확인하지 않는다(그 이름이 정의 되어 있는지만 확인). non-empty인지 확인하기 위해서는 ifeq($(foo),)를 사용한다.
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
sets ‘frobozz’ to ‘yes’, while:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
sets ‘frobozz’ to ‘no’.
- ifndef variable-name
만약 vraiable-name이 empty 값이라면, text-if-true 가 적용된다.
7.3 Conditionals that Test Flags
findstring 함수와 함께 MAKEFLAGS 변수를 사용하여 -t 와 같은 make command flags를 테스트하는 조건을 쓸 수 있다.
이것은 touch가 파일을 갱신하는데 충분하지 않을 때 유용하다.
findstring 함수는 한 문자열이 다른 부분 문자열로 나타나는지 확인한다. 만약 '-t' 플래그에 대해서 테스트하길 원한다면, 첫번째 문자열로 't'를 사용하고 비교할 다른 문자열로 MAKEFLAGS의 값을 사용한다.
다음은 아카이브 파일을 갱신하는 것에대해 마킹하는것을 종료하기 위해 'ranlib -t'를 사용하는것을 어떻게 정리하는지를 보여준다.
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
+touch archive.a
+ranlib -t archive.a
else
ranlib archive.a
endif
'+' 접미어는 명령행 라인이 '-t' 플래그를 사용했음에도 불구하고 실행될 수 있게 하기 위해 "recursive" 하다는 것을 표시한다. (Section 5.7 Recursive Use of make 참고)
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 에서는 변수가 값을 갖도로 하는 네 가지 방법이 있다.
- 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
와 같이 한 경우, 변수 확장에 의해 무한 루프를 돌게 된다.
- 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를 정의한다.
|