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