'Program Lang./Makefile'에 해당되는 글 9건

  1. 2013.05.18 8. static, shared library makefile
  2. 2013.05.13 6. source와 object 분리
  3. 2013.05.13 5. Makefile Rules
  4. 2013.05.11 1. basic makefile structure syntax
  5. 2013.05.09 3. VPATH(vpath), conditional and include 지시자
  6. 2013.05.09 4. variable and macros
  7. 2012.12.27 9. makefile structure for large project
  8. 2012.12.26 7. Automatic Dependency Generation
  9. 2012.12.08 2. Wildcard, Phony Target, Empty Target Usage

8. static, shared library makefile

Program Lang./Makefile 2013. 5. 18. 14:11

1. Makefile Rule for static library build

 

static library는 archive library라고도 불리고, 빌드를 위한 Makefile Rule은 아래와 같다.

 

libname.a : libname.a 을 구성할 object 파일 목록들 기술

[ TAB ] $(AR) $(ARFLGS) $@ @^

또는

[ TAB ] $(AR) $(ARFLGS) $@ @?                        # 변경이 있는 object만을 반영하기 위해서는 $? 사용

 

여기서 $(AR)은 ar 명령어를 나타내며, 사용법과 옵션은 아래와 같다. $(ARFLGS)의 기본값은 rv이다.

 

ar option archive object-file...

 

option 

설명 

 r

 오브젝트를 삽입, 이미 같은 이름이 있으면 대체한다. 정적라이블러리를 만든는 표준방법

 t

 아카이브의 내용을 테이블로 출력, 자세한 출력은 v 옵션을 추가로 설정

 d

 아카이브에서 지정한 오브젝트를 삭제

 

마지막으로 archive library는 자신이 포함하고 있는 심볼에 대해서 index정보를 가지고 있어야 한다. 현재 GNU같은

최신 make는 자동으로 ar 명령어가 생성하지만 그렇지 않은 make는 아래와 같은 추가 작업이 필요하다.

 

라이블러리이름(확장자 a) : archive library를 구성하는 object member들 기술

[ TAB ] $(RANLIB) $@

 

정적 라이블러리 생성 룰과 index 생성 룰을 하나로 합쳐서 만들면 더 좋겠죠... 

 

2. Makefile Rule for shared library build

 

정적 라이블러리가 빌드과정에서 모든 라이블러리를 실행파일에 포함시키는 구조라면 동적 라이블러리는 빌드 중에는

라이블러리 사용에 대한 정보만 포함하고 실제 로딩은 실행파일 실행 중에 수행한다. 따라서 동적 라이블러리는

이를 만족하기 위해서 추가적으로 몇가지 단계가 필요하다. 두 라이블러리 간의 차이점과 사용법은 해당 부분 참조 바람.

 

단계별로 살펴보면 다음과 같다.

 

1) 위치 독립적인 코드 생성 : -fPIC 컴파일 옵션으로 object 파일 생성

 

gcc -g -c -fPIC -\all bar.c foo.c

 

2) 공유 라이블러리 생성 : -shared 컴파일 옵션 추가

 

gcc -g -shared -o libdemo.so bar.o foo.o 


 

3) 동적 라이블러리를 Alias를 이용해 생성: -\, soname, 옵션

 

gcc -g -shared -\l, -soname, libdemo.so.1 -o bar.o foo.o

 

2), 3)은 동일하게 동적 라이블러리를 생성하는 방법이지만 3)은 좀 더 관리를 효율적으로 하기위해서 사용한다.

여기서 일일이 모든 것을 기술하면 지문이 지저분해지므로 라이블러리 이용편을 참조

 

3. 예제 Rule 

 

아래 예제는 정적과 동적 라이블러리를 만들어내는 rule이고, 동적 라이블러리 생성 시에는 -fPIC 옵션이 들어가야한다.

 

$(static_lib) : $(objects)

@echo "static library building : "\$@\""

@test -d $(lib_dir) || mkdir -p $(lib_dir)

@rm -rf $@

@$(AR) $(ARFLGS) $@ $?  

 

$(shared_lib) : $(objects)

@echo "shared library building : "\$@\""

@test -d $(lib_dir) || mkdir -p $(lib_dir)

@rm -rf $@

@$(CC) -shared --\l,-soname,$@.0 -o $@.0.0.0 $?

@ln -f $(notdir $@.0.0.0) $@

@ln -f $(notdir $@.0.0.0) $@.0

 

추가적으로 동적 라이블러리는 그 관리 및 사용상의 특징으로 세가지의 파일이 필요하다.

위 동적 라이블러리 생성 rule에서 $@.0.0.0 형태의 동적 라이블러리만 만들어진다.

하지만 실제 실행 시에는 -soname에 명시된 이름을 실행 파일에서 찾게된다. 따라서 이를 위해 링크를 생성해줘야 한다.

마지막으로 빌드 중 링크과정에서 확인하는 라이블러에 대해서도 링크를 걸어줘야 한다.

