동적 적재(DL) 라이브러리
출처 : http://wiki.kldp.org/HOWTO/html/Program-Library-HOWTO/dl-libraries.html
4. 동적 적재(DL) 라이브러리
동적 적재 라이브러리는 프로그램이 시작할때가 아닌 다른 시기에 적재되는 라이브러리이다. 이것들은 플러그인이나 모듈을 구현할때 적합하다. 왜냐하면 그것들이 필요해질때까지 적재를 기다릴 수 있기 때문이다. 예를들어, PAM(Pluggable Authentication Modules)시스템은 관리자가 인증을 관리하는 것을 허용하기 위해 DL라이브러리를 사용한다. 이것들은 또한 때때로 코드를 머신 코드로 바꾸고 효율을 위해 멈추지 않고 컴파일된 코드로 만드는 인터프리터를 구현하는데 유용하다. 이것은 실시간의(just-in-time) 컴파일러나 MUD(multi-user dungeon)을 구현하는데에 유용하다.
리눅스에서, DL 라이브러리는 그들의 포멧의 관점에 있어서 특별하지 않다; 그들은 표준의 오브젝트 파일로 만들어지거나, 위에서 언급된 표준의 공유 라이브러리 파일로 만들어진다. 주요 차이점은 프로그램의 링크시나 시작시에 적재되지 않는다는 것이다; 대신, 라이브러리를 열거나, 심볼을 찾거나, 에러를 조정하거나, 라이브러리를 닫는 특별한 API가 있다. C 사용자들은 이런 API를 사용하기위해 dlfcn.h라는 헤더파일을 포함해야 한다.
리눅스에서 사용되는 인터페이스는 솔라리스에서 사용되는 인터페이스와 같다. 이것을 나는 ``dlopen()'' API라고 불를 것이다. 그러나, 이 같은 인터페이스가 모든 플랫폼에서 지원되는 것은 아니다; HP-UX는 shl_load()방법을 사용하고, 윈도우즈는 완전히 다른 인터페이스의 DLLs을 사용한다. 만약 당신이 폭넓은 포팅성이 목표라면, 당신은 이런 다른 플랫폼을 숨기는 라이브러리를 생각해야 할것이다. 하나의 방법은 모듈의 동적 적재를 지원하는 glib 라이브러리이다; 그것은 이 함수들의 포팅가능한 인터페이스를 구현하기위해 플랫폼의 동적 적재 루틴을 사용한다. http://developer.gnome.org/doc/API/glib/glib-dynamic-loading-of-modules.html의 링크에서 glib에 대해 많은 것을 찾아볼 수 있다. glib 인터페이스가 이 문서에 잘 설명되있기 때문에 더 언급하지 않겠다. 다른 방법은 GNU libtool의 일부인 libltdl을 사용하는 것이다. 당신이 이것보다 더 기능적인것을 원한다면, CORBA ORB(Object Request Broker)를 찾아보아라. 당신이 리눅스와 솔라리스에서 직접 지원되는 것을 아직도 원하고 있다면, 계속 읽어나가라.
4.1. dlopen()
dlopen(3)함수는 라이브러리를 열고 그것이 사용되도록 준비시켜준다. C에서 프로토타입은 다음과 같다:
void * dlopen(const char *filename, int flag); |
-
사용자의 LD_LIBRARY_PATH의 환경변수의 콜론으로 구분지어진 디렉토리
-
(/etc/ld.so.conf에서 파생된) /etc/ld.so.cache에 명시되어있는 라이브러리의 목록
-
/lib, /usr/lib. 순서를 주의하라; 이것은 예전의 a.out로더가 사용한 순서의 역이다. 예전의 a.out로더는 프로그램을 로드할때 /usr/lib을 찾고 /lib을 찾았다(ld.so(8)의 man페이지를 참고하라). 보통은 어떤 디렉토리나 다른디렉토리 하나에만 라이브러리가 있기 때문에(둘다 없을수도 있다) 문제가 되지 않는다. 그리고 같은이름을 가진 다른 라이브러리는 잠재적인 위험을 가지고 있다.
라이브러리들이 서로 의존한다면(예를들어 X가 Y에 의존한다면), 당신은 의존당하는 것을 먼저 로드해야한다(이 예제에서 Y를 로드하고 X를 로드해야 한다).
dlopen()의 리턴 값은 다른 DL라이브러리 루틴이 사용하기에 애매모호하게 느껴지는 ``핸들''이다. dlopen()은 로드가 성공하지 못하거나 당신이 체크해야 할 필요가 있다고 생각하면 NULL을 리턴한다. dlopen()에 의해 같은 라이브러리가 한번이상 로드되면 같은 파일 핸들이 리턴된다.
라이브러리가 _init이라 이름지어진 루틴을 사용한다면(export), 그 코드는 dlopen()이 반환하기 전에 실행된다. 당신은 초기화 루틴을 구현하기위해 당신의 라이브러리에서 이 사실을 사용했을것이다. 더 자세한 내용을 위해 5.2절을 보아라.
4.2. dlerror()
에러는 dlerror()를 호출함으로써 보고될수 있다. dlerror()는 dlerror(), dlsym(), dlclose()중 마지막 부른것의 에러의 스트링을 반환한다. 하나의 이상한점은 dlerror()를 부르고 나서 dlerror()를 부르는 것은 그 사이에 다른 에러가 없으면 NULL을 반환한다는 것이다.
4.3. dlsym()
당신이 사용할 수 없다면 DL라이브러리를 로딩하는 의미가 없다. DL라이브러리를 사용하는 중요한 루틴은 dlsym(3)이다. 이것은 열려진 라이브러리의 심볼의 값을 찾아준다. 이 함수는 다음과 같이 정의된다:
void * dlsym(void *handle, char *symbol); |
dlsym()은 심볼이 없으면 NULL을 반환할 것이다. 만약 당신의 심볼에 NULL이나 0이 없다는 것을 알면 좋겠지만, 다음과 같은 잠재적인 문제가 있다: 당신이 받은 NULL이 에러인가, 아니면 심볼의 값이 NULL인가? 표준적인 해결법은 dlerror()를 부르고(전에 있던 에러들을 없앤다), dlsym()을 불러서 심볼의 값을 부르고, dlerror()를 불러서 에러가 났는지 체크한다. 단순한 코드는 다음과 같다:
dlerror(); /* clear error code */ s = (actual_type) dlsym(handle, symbol_being_searched_for); if ((err = dlerror()) != NULL) { /* handle error, the symbol wasn't found */ } else { /* symbol found, its value is in s */ } |
4.4. dlclose()
dlopen()의 반대는 dlclose()로서, DL 라이브러리를 닫아준다. DL 라이브러리가 동적 파일 핸들의 링크 수를 관리하기 때문에, 동적 라이브러리는 dlopen이 성공한 만큼 모두 dlclose를 불러주기 전에 다 할당이 없어지지는 않는다. 따라서, 같은 프로그램이 같은 라이브러리를 여러번 불러주는것은 문제가 되지 않는다. 라이브러리가 할당이 없어진다면, 함수의 _fini가 불린다(존재한다면); 더 자세한 정보를 위해 5.2절를 보아라. 주의하라 : dlclose()는 성공하면 0을 리턴하고, 아니면 0이 아닌 값을 리턴한다; 어떤 리눅스 메뉴얼은 이것을 언급하고 있지 않다.
4.5. DL 라이브러리 예제
여기에 있는 예제는 dlopen(3)의 맨페이지에 나오는 예제이다. 이 예제는 math라이브러리를 로드해서, 코사인 2.0을 출력한다. 또한, 각각의 단계에서 에러 체크를 한다(이렇게 하기를 추천한다).
#include <stdlib.h> #include <stdio.h> #include <dlfcn.h> int main(int argc, char **argv) { void *handle; double (*cosine)(double); char *error; handle = dlopen ("/lib/libm.so.6", RTLD_LAZY); if (!handle) { fputs (dlerror(), stderr); exit(1); } cosine = dlsym(handle, "cos"); if ((error = dlerror()) != NULL) { fputs(error, stderr); exit(1); } printf ("%f\n", (*cosine)(2.0)); dlclose(handle); } |
만약 이 프로그램의 파일이름이 "foo.c"라면, 다음과 같은 명령으로 프로그램을 만들 수 있을 것이다:
gcc -o foo foo.c -ldl |
'C & C++ 관련' 카테고리의 다른 글
Program Library HOWTO (0) | 2009.09.26 |
---|---|
어느 학교의 과제 Vector 실습. (0) | 2009.09.25 |
C++ 에서 C함수 쓰는 방법 (0) | 2009.09.23 |