안녕하세요:)
최근 makefile을 분석할 일이 있어, 공부하며 정리한 내용을 포스팅해보려 합니다 ㅎㅎ
잘못된 정보는 댓글로 남겨주세요 ㅎㅎ
💡 make - GNU Uitilty to maintain gruop of programs 프로그램 그룹 중 어느 부분이 새롭게 컴파일되어야 하는지 자동적으로 판단해 필요한 커맨드(e.g. gcc)를 이용해 프로그램을 재컴파일하는 유틸리티.
💡 Makefile make의 입력이 되는 file로 쉘스크립트 언어와 유사하게 되어있으며, output file을 생성하기 위한 파일들 간의 관계, 명령어 등이 기술되어 있다.
Makefile Structure
Syntax
: Target, Dependancy, Command로 구성되어 있는 basic form 이 연속으로 나열되어 있다.
target : dependancy ...
command ...
command ...
- target : command가 수행되어 나온 결과.
- dependancy : target을 생성하기 위해 필요한 file.
- command : target을 생성하기 위한 command, target file이 존재하지 않거나 dependancy file이 수정되었을 때 command가 수행된다.
Macro
: Makefile 작성을 편리하게 해주는 변수 같은 개념이다.
OBJECT=main.o read.o write.o
test : $(OBJECT)
gcc -o test $(OBJECT)
- $ 기호를 사용해 정의한 macro를 사용한다.
Macro 생성
- = (recursively expand variable) : macro 내에서 다른 macro의 참조가 있을때, macro가 사용될 때 마다 recursive하게 참조를 확장한다.
foo=a
bar=$(foo)
echo $(bar) -> a
foo=b
echo $(bar) -> b bar 가 사용될때 마다 bar에 포함된 참조를 확장한다.
- := (simply expand variable) : macro 내에서 다른 macro의 참조가 있을때, macro 생성 시 참조에 대한 확장을 한번반 수행하여 상수처럼 동작한다.
foo=a
bar:=$(foo)
echo $(bar) -> a
foo=b
echo $(bar) -> a bar 가 생성될때 한번만 bar에 포함된 참조를 확장한다.
- += : 이미 정의된 macro에 text를 추가한다.
- ?= : macro가 정의되어 있지 않은 경우 macro를 생성한다.
Pre-defined Macro
: make가 내부적으로 사용하는 미리 정의된 macro로 사용자가 필요에 의해 재정의 하는 경우가 상당수 이지만, make의 내부적인 연산을 수행하기 위해 미리 정의되어 있다.
-p option으로 pre-defined macro 목록을 출력할 수 있다.
make -p
ex. CC, CXX, CFLAGS, CPPFLAGS, LD, LFLAGS 등 많은 매크로가 pre-define 되어 있다.
Internel macro
- $* : 확장자가 없는 target
- $@ : target
- $^ : dependancy
- $< : target 보다 최근에 갱신된 file list
- $? : target 보다 최근에 갱신된 file list
Label
: command를 실행하기 위한 목적의 구문으로 target 부분이 lable로 사용되며 dependancy가 없다.
clean : ______________ <- dependancy가 없으며 command 만 수행이 된다.
rm $(OBJECT)
Suffix Rule
: 파일들 간 확장자를 파악해 그에 따른 적절한 연산을 수행하는 규칙으로, command가 작성되지 않은 구문에 대해 .{target suffix}.(dependanch suffix) 의 이름으로 pre-define된 Lable을 실행한다.
ex) .c 를 .o로 compile하는 command가 작성되어 있지 않을 때, suffix rule에 의해 아래의 구문이 실행된다.
.c.o :
$(CC) $(CFLAGS) -C $< -o $@
즉, target과 dependancy간의 확장자의 관계를 파악해 .{target suffix}.(dependanch suffix) 의 이름으로 정의된 Lable을 실행한다.
.SUFFIXS
: suffix rule 에 의해 처리할 확장자를 등록하기 위한 pre-defined macro.
사용자가 suffix를 추가할 수 있으며, 그에 따른 lable(e.g. .c.o)를 정의해 원하는 작업을 수행하도록 할 수 있다.
Functions
💡 $([function name] [arguments ...]) 의 form으로 함수를 사용한다.
쉘 명령어 처리
$(shell [shell command])
: shell command의 실행결과를 리턴한다.
var=$(shell pwd)
echo $(var)
-------------------------------------
/home/yusang
문자열 처리
$(subst [from], [to], [string])
: string에 포함된 from을 to로 치환한다.
var=$(subst ee,EE,feet on the street)
echo $(var)
-------------------------------------
fEEt on the strEEt
$(patsubst [pattern], [replacement], [text])
: 공백문자로 구분된 단어 중에서 pattern과 매치되는 단어를 replacement로 치환한다. %가 와일드카드로 사용된다.
var=$(patsubst %.c,%.o,foo.c bar.c)
echo $(var)
-------------------------------------
foo.o bar.o
아래는 patsubst과 동일한 결과를 제공한다.
$(var:pattern=replacement)
$(sort [list])
: list에 있는 단어를 사전 순으로 정렬하며, 중복을 제거한다.
var=$(sort foo bar lose)
echo $(var)
-------------------------------------
bar foo lose
$(strip [string])
: string의 앞뒤에 있는 공백문자들을 제거하고 내부에 있는 하나 이상의 공백문자들을 단일 스페이스로 교체한다.
var=$(strip foo bar lose)
echo $(var)
-------------------------------------
foo bar lose
문자열 필터링
$(filter [pattern, ...], [text])
: 공백문자로 구분된 단어 중 pattern들과 일치하지 않는 단어를 제거하고 일치하는 단어들만 리턴한다.
sources := foo.c bar.c baz.s ugh.h
var=$(filter %.c %.s,$(sources))
echo $(var)
-------------------------------------
foo.c bar.c baz.s
$(filter-out [pattern, ...], [text])
: 공백문자로 구분된 단어 중 pattern들과 일치하는 단어를 제거하고 일치하지 않는 단어들만 리턴한다. fileter 함수와 반대의 기능을 수행한다.
sources := foo.c bar.c baz.s ugh.h
var=$(filter-out %.c %.s,$(sources))
echo $(var)
-------------------------------------
ugh.h
$(findstring [src], [string])
: string에서 src 를 찾는다. src가 존재하면 src를 리턴하고, 존재하지 않으면 ''(empty string)을 리턴한다.
var=$(findstring fo b, fo bar lose)
echo $(var)
-------------------------------------
fo b
$(word [index], [text])
: 공백문자로 구분된 단어들 중 index 번째 단어를 리턴한다. index 가 단어개 갯수보다 크다면 ''(empty string)을 리턴한다.
sources := foo.c bar.c baz.s ugh.h
var=$(word 3,$(sources))
echo $(var)
-------------------------------------
baz.s
$(wordlist [start], [end], [text])
: 공백문자로 구분된 단어들 중 start번째부터 end 번째 단어를 리턴한다.
sources := foo.c bar.c baz.s ugh.h
var=$(word 1, 3,$(sources))
echo $(var)
-------------------------------------
foo.c bar.c baz.s
$(firstword [text])
: 공백문자로 구분된 단어들 중 첫번재 단어를 리턴한다.
sources := foo.c bar.c baz.s ugh.h
var=$(firstword $(sources))
echo $(var)
-------------------------------------
foo.c
$(words [text])
: 공백문자로 구분된 단어들의 갯수를 리턴한다.
sources := foo.c bar.c baz.s ugh.h
var=$(words $(sources))
echo $(var)
-------------------------------------
4
파일 이름 처리
$(dir [file list])
: file list에 있는 각 파일 이름에서 디렉토리-파트를 리턴한다. 파일 이름의 디렉토리-파트는 그 안에 있는 마지막 슬래쉬까지의 (마지막 슬래쉬를 포함한)문자열이다. 파일 이름에 슬래쉬가 없으면 디렉토리 파트는 문자열 "./"가 된다.
sources := src/foo.c hacks
var=$(dir $(sources))
echo $(var)
-------------------------------------
src/ ./
$(notdir [file list])
: file list에 있는 각 파일 이름의 디렉토리-부분을 제외한 모든 것을 추출한다. 파일 이름에 슬래쉬가 없으면 값을 유지한다. 그렇지 않는 경우 마지막 슬래쉬까지 문자열이 제거된다.
sources := src/foo.c hacks
var=$(notdir $(sources))
echo $(var)
-------------------------------------
foo.c hacks
$(basename [file list])
: 각 파일 이름의 "."를 이후의 문자열을 제거한다. 파일 이름이 "."을 갖고 있다면 basename은 처음부터 마지막 "." 까지의 ("."은 포함하지 않음) 문자열이 된다. 디렉토리 부분에 있는 소숫점들은 모두 무시된다. "."이 없으면 basename은 전체 파일 이름이 된다.
sources := src/foo.c hacks src/bar.v1.c
var=$(basename $(sources))
echo $(var)
-------------------------------------
src/foo hacks bar.v1
$(suffix [file list])
: 각 파일 이름의 확장자를 리턴한다. 즉, 마지막 "." 이후의 문자열을 리턴한다("." 포함). "."가 포함되지 않다면 빈 문자열을 리턴한다.
sources := src/foo.c hacks src/bar.v1.c
var=$(suffix $(sources))
echo $(var)
-------------------------------------
.c .c
$(addsufiix [suffix], [file list])
: 각 파일 이름의 끝에 suffix 를 추가한다.
source=foo bar
var=$(addprefix .c, $(source))
echo $(var)
-------------------------------------
foo.c bar.c
$(addprefix [prefix], [file list])
: 각 파일 이름 처음에 prefix 를 추가한다.
source=foo.c bar.c
var=$(addprefix src/, $(source))
echo $(var)
-------------------------------------
src/foo.c src/bar.c
$(join [text1], [text2])
: text1과 text2의 concatenate를 수행한 결과를 리턴한다.
str1=foo.c
str2=bar.c
var=$(join str1, str2)
echo $(var)
-------------------------------------
foo.c bar.c
$(wildcard [pattern])
: 특정 파일 명칭 패턴을 통해 원하는 종류의 파일들을 불러오는데 사용한다. pwd는 Makefile이 있는 디렉토리이다.
var=$(wildcard ../target/*.c)
echo $(var)
-------------------------------------
../target/main.c ../target/source.c
- 와일드카드 문자(wildcard character)는 컴퓨터에서 특정 명령어로 명령을 내릴 때, 여러 파일을 한꺼번에 지정할 목적으로 사용하는 기호를 가리킨다. 이 문자는 어느 곳에서 사용하느냐에 따라 약간의 차이를 보인다. 주로 특정한 패턴이 있는 문자열 혹은 파일을 찾거나, 긴 이름을 생략할 때 쓰인다. 유닉스 계열 운영 체제에서 파일명이나 경로를 지정할 때 가장 흔히 쓰이는 와일드카드 문자는 별표 문자( * )인데, 이 문자는 0 이상의 모든 문자열로 치환된다. 예를 들어 a*는 a, ab, abc 등 a로 시작하는 모든 글자를 의미하며, 이와 비슷한 a+는 a를 제외한 모든 문자열(ab, abc 등, a 제외)로 치환된다.
$(foreach [var], [list], [text])
: 공백문자로 구분된 list의 단어들을 매 루프마다 var(macro)에 할당하고 var를 text에서 사용한 각각의 결과를 리턴한다.
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
- a b c d가 순서대로 dir의 이름을 가진 macro에 할당되어 $(wildcard $(dir)/*)문에서 사용된다. 이는 아래와 동일한 결과를 가져온다.
files := $(wildcard a/* b/* c/* d/**)*
- foreach 문에서 사용된 macro는 foreach문에서만 유효하다.
Etc.
$(origin [macro name])
: macro 가 정의된 방법을 리턴한다. macro 정의 방법에 따른 리턴값은 아래와 같다.
Return | Description |
undefined | Makefile 내에 정의되지 않음 |
file | Makefile 내에 정의되어 있음 |
environment | 환경변수 |
command line | |
environment override | |
automatic | |
override |
- 해당 macro의 값을 참조하는 것이 아니므로, 일반적으로 $으로 macro 이름을 감싸지 않는다.
var = $(origin HOME)
@echo $(var)
-------------------------------------
environment
여기까지 제가 공부하며 정리한 내용입니당.
지적은 언제든 환영입니다!ㅎㅎㅎ
refs)
* http://doc.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make.html#toc2
GNU Make 강좌
doc.kldp.org