아래 매크로(함수)는 그런 기능을 수행하는 것으로 install Target에서 호출하면 일을 덜 수 있다.   

 

make_symlink = test -L $2 -a $1 == "`readlink $2`" || (rm -rf $2; ln -v $1 $2)

 

$(call make_symlink, libcurl.so.7.31.0, libcurl.so)                    # 빌드 중 링크 과정에서 필요한 라이블러리 생성

$(call make_symlink, libcurl.so.7.31.0, libcurl.so.7)                 # 실행 중 필요한 Allias 라이블러리 생성

'Program Lang. > Makefile' 카테고리의 다른 글

6. source와 object 분리  (0) 2013.05.13
5. Makefile Rules  (0) 2013.05.13
1. basic makefile structure syntax  (0) 2013.05.11
3. VPATH(vpath), conditional and include 지시자  (0) 2013.05.09
4. variable and macros  (0) 2013.05.09
:

6. source와 object 분리

Program Lang./Makefile 2013. 5. 13. 14:27

1. 개요

 

3장의 VPATH 설명 부분에서 소스 파일은 소스 디렉토리에 헤더 파일은 헤더 파일로 분리하였다.

Makefile에서 make가 실행되어 소스 파일을 찾는 부분은 현재 make가 실행되는 위치에 모두 있어야 한다.

하지만 VPATH라는 내부 규칙을 사용함으로써 디렉토리를 용도에 맞게 분리할 수 있었다.

 

2. 개선

 

3장의 VPATH 예제에서 문제점은 소스 파일 디렉토리인 src 폴더에 Command가 성공적으로 실행되면

오브젝트 파일이 모두 src 폴더에 존재한다는 것이다. 딱히 문제되지는 않지만 SVN 같은 툴을

써서 소스의 변경사항을 commit할 시 이들이 같이 존재하면 상당히 번거롭다.

 

아래 예제는 오브젝트 파일이 obj 폴더에 별도로 만들어지도록 하였다. 차 후 Dependency 파일 또한 만들어야

하는데 이렇게 분리하여 관리하는 것이 바람직하다.

 

3. 예제

 

exam3.zip

 

Pattern Rule의 Target이 기존 Pattern Rule에 비해 어떻게 바뀌었는지 보자.

또한 object 파일을 만들때 기존에는 소스파일의 확장자를 단순히 오브젝트 파일의 확장자를 변경하는

내부 매크로 함수를 사용하였느나, 디렉토리 또한 Prefix로 붙어야 해서 다른 함수를 사용하였다.

즉 object 변수에는 obj폴더가 앞에 붙어서 오브젝트 이름이 생성되어 pattern rule에 전달되고

pattern rule도 이를 지원하기 위해서 바뀌었다.

 

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

obj_dir = obj
include_dir = include

VPATH = src
CFLAGS += -I $(include_dir)

sources = 
sources += bar.c foo.c main.c

objects = $(foreach src,$(sources),$(obj_dir)/$(src:.c=.o))

all : $(objects) exec

exec : $(objects)
	gcc -o exec $^			# Using Automatic Expanded Variable
	
clean :
	rm -rf $(obj_dir) *.exe
	
$(obj_dir)/%.o : %.c
	echo "Starting Pattern Rules ..."
	@test -d $(obj_dir) || mkdir -p $(obj_dir)
#	$(CC) -MMD -MF $*.d $(CFLAGS) -o $@ -c $<
	$(CC) $(CFLAGS) -o $@ -c $<


 

'Program Lang. > Makefile' 카테고리의 다른 글

8. static, shared library makefile  (0) 2013.05.18
5. Makefile Rules  (0) 2013.05.13
1. basic makefile structure syntax  (0) 2013.05.11
3. VPATH(vpath), conditional and include 지시자  (0) 2013.05.09
4. variable and macros  (0) 2013.05.09
:

5. Makefile Rules

Program Lang./Makefile 2013. 5. 13. 08:05

1. Rule의 종류

 

  • Explicit Rules

 

- Rule의 구성에 생략되는 부분이 없으며, 각 대상을 명확하게 지정한다. 참 애매하긴 하지만

  앞에서 살펴본 것처럼 일반적으로 wildcard나 내부 변수를 사용하지 않는 경우이다.

 

  • Pattern Rules

 

- 명확하게 Target이나 Prerequisite에 대한 파일이름 대신에 Wildcard를 사용한 어떤 패턴 형태이다.

  위의 Explicit Rule과 반대되는 경우라고 보면 된다.

 

  • Implicit Rules

 

- Pattern Rule이나 Suffix Rule이긴 하나 make 내부변수나 database를 이용하여 정의한 Rule이다.

  Suffix Rule은 파일의 상관관계를 이용하여 자동으로 의존관계를 확장하는 Rule로 Pattern Rules

  이 나오기 전에 많이 사용하던 방식이다.

 

  • Static Pattern Rules

 

