from https://developer.gnome.org

GObject 위한 코드 작성의 첫 단계는 “타입의 header"를 작성하는 일입니다. 여기에는 필요한 타입, 함수, 매크로가 포함됩니다. 이들 요소들은 “거의 대부분의 유저들에 의해 지켜지고 있는 표준"으로, GObject-based 코드를 수 년동안 개발해 온 경험을 통해 다듬어진 내용들입니다. 만일 라이브러리를 작성하고 있다면, 이들 표준을 준수하는 것이 매우 중요합니다. 왜냐하면 이 라이브러리의 사용자들은 작성자가 표준을 따라서 이를 작성했으리라고 가정할 것이기 때문입니다. 만일 라이브러리를 작성하는 것이 아니라고 하더라도, 표준을 지켜서 코드를 작성하는 것은 프로젝트에 참여하기를 원하는 다른 사람들에게 도움이 될 것입니다.

파일 이름 규칙

아래의 헤더/소스코드 name convension 중 하나를 택해서 파일들의 이름을 일관성있게 유지하세요:

  1. Prefix와 typename을 구분하기 위해 대쉬(-)를 사용: viewer-file.h 그리고 viewer-file.c (Nautilus와 대부분의 GNOME 라이브러리들이 사용하는 규칙임).
  2. Prefix와 typename을 구분하기 위해 언더스코어(_)를 사용: viewer_file.h 그리고 viewer_file.c
  3. prefix를 typename으로부터 구분하지 않음: viewerfile.h 그리고 viewerfile.c. (GTK+에서 사용하는 표준)

어떤 사람들은 1번과 2번 방법을 선호합니다: 안력이 떨어지는 사람들에게 파일 이름을 더 읽기 쉽게 해 주니까요.

Header 파일 안에 적용되는 Symbol Name 규칙들

GType을 외부로 노출하는 모든 header파일에 적용되는 기본적인 표준이 Conventions에 기술되어 있습니다.

‘viewer’ namespace 안에서 ‘file’ type을 생성하려는 경우 instance는 ViewerFile로, class는 ViewerFileClass로 명명합니다(이들 이름은 case sensitive함에 유의).

Header에서의 type 선언은 해당 type이 final인지 derivable인지에 따라 다음의 두 가지 방법이 권장됩니다.

Final type은 더이상 subclass 될 수 없는 type이며, 새로운 타입을 선언할 때의 표준적인 선택입니다 — final type을 derivable로 변경하는 것은 항상 이미 구현된 구현들과의 호환성을 보장하지만, 그 반대는(final type에서 derivable로의 변경은) 자주 문제를 발생시킵니다.

Final Type을 선언하는 Header 예제

Final type은 G_DECLARE_FINAL_TYPE 매크로를 통해 정의되며, 이 때 instance data를 저장해 두기 위한 structure가 소스코드에(헤더파일이 아니라) 함께 선언되어야 합니다.

/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __VIEWER_FILE_H__
#define __VIEWER_FILE_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

G_BEGIN_DECLS

/*
 * Type declaration.
 */
#define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)

/*
 * Method definitions.
 */
ViewerFile *viewer_file_new (void);

G_END_DECLS

#endif /* __VIEWER_FILE_H__ */

G_BEGIN_DECLSG_END_DECLS는 c++ compiler 사용 시 extern c {} 로 변환되는 매크로입니다.

Derivable Type을 선언하는 Header 예제

Derivable type은 앞으로 subclass 될 수 있는 type입니다. 그러므로 API의 안정성을 고려할 때, 해당 type의 class와 instance structure는 변경되지 않는 public API의 부분이 되어야 합니다.

Header 파일은 일반적으로 모듈의 ‘외부’에 노출되는 ‘public’한 성격의 파일입니다. Derivable한 parent class의 structure가 변경되면 subclass가 영향을 받으므로, 이는 public하게 노출해 두어야 한다는 의미입니다.

이 type은 G_DECLARE_DERIVABLE_TYPE를 통해 선언됩니다:

/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __VIEWER_FILE_H__
#define __VIEWER_FILE_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

G_BEGIN_DECLS

/*
 * Type declaration.
 */
#define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)

/*
 * Public API의 일부로써 header에 선언된 class structure.
 */
struct _ViewerFileClass
{
  GObjectClass parent_class;

  /* Class virtual function fields. */
  void (* open) (ViewerFile  *file,
                 GError     **error);

  /* Padding to allow adding up to 12 new virtual functions without
   * breaking ABI. */
  gpointer padding[12];
};

/*
 * Method definitions.
 */
ViewerFile *viewer_file_new (void);

G_END_DECLS

#endif /* __VIEWER_FILE_H__ */

12개의 gpointer를 class structure 가장 아래에 선언함으로써 이 후의 subclass에서 최대 12개의 method를 추가할 수 있는 공간을 마련한 것에 주목하세요. 이와같은 방법을 통해서 derivative type인 super class를 이용하여 빌드된 library를 재빌드하지 않아도 문제없이 링크할 수 있게 되며, 이를 ABI(Application Binary Interface)를 연속성 있게 유지한다고 표현합니다.

Include 규칙

Header include의 규칙은 “해당 헤더를 빌드하기 위해 필요한 최대한 작은 수의 다른 header를 include한다” 입니다. 이는 이 header를 사용하는 client code에서 해당 module의 prerequisites에 대해 알 필요 없이 #include "viewer-file.h"를 적음으로써 해당 모듈을 사용할 수 있도록 합니다.