개발자라고 하면, Make를 모르는 사람이 없을 것이지만, 직접 Makefile을 처음부터 작성해야하는 일은 요즘 드문일 같다.
하지만, Makefile을 수정해야하는 일과 간혹은 처음부터 만들어야 하는 경우가 존재하며,
그때마다 opensource의 Makefile 파일을 참조하면서 보게 되지만, 매번 Makefile을 작성하기가 힘이 든다. 그래서 아래와 같이 정리하고 한다.
보통 Linux에서는 GNU Make사용하지만 다른 플랫폼에서 사용되는 Make와 완벽하게 호환이 된다고 착각하지 말기 바란다.
기본규칙과 GNU Make 내부 규칙을 가급적 분리해서 알아야 두면 편하다.
2. Make의 기본구성 및 구조
GNU Make or Make의 기본구성은 3가지로 구성 되며, 각 용어와 구성내용을 알아보자.
Makefile 분석을 하면 항상 기본형태는 아래와 같이 구성이 되며, 세부내용들은
천천히 메뉴얼과 함께 봐야할 부분들이다.
https://www.gnu.org/software/make/manual/html_node/Rule-Syntax.html#Rule-Syntax
2.1 Make의 기본구성의 규칙
Make의 Rule은 위에서 언급한 target prerequisites recipe 의 다양한 기능과 구조를 익히면될것 같다.
자세한 내용은 아래의 링크된 Manual을 참조
target 는 wildcard 와 변수도 사용가능하며, 다중 target 등에 다양하게 사용이 가능하다.
target의 특정목적의 target도 존재하니 이부분도 익혀두자.
normal-prerequisites | order-only-prerequisites
1. normal-prerequisites
target 보다 먼저 순서적으로 prerequisites 진행하지만, 종속적인 관계를 유지하고
prerequisites가 target 보다 시간적으로 새거라면 현재 target은 쓸모가 없어지고 동작되지 않는다.
쉽게말해서 빌드 할경우 수정하지 않은 파일을 빌드하지 못하게하는 기능이라고 생각하면된다.
위에서 의 기준은 항상 시간이며, 빌드를 할 경우 수정된 시간은 Make에게 중요하게 영향을 미친다.
2. order-only-prerequisites
위와 상관없이 강제로 순서대로 실행하는 방법이다.
https://www.gnu.org/software/make/manual/html_node/Rules.html#Rules
http://korea.gnu.org/manual/4check/make-3.77/ko/make_4.html#SEC19
그리고, 이부분이 핵심이기에 이 부분은 따로 분리해서 설명하겠다.
https://www.gnu.org/software/make/manual/html_node/Recipes.html#Recipes
2.2 Make의 기본규칙
Make의 기본구성과 그 사용법을 알았으니, 자세한 동작방식에 대해 알아보자
이를 알아보려면, Make 내부에서 암묵적으로 사용하되는 변수들을 알아야한다.
주의사항이 이 내용은 filename에만 적용이 되고, shell에 의존적이다.
TEST를 위해 아래와 같이 구성했다
https://www.gnu.org/software/make/manual/html_node/Wildcards.html#Wildcards
많은도움을 받는다.
https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-8.html
https://www.gnu.org/software/make/manual/html_node/Appending.html#index-appending-to-variables
https://www.gnu.org/software/make/manual/html_node/Shell-Function.html#Shell-Function
공통된 규칙은 '$'로 시작이되며, target과 prerequisites 을 기준으로 이 변수를 사용을 한다.
사용되는곳은 recipe에서 주로 적용하여 사용한다.
사실 매번 사용법을 잊어버려 Manual을 보기때문에, 자세한 내용은 Manual을 보자.
주의사항은 prerequisite은 동작모드가 2가지 모드이니 이부분을 잘 이해하고 보기바란다.
https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
많이 사용되는 것 두개를 다루면 다른 Special Target은 Manual 참조
.POHNY : target 과 filename을 구분과 성능향상을 위해서 사용
.SUFFIXES : The prerequisites of the special target, 즉 prerequisites의 접미사 규칙
https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets
https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-3.html
특히 임베디드에서는 이부분을 별도로 설정을 해야한다.
https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#Implicit-Variables
정확히 말해 Suffix 의 Pattern을 변경할때 필요하다.
GNU Make or Make의 기본구성은 3가지로 구성 되며, 각 용어와 구성내용을 알아보자.
Makefile 분석을 하면 항상 기본형태는 아래와 같이 구성이 되며, 세부내용들은
천천히 메뉴얼과 함께 봐야할 부분들이다.
- targets : targets 으로 말하며, file name도 있으며, 일종 함수 같은 존재
- prerequisites : 현재 targets의 recipe를 실행하기전에 다른 targets 들을 순차적으로 호출
- recipe : 실제 동작하는 기능이며, command 및 shell script 내부구현.
targets : prerequisites recipe … # prerequisites는 스페이스로 구분자를 사용한다. targets : prerequisites ; recipe recipe .... # 세미콜론은 prerequisites 의 종료를 의미한다.
- Simple Test Example
TARGET = MainTest # Makefile안에 변수가 사용이 가능 # 변수는 암묵적으로 사용가능한 변수도 존재 CFLAGS, LDFLAGS OBJS = tst1.o tst2.o # tst1.o tst2.o tst1.c와 tst2.c의 filname이며, target 지정가능 # Make 내부에 기본적으로 설정된 규칙이 있으며, SUFFIX 및 PATTERN에 의해 변경가능 # 작성자가 규칙과 세부설정을 선언하지 않았다면 기본규칙처리 # make를 실행하면 기본으로 all이 실행된다. all: $(TARGET) # $(OBJS)는 prerequisites들 중 하나이므로 먼저 실행 한다 . 최종 $(TARGET) 실행한다. # $(TARGET): $(OBJS) @echo --------------------------------- @echo Test Result Program @echo --------------------------------- @echo $? # # $? 는 The names of all the prerequisites 이므로, tst1.o , tst2.o 출력 # clean: @rm -rf *.o # @ 는 echo의 실행화면을 감춘다.
https://www.gnu.org/software/make/manual/html_node/Rule-Syntax.html#Rule-Syntax
2.1 Make의 기본구성의 규칙
Make의 Rule은 위에서 언급한 target prerequisites recipe 의 다양한 기능과 구조를 익히면될것 같다.
자세한 내용은 아래의 링크된 Manual을 참조
- target 의 다양한 기능
target의 특정목적의 target도 존재하니 이부분도 익혀두자.
- prerequisites의 기능 및 자동기능
normal-prerequisites | order-only-prerequisites
1. normal-prerequisites
target 보다 먼저 순서적으로 prerequisites 진행하지만, 종속적인 관계를 유지하고
prerequisites가 target 보다 시간적으로 새거라면 현재 target은 쓸모가 없어지고 동작되지 않는다.
쉽게말해서 빌드 할경우 수정하지 않은 파일을 빌드하지 못하게하는 기능이라고 생각하면된다.
위에서 의 기준은 항상 시간이며, 빌드를 할 경우 수정된 시간은 Make에게 중요하게 영향을 미친다.
2. order-only-prerequisites
위와 상관없이 강제로 순서대로 실행하는 방법이다.
https://www.gnu.org/software/make/manual/html_node/Rules.html#Rules
http://korea.gnu.org/manual/4check/make-3.77/ko/make_4.html#SEC19
- recipe 의 규칙
그리고, 이부분이 핵심이기에 이 부분은 따로 분리해서 설명하겠다.
https://www.gnu.org/software/make/manual/html_node/Recipes.html#Recipes
2.2 Make의 기본규칙
Make의 기본구성과 그 사용법을 알았으니, 자세한 동작방식에 대해 알아보자
이를 알아보려면, Make 내부에서 암묵적으로 사용하되는 변수들을 알아야한다.
- Make 내부에서 Filename에서 wildcard 사용법
주의사항이 이 내용은 filename에만 적용이 되고, shell에 의존적이다.
TEST를 위해 아래와 같이 구성했다
$ ls Makefile build clean cst.c dst.c est.c print1 tst1.c tst11.c tst2.c tst22222.c tst3.c // *.c 는 전부 동일한 file 로 구성, build clean print1 는 diretory 이는 PHONY Target을 테스트 $ cat tst1.c // 전부 동일한 file들 #includeint test01() { printf("TEST 01 \n"); return 0; }
$ vi Makefile all: build ## filename or directory 와 구분 및 성능 향상이용 .PHONY: print1 print2 print3 build clean ### 규칙에 적용될 filename SRC1 = *.c ## wildcard '*' , 모든 filename SRC2 = $(wildcard *.c) ## Make 내부함수이용 $(SRC1) 동일 SRC3 = tst?.c ## wildcard '?' , filename 중 한 charter 선택 SRC3 ?= cst*.c ## SRC3 변수가 선언이 안되었다면 설정이 된다. SRC5 += $(SRC3) est*.c SRC6 += $(SRC3) dst*.c # 고급스럽게 ,shell 이용해보자. FILES := $(shell echo *.c) # build를 하기 위해서 모든 *.c를 *.o로 변경 # 아래와 같이 $(var)에서 pattern을 replaements로 변경한다. # $(wildcard *.c) 모든 *.c를 에서 %.c ->%.o 로 변경 # # $(patsubst pattern,replacement,$(var)) OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) # *.c를 *.o로 변경 ## wildcard '*' , 모든 filename clean: @rm -f *.o # print1 과 print2 는 결과 동일 print1: ${SRC1} @echo $? print2: ${SRC2} @echo $? # @cat $? # tst1.c tst2.c tst3.c print3: ${SRC3} @echo $? # @cat $? # tst1.c tst2.c tst3.c est.c print4: ${SRC5} @echo $? # tst1.c tst2.c tst3.c dst.c print5: ${SRC6} @echo $? # print1,2와 동일 files: ${FILES} @echo $? # buld *.o로 변경이 되었기 때문에 build build: ${OBJS} @echo $?
https://www.gnu.org/software/make/manual/html_node/Wildcards.html#Wildcards
- 기본예제
- 에러처리 (중요)
많은도움을 받는다.
https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-8.html
- Make 의 변수 설정 및 추가
https://www.gnu.org/software/make/manual/html_node/Appending.html#index-appending-to-variables
https://www.gnu.org/software/make/manual/html_node/Shell-Function.html#Shell-Function
- Make 의 Automatic Variables (자동변수)
공통된 규칙은 '$'로 시작이되며, target과 prerequisites 을 기준으로 이 변수를 사용을 한다.
사용되는곳은 recipe에서 주로 적용하여 사용한다.
사실 매번 사용법을 잊어버려 Manual을 보기때문에, 자세한 내용은 Manual을 보자.
주의사항은 prerequisite은 동작모드가 2가지 모드이니 이부분을 잘 이해하고 보기바란다.
- $@ : The file name of the target of the rule. (반드시 알아두자)
- $% : The target member name
- $? : The names of all the prerequisites
- $< : The name of the first prerequisite
- $| : The names of all the order-only prerequisites
https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
- Make의 Special Target
많이 사용되는 것 두개를 다루면 다른 Special Target은 Manual 참조
상위에서도 간단하게 작성했지만, target의 이름과 동일한 filename or directory가 존재한다면,
make가 문제가 생긴다. 이를 방지하고자 사용하며, 이를 이용하면, 이를 체크할 필요가 없기에 성능이 향상이 된다.
.SUFFIXES : .c .o .SUFFIXES : .cpp .o ## 본인이 정의 하면 된다. .c.o: ## 이와 같이 직접 정의 해줘도 정의 해줘도 되며, 세부설정이 가능하다. $(CC) $(CFLAGS) $(INC_DIR) -c $<
https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets
https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-3.html
- Make의 빌드에 관련된 변수 (Implicit-Variables)
특히 임베디드에서는 이부분을 별도로 설정을 해야한다.
https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#Implicit-Variables
- Make의 Pattern Rule
정확히 말해 Suffix 의 Pattern을 변경할때 필요하다.
Pattern Rule만 소개
https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html#Pattern-Rules
Old Style Pattern 규칙
https://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html#Suffix-Rules
2.3 Make의 기능의 확장
상위에서도 간단하게 사용했지만, GNU make 내부에 함수가 존재하며, 아래와 같이
이를 이용하면 편한하게 Make 작성이 가능하다.
- Make 내부 안에서 사용가능한 함수 (중요)
$(subst from,to,text) // 대체하는 함수 $(subst ee,EE,feet on the street) // fEEt on the strEEt’, ee->EE 대체
$(filter pattern…,text) // filter 역할함수 sources := foo.c bar.c baz.s ugh.h foo: $(sources) cc $(filter %.c %.s,$(sources)) -o foo // foo.c bar.c baz.s 만 빌드
$(foreach var,list,text) // shell script의 반복문과 유사하다 , text는 결과로 생각하면 되겠다. dirs := a b c d files := $(foreach dir,$(dirs),$(wildcard $(dir)/*)) // a/* b/* c/* /d*
https://www.gnu.org/software/make/manual/html_node/Functions.html#Functions
- Make 내부의 조건문 (변수와 함께 사용)
ifeq ($(CC),gcc) $(CC) -o foo $(objects) $(libs_for_gcc) else $(CC) -o foo $(objects) $(normal_libs) endif
https://www.gnu.org/software/make/manual/html_node/Conditionals.html#Conditionals
https://www.gnu.org/software/make/manual/html_node/Conditional-Example.html#Conditional-Example
https://www.gnu.org/software/make/manual/html_node/Conditional-Syntax.html
3. Make의 recipe 구현
make의 recipe는 실제의 동작이며, 가장 중요한 부분이기에 어떻게 사용할 것인지,
응용은 어떻게 할것인지에 대해 좀 자세히 알아보자
3.1 recipe의 Linux command 적용
Linux 내부에서 사용되는 다양한 command를 이용하여, Make 에 적용하는 방법이다.
가장 많이 사용하는 command를 아래와 같이 구성했으며, 이를 보고 간단히 구현을 해보자.
@는 command의 실행을보여주지 않는다.
`` 먼저 이 command를 실행한 후 결과를 연결해준다. (파이프 개념) (stdout -> stdin)
export를 이용하여 변수에 할당 및 변수값 조정을 했었는데, 이부분은 지금 힘든것 같다.
(다른방법으로 찾아보자, 가능하면 user mode에서 해결하자 )
$ vi Makefile test: @echo finished sub direcory clean: @rm -rf *.o install: install -d $(DESTDIR) ## 존재하지 않는 디렉토리 생성 install ./MainTest $(DESTDIR) ##생성 후 이를 이 디렉토리에 복사 test-version-recur1: @echo Building other program1 ##다른 Make program 관리 @cd test-rec; cd `find . -name "*test*"`; make CROSS_COMPILE=$(CROSS_COMPILE) test-version-recur2: @echo Building other program2 ##다른 Make program 관리 make -J 2 -C $(TEST_PATH)/test-* ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) ## @을 사용하면, 사용하는 command 실행되는 과정을 안보이게 할수 있다.
3.2 Make의 recipe 에 script 적용
Shell Script의 기능을 Make 안에 적용하는 것이지만 변수 사용법 이부분은 아래의 변수사용법 참조
이를 이용하면 좀 더 복잡하고 정교한 Make를 만들 것이 가능하다.
이 뿐만 아니라, sed , awk 등 다양한 것을 적용가능하다.
기본 Script를 익혀서 이를 Makefile 내부에 적용을 해보자
- 주의 및 확인사항 ( 반드시 확인 )
- 보통 line이 길어지는 '\'을 사용하여 다음줄로 한다. 이때 '\' 다음에 \n로 하고 빈공간을 없애자.
- Script 내부에 세미콜론(;)을 주의하자
- Makefile은 탭이 중요하기때문에 다시 확인하자
- Script 실행되는 것을 되는것을 보이지 않게하려면 @사용하여 전체를 가리자.
- Loop 문의 구분자, 즉 변수들을 구분하는 구분자는 스페이스이다.
그리고 위에서 설명했듯이 Loop의 List 변수의 구분자는 스페이스 이다.
- Recipe 안의 변수 사용법
https://www.gnu.org/software/make/manual/html_node/Variables-in-Recipes.html
A. For Loop 예제-1 (recipe 안에서 $$사용)
- $SUB_DIRS에서 하나씩 가져와서 dir 변수를 사용하여 반복되는 Loop문 구조
- @을 한번사용하여 전체적용
@for dir in $(SUB_DIRS); do \ $(MAKE) -C $$dir clean; \ done
B. For Loop 예제-2
아래와 같이 1 2 3의 구분자는 스페이스이다.
- 상위와 같지만, 1,2,3을 직접넣어 변수 i에 작동하는 Loop 구조
- @을 하나를 사용하여 전체 적용하여, 변수는 $${i} or $$i로 사용
@for i in 1 2 3; \ do \ echo TEST$${i}_$$i ; \ done
C. For Loop 예제-3
- 상위와 기본구조가 같지만 이중루프로 동작
- @을 한번사용하여 전체적용
@for i in 1 2 3; \ do \ for j in 1 2 3 4 5; \ do \ echo TEST$${i}_$$j ; \ done; \ done
D. IF문 및 EXIT 예제-1 (File 및 Directory 존재 여부 확인)
- if 문 File 및 Diretory으로 점검하는 구조
- exit 1는 에러로 표시하여 추후 재귀호출시 에러점검.
@if [ -f test]; then \ echo "You have test file \ else \ echo You have no test file \ exit 1; fi @if [ ! -d $(DIR) ]; then \ echo "You have no test directory \ fi @if [ -e $(FILE) ]; then \ echo "You have test file \ fi @if [ -d test]; then \ echo "You have test directory \ else \ echo You have no test directory \ exit 1; fi
- IF/LOOP및 기타 기본예제
http://egaoneko.github.io/os/2015/05/24/linux-starter-guide-8.html#fnref:1
- IF/CASE 예제
- Bash Script 여러예제
- Bash Loop/awk 활용
4. GCC의 다양한 Option 설정
이부분은 상위 Implicit-Variables 와 연관이 있으며 Make 내부에 GCC의 옵션 변경을 할때 아래와 같이 GCC Manual을 이용하여 설정을 변경하자
아래의 GCC 옵션들은 GCC-5.4.0 기준이며, 본인이 사용하는 GCC version에 맞추어
문서를 찾아 Index를 찾으면 될 것이다.
- Index 주의사항
https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Option-Index.html#Option-Index
- ARM 용 별도의 option
5. Make의 관련 다양한 예제
Make의 기본 기능은 Target과 그의 종속된 Target 을 연결하여 실행하는 것이다.
그리고, Make를 재귀적용법으로도 실행을 하여 다른 Makefile을 제어도 가능하다.
- Simple Makefile
- 사용목적과 기본사용방법
https://www.joinc.co.kr/w/Site/C/Documents/minzkn_make
http://developinghappiness.com/?p=28
- Make의 재귀적 용법사용
- 일반적으로는 make -C 옵션을 주어 내부에서 재귀적으로 호출한다.
- 다른방법은 cd로 직접 해당주소로 가서 make를 실행을 한다.
- Make의 재귀적 용법의 다양한 예제
6. GNU Make Manual 관련사항
- GNU Make의 전체 Manual
http://korea.gnu.org/manual/4check/make-3.77/ko/make_toc.html
https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make.html#toc8
GNU Make의 Manual 내용이 많다보니, 상위 Manual에서도 아래와 같이 읽어보라고 권하고 있다.
- GNU Make의 Manual
- Introduction : 소개
- Features : 기본 기능
- Incompatibilities and Missing Features : 비호환성과 빠진 기능
- Special Target : 내부에 암묵적으로 사용가능한 Target
- Quick-Reference: Make에 익숙하다면, 많이 도움이되는 Page
- Options-Summary: Make의 재귀를 사용시 Make의 option 기능을 알수 있다.
https://www.gnu.org/software/make/manual/html_node/Features.html#Features
https://www.gnu.org/software/make/manual/html_node/Missing.html#Missing
https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets
https://www.gnu.org/software/make/manual/html_node/Quick-Reference.html#Quick-Reference
https://www.gnu.org/software/make/manual/html_node/Options-Summary.html#Options-Summary
- GNU Make Index
7. Kernel Makefile 관련내용
Kernel Makefile을 보면 상위부분은 복잡하지만, 밑으로 갈수록으로 모듈화가 잘되어있어
사용하기가 편하다.
U-Boot Makefile 역시 비슷하지만 다르게 구성이 되어있지만, 유사한 부분이 많이 있다.
솔직히 Kernel Makefile과 U-Boot Makefile은 수정할 일이 거의 없으며 간단한 Config 규칙과 Makefile 추가하는 식을 알면된다.
- obj-y obj-n -obj-m 설정
https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt
댓글 없음 :
댓글 쓰기