- Target 파일에 대한 리스트가 한정적으로 지정되어 있을 경우에 해당한다.

 

Rule을 위에서처럼 나누기는 했지만 makefile에서 Rule은 일반적으로 위의 Rule이 섞어있는 구조가

대부분이다. 앞으로 Explicit Rule 중심으로 살펴보면서 Target과 Prerequisite을 어떻게 다른 Rule로

확장해 가는지 보는 것이 이해가 빠를 것으로 보인다.

 

2. Suffix Rule

 

Implicit Rule을 정의하는 구형 방식이다. 하지만 여전히 많은 makefile에서 사용되므로 간단히 소개한다.

GNU makefile에서 Suffix Rule을 Pattern Rule로 대체되었다.

이름에서 유추되듯이 파일 확장자 규칙을 이용하여 Rule을 확장함을 알 수 있다.

 

.c.o :

$(COMPILE.c) $(OUTPUT_OPTION) $< 

 

Pattern Rule로 위의 Suffix Rule을 다시 쓰면 아래와 같다. 다만 Target과 Prerequisite를 선언하는 방식이 다르다.

 

%.o : %.c

$(COMPILE.c) $(OUTPUT_OPTION) $< 

 

위의 예제는 double suffix rule에 해당하고 single-suffix rule은 일반적으로 실행파일을 생성시 사용한다.

 

.p :

$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@ 

 

동일한 Pattern Rule은 아래와 같다.

 

%: %.p 

$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@ 

 

Suffix Rule은 일반적으로 알려진 파일 확장자 규칙을 사용한다. 파일 확장자 규칙에 등록은 .SUFFIXES 지정자를

통해서 이루어지고 이를 수정하면 자신에 맞는 구성을 할 수 있다.

 

.SUFFIXES : .out .a .ln .o .c .cc .C .cpp .p .f .F .r .y .l

 

.SUFFIXES :                                    # make --no-builtin-rules (or -r)와 동일 : 확장자가 등록 해제  

 

3. Implicit Rules

 

Implicit Rule은 built-in pattern rule이다. 즉 make에서 지원하는 rule 확장 규칙이다.

implicit rule을 사용하고자 하면 command 부분을 생략하면 된다. make가 target에 가장 적합한 rule을 찾아서 빌드한다.

 

make에서 지원하는 built-in pattern rule은 아래와 같은 명령어로 확인할 수 있다.

 

make -p or make --print-data-base

 

impilicit rule을 사용 시에는 Target이 원하는 rule에 의해서 빌드되도록 주의를 기울여야 한다.

또한 implicit rule에 적용된 변수들을 제정의할 때도 주의를 기울여야 한다.

 

COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

CC = gcc

OUTPUT_OPTION = -o $@ 

 

위 implicit rule에 정의된 CFLAGS 변수에 대한 내용을 잘못 수정하면 원하는 동작을 할 수 없을 수 있으니

주의를 기울여야 한다.

 

아래 예제는 1장에서 다루었던 기본 Makefile 구조를 내부 확장 규칙을 사용하는 Implicit Rule로 바꾼 것이다.

Target 인 all 밑에 아무 command가 존재하지 않는데 소스파일에서 오브젝트 파일이 생성된다.

내부 확장 규칙을 사용하여 빌드가 된 것이다. 내부 매크로인 subst와 자동 확장 변수는 다음에 소개된 장을

참조하고 여기서는 주의를 기울일 필요없다.

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

sources = 
sources += bar.c foo.c main.c

objects = $(subst .c,.o,$(sources))

all : $(objects) exec

exec : $(objects)
#	gcc -o exec $(objects)
	gcc -o exec $^			# Using Automatic Expanded Variable

clean :
	rm -rf *.o *.exe


 

4. Pattern Rules

 

아래의 예제는 위의 Impilicit Rule Makefile에서 소스를 오브젝트로 빌드하는 내부 규칙 대신에

새로운 Pattern을 적용하였다. Pattern Rule을 어떻게 사용하는지 확인할 수 있다.

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

sources = 
sources += bar.c foo.c main.c

objects = $(subst .c,.o,$(sources))

all : $(objects) exec

exec : $(objects)
#	gcc -o exec $(objects)
	gcc -o exec $^			# Using Automatic Expanded Variable
	
clean :
	rm -rf *.o *.exe
	
%.o : %.c
	echo "Starting Pattern Rules ..."
	@test $(dir $@) || mkdir -p $(dir $@)
#	$(CC) -MMD -MF $*.d $(CFLAGS) -o $@ -c $<
	$(CC) $(CFLAGS) -o $@ -c $<


 

'Program Lang. > Makefile' 카테고리의 다른 글

8. static, shared library makefile  (0) 2013.05.18
6. source와 object 분리  (0) 2013.05.13
1. basic makefile structure syntax  (0) 2013.05.11
3. VPATH(vpath), conditional and include 지시자  (0) 2013.05.09
4. variable and macros  (0) 2013.05.09
:

