본문 바로가기
myCortex

adc 예제 makefile 분석

by irmus 2008. 6. 24.
myCortex-LM308의 example에 있는 adc 예제의 makefile을 살펴보자. makefile의 문법을 모두 설명하는 것은 너무 큰 일이 되기 때문에 문법 설명은 reference manual에 맏겨두고, 이 포스팅에서는 전체적인 구조와 흐름만 살펴보도록 한다.

참고: 이 포스팅은 myCortex 예제 20091029 버전을 기준으로 내용 수정되었습니다.
- 2010.07.20 -


- adc 예제의 Makefile -

myCortex-LM308의 예제 중 하나인 adc 예제의 Makefile을 분석해 본다. myCortex-LM608, myCortex-LM808, myCortex-LM8962의 adc 예제도 동일하다.

이 Makefile은 기본적으로 Luminary micro에서 제공하는 StellarisWare에 포함된 예제 코드의 Makefile을 참고하여 myCortex의 환경에 맞도록 일부 수정하고, 몇가지 편의기능을 추가해서 만들어진 것이다.

1~24 라인은 주석. makefile의 주석은 # 문자로 시작한다.

29. 부트로더용 이미지를 만들 것인지 stand-alone 이미지를 만들 것인지 설정.
USES_BOOTLOADER 변수 값이 "no" 이면 stand-alone 이미지가 만들어지고, "yes"이면 boot loader용 이미지가 만들어진다. 부트로더용 이미지와 stand-alone 이미지는 link할 때 시작 주소가 서로 다르다. stand-alone 이미지는 0번지부터 링크되는 반면 boot loader용 이미지는 0x800 번지부터 이미지가 시작한다. 이 변수값은80~84 라인에서 참조되어 서로 다른 ld(link description)파일이 사용된다. 두 개의 ld파일을 diff 해 보면 시작 주소와 플래쉬 사이즈가 다른 것을 볼 수 있다.


34. 공통 makefile을 include.
myCortex 시리즈용 예제는 각 모델 별 공통 makefile을 사용하고 있다. 예제 폴더에 있는 Makefile.conf 가 그 파일이며, 예제들이 공통으로 사용되는 내용들을 모아둔 것이다. 이 파일의 내용을 변경하면 모든 예제에 적용된다.


39. TARGET_NAME - 프로젝트 이름 설정.
현재 폴더 이름을 프로젝트 이름으로 사용한다. 이 이름은 최종 bin 파일의 이름으로도 사용된다. adc 예제에서는 현재 폴더명이 adc이므로 TARGET_NAME 변수에 adc가 입력된다.

40. TARGET - axf 파일 이름 설정.
프로젝트 이름을 이용해서 axf 파일 이름을 만든다. adc 예제에서는 TARGET 변수에 adc.axf가 입력된다.

42. EXTDIR - 외부 소스 폴더 설정.
프로젝트에 속한 소스 파일들은 현재 폴더 내에 있는 것이 일반적이지만 그렇지 않은 경우를 위해 사용하는 변수이다. 대표적으로 usnprintf()함수를 가지고 있는 ustdlib.c 파일이나 file system, ethernet stack 등과 같은 외부 라이브러리들의 소스 파일등을 예로 들 수 있다. 프로젝트 폴더가 아닌 다른 폴더에 있는 소스를 컴파일 해야하는 경우 이 변수에 해당 폴더의 경로를 적어주면 된다. 만일 외부 소스를 사용하지 않는다면 다음과 같이 빈 변수로 남겨두면 된다.
EXTDIR :=

adc 예제에서는 usnprintf() 함수를 사용하기 위해 ustdlib.c 파일을 같이 빌드해야 하고, ustdlib.c 파일은 DriverLib가 설치된 폴더(ROOT 변수) 아래의 utils 폴더에 있다. 참고로 ROOT 변수의 정의는 위에서 include했던 Makefile.conf 파일 내에 있다.

