Text Functions

기본적으로 space 로 분리된 단어들을 대상으로 함수가 처리되지만 subst, findstring, strip 함수는 전체 스트링을 대상으로 처리가 됩니다.

$( subst from , to , text )

text 에서 fromto 로 모두 치환합니다.

전체 스트링을 대상

text := foo bar zoo

$(subst oo,xx,$(text))
결과: fxx bar zxx

$(subst oo ba,x,$(text))
결과: fxr zoo

$(subst oo b,,$(text))
결과: far zoo

$( patsubst pattern , replacement , text )

text 에있는 space 로 분리된 파일 리스트에 pattern 을 적용하여 replacement 로 치환합니다. 패턴에는 % 문자가 사용되는데 일반 문자로 사용할 경우 \ 로 escape 하면 됩니다. leading, trailing space 가 있을 경우 제거되고 단어 사이에 여러 개의 space 가있을 경우 하나만 남게 됩니다.

files := xa xab xabc
$(patsubst x%,y%,$(files))                      # $(files:x%=y%) 와 같다.
# 또는
$(patsubst x%,y%,xa xab xabc)
결과: ya yab yabc

files := aaa.c bbb.c ccc.c
$(patsubst %.c,%.o,$(files))                    # $(files:%.c=%.o) 
# 또는
$(patsubst %.c,%.o,$(wildcard *.c))
결과: aaa.o bbb.o ccc.o

files := aaa.c bbb.c ccc.c
$(patsubst %,src/%,$(files))                    # $(files:%=src/%)
# 또는
$(patsubst %,src/%,$(wildcard *.c))
결과: src/aaa.c src/bbb.c src/ccc.c

files := foo/aaa.c foo/bbb.c foo/ccc.c
$(patsubst foo/%,bar/%,$(files))                # $(files:foo/%=bar/%))
# 또는
$(patsubst foo/%,bar/%,$(wildcard foo/*.c))
결과: bar/aaa.c bar/bbb.c bar/ccc.c

files = src/aaa/module.mk src/aaa/bbb/module.mk src/ccc/ddd/module.mk
$(patsubst src/%/module.mk,%,$(files))          # $(files:src/%/module.mk=%) 
결과: aaa aaa/bbb ccc/ddd

다음은 디렉토리 명에서 / 문자를 제거합니다.

sh$ ls
foo/  bar/  zoo/  Makefile  tmp.txt
---------------------------------------

$(info $(wildcard */))                     $(info $(patsubst %/,%,$(wildcard */)))

######  실행 결과  ######                    ######  실행 결과  ######
sh$ make                                   sh$ make
foo/ bar/ zoo/                             foo bar zoo

$( strip text )

Leading, trailing space 가 있을 경우 제거되고 또한 중간에 space 가 여러개 있을 경우 하나만 남습니다.
( space 값은 empty 가 아니므로 기본적으로 true 에 해당합니다. )

text := foo     bar zoo   #
$(info xxx$(text)xxx)
결과: xxxfoo     bar zoo   xxx     # $(text) 값의 끝에 공백이 포함됨

$(info xxx$(strip $(text))xxx)
결과: xxxfoo bar zooxxx

# 값을 비교하기 전에 strip 함수를 이용하여 space 를 제거
ifeq "$(strip $(foo))" ""
    . . .
endif

$( findstring str , text )

text 스트링에서 str 스트링을 찾아서 매칭이 존재할 경우 str 값이 출력됩니다.
존재하지 않을 경우는 empty 값이 출력됩니다.

전체 스트링을 대상

text := foo bar zoo   

$(findstring oo,$(text))
결과: oo

$(findstring oo ba,$(text))
결과: oo ba

$(findstring oo    ba,$(text))
결과:                          # empty

$(findstring foX,$(text))
결과:                          # empty

$( filter pattern... , text )

text 에서 pattern... 과 매칭되는 단어들을 추출합니다. 패턴에는 % 문자가 사용됩니다.

files := foo.c bar.c baz.s ugh.h

$(filter %.c %.s,$(files))
결과: foo.c bar.c baz.s            # ugh.h 는 제외됨

$(filter foo.c,$(files))          # 직접 파일명을 사용해도 된다.
결과: foo.c                        

$(filter foo,$(files))            # 부분 매칭은 안된다.
결과:

$( filter-out pattern... , text )

이것은 위의 filter 함수와 반대로 pattern... 과 매칭되는 단어들을 out 시키고 나머지를 출력합니다.

files := foo.c bar.c baz.s ugh.h
$(filter-out %.c %.s,$(files))
결과: ugh.h                       # foo.c bar.c baz.s 가 제외됨

$( sort list )

sort 함수는 두 가지 기능이 있는데

  1. list 에 포함된 단어들을 정렬하여 출력합니다. ( single space 로 분리 )
  2. 중복되는 단어가 있을 경우 하나만 남습니다. ( 중복제거 )
list := foo foo     bar   zoo
$(sort $(list))
결과: bar foo zoo     # 중복이 제거되고 single space 로 분리되어 출력된다.

$( word n , text )

text 에서 n 번째 단어를 출력합니다. ( 시작은 1 부터 입니다. )

$(word 2, aaa bbb ccc ddd eee)
결과: bbb

$( wordlist s , e , text )

text 에서 s 번째 부터 e 번째 까지의 단어를 출력합니다. ( 시작은 1 부터 입니다. )

$(wordlist 2, 4, aaa bbb ccc ddd eee)
결과: bbb ccc ddd

$( words text )

text 에 포함된 단어의 개수를 출력합니다.

text := foo bar zoo
$(words $(text))
결과: 3

$( firstword names... )

names... 에서 첫 번째 단어를 출력합니다.

names := foo bar zoo
$(firstword $(names))
결과: foo

$(word 1,$(names))   # 같은 결과
결과: foo

$( lastword names... )

names... 에서 마지막 단어를 출력합니다.

names := foo bar zoo
$(lastword $(names))
결과: zoo

$(word $(words $(names)),$(names))    # 같은 결과
결과: zoo

Quiz

make 에서 사용하는 script 기능에는 스트링을 비교할 수 있는 equal 연산자도 없습니다. 그렇다고 equal 연산을 하지 못하는 것은 아닌데요. 어떻게 두 개의 스트링 값을 비교할 수 있을까요?

AA := foobar

# 다음과 같이 filter 함수를 사용하면 됩니다.
$(if $(filter foobar,$(AA)),$(info yes),$(info no))
결과: yes

# filter 함수는 단어 전체가 매칭돼야 합니다.
$(if $(filter foo,$(AA)),$(info yes),$(info no))
결과: no

# findstring 함수는 부분만 매칭이 되어도 yes 가 됩니다.
$(if $(findstring foo,$(AA)),$(info yes),$(info no))
결과: yes

다음은 multi-word 비교 입니다.

AA := hello text functions

res := $(if $(and \
    $(filter hello,$(word 1,$(AA))), \
    $(filter text,$(word 2,$(AA))), \
    $(filter functions,$(word 3,$(AA)))), \
    yes,no)

$(info $(res))
결과: yes

또는 shell 함수를 이용해 외부 명령을 사용해도 됩니다.

AA := hello text functions

res := $(if $(shell test "$(AA)" = "hello text functions" && echo 1 ), \
        yes,no)

$(info $(res))
결과: yes