1. basic makefile structure syntax

Program Lang./Makefile 2013. 5. 11. 15:35

1. makefile란

 

make 유틸리티는 소스간에 dependency와 timestamp 관계를 이용하여 빌드를 자동으로 해주는 유틸리티이다.

이 유틸리티에서 사용하는 자동 스크립터가 makefile이다.

 

$ make [Target]                       /* -C 옵션 : 스크립트가 위치한 디렉토리 지정, -f 옵션 : 기본 이외의 파일 지정 */

 

쉘에서 위처럼 make 명령어를 수행하면 기본값으로 현재 디렉토리에서

makefile, Makefile 또는 GNUMakefile 의 이름을 갖는 자동 스크립트 파일이 존재하는지 검사하여 실행한다.

 

만약 기본값을 바꾸고 싶으면 옵션을 이용하여 변경할 수 있다.

 

2. makefile 기본 구조

 

makefile은 아래와 같이 Target, Prerequisite, Command의 묶음으로 이루어져 있고, 이를 Rule이라고 한다.

Rule의 동작은 Target을 생성하기 위해서 Command를 수행한다. Command를 수행하기 전에 먼저 Prequisite의 

존재 여부나 변경 여부를 검사한다. 만약 Prerequisite가 존재하지 않거나 변경이 있으면 Prerequisite를 만드는

Rule 찾아서 먼저 수행한다. Prerequisite를 만드는 Rule또한 아래와 같은 기본 구조로 이루어져 있다.

 

하나의 Rule에는 아래와 같이 Target. Prerequisite, Command가 여러개로 구성될 수 있다.

이 경우에는 각 Target은 동일한 Prerequisite와 Command 동작을 수행함을 알 수 있다.  

 

[상기 사항] Command 영역은 쉘상에서 수행되며, 실제 명령어 수행은 새로운 쉘인 Sub-Shell에서 수행한다.  

 

Target1 Target2 Target3 : Prerequisite1 Prerequisite2

[ tab ] command1                                                                                /* Shell Command 영역 */

[ tab ] command2 

 

3. 용어 정리

 

  • Default Rule

 

- makefile가 Rule의 집합으로 이루어져 있다. 가장 최상위에 존재하는 Rule을 Default Rule이라 한다.

 

  • Default Target

 

- make 명령어를 쉘상에서 실행 시, Target를 지정하지 않으면 스크립트 상의 최상위 Target이 실행된다.

  이를 Default Target이라고 한다.

 

4. 예제

 

exam1.zip

 

예제 파일은 makefile의 Rule의 기본 구조와 의존관계처리를 어떻게 처리하는지 정도만 알아보는 구조이다.

main.c파일은 실제 실행코드가 들어있고 bar.c와 foo.c 파일을 단순히 자신의 이름을 출력하는 함수를 가지고 있다.

더 형식적이고 일반적인 구조는 더 진행하면서 알아보도록 한다.

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

exec : bar.o foo.o main.o
	gcc -o exec bar.o foo.o main.o

#bar.o : bar.c
bar.o : bar.h bar.c
	gcc -c bar.c

foo.o : foo.h foo.c
	gcc -c foo.c	
	
main.o : bar.o foo.o
	gcc -c main.c

clean :
	rm -rf *.o *.exe


위 예제에서 bar.o Target를 생성하는 Rule에서 bar.h 파일이 Prerequisite에 존재하지 않게하고

bar.h을 수정하였을 경우, make 동작은 할 일이 없다는 메세지를 출력한다. 즉 헤더파일도 의존관계에 포함시켜야

한다는 것이다. 이에 대한 자세한 내용은 앞으로 알아볼 것이다.  

 

5. 마무리

 

이 장에서 중요한 것은 기본적인 용어와 makefile의 구조이다. Rule에 대한 정의를 이해하는 것이 중요하다.

 

6. reference

 

● GNU make 문서

http://www.gnu.org/software/make/manual/make.html


● GNU make 한글판 버전

     http://www.viper.pe.kr/docs/make-ko/make-ko_toc.html


● 참고 사이트

http://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make.html
http://wiki.kldp.org/KoreanDoc/html/gcc_and_make/gcc_and_make-3.html

 

● OREILLY Open Book

http://oreilly.com/catalog/make3/book/

 

'Program Lang. > Makefile' 카테고리의 다른 글

6. source와 object 분리  (0) 2013.05.13
5. Makefile Rules  (0) 2013.05.13
3. VPATH(vpath), conditional and include 지시자  (0) 2013.05.09
4. variable and macros  (0) 2013.05.09
9. makefile structure for large project  (0) 2012.12.27
:

3. VPATH(vpath), conditional and include 지시자

Program Lang./Makefile 2013. 5. 9. 13:23

1. VPATH, vpath 란?

 

