c 로 만든 플러그인 인터페이스
만들고 보니 glib 랑 유사함. 객체 지향 냄새가 물씬 풍김
c 로는 이렇게 만듦. language.h 는 인터페이스임.
프로그램 입장에서는 플러그인 이름을 모르기 때문에 동일한 인터테이스로 플러그인(모듈)을
로딩/언로딩할 필요가 있음. 그리고 작동시킬 때에도 동일한 인터페이스가 필요함.
플러그인(모듈)을 만들기 위해서는 저런 인터페이스를 만들고 저걸 구현하면 됨
language.h
----------
typedef struct _Language Language;
struct _Language
{
char * (* get_id) (Language *lang);
int (* filter) (Language *lang, int val);
void (* free) (Language *lang);
};
Language *language_new (void);
char *language_get_id (Language *lang);
int language_filter (Language *lang, int val);
void language_free (Language *lang);
language.c
----------
#include "language.h"
#include
#include
char *language_get_id (Language *lang)
{
return (lang->get_id) ? lang->get_id (lang) : NULL;
}
int language_filter (Language *lang, int val)
{
if (lang->filter)
return lang->filter (lang, val);
return 0;
}
void language_free (Language *lang)
{
if (lang->free)
return lang->free (lang);
fprintf (stderr, "Implement language_free()");
}
english.c 는 language.h 를 구현한 구현체입니다.
english.c
---------
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
#include "language.h"
#include
#include
#include
#include
typedef struct _English
{
Language base;
char *id;
} English;
char *english_get_id (Language *lang)
{
English *english = (English *) lang;
return english->id;
}
int english_filter (Language *lang, int val)
{
return val;
}
void english_free (Language *lang)
{
English *english = (English *) lang;
free (english->id);
free (english);
}
Language *language_new ()
{
English *english;
english = calloc (1, sizeof (English));
english->id = strdup ("english");
english->base.get_id = english_get_id;
english->base.filter = english_filter;
english->base.free = english_free;
return (Language *) english;
}
korean.c 는 language.h 를 구현한 구현체입니다.
korean.c
--------
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
#include "language.h"
#include
#include
#include
#include
typedef struct _Korean
{
Language base;
char *id;
} Korean;
char *korean_get_id (Language *lang)
{
Korean *korean = (Korean *) lang;
return korean->id;
}
int korean_filter (Language *lang, int val)
{
return val;
}
void korean_free (Language *lang)
{
Korean *korean = (Korean *) lang;
free (korean->id);
free (korean);
}
Language *language_new ()
{
Korean *korean;
korean = calloc (1, sizeof (Korean));
korean->id = strdup ("korean");
korean->base.get_id = korean_get_id;
korean->base.filter = korean_filter;
korean->base.free = korean_free;
return (Language *) korean;
}
korean.so, english.so 를 dlopen() 으로 로딩 후
동일 인터페이스로 korean.so english.so 안의 함수를 실행함.
.so 파일은 shared object 이게 여기서는 모듈(플러그인) 되는 것임
(참고로 libname.so.X.Y.Z 형식이 되면 라이브러리가 됨)
main.c
------
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
#include
#include
#include
#include "language.h"
int main (int argc, char **argv)
{
void *korlib;
void *englib;
Language *kor;
Language *eng;
char *errstr;
Language * (* language_new) ();
/* Korean */
if (!(korlib = dlopen ("./korean.so", RTLD_LAZY | RTLD_LOCAL)))
goto FAIL;
if (!(language_new = dlsym (korlib, "language_new")))
goto FAIL;
kor = language_new ();
printf ("%s\n", kor->get_id (kor));
printf ("%d\n", kor->filter (kor, 97));
printf ("%s\n", language_get_id (kor));
printf ("%d\n", language_filter (kor, 98));
language_free (kor);
dlclose (korlib);
/* English */
if (!(englib = dlopen ("./english.so", RTLD_LAZY | RTLD_LOCAL)))
goto FAIL;
if (!(language_new = dlsym (englib, "language_new")))
goto FAIL;
eng = language_new ();
printf ("%s\n", eng->get_id (eng));
printf ("%d\n", eng->filter (eng, 65));
printf ("%s\n", language_get_id (eng));
printf ("%d\n", language_filter (eng, 66));
language_free (eng);
dlclose (englib);
return 0;
FAIL:
if ((errstr = dlerror ()))
printf ("%s\n", errstr);
if (korlib)
dlclose (korlib);
if (englib)
dlclose (englib);
return 1;
}
Makefile 에서 좌측 공백은 탭 문자입니다. 스페이스 공백 아닙니다.
실행 편의를 위해 rpath 를 현재 디렉토리로 지정했음
Makefile
--------
PROGRAM = main
MODULES = korean.so english.so language.so
all: $(PROGRAM) $(MODULES)
$(PROGRAM): main.o language.so
$(CC) -Wl,-rpath=. -o main main.o language.so -g -ldl
%.so: %.o
$(CC) -shared -fPIC $< -o $@
%.o: %.c
$(CC) -fPIC -c -o $@ $< $(CFLAGS)
clean:
rm -f $(MODULES) $(MODULES:.so=.o) $(PROGRAM) $(PROGRAM).o
에잇 ㅅㅂ 버그 있네... void *korlib = NULL; void *englib = NULL; 초기화 해줘야 함 ㅠㅠ