glib2 라이브러리는 gobject라는 라이브러리를 포함하고 있다. 해당 라이브러리는 C에서 객체를 생성하여 다룰 수 있도록 해준다.
C에서 객체라니... C는 절차적 언어 아닌가? 라고 생각이 들 수 있지만 객체 지향 프로그래밍 자체는 프로그래밍을 개발하는 프로그래밍 사고 방식이며 어떤 프로그램 언어이든 적용은 가능하다. 그러나 객체지향의 스펙을 지원하기 위해 개발된 OOP 언어가 아니기 때문에 제약은 있다.
https://onurmark.tistory.com/10
[GLIB2] 개발 환경 구축
GLIB는 GTK+ 프로젝트의 일부분에서 UI를 제외한 부분이 독립적으로 떨어져 나온 라이브러리로 다양한 소프트웨어 라이브러리를 포함하고 있다. 많은 운영체제에 이미 포팅되어있어 크로스플랫폼
onurmark.tistory.com
위 포스트에서 설명한 개발환경 위에서 진행한다. 먼저 위의 포스트를 따라 환경을 구축한다음 진행하도록 하자
GObject header
src/exam-car.h
#ifndef EXAM_CAR_H_BAQCYW7H
#define EXAM_CAR_H_BAQCYW7H
#include <glib-object.h>
G_BEGIN_DECLS
#define EXAM_TYPE_CAR exam_car_get_type()
G_DECLARE_DERIVABLE_TYPE(ExamCar, exam_car, EXAM, CAR, GObject)
struct _ExamCarClass {
GObjectClass parent_class;
};
void
exam_car_print(ExamCar *self);
ExamCar *
exam_car_new(void);
G_END_DECLS
#endif /* end of include guard: EXAM_CAR_H_BAQCYW7H */
gobject는 {prefix}-{name}.h 형태로 네이밍한다. 이 예제에서는 prefix는 exam을 사용하고 car라는 object를 생성하도록 한다.
해당 코드가 복잡해 보이지만 템플릿이라고 생각하고 접근하자
먼저 glib의 object를 사용하기 위해서는 glib-object.h 헤더를 인클루드 한다. G_BEGIN_DECLS, G_END_DECLS는 C++ 에서도 해당 파일을 사용할 수 있도록 해주는 "extern C {}"와 동일한 구문이다.
EXAM_TYPE_CAR와 G_DECLARE_DERIVABLE_TYPE은 해당 객체를 선언하는 부분이다. derivable type으로 선언하였기 때문에 나중에 해당 객체를 상속하여 자식 객체를 생성할 수도 있다. 그러기 위해 _ExamCarClass를 외부로 노출시켜준다. 해당 객체는 GObject로 부터 상속을 받는다. GObject는 기본이되는 오브젝트이다.
exam_car_print()은 해당 자동차의 정보를 stdout으로 출력하기 위한 함수이다. exam_car_new()는 해당 객체를 생성하는 함수이다.
이 모든걸 반드시 하나하나씩 이해하기 보다는 객체를 선언하기 위해서는 위와 같은 템플릿을 사용한다로 이해하자.
GObject source
src/exam-car.c
#include "exam-car.h"
typedef struct {
gchar *model;
gint year;
} ExamCarPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(ExamCar, exam_car, G_TYPE_OBJECT);
static void
exam_car_class_init(ExamCarClass *klass)
{
}
static void
exam_car_init(ExamCar *self)
{
}
void
exam_car_print(ExamCar *self)
{
ExamCarPrivate *priv =
exam_car_get_instance_private(self);
if (!priv->model) {
g_print("Unknown model\n");
return;
}
g_print("%d %s", priv->year, priv->model);
}
ExamCar *
exam_car_new(void)
{
return g_object_new(EXAM_TYPE_CAR, NULL);
}
자 또한 복잡해 보이지만 어렵지 않다. ExamCarPrivate는 외부로 노출되지 않는 객체가 가지고 있는 변수들이다. G_DEFINE_TYPE_WITH_PRIVATE는 해당 객체가 private 변수를 가지고 있고 G_TYPE_OBJECT로 부터 상속을 받는 다는 의미이다.
exam_car_class_init() 에서는 상위 객체를 오버라이딩할 수 있다 exam_car_init()에서는 객체 생성시 초기화를 수행하는 부분이다. exam_car_new()는 객체를 생성하는 부분이다.
클라이언트 코드
src/main.c
#include <glib.h>
#include "exam-car.h"
int main(int argc, char *argv[])
{
ExamCar *my_car;
my_car = exam_car_new();
exam_car_print(my_car);
return 0;
}
my_car 객체를 생성하고 출력하는 클라이언트 코드이다.
빌더에 해당 코드를 같이 컴파일 하도록 수정
src/Makefile.am
bin_PROGRAMS = glibexam
glibexam_SOURCES = \
main.c \
exam-car.h \
exam-car.c
glibexam_CFLAGS = \
$(AM_CFLAGS) \
$(GLIB_CFLAGS) \
$(GIO_CFLAGS) \
$(GOBJECT_CFLAGS)
glibexam_LDADD = \
$(GLIB_LIBS) \
$(GIO_LIBS) \
$(GOBJECT_LIBS)
방금 생성한 exam-car.h exam-car.c 를 포함하여 빌드하도록 수정한다.
$ autoreconf -i
을 수행하여 방금 변경된 빌드를 추가한다. 매번 소스 파일을 추가할때마다 이 작업을 반복하기가 번거롭기 때문에 configure시 automake의 변경 사항을 검사하여 자동으로 추가하는 설정을 해주는게 좋다.
./configure --enable-maintainer-mode
maintainer-mode가 활성화되면 Makefile.am 의 변경사항을 자동으로 추적해 빌드에 포함시켜 주기 때문에 더이상 autoreconf를 수행할 필요 없이 make 명령으로 컴파일 할 수 있게 해준다.
~/Workspaces/glibexam ❯ ./src/glibexam
Unknown model
make 로 컴파일 후 실행하면 다음과 같이 정상적으로 출력되는 것을 확인 할 수 있다.
지금까지 객체를 생성하고 호출 하는 방법에 대해 간략히 개발을 하였다. 다음 포스트에서는 해당 object의 private 변수에 있는 property에 접근하여 값을 설정하고 얻어오는 방법이랑 상속에 대해서 좀 더 자세히 들어가 볼 예정이다.
'C' 카테고리의 다른 글
C언어 개발 환경 구축 (4) - 자동완성, CoC 그리고 bear (0) | 2022.02.21 |
---|---|
[GLIB2] 개발 환경 구축 (0) | 2022.02.08 |
[Data Structures in c #0] 시작 전 환경 구성 (0) | 2020.08.31 |
C언어 개발 환경 구축 (3) - YouCompleteMe (0) | 2020.07.17 |
C언어 개발 환경 구축 (2) - autotools (0) | 2020.07.17 |