make가 Target과 Prerequisite를 찾을 위치를 현재 디렉토리 뿐만 아니라 VPATH에 명시된 위치에서 

추가적으로 찾아보도록 지시할 수 있다. VPATH는 Target과 Prerequisite에 대해서 찾을 위치를 추가적으로 명시하는

것이지 command line에 있는 파일의 위치는 명시하지 않는다.

 

첫번째에서 소개한 예제를 아래와 같이 소스 파일은 src 디렉토리에 header파일은 include에 Makefile과 main.c파일

은 exam 상위 폴더에 위치하도록 수정하고 Makefile을 수정하였다.

 

예제 파일 : 

exam2.zip

 

 

아래 Makefile에서 주석처리된 부분을 풀면 VPATH를 활성화하고 VPATH에 대한 동작을 확인할 수 있다.

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

#VPATH = src

exec : bar.o foo.o main.o
	gcc -o exec bar.o foo.o main.o

bar.o : src/bar.c include/bar.h
#bar.o : bar.c include/bar.h
	gcc -I include -c src/bar.c

foo.o : src/foo.c include/foo.h
#foo.o : foo.c include/foo.h
	gcc -I include -c src/foo.c	
	
main.o : bar.o foo.o
	gcc -I include -c main.c

clean :
	rm -rf *.o *.exe

 

VPATH는 찾을 디렉토리만을 설정한다. 따라서 어떤 소스파일을 찾기 위해서 VPATH를 모두 찾아봐야 한다.

소스의 리스트가 적으면 그리 큰 문제가 되지 않지만 소스파일이 많으면 부하가 걸리는 문제가 있다.

이를 좀 개선한 것이 vpath 구문이다. 사용법과 수정된 Makefile은 아래와 같다.

 

vpath pattern directory-list

 

아래에서 header의 위치까지 포함시키면서 Prerequisite에서 include폴더의 명시를 제거할 수 있다.

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

vpath %.c src
vpath %.h include

exec : bar.o foo.o main.o
	gcc -o exec bar.o foo.o main.o

#bar.o : include/bar.h src/bar.c
bar.o : bar.c bar.h
	gcc -I include -c src/bar.c

#foo.o : include/foo.h src/foo.c
foo.o : foo.c foo.h
	gcc -I include -c src/foo.c	
	
main.o : bar.o foo.o
	gcc -I include -c main.c

clean :
	rm -rf *.o *.exe



마지막으로 command line를 더 Makefile의 일반적인 표현으로 수정하려면 makefile variable 편에서

Automatic variable을 숙지한 후 더 간단한 makefile을 만들 수 있다.

 

2. Conditional Processing

 

Makefile에서 코드를 선택적으로 포함시키거나 배제할 수 있다. 형식은 아래와 같다.

 

ifdef variable-name                    # variable-name : $( )로 정의되면 안된다.  

ifndef variable-name

ifeq test                                    # test : (a, b), "a" "b", 'a' 'b' 가 될 수 있다.

ifneq test 

 

예제는 아래와 같다.

 

libGui.a : $(gui_objects)

$(AR) $(ARFLAGS) $@ $<

ifdef RANLIB

$(RANLIB) $@

endif

 

 

3. Include Directive (Include 지시자)

 

makefile 하나에 모든 rule을 기술할 수 있다. 하지만 공통으로 사용되는 makefile은 별도로 분리하여 필요할 때

현재 makefile에 포함시켜 사용하면 구조적으로 이해하기 쉽고 일반적으로 대형 프로젝트에서는 그렇게 한다.

 

사용법은 아래와 같다. 자세한 예제는 생략하고 차 후 어느정도 형식을 갖쳐진 makefile에서 소개할 것이다.

 

include [상위위치] definitions.mk                                     # makefile 상에서

 

make --include-dir [찾을 디렉토리 위치] (-I)                     # command 상에서 include 디렉토리 위치 지정법  

 

include 지시자는 C언어의 #include문과 유사하게 동작하며, make에서 rule 처리 과정 중에 include를 만나면

그 makefile까지 포함하여 rule에 대한 전반적인 2단계 스캔을 수행한다. 이 부분은 rule 소개 부분을 참조 바람.

 

 

'Program Lang. > Makefile' 카테고리의 다른 글

5. Makefile Rules  (0) 2013.05.13
1. basic makefile structure syntax  (0) 2013.05.11
4. variable and macros  (0) 2013.05.09
9. makefile structure for large project  (0) 2012.12.27
7. Automatic Dependency Generation  (0) 2012.12.26
:

4. variable and macros

Program Lang./Makefile 2013. 5. 9. 09:01

1. Variables (변수)

 

makefile에서 사용자 변수를 지정할 수도 있고 환경변수나 make 내부 변수를 사용할 수 있다.

 

1.1. 변수 사용 규칙

 

makefile은 대소문자를 구분한다. 일반적으로 환경변수나 make 내부 변수를 재정의하고자 할 경우에는