44. CFILES - C 소스 파일 나열.
CFILES는 컴파일 할 C 소스 파일들을 정의하는 변수이다. 46라인의 EXTCFILES와 같은 형식으로 개별 파일 이름을 일일이 적어줘도 되고, 44라인에서와 같이 매크로를 이용해 좀 더 자동화 시킬 수도 있다. 이 예제에서는 프로젝트 폴더 내에 있는 파일들 중 확장자가 .c인 모든 파일을 이 변수에 등록하고 있다. 만일 프로젝트 폴더 내에 컴파일 할 대상이 아닌 .c 파일이 있다면 이 변수의 내용을 고쳐주도록 하자.

45. SFILES - 어샘블리 소스 파일 나열.
CFILES와 마찬가지 용도인 변수. 단 C 소스파일이 아닌 어샘블리 소스 파일만 나열한다. 역시 폴더내의 모든 .S 파일이 기본적으로 컴파일 된다.

46. EXTCFILES - 외부 폴더의 C 소스 파일 나열.
EXTDIR 변수에 등록한 외부 소스 폴더에 있는 파일 들 중 컴파일 할 소스 파일들을 나열한다. 만일 외부 소스를 사용하지 않는 프로젝트라면 역시 비워두면 된다.
adc 예제에서는 ustdlib.c 파일을 사용하기 때문에 이 파일만 적혀있다.
만일 외부 폴더의 소스 파일 중 어샘블리 파일이 있다면 비슷한 방법으로 EXTSFILES 변수를 등록해서 쓰면 된다.

48~50. OBJS - 컴파일 된 object 파일 이름 나열.
앞에서 정의했던 CFILES, SFILES, EXTCFILES 등과 같은 변수들에는 소스 파일 이름을 나열한다. OBJS 변수는 이 소스 파일 변수들을 참조해서 확장자만 .o 로 바꿔 사용한다. 예를들어 adc.c 파일이 컴파일되면 adc.o 파일이 만들어지기 때문에 확장자만 바꿔서 사용하면 된다.

52. INC_PATHS - 헤더파일 검색 경로 설정.
소스파일에서 #include "my_header.h"와 같이 따옴표로 표시한 헤더파일은 이 변수에 나열한 폴더들 중에서 찾는다. 현재 폴더, DriverLib 폴더, EXTDIR에서 나열한 폴더 순서로 찾도록 설정되어있다. 만일 추가적으로 헤더파일이 있는 폴더를 넣고 싶다면 경로명을 이 변수에 추가해서 나열하면 된다.

53. CFLAGS - C 소스파일 컴파일 옵션 설정.
CFLAGS 변수는 C 소스파일을 컴파일 할 때 컴파일러 옵션으로 사용된다. 이 makefile에서는 INC_PATHS에 지정된 폴더들을 헤더파일 검색에 사용하도록 하는 -I 옵션을 '추가'하는 예를 볼 수 있다. +=는 C 에서와 마찬가지로 기존 변수 값 뒤에 덧붙여 추가하는 것을 의미한다.

54. vpath - C 소스파일 검색 경로 설정.
make는 소스 파일을 컴파일 할 때 기본적으로 현재 폴더에서 소스 파일을 찾는다. 만약 다른 폴더에 소스파일이 있는 경우에는 해당 소스파일의 경로까지 모두 지정해서 컴파일을 하는 방법을 사용하거나, 지금처럼 소스 파일 검색 폴더를 지정하는 방법도 사용할 수 있다. vpath 명령은 특정 확장자로 끝나는 파일을 검색할 때 지정된 폴더를 마치 현재 폴더처럼 사용하게끔 하는 명령이다.

60. all - default target 정의.
makefile에는 여러개의 target이 있을 수 있다. 이 adc 예제의 makefile에는 all, clean, flash의 3가지 symbolic target이 사용되고 있다. default target은 target 중 첫번째로 나오는 것을 의미한다. default 라는 의미 그대로 도스창에서 make를 아무런 옵션 없이 실행하면 default target이 수행된다. make clean과 같이 clean이라는 target을 지정해서 실행하는 것은 default target이 아닌 지정된 targe을 수행하기 위한 것이다.
일반적인 makefile에서는 all 이라는 이름을 default target 이름으로 많이 사용한다. 특별히 이유가 있는 것은 아니지만 오랫동안 관행적으로 쓰여왔기 때문에 가독성을 위해 all을 사용하고 있다.

