2009년 12월 19일 토요일
중소규모 프로젝트를 위한 Makefile 만들기
먼저 디렉토리 구조는 아래와 같다
./
|---main.c
|--Makefile
./include
|--- func1.h
|--- func1.h
./srcdir1
|--- func1.c
./srcdir2
|--- func2.c
./obj
|--- *.obj files
|--- Makefile
|--- depend file
아래와 같이 동작되도록 Makefile을 작성할 것이다.
- 실행 파일은 ./ 디렉토리에 생성되도록 한다.
- object파일은 모두 ./obj 디렉토리에 생성되고 make clean시 모두 지워지도록 한다.
- make depend로 dependency file 설정하여 수정된 파일만 컴파일 되도록 한다.
./Makefile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 OBJDIR = ./obj
2
3 all:
4 cd $(OBJDIR) && make
5
6 clean:
7 cd $(OBJDIR) && make clean
8
9 depend:
10 cd $(OBJDIR) && make depend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./obj/Makefile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 CC = gcc
2 LD = gcc
3
4 INCDIR = ../include
5 SRCDIR1 = ../srcdir1
6 SRCDIR2 = ../srcdir2
7
8 VPATH = $(SRCDIR1) $(SRCDIR2) ..
9
10 CFLAGS = -O2 -I$(INCDIR)
11
12 TARGET = testapp
13
14 SRCS = $(foreach dir, .. $(SRCDIR1) $(SRCDIR2), $(wildcard $(dir)/*.c))
15 SRCS := $(notdir $(SRCS))
16
17 OBJS = $(SRCS:.c=.o)
18
19 all: $(TARGET)
20
21 $(TARGET) : $(OBJS)
22 $(LD) $^ -o$(TARGET) $(LIBS)
23 mv $(TARGET) ../
24
25
26 %o:%c
27 $(CC) $(CFLAGS) -c $< -o $@
28
29 clean:
30 -rm -rf $(OBJS)
31 -rm -f ../$(TARGET)
32
33 depend: $(SRCS)
34 $(CC) -M $(CFLAGS) $^ > $@
35
36 -include depend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Line:14 모든 디렉토리에서 c파일을 골라낸다.
Line:15 c파일 리스트에서 경로명을 제거한다.
Line:17 각 c파일에 해당하는 o파일 리스트를 만든다.
Line:22 $^ 는 현재 타겟의 종속 항목 리스트 전체로 치환된다.
Line:26 $< 는 확장자 규칙에서만 사용되며 사용되며 현재 타겟보다 최근에 변경된 종속 항목 중 하나로 대체된다. 아래에서 makefile 내부 매크로 관련 정보를 더 찾아볼 수 있다. http://haneul0318.springnote.com/pages/14554?print=1
Line:34 모든 파일의 의존성리스트를 만든다.
Line:36 depend파일을 include하도록 하였으므로 이 Makefile이 불릴때마다 depend target에 자동으로 실행된다. 이때 obj디렉토리에 depend 파일이 만들어지며, 이 파일은 Makefile의 일부로 간주되게 된다. 이 파일로 인하여, 최근에 수정된 c파일이 자동으로 새로 컴파일 되며, h파일의 경우 해당 h파일을 사용하는 모든 c파일이 다시 컴파일 되게 된다. 하지만 변경되지 않은 파일들은 새로 컴파일 되지 않아 매번 모든 파일을 새로 컴파일하는 수고를 덜 수 있다. 명령문 앞에 "-"를 붙이면 오류발생시 무시하고 나머지 명령을 계속 진행한다. "-"가 없을 경우에는 오류 발생시 make가 중단된다.
아래는 위 메이크 파일 실행시 결과이다.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dooeui@dooeui-laptop:~/test$ make
cd ./obj && make
make[1]: Entering directory `/home/dooeui/test/obj'
gcc -O2 -I../include -c ../srcdir1/file1.c -o file1.o
gcc -O2 -I../include -c ../srcdir1/main.c -o main.o
gcc -O2 -I../include -c ../srcdir2/file2.c -o file2.o
gcc file1.o main.o file2.o -otestapp
mv testapp ../
make[1]: Leaving directory `/home/dooeui/test/obj'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Makefile관련 추가 정보는 아래에서 찾을 수 있다.
http://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make.html#toc1
도서 중에서 make에 관련 사용법을 속시원히 설명한 책은 "유닉스-리눅스 프로그래밍 필수 유틸리티"- 한빛 미디어를 추천한다.
2009년 12월 6일 일요일
안드로이드 시작하기
1. 리눅스 설치
안드로이드 커널 컴파일을 위해서 노트북에 우분투를 설치하여 시도하기로 한다. 마침 ubuntu 9.10 iso 파일이 있으므로, VirtualBox에 우분투 9.10을 아래와 같이 설치한다. 안드로이드 커널 컴파일에 시간이 오래 걸리고 꽤 많은 용량이 필요하다고 하므로, 메모리와 하드 디스크를 넉넉하게 할당하였다.
호스트 컴퓨터는 Windows7-64bit-Pro 이다.
- Memory : 2G
- HardDisk : 25G
2. 커널 컴파일 따라하기
일단 아는게 없으므로, 인터넷을 찾아본다. 일단은 아래 국내 사이트에서 정보를 조금 얻을 수 있었다.
http://www.kandroid.org/
http://forum.falinux.com/zbxe/
http://www.androidpub.com/
하지만, 빌드는 공식 사이트를 참고한다.
http://source.android.com/download
영어라 편하지는 않지만, 구글이 제공하는 동영상과 슬라이드 자료에서 가장 정확하고 많은 정보를 얻을 수 있었다.
http://source.android.com/documentation
특히 Anatomy & Physiology of an Android 동영상 및 강연 자료가 나의 궁금증을 가장 속 시원히 풀어주었다.
만일 플래폼 빌드보다 안드로이드 어플리케이션에 더 관심이 많다면 아래 사이트를 참조하자.
http://developer.android.com/
아래는 이미지 빌드를 시도하면서 얻은 몇가지 정보 사항이다.
- JDK 5.0 update 12 or higher가 필요하다. 하지만 JDK 6.0은 지원하지 않는다.
- 15G HDD, 512MByte에서도 빌드에 성공하였다.
- .bashrc에 아래와 같이 path를 지정(Repo를 설치한 디렉토리에 대한 path임)
export PATH="~/bin:$PATH"
가장 큰 문제는 apt-get install시 sun-java5-jdk 패키지를 찾지 못하는 것었다.
JDK 5.0을 수동으로 설치할 수도 있겠지만, 아래 사이트에서 쉬운 해결책을 찾을 수 있었다.
http://www.androidpub.com/android_porting_info/38814
간단히 설명하면,
1. /etc/apt/sources.list에 아래 두줄을 추가.
deb http://us.archive.ubuntu.com/ubuntu/ jaunty multiverse
deb http://us.archive.ubuntu.com/ubuntu/ jaunty-updates multiverse
2. sudo apt-get update 실행
3. sudo apt-get sun-java5-jdk 실행
그 외에는 큰 문제 없이 빌드가 성공!!!
일단 첫 발에 의미를...
참고:
만약 java 1.6와 java1.5를 모두 설치하였다면 아래 명령으로 java 1.5를 사용하도록 지정할 수 있다.
sudo update-java-alternatives -s java-1.5.0-sun
2009년 11월 20일 금요일
Priority Inversion Protection
예를들어 flash driver에서 우선순위 상속이 발생하여 flash recalim등과 같이 CPU를 오래 소모하는 작업의 우선순위가 상승할 경우, 예기치 못한 우선순위 역전이 발생할 수 있다. flash reclaim자체는 write 작업에서만 발생하지만, 우선순위가 높은 task에서 요청한 flash read가 낮은 우선순위 task의 flash reclaim으로 지체 될 경우, OS는 priority inheritance로 이를 해결하려 하고, 이 때문에 flash reclaim이 높은 우선순위에서 실행되어, 예기치 못하게 오랜 시간동안 다른 테스크들의 실행을 막을 수 있는 것이다.
이와 같은 경우를 고려하여 우선순위 역전이 발생하지 않도록 appliacation들의 우선순위를 조절하고, flash driver의 서비스 처리 테스크 수를 늘려, 동시 접근에 대한 처리를 가능하도록 하여 문제를 해결할 수 있다.
2009년 10월 23일 금요일
Shell과 Makefile에서 PATH수정하기
Shell에서는...
export PATH=/added_path:$PATH
Makefile에서는...
TEMP=/added_path:$(PATH)
PATH:=$(TEMP)# :=를 사용해서 $(PATH)가 recusive하게 해석되지 않도록 함.
PATH=$(TEMP) # 이렇게 하면 error, $(PATH)가 recusive하게 해석됨. 혹은
PATH=/added_path:$(PATH) #이렇게 해도 상관 없음Makefile에서 매크로를 참조할때는 꼭 괄호를 사용할 것.
PATH:=/added_path:$(PATH)
Shell에서는 괄호가 없어도 됨.
2009년 10월 8일 목요일
2009년 10월 2일 금요일
State Patten을 C로 짜려면?
아래 예에서는 구현을 단순화하기 위해서 상태는 ON/OFF두가지 상태만을 가정하였고, 'n' 입력시 ON상태로, 'f' 입력시 OFF상태로 상태 천이를 하도록 하였다.
#include <stdio.h>
/**********************************************************************
*
* 1. Type defination for Power State management
*
**********************************************************************/
typedef enum {ON,OFF} PowerState;
typedef struct
{
PowerState currPS;
void (*on_received_fptr)(struct PwrState **ps );
void (*off_received_fptr)(struct PwrState **ps );
}PwrState;
/**********************************************************************
*
* 2. Function table for each State.
*
**********************************************************************/
//Prefix ON/OFF means current status when these functions are called.
void ON_off_received(PwrState **ps );
void OFF_on_received(PwrState **ps );
void null_func(PwrState **ps);//C에서는 가상 함수를 사용할 수 없기 때문에, 아래와 같은 각 상태별
//함수 테이블을 별도로 유지해야 한다.
PwrState psON= {ON, null_func, ON_off_received};
PwrState psOFF={OFF, OFF_on_received, null_func};
void ON_off_received(PwrState **ps)
{
printf("Currnt State =%d : 0:ON 1:OFF \n",(int)(*ps)->currPS);
printf("%s is called\n",__func__);
printf("change curr power state from ON to OFF\n");
*ps=&psOFF;
}
void OFF_on_received(PwrState **ps)
{
printf("Currnt State =%d : 0:ON 1:OFF \n",(int)(*ps)->currPS);
printf("%s is called\n",__func__);
printf("change curr power state from OFF to ON\n");
*ps=&psON;
}
void null_func(PwrState **ps){}
int main(void)
{
char keyin;
PwrState *ps=&psOFF;
printf("Current power state is OFF\n");
printf("type \'n\' to change power state to ON\n");
printf("type \'f\' to change power state to OFF\n");
while(1)
{
keyin = getchar();
switch(keyin)
{
case 'n':// change state to ON
ps->on_received_fptr(&ps);
break;
case 'f':// change state to OFF
ps->off_received_fptr(&ps);
break;
default:
break;
}
}
}
2009년 10월 1일 목요일
원하는 폴더에서 마우스 오른쪽 버튼으로 커맨드 창 열기
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\shell\OpenNew]@="Dos Prompr t(&Z)"
[HKEY_CLASSES_ROOT\Directory\shell\OpenNew\Command]@="cmd.exe /k"
아래 블로그에서 관련 내용을 포함한 추가 정보를 얻을 수 있습니다.
http://youngsam.kr/
2009년 7월 3일 금요일
ELF Header
ELF? 엘프?
- Object file.
- Executable file.
- Shared Library.
- core파일.
ELF file구조 및 readelf 사용법.
- ELF file Header
- Program Header Table
- Section1
- Section2
- ...
- Section Header Table
- -h Display the ELF file header
- -l Display the program headers
- -S Display the sections' header
- -d Display the dynamic segment (if present)
2009년 6월 7일 일요일
디버깅은 근성이다!!!
2009년 3월 2일 월요일
do(...}while(0)의 또다른 용도
바로 예제를 보고 이해하자.
if(...)
{
if(...)
{
....
goto ESCAPE;
}
}
ESCAPE:
위코드는 아래와 같이 goto없이 작성이 가능하다.
do{
if(...)
{
if(...)
{
....
break;
}
}
}while(0);
2009년 1월 21일 수요일
라이브러리 이해하기 2 - 공유 라이브러리 버전 관리.
libMyLibrary.so.1.2.3
라이브러리는 용도에 따라 몇가지 서로 다른 이름을 가지고 있는데 혼돈되기 쉬우니 주의가 필요하다.
1. 링커 이름.(linker name)
링커 이름은 라이브러리 파일 명에서 버젼을 나타내는 숫자를 뺀 so까지의 이름이다. 즉 위에서는 libMyLibrary.so까지가 linker name이 된다. 링커 이름은 해당 라이브러리를 사용하는 프로그램을 빌드 할 때 사용되는 이름이다. 더 정확히 말하면, 프로그램이 빌드될 때 해당 프로그램이 사용하는 공유 라이브러리를 찾기 위해 링커 이름을 가진 파일이 빌드하는 시스템에 있어야 한다. 예를들어 어떤 어플리케이션이 libMyLibrary.so.1.2.3을 사용하여 컴파일 할 경우 빌드 옵션에 -lMyLibrary를 추가하게 되는데 이때 기본 라이브러리 경로나 혹은 –L 옵션을 사용하여 지정한 디렉토리에 libMyLibrary.so 파일, 즉 링커 이름으로 된 라이브러리 파일이 있어야 한다. (보통은 libMyLibrary.so.1.2.3에 대한 심볼링 링크로 이 파일을 만든다 이렇게 하는 이유는 호스트 개발 환경에 해당 라이브러리의 여러 버젼이 존재할 경우 이를 관리하기 위함이다. ) 크로스 컴파일을 하는 환경에서는 빌드시에만 링커 이름을 가진 파일이 필요하며, 타겟에서 실행 시에는 이 파일이 필요치 않다. 즉 개발하는 호스트 컴퓨터에는 라이브러리 파일 이름이 링커 이름으로 되어 있거나 이를 심볼링 링크로 만들어야 한다. 컴파일러/링커는 링커 이름을 가진 파일에서 이 라이브러리의 soname을 읽어오게 된다. 따라서 공유 라이브러리는 빌드시 실행 파일에 포함되지는 않지만 soname을 읽어와야 하기 때문에 공유 라이브러리가 빌드하는 호스트 시스템에 없으면 빌드가 되지 않는다.
2. soname
이 이름은 로더가 라이브러리를 실행할 때 찾는 이름으로 타겟에는 soname을 가진 파일이 반드시 있어야 한다. 때때로 이 파일은 심볼릭 링크로 다른 파일로 링크되어 있다.
일반적으로 soname은 so뒤에 숫자 하나를 추가하여 만든다. 예를 들어 libMyLibrary.so.1 가 위 라이브러리의 soname으로 적합하다. 아래와 같은 명령으로 soname을 지정할 수 있다.
gcc –shared –Wl,-soname libMyLibrary.so.1 –o libMyLibrary.so.1.2.3 MyLibrary.o
so뒤에 오는 첫번째 숫자는 라이브러리의 Major version number로 일반적으로 호환성이 변경되는 경우에 증가시킨다. 이렇게 라이브러리를 빌드하고 또 이 라이브러리를 사용하는 프로그램을 빌드하면 해당 프로그램 실행 시 로더에 의해서 soname을 가진 파일을 라이브러리 경로에서 찾게 된다. 즉 프로그램이 실행될 때에는 soname을 가진 라이브러리 파일이 필요하다. 크로스 컴파일을 하는 환경에서는 빌드 시에는 soname을 가진 파일이 아닌 링커이름을 가지는 파일(일반적으로 xxx.so로 끝나는 파일)이 필요하고 실행시에는 soname을 가지는 라이브러리(혹은 이에 대한 심볼릭 링크 )가 필요한 것이다.
라이브러리 full name에서 두번째 숫자는 라이브러리의 minor version number로 호환성에는 변경이 없지만 새로운 함수등이 추가되는 경우에 변경되며, 세번째 자리는 release 버전으로 버그 수정 등으로 라이브러리가 새로 릴리즈되는 경우에 변경된다.
따라서 크로스 컴파일 환경에서, 호스트에서 공유 라이브러리 libMyLibrary.so.1.2.3 를 만들어 타겟 시스템에 넣을 경우 타켓 시스템에는 아래와 같이 soft link file을 만들어 soname을 가진 파일을 만들어야 한다.
ln –s libMyLibrary.so.1.2.3 libMyLibrary.so.1
or
mv libMyLibrary.so.1.2.3 libMyLibrary.so.1
또한 해당 라이브러리를 사용하여 프로그램을 만드는 모든 개발자는 자신의 빌드 환경에 아래와 같이 공유 라이브러리가 링커 이름을 가지도록 설정하여야 한다. (즉 .so.1 파일은 호스트(빌드)시스템에서는 필요 없다)
ln –s libMyLibrary.so.1.2.3 libMyLibrary.so
or
mv libMyLibrary.so.1.2.3 libMyLibrary.so
특정 라이브러리의 soname을 확인하기 위해서는 아래와 같은 명령을 사용할 수 있다.
objdump -p libMyLibrary.so.1.2.3 | grep SONAME
더 자세한 내용은...
http://wiki.kldp.org/wiki.php/DocbookSgml/Program-Library-HOWTO#DL-LIBRARIES
od와 xxd
먼저 바이너리 파일을 hex 모드로 읽기만 하는 경우에는 xdd나 od를 사용하면 된다.
xxd -g1 filename
or
od -tx1 -Ax filename
두 프로그램은 거의 동일한 포맷으로 출력을 보여주지만 od가 좀 더 포맷을 자유롭게 지정할 수 있다. -tx1는 type을 16진수로 해서 1바이트 단위로 표시하라는 뜻이며, -Ax는 Address표시를 16진수로 지정하는 옵션으로 위 예와같이 데이터와 어드레스의 표시 형식을 서로 다르게 지정할 수도 있다. od는 octal dump의 약자로 옵션을 주지 않을 경우 8진수로 출력된다.
od가 여러가지 타입으로 출력을 지원하는 것과 달리 xxd는 오직 16진수 형식만 지원한다. -g옵션으로 출력 바이트 단위를 지정해줄 수 있으며 기본값은 2바이트 단위이다.
바이너리 파일을 수정하기 위해서는 vi와 xxd를 함께 사용하면 된다. xxd는 -r 옵션을 제공하는데 이는 reverse 기능으로, 원래 xxd가 바이너리 파일을 16진수 텍스트 형태로 변경해주는 프로그램인데 -r옵션을 사용하여 실행하면 16진수 텍스트를 그대로 다시 바이너리로 변경해 주게 된다. 따라서 바이너리 파일을 헥사 에디팅하려면 vi에서 xxd를 사용하여 바이너리를 16진수 텍스트 형태로 바꾸에 표시하여 주고, 이를 수정한 후 xxd -r을 사용하여 다시 바이너리 형태로 바꾸어준 다음 저장하면 된다.
먼저 vi 실행 시 -b옵션을 사용하여 수정하고자 하는 바이너리 파일은 연다. 이 옵션을 사용하게 되면 vi에서 binary 파일을 열 때 문제를 야기할 수 있는 여러가지 vi 기능들이 모두 turn off 된다.
vi -b filename
이후 아래와 같이 파일을 hex 포맷으로 변환한다.
:%!xxd
이제 헥사 포맷으로 변환된 텍스트를 수정한다. 수정시에는 데이터를 insert나 delete하면 안된다. (아쉬운 제약 사항이지만 어쩔 수 없다.) 따라서 r 명령을 사용하여 데이터를 원하는 값으로 한자씩 수정하는 것이 좋다. 수정이 끝나면 아래 명령으로 이를 다시 바이너리 데이터로 바꾸면 된다.
:%!xxd -r
-r 옵션으로 xxd를 실행시에는 16진수로 표시되는 데이터 영역의 값들만 참조되기 때문에 vi에서 16진수 데이터영역 외에 주소 영역이나 아스키로 표시되는 영역을 수정하더라도 이는 무시된다.
이제 데이터를 저장하고 나가면 된다.
:wq
수정사항을 xxd나 od로 확인해 볼 수 있다.
od -tx1 -Ax filename more +20 -10
라이브러리 이해하기 1.
- 정적 라이브러리
- 공유 라이브러리
- 동적 적재 라이브러리
정적 라이브러리는 .a로 끝나는 파일로 빌드 시 실행 파일에 포함되게 된다. 정적 라이브러리를 사용하는 프로그램을 만들기 위해서는 해당 라이브러리가 extern하는 함수가 선언된 헤더 파일과 해당 라이브러리가 필요하다.
공유 라이브러리는 .so로 끝나는 파일로 빌드 시 실행 파일에 포함되지 않는다. 따라서 여러 프로그램이 공유하는 기능을 공유 라이브러리로 만들 경우 디스크 공간을 아낄수 있고 공유 라이브러리에 버그가 존재할 경우 공유 라이브러리만 재배포하여 문제를 수정할 수 있다. 또한 공유 라이브러리가 이를 사용하는 프로세스에 의해 메모리에 로드되면, 해당 공유 라이브러리를 사용하는 또다른 프로세스가 실행되었을 때 이전 프로세스가 로딩해 놓은 내용을 공유하여 사용하기 때문에 메모리 사용량 또한 절약된다.
공유 라이브러리를 사용하는 프로그램을 만들기 위해서는 해당 라이브러리가 extern하는 함수가 선언된 헤더 파일과 해당 공유 라이브러리가 필요하다. 공유 라이브러리는 실행 파일이 실제로 시스템에서 실행되는 시점에 프로그램 링커 로더가 /lib, /usr/lib, 그리고 LD_LIBRARY_PATH등에서 해당 파일의 존재유무를 확인하고 이를 사용되게 된다. 공유 라이브러리는 앞서 말한바와 같이 링크되는 시점(해당 공유 라이브러리를 사용하는 어플리케이션을 빌드하는 시점)에 공유 라이브러리의 헤더와 라이브러리( .so)파일이 필요하다. 왜 실행파일에 포함되지 않는 라이브러리 파일이 필요한 것인까? 이는 빌드되는 어플리케이션이 실행될 때 찾아야 할 라이브러리의 이름이 공유 라이브러리 파일 안에 적혀있기 때문인데 이를 soname이라고 하고 이 soname은 라이브러리의 파일명하고 다를 수 있으므로 서로 구분하여야 한다. 공유 라이브러리를 컴파일할 때에는 아래와 같이 –fPIC (Position Independent Code)옵션이 필요하다.
gcc –fPIC –c MyLibrary.c
gcc –shared –Wl,-soname libMyLibrary.so.1 –o libMyLibrary.so.1.2.3 MyLibrary.o
동적 적재 라이브러리는 실행 중에 동적으로 로딩되는 라이브러리며, 프로그램 실행시가 아닌 해당 라이브러리에 포함된 함수가 사용되는 시점에 불려와 사용되게 된다. 따라서 동적 라이브러리를 사용하는 프로그램은 첫 실행이 정적 혹은 공유 라이브러리를 사용할 때 보다 빠르다는 장점이 있다. 또한 동적 적재 라이브러리는 실행 시 동적으로 라이브러리에서 직접 정보를 얻어와 실행한다. 따라서 동적 적재 라이브러리를 사용한 어플리케이션을 빌드하는 시점에서는 해당 라이브러리에 대한 헤더 파일이나 심지어 해당 라이브러리 자체도 필요 없다. 리눅스에서는 일반 공유 라이브러리를 동적으로 적재가 가능하므로 공유 라이브러리와 동적 적재 라이브러리가 같다고 할 수 있다. 다만 이를 사용하는 방법으로 구분될 뿐이다. 즉 so파일을 공유 라이브러리도 사용할 수도 동적 적재 라이브러리로 사용할 수도 있으며 동적 적재 라이브러리로 사용하려면 라이브러리를 사용하고자 하는 프로그램에서 dlopen, dlsym등을 사용하여 원하는 심볼을 불러오도록 처리하면 된다.
대부분의 unix/linux 시스템에서 LD_LIBRARY_PATH가 사용 가능하지만 모든 시스템에서 그런 것은 아니다. 리눅스에서는 LD_LIBRARY_PATH 사용이 가능하지만, /etc/ld.so.conf 파일과 ldconfig을 사용하여 /etc/ld.so.cache 파일을 생성하는 방법이 더 권장된다.
또다른 방법으로는 rpath를 지정하는 방법이 있다. rpath는 실행 파일을 compile할때 지정해 주면 된다.
gcc -Wall -o myexefile -Wl,rpath,. main.o -L. -lMyLibrary
위 예제에서는 rpath를 현재 디렉토리 [.]로 설정하였으며 이는 실행할 때 MyLibrary를 찾는 위치에 현재 디렉토리를 추가한 것이다. -L옵션은 링크시에 MyLibrary를 찾는 위치를 지정하는 옵션으로 역시 [.] 현재 디렉토리로 지정하였다. 굳이 -l 옵션으로 라이브러리를 지정할 필요 없이 경로를 포함한 파일 이름을 사용하여도 된다.
gcc -Wall -o myexefile -Wl,rpath,. main.o ./libMyLibrary.so.1.2.3
2009년 1월 11일 일요일
MTD 이해하기...
USB drive같은 몇몇 flash devices는 FTL을 아예 H/W로 구현하여 제품에 내장하여 출시하고, 이런 장치는 MTD가 아닌 block device로 보는 것이 타당하다. 그렇지 않은 Flash device에서는 FTL을 소프트웨어로 구현하게 된다.
MTD는 때로는(오히려 더 자주, 일반적으로) device차체가 아닌, device driver를 지칭하는 말로 사용된다. 이 경우에는 MTD는 FTL이 해당 Device를 control 할 수 있도록 도와주는 Low Level Driver라고 생각하면 된다. 제조사 별로, device별로 device를 제어하는 방법이 조금씩 다르기 때문에 MTD Layer에서 이를 일반화하여 주는 것이다. 따라서 FTL은 하위 device의 제조사나 특정 제품에 상관 없이 구현 될 수 있는 것이다. 아래는 FTL 을 사용하는 시스템의 구조를 표현한 것이다.
File System for block device
-----------------------------
FTL
-----------------------------
MTD Layer
최근에는 flash device를 위해서도 몇몇 파일 시스템이 개발되었으며, 이 경우 FTL이 없이 file system이 MTD Layer위에 올리기도 한다.
File System for flash device
-----------------------------
MTD Layer
하지만 필요에 따라서 flash file system이 FTL을 포함하고 있는 경우도 있으며, 이 경우의 FTL은 위에서 설명한 FTL과는 약간 다른 일을 수행하게 된다. 즉 최초의 FTL은 flash device를 block device로 변환시켜주기 위해 사용한 library 나 h/w를 의미하였으나, 최근에는 좀더 광범위한 의미로 사용되고 있다.
읽어볼만한 자료들
http://www.linux-mtd.infradead.org/faq/general.html
http://blog.naver.com/idkiss?Redirect=Log&logNo=50018755390
http://lsea.tistory.com/160
http://www.hongikcom.com/entry/4FTLFlash-Translation-Layer
2009년 1월 10일 토요일
#define에서 do{...}while(0) 을 사용하는 이유는?
//do{...}while(0)문을 사용하지 않은 경우
#define Inc2Each(x,y) { x+=2;y+=2;}
//do{...}while(0)문을 사용한 경우
#define Inc2Each(x,y) do{ x+=2;y+=2}while(0)
do{...}while(0)을 사용하지 않은 첫번째 방식의 경우 어떤 문제가 사용하는지 살펴보자
if ( x > y )
Inc2Each(x,y);
else
x=y;
위 코드는 아래와 같이 확장될 것이다.
if ( x > y )
{ x+=2;y+=2;};
else
x=y;
즉 if 와 else 사이에 원치 않는 ; 가 포함됨으로써 예상치 못했던 오류를 만들어 내게 된다.
하지만 do{...}while(0)을 사용하면 아래와 같이 문제가 깨끗하게 해결된다.
if ( x > y )
do{ x+=2;y+=2;}while(0);
else
x=y;
혹시 아직도 뭐가 문제인지 모르겠다면...
if ( x > y )
{
x+=2;
y+=2;
} //if 문은 여기서 끝난다.
; //빈 라인이 되고...
else //이 else는 if문이 없는 else가 되므로 컴파일 에러 발생할 것임.
x=y;
자세한 내용은 http://kernelnewbies.org/FAQ/DoWhile0