대문자를 사용한다. makefile 내에 사용자 정의 변수를 선언하고자 하는 경우에는 소문자를 사용하는 것이 일반적이다.

 

# make built-in 변수 재 정의

CC         := gcc

MKDIR    := mkdir -p

 

#internal variable 정의

source = *.c

objects = $(subst .c,.o,$(source)) 

 

1.2. 변수 유형 (Variable Types)

 

변수의 유형은 크게 simply expanded와 recursively expanded 변수로 분류한다.

 

  • simply expaned variable (:=)

 

- := 할당자를 사용한다. 할당자 오른쪽 내용은 해당 라인을 읽음과 동시에 확장된다.

 

  • recursively expanded variable (=)

 

- = 할당자를 사용한다. 할당자 오른쪽에 정의된 내용은 실제 변수가 사용되기 전까지 확장을 연기한다.

 

MAKE_DEPEND := $(CC) -M                                            # simply expanded variable

MAKE_DEPEND = $(CC) -M                                            # recursively expanded variable

 

위의 예제에서 simply expaned 변수에서 CC가 정의되지 않을 경우, MAKDE_DEPEND는 <space> -M으로 확장한다.

space는 아무 데이터가 없다는 뜻이다. 하지만 recursively expanded 변수에서는 변수를 읽을 당시에는 선언되지

않았더라도 변수를 실제 사용하기 전에 선언되었다면 정상적으로 gcc -M으로 확장할 것이다.

 

추가적으로 변수를 할당하는 방식에 따라 두 가지 할당 방식이 있다.  

 

  • conditional variable assignment operator (?=)

 

- 왼쪽 변수에 초기값이 설정되어 있지 않을 경우에만 오른쪽에 할당된 값을 할당한다.

 

  • append assigment operator (+=)

 

- 이 할당자는 기존 할당내용에 추가적으로 내용을 할당한다

 

2. 매크로 (Macro)

 

변수가 한라인 정의를 하는 구조라면 매크로는 여러줄로 명령어나 해야할 일을 정의할 수 있다.

매크로의 시작은 define이라는 지정자를 통해서 이루어진다. 자세한 내용은 생략하고 사용예만

소개하고 마무리한다.  

 

define free-space

$(PRINTF) "Free disk space"

$(DF) . | $(AWK) 'NR == 2 {print $$4}'

endef                                                                # end of define 매크로 정의  

 

3. 변수 및 매크로 확장 규칙

 

위에서 변수의 유형과 할당 방식에 따라서 확장 규칙이 다양하다. 언제 변수와 매크로 또는 지시자들이 확장되는지를

요약한다.

 

make는 두번에 걸쳐서 makefile을 스캔한다. 첫번째는 변수와 매크로 또는 include 지시에 명시된 makefile에 대해서

모든 변수와 매크로를 make 내부적으로 데이터베이스화하고 저장한다.

두번째 스캔에서는 실제 업데이트되어야 할 Target과 Prerequisite를 확인하고 command를 수행한다.

 

아래 표는 변수 및 매크로가 언제 확장되거나 확장을 지연하는지에 대해서 요약하였다.

또한 예제를 통해서 이를 확인해 본다.

 

 Definition

Expansion of a 

Expansion of b 

 a = b

 Immediate

 Deferred (recursively expanded variable)

 a ?= b

 Immediate

 Deferred

 a := b

 Immediate

 Deferred

 a += b

 Immediate

 Deferred or Immediate

 define a

 Immediate

 Deferred

 b...

 

 Deferred

 b...

 

 Deferred

 b...

 

 Deferred

 endef

 

 Deferred

 

BIN, PRINTF, DF와 AWK의 정의가 뒤에 나오지만 Makefile을 실행하면 정상적으로 동작한다.

이는 매크로가 실제 사용될 때까지 모든 변수에 대한 정의는 연기되고 실제 사용될 때 확장되기 때문이다.

각 변수는 simply expanded로 구성되어 있는데 recursively expanded 변수로 정의해도 동작은 정상적이다.

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

OUTPUT_DIR := /tmp

$(OUTPUT_DIR)/very_big_file:
	$(free-space)

define free-space
$(PRINTF) "Free disk space"
$(DF) . | $(AWK) 'NR == 2 {print $$4}'
endef

BIN 	:= /usr/bin
PRINTF	:= $(BIN)/printf
DF		:= $(BIN)/df
AWK		:= $(BIN)/awk


 

4. Target Specific Variable

 

변수의 효력이 특정 타겟에만 유효하도록 지정하고 싶을 경우에 사용하는 방식이다.

예제를 통해서 알아본다. 아래 코드를 보면 어떤식으로 정의하는지 이해할 수 있을 것이다.

 

gui.o : gui.h

$(COMPILE.c) -DUSE_NEW_MALLOC=1 $(OUTPUT_OPTION) $<

 

[Target Specific Variable]로 변경

gui.o: CPPFLAGS += -DUSE_NEW_MALLOC=1