65~67. clean target 정의.
clean은 컴파일 해서 만들어진 object 파일과 같은 중간 결과물 파일과 최종 target등을 깨끗이 지워서 소스만 있는 처음 상태로 만들어 주는 target을 말한다. 이 역시 clean이라고 정해진 이름은 아니지만 관행적으로 사용되어온 이름이기 때문에 그대로 사용하는 것이 좋다.
adc 예제에서는 간단히 gcc 폴더를 삭제하는 작업만 한다. 빌드 중간 생성물들은 모두 gcc 폴더 내에 만들어지게끔 makefile이 만들어져 있기 때문에 clean 작업이 간단하다.
target을 정의하고 그 target에서 수행 할 task를 정의할 때 주의해야할 것이 하나 있다. 66, 67라인의 task들은 반듯이 tab 문자로 들여쓰기 해야 한다는 것이다. 공백이 아니라 반듯이 tab을 사용해야만 한다.

72~73. gcc 폴더 만들기.
COMPILER 변수는 사용하는 컴파일러를 구분짓기 위해 Luminary Micro의 DriverLib에 포함된 Makefile.def 에서 정의해서 사용하는 변수이다. 이 변수값으로 폴더를 만들고 빌드 중간 생성물들은 모두 그 폴더 내에만 만들어지도록 하고 있다. CodeSocery G++ Lite를 사용하는 경우에는 COMPILER 변수 값이 'gcc'이다.

78. gcc/adc.axf 만들기.
빌드 최종 생성파일 gcc/adc.axf를 만들 때 필요한 파일들을 나열하고 있다. 이 문장 역시 하나의 target이다. 앞에서 나왔었던 다른 target과 다른 점이라면 ':' 뒤의 dependency만 있고 실제 target command는 없다는 점이다. 이런 경우는 makefile의 다른 곳에 target command가 따로 정의되어 있는 경우로써, Makefile.conf파일의 *.axf 파일을 위한 rule 정의 부분에서 링크 방법을 정의하고 있다. 마치 함수를 하나 정의해 두고 여기저기에서 불러다 쓰는 것과 비슷하다고 생각하면 된다.

79~83. ld 파일 정하기.
USES_BOOTLOADER 변수값에 따라 다른 .ld 파일을 사용한다. ifeq~else~endif 구문의 사용예를 볼 수 있다.

84. Entry 설정.
링크 단계에서 ENTRY 포인트를 알려주기 위해 사용되는 변수이다. Cortex-M3 아키텍쳐에 관련된 내용이며, 간단하게 설명하자면 bin 파일의 가장 앞머리 섹션을 ResetISR 섹션으로 지정한 것이다. 딱히 건드릴 일은 없다^^

85. 추가 LDFLAGS 정의.
혹시 필요하다면 링크 옵션을 여기에서 추가할 수 있다.

91~93. dep 파일 include하기.
make는 빌드 할 때 마다 모든 소스파일들을 다시 컴파일 하는 대신 파일 시간을 기준으로 하여 수정된 파일만 다시 컴파일한다. 이렇게 함으로써 전체 빌드 시간을 줄일 수 있다. 한편 소스 파일에서 헤더파일을 include 하는 경우와 같이 소스 파일들 간의 복잡한 dependency를 모두 추적해야만 "컴파일이 필요한 파일"을 결정할 수 있다. 이 문장은 dependency가 정의된 .d 파일을 include하라는 명령이다. include 앞의 - 기호는 에러 무시 옵션을 나타낸다. include 수행도중 에러가 발생하더라도 make를 중단하지 말고 계속 진행하라는 의미이다.
dependency 파일은 소스파일 컴파일 단계에서 gcc 폴더에 자동으로 생성된다. clean을 한 직후에는 이 .d 파일이 존재하지 않기 때문에 include를 할 수 없다는 에러가 발생하지만, 그 에러를 무시하겠다는 의미이다.

95~98. 플래시 메모리에 프로그램 다운로드 및 프로그래밍.
OpenOCD를 이용하여 myCortex 보드에 adc.bin 파일을 다운로드 하고 플래시 퓨징 한다.

100. .PHONY - logical target 정의
.PHONY는 산출물이 없는 logical target을 알려주기 위해 사용된다. 사실 생략해도 무방한데, make가 좀 더 똑똑하게 동작하게끔 힌트를 주기 위한 구문이다.