gui.o : gui.h

$(COMPILE.c) $(OUTPUT_OPTION) $<

 

 

5. 변수의 정의는 어디서 가능한가?

 

  • File

 

- makefile 내에서 아니면 include 지시자에 의해 포함된 다른 makefile로부터 가능하다.

 

  • Command Line

 

- make를 실행하는 쉘명령어 프롬프트상에서 가능하며 여기서 지정한 값은 기존 파일에서 지정한 값을

  override한다. 이를 금하고 싶으면 override 지시자를 변수앞에 지정한다.

 

  • Enviroment

 

- 쉘의 환경변수를 변수로 사용할 수 있으며, 다른 것으로 선언할 수 있다.

 

6. export or unexport 지시자

 

현재 makefile에서 선언된 변수를 다른 makefile에서도 사용가능하도록 하고자할 때 많이 사용한다.

이 지시자는 export로 지정한 변수를 환경변수에 등록하여 모든 makefile에서 참조하도록 할 수 있다.

중요한 내용이고 makefile은 단순한 구조를 갖는 것이 아니고 tree 구조의 복잡한 구조를 가질 수 있다.

이 때 export의 사용은 매우 유용하다.

 

7. Automatic Variables

 

내부적으로 정의되어 command script에서 Target이나 Prerequisite에 대한 기술을 반복하는 것을

쉽게 해당 변수로 대체할 수 있다.

 

 Variable

설명 

$@ 

 Target을 나타내는 파일 이름

$% 

 현재 Target이 라이블러리 일때, .o파일에 대응하는 이름, gnu makefile에서는 사용하지 않음

$< 

 첫번째 Prerequisite  (확장자 규칙에서 사용가능)

$?

 현재 Target보다 최근에 변경된 Prerequisite List를 정의 (확장자 규칙에서 사용불가)

$^ 

 모든 Prerequisite에 대한 목록 (중복 목록을 출력할 수 있다, 확장자 규칙에서 사용불가)

$+ 

 $^과 유사하다. 중복을 출력하지 않는다.  

$* 

 Target 파일이름에서 확장자를 제외한 파일이름을 표시

 

8. Standard make Variables

 

make는 자신의 상태를 관리하거나 보여주기위해서 아래와 같은 표준 변수를 내부적으로 관리한다.

몇가지 변수는 큰 makefile를 만들 때 유용하다.

 

 Variables

설명 

 MAKE_VERSION

 make의 버전정보를 가지고 있다.

 CURDIR

 현재 작업 디렉토리 표시 (--directory (-C) 옵션을 사용하지 않을 경우)

 MAKEFILE_LIST

 make가 빌드를 위해 읽은 makefile list 표시

 MAKECMDGOALS

 command line상에서 지정한 target를 표시

 .VARIABLES

 makefile을 읽는 동안 정의된 변수 목록을 출력

 

 

:

9. makefile structure for large project

2012. 12. 27. 10:20

보호되어 있는 글입니다. 내용을 보실려면 비밀번호를 입력하세요.


7. Automatic Dependency Generation

Program Lang./Makefile 2012. 12. 26. 12:57

1. 개요 

 

1장 기본 Makefile 소개 부분에서 각 오브젝트 파일과 관계되는 헤더파일을 일일이 수작업으로 의존관계를 명시하였다.

이런 관계 명시는 예제 수준에서는 가능하나 일반 프로젝트에서는 불가능한 일이다. 일반적으로 프로젝트는 매우 많은

의존 관계로 엮어 있으며, 헤더 파일은 또 다른 헤더 파일을 포함하는 둥 매우 복잡한 구조이다. 

따라서 exam1 예제처럼 일일이 기술하는 것은 의미없는 일이라는 것을 유추할 수 있다.  

 

역사적으로 의존관계 설정에 관해서 몇가지 변화를 거쳤다. 소개하면 다음과 같다.

1) 의존 관계 자동 생성 후, Makefile 하단에 붙이는 방식

 

초창기에는 아래와 같은 문구 아래에 의존관계 내용을 기술하였으나, 좋은 방식은 아니다.  

 

Automatically generated dependecies follow - Do Not Edit 

 

2) 의존관계 생성을 위한 Target 지정하고 빌드 전에 호출하도록 하는 방식

 

1)번에서 매번 수작업으로 붙여야하는 번거로움은 제거하였으나 여전히 빌드전에 의존관계 Target을 수행해야

하는 번거로움이 있다. 학창 시절에 make전에 make depend를 수행했는데 이런 시절에 사용하던 방식인가 보다.  

 

depend: count_words.c counter.c

$(CC) -M $(CFLAGS) $^ > $@

include depend 

 

마지막 방법은 GNU에서 개선한 방법으로 아래에서 설명하도록 하겠다.

 

2. GNU 또는 최신 make에서 의존 관계 생성

 

GNU나 최신 make에서는 위의 두 가지 방식에서의 번거로움을 개선하였다.

일단 각 소스파일에 해당하는 의존 관계 파일을 -M 옵션으로 생성한다. 마지막으로 include 지시자를 통해서

생성된 파일을 추가하여 변경사항에 대해서 자동으로 빌드에 반영하도록 하였다.

 

3. 예제

 

exam4.zip

 

소스와 헤더가 분리된 exam 예제를 가지고 의존관계를 자동으로 생성하여 빌드에 반영하도록 Makefile을

수정하였다. 기존 예제와 변경한 예제간의 차이를 보면 이해할 수 있을 것이다.

일단 의존관계를 생성하는 패턴 룰이 추가적으로 추가되었고 마지막에 include 지시자를 통해서 의존관계

파일을 Makefile에 추가하는 부분이 추가되었다. 컴파일 옵션을 통해서 의존관계에 대한 패턴 룰은 제거할 수 있다.

좀 더 관심 있는 사람은 찾아보고 적용해 보자. (주석처럼 부분 참고)

 

#***********************************************************************#
# ----------------------------------------------------------------------
#  Copyright(c) 2012-2013 by hee-soon kim 
#
# All rights are reserved
# 
# ----------------------------------------------------------------------#
#
#  FILE NAME    : Makefile
#  VERSION      : 1.0
#  AUTHOR       : heesoon,kim(김희순), chipmaker.tistory.com)
#  DATE         : 2012/12/21
#
#***********************************************************************#

obj_dir = obj
include_dir = include

VPATH = src
CFLAGS += -I $(include_dir)

sources = 
sources += bar.c foo.c main.c

objects = $(foreach src,$(sources),$(obj_dir)/$(src:.c=.o))
dependencies = $(foreach src,$(sources),$(obj_dir)/$(src:.c=.d))

all : $(objects) exec

exec : $(objects)
	gcc -o exec $^			# Using Automatic Expanded Variable
	
clean :
	rm -rf $(obj_dir) *.exe
	
$(obj_dir)/%.d : %.c
	echo "Generating Dependencies ..."
	@test -d $(obj_dir) || mkdir -p $(obj_dir)
	$(CC) -M $(CFLAGS) $< > $@.$$$$;						\
	sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; 		\
	rm -rf $@.$$$$

$(obj_dir)/%.o : %.c
	echo "Starting Pattern Rules ..."
	@test -d $(obj_dir) || mkdir -p $(obj_dir)
#	$(CC) -MMD -MF $*.d $(CFLAGS) -o $@ -c $<
	$(CC) $(CFLAGS) -o $@ -c $<	

include $(dependencies)

 

:

2. Wildcard, Phony Target, Empty Target Usage

Program Lang./Makefile 2012. 12. 8. 14:57

1. Wildcard를 이용한 Target, Prerequisite 구성

 

make에서 wildcard (~, *, ?, [...], [^...]) 사용은 Born Shell상에서 사용법과 동일하다. 

 

prog : *.c

$(CC) -o $@ $^                                         # $@ : 현재 Target , $^ : 현재 Prerequisite

 

 

2. Phony Targets

 

일반적으로 Target과 Prerequisite에는 업데이트될 파일에 대한 파일 이름을 기술하였다. 하지만 Phony Target 은

파일 이름이 아닌 단순 라벨(Label)로 기술된다. Phony Target은 파일 이름을 기술하지 않기 때문에 항상 업데이트

되야할 타겟이다. 일반적으로 Prerequisite를 가지지 않는 구조이다.

 

실제 make는 Phony Target과 일반 파일 이름의 타겟을 구분하지 못한다. 이를 구분하기 위해서 make는

Phony Target을 지정하는 지정자 (.PHONY)를 통해서 명시적으로 Phony Target를 지정할 수 있다.  (아래 예제 참조)

 

.PHONY : all clean

clean :

rm -rf *.o *.exe  

 

이미 make에 지정된 표준 Phony Target이 존재한다. 이는 아래와 같다.

 

 

Target 

설명 

 all

 일반적으로 실행파일을 빌드하기 위해 필요한 타겟리스트를 명시한다.

 install

 실행파일을 설치할 목적

 clean

 소스 파일로부터 생성된 바이러리 파일 삭제

 distclean

 소스 이외의 모든 파일 삭제

 TAGS

 테그 생성

 info

 정보 출력

 check

 테스트 목적

 

 

3. Empty Targets

 

위의 Phony Target은 항상 업데이트되어야 타겟이다. 하지만 경우에 따라서는 필요할 때만 업데이트를 원할 때

가 있을 것이다. 이런 요구 사항을 만족하기 위해서 필요한 Target이 Empty Target이다.

예제는 아래와 같고 이런 타겟이 있다라고만 한번 보고 넘어간다.

 

prog : size prog.o

$(CC) $(LDFLAGS) -o $@ $^

size : prog.o                                            # prog.o가 prerequisite로 사용되었다.

size $^

touch size

 

 

: