Doxygen을 이용한 프로젝트 소스 문서화 하기 Part II
6. 기본적인 코멘트 작성법
먼저, 기본적으로 Doxygen을 이용한 문서화를 위해서 필요한 규칙에 대해서 알아 보겠습니다.
문서화를 위해서 C나 C++에서의 주석 블록에 Doxygen이 이해할 수 있는 추가적인 표시를 해야 합니다.
각각의 코드에는 두가지 형태의 설명이 있는데, brief절과 detailed절로서 선택적으로 문서화에 사용될 수 있습니다.
단, Doxygen은 하나이상의 brief, detailed절이 존재하는 것은 허용하지 않습니다. 이 둘의 차이점은 이름에서도 알 수 있듯이 brief절은 간단한 요약을 기술하는 것이고, detailed절은 보다 자세한 설명을 작성하는 것입니다.
그럼 주석 블록에 문서화를 위해 표시를 하고 설명을 하는 몇가지 방법을 알아보겠습니다.
1. 먼저 C언어에서의 주석 블록에 JavaDoc 스타일과 Qt스타일을 사용하는 방법이 있습니다.
C언어에서의 주석블록이 ‘/*’로 시작하고, JavaDoc 스타일의 경우에는 이 뒤에 두개의 ‘*’ 문자를 추가하고 설명을 작성합니다.
*
* … 설명 …
Qt 스타일의 경우는 뒤에 느낌표 ‘!’ 를 추가하고 중간에 ‘*’ 문자를 추가한 다음 설명을 작성합니다.
!
* … 설명 …
즉, 실제로는 다음과 같이 작성이 되겠습니다.
/**
* some comment with JavaDoc style
*/또는
/*!
* some comment with Qt style
*/
위의 두가지 방법에서 모두 중간의 ‘*’ 문자는 생략이 가능합니다. 따라서, 다음과 같이 작성하는 것도 올바른 방법입니다.
/**
some comment with JavaDoc style
*/또는
/*!
some comment with Qt style
*/
2. 두번째로 C++의 주석 라인에 추가로 ‘/’ 문자나 ‘!’ 문자를 추가하고 설명을 작성하는 방법이 있습니다.
///
/// … 설명 …
///또는
//!
//! … 설명 …
//!
3. 가독성을 위해서 다음과 같이 작성하는 사람들도 있습니다. 개인 취향이겠죠.
///////////////////////////////////
/// … 설명 …
///////////////////////////////////
본인이 사용하기에 익숙한 스타일이나, 가독성이 더 뛰어나다고 생각되는 스타일을 사용하면 되겠습니다.
저의 경우 C언어를 주로 사용하고, ‘/’ 문자와 ‘\’ 문자가 서로 비슷하게 보일 때가 있어서 (:)) C언어 스타일에 JavaDoc 스타일을 선호합니다. 귀차니즘의 영향으로 중간에 ‘*’ 문자는 생략을 합니다. (깔끔해 보인다고 우기면서 말입니다.) 따라서, 앞으로의 설명도 주로 C + JavaDoc 스타일로 하겠습니다.
그럼 앞에서 잠깐 언급했던 brief절과 detailed절을 어떻게 작성하는지 알아보겠습니다.
1. ‘\brief’ 또는 ‘@brief’ 명령어를 주석 블록 위에 사용하는 방법이 있습니다. 이 명령어는 단락(절)의 끝까지 적용되기때문에, detailed절과 구분하기 위해 공백라인 한줄이 필요하게 됩니다.
/**
\brief 간단한 요약 설명을 적습니다.
여기도 계속 요약 설명입니다.한줄의 공백이 추가되었으며, 이곳은 자세한 설명을 합니다.
*/
2. 설정파일에서 JAVADOC_AUTOBRIEF를 YES로 설정했다면 JavaDoc 스타일의 주석 블록에서 brief 절은 자동으로 첫번째 마침표 ‘.’ 를 만날때까지 적용됩니다. 첫번째 마침표 이후가 자동적으로 detailed 절이 됩니다. 여러줄의 C++ 주석블록에서도 동일하게 적용됩니다.
C 스타일의 경우
/**
Brief절은 첫번째 마침표 까지 입니다 . 여기서부터 detailed 절이 되겠습니다.
자세한 설명을 적습니다.
*/
C++ 스타일의 경우
///마찬가지로 첫번째 마침표까지 Brief 절입니다. 이후로는 detailed 절입니다.
///계속 detailed 절입니다.
저의 경우는 1.의 방식으로 사용합니다. JAVADOC_AUTOBRIEF를 YES로 사용하고 ‘\brief’, ‘@brief’ 명령어를 입력하지 않고 코멘트를 작성하게 되면 타이핑을 덜하게 되는 장점이 있을지는 몰라도, 첫번째 마침표까지만 brief 절로 인식이 되기 때문에 원하는 대로 문서화를 시키지 못하게 되는 경우가 생길 수도 있기 때문입니다. 개인적인 취향이나, 팀원들간에 협의가 된 방향으로 선택하여 사용하면 되겠습니다.
지금까지 Doxygen의 기본적인 코멘트 작성 방법에 대해서 알아보았습니다. 실제로 예제에서 어떻게 코멘트를 작성하는지 예제를 통해서 알아보도록 하겠습니다. 예제는 Doxygen의 공식 메뉴얼에서 발췌하였습니다. 좀더 자세한 내용이 궁금하시면 메뉴얼을 참조 하시길 바랍니다.
7.소스 코드에 코멘트 작성법 예제
다음의 예제는 C++ 코드에 Qt 스타일로 코멘트가 작성된 것입니다.
[cpp]
//! A test class.
/*!
A more elaborate class description.
*/
class Test
{
public:
//! An enum.
/*! More detailed enum description. */
enum TEnum {
TVal1, /*!< Enum value TVal1. */
TVal2, /*!< Enum value TVal2. */
TVal3 /*!< Enum value TVal3. */
}
//! Enum pointer.
/*! Details. */
*enumPtr,
//! Enum variable.
/*! Details. */
enumVar;
//! A constructor.
/*!
A more elaborate description of the constructor.
*/
Test();
//! A destructor.
/*!
A more elaborate description of the destructor.
*/
˜Test();
//! A normal member taking two arguments and returning an integer value.
/*!
\param a an integer argument.
\param s a constant character pointer.
\return The test results
\sa Test(), ˜Test(), testMeToo() and publicVar()
*/
int testMe(int a,const char *s);
//! A pure virtual member.
/*!
\sa testMe()
\param c1 the first argument.
\param c2 the second argument.
*/
virtual void testMeToo(char c1,char c2) = 0;
//! A public variable.
/*!
Details.
*/
int publicVar;
//! A function variable.
/*!
Details.
*/
int (*handler)(int a,int b);
};
[/cpp]
예제에서 알 수 있듯이, 한줄의 brief절과 여러줄의 detailed 절로 구성 되어있습니다.
다음의 예제는 위의 예제와 똑같은 코드이지만 설정 파일의 JAVADOC_AUTOBRIEF 옵션을 YES로 세팅하고 JavaDoc 스타일로 코멘트를 작성한 것입니다.
[cpp]
/**
* A test class. A more elaborate class description.
*/
class Test
{
public:
/**
* An enum.
* More detailed enum description.
*/
enum TEnum {
TVal1, /**< enum value TVal1. */
TVal2, /**< enum value TVal2. */
TVal3 /**< enum value TVal3. */
}
*enumPtr, /**< enum pointer. Details. */
enumVar; /**< enum variable. Details. */
/**
* A constructor.
* A more elaborate description of the constructor.
*/
Test();
/**
* A destructor.
* A more elaborate description of the destructor.
*/
˜Test();
/**
* a normal member taking two arguments and returning an integer value.
* @param a an integer argument.
* @param s a constant character pointer.
* @see Test()
* @see ˜Test()
* @see testMeToo()
* @see publicVar()
* @return The test results
*/
int testMe(int a,const char *s);
/**
* A pure virtual member.
* @see testMe()
* @param c1 the first argument.
* @param c2 the second argument.
*/
virtual void testMeToo(char c1,char c2) = 0;
/**
* a public variable.
* Details.
*/
int publicVar;
/**
* a function variable.
* Details.
*/
int (*handler)(int a,int b);
};
[/cpp]
저의 경우는 JAVADOC_AUTOBRIEF 옵션을 NO로 세팅 하고 가능한 C 스타일의 주석을 사용하기 때문에 위의 예제는 다음과 같이 됩니다.
[cpp]
/**
@brief A test class.
A more elaborate class description.
*/
class Test
{
public:
/**
@brief An enum.
More detailed enum description.
*/
enum TEnum {
TVal1, /**< enum value TVal1. */
TVal2, /**< enum value TVal2. */
TVal3 /**< enum value TVal3. */
}
*enumPtr, /**< enum pointer. Details. */
enumVar; /**< enum variable. Details. */
/**
@brief A constructor.
A more elaborate description of the constructor.
*/
Test();
/**
@brief A destructor.
A more elaborate description of the destructor.
*/
˜Test();
/**
@brief a normal member taking two arguments and returning an integer value.
@param a an integer argument.
@param s a constant character pointer.
@see Test()
@see ˜Test()
@see testMeToo()
@see publicVar()
@return The test results
*/
int testMe(int a,const char *s);
/**
@brief A pure virtual member.
@see testMe()
@param c1 the first argument.
@param c2 the second argument.
*/
virtual void testMeToo(char c1,char c2) = 0;
/**
@brief a public variable.
Details.
*/
int publicVar;
/**
@brief a function variable.
Details.
*/
int (*handler)(int a,int b);
};
[/cpp]
brief절과 detailed절을 구분하기 위해 공백라인이 추가된 것을 보실 수 있습니다. '@param' 은 함수의 파라미터에 대한 설명을 적으며 '@return'은 함수의 반환값에 대한 설명을 적어줍니다. '@see' 는 Qt 스타일의 경우 '\sa' 와 같은 의미이며 see also를 표현합니다.
위의 예제에서 특이한 점은 '<' 문자가 추가된 부분일 것입니다. file, struct, union, class, enum 의 멤버들에 대해 문서화를 하고 싶을때 다음과 같이 '<'를 이용하여 멤버변수나 함수 바로 뒤에 코멘트를 작성하면 됩니다.
int var1; /**< C, JavaDoc */
int var2; /*!< C, Qt */
int var3; ///< C++
int var4; //!< C++
다음은 이러한 멤버들에 대해 코멘트를 작성한 간단한 예제입니다.
[cpp]
/*! A test class */
class Test
{
public:
/** An enum type.
* The documentation block cannot be put after the enum!
*/
enum EnumType
{
int EVal1, /**< enum value 1 */
int EVal2 /**< enum value 2 */
};
void member(); //!< a member function.
protected:
int value; /*!< an integer value */
};
[/cpp]
예제에서도 여러가지 스타일로 코멘트를 작성해 놓았습니다.
여기서 중요한 것은, '/**< comment */ 와 같은 멤버들을 위한 코멘트 블록은 멤버와 파라미터에만 적용할 수 있다는 것입니다. 즉, 파일이나 클래스, 구조체, 그룹, 네임스페이스나 열거형 타입 자체를 문서화 할때는 사용할 수 없다는 것을 의미합니다.
몇가지 규칙만 이해하면 Doxygen을 이용하여 코멘트를 작성하는 것은 예제에서와 같이 어렵지 않습니다. 지금까지 알아본 방법들만 이용해도 훌륭한 문서를 얻을 수 있습니다.
8. 문서의 다른 곳에 코멘트를 작성하는 방법
앞에서의 예제를 살펴보면 모든 코멘트 블록은 파일, 클래스, 구조체, 네임스페이스 등의 선언부나 정의부 앞에서 작성된 것을 알 수 있습니다. (멤버인 경우는 바로 뒤에서 작성을 했습니다.) 몇가지 특수한 명령어를 사용하면 문서내의 아무곳에다가 원하는 코드에 대한 코멘트를 작성 할 수 있습니다.
다른 명령어들과 마찬가지로 ‘\’ 나 ‘@’로 시작하는 명령어로 다음과 같은 것들이 있습니다.
@class @struct @union @enum @fn @var @def @file @namespace @package @interface
명령어 이름에서도 나타나듯이, 각각 class, struct, union, enum, function, var, define, file, namespace, package, interface 에 대해서 코멘트를 작성 하기 위해 사용하는 명령어 입니다. (보다 자세한 내용이 궁금하시다면 공식 메뉴얼의 Reference 파트의 ‘Special Commands’ 부분을 참조하시면 됩니다.)
다음의 structcmd.h 라는 C 헤더 파일에서 위의 명령어들을 사용하여 코멘트를 작성한 예를 보겠습니다.
[cpp]
/**
@file structcmd.h
@brief A Documented file.
Details.
*/
/**
@def MAX(a,b)
@brief A macro that returns the maximum of \a a and \a b.
Details.
*/
/**
@var typedef unsigned int UINT32
@brief A type definition for a .
Details.
*/
/**
@var int errno
@brief Contains the last error code. \ warning Not thread safe!
*/
/**
@fn int open(const char *pathname,int flags)
@brief Opens a file descriptor.
function details.
@param pathname The name of the descriptor.
@param flags Opening flags.
*/
/**
@fn int close(int fd)
@brief Closes the file descriptor \a fd.
@param fd The descriptor to close.
*/
/**
@fn size_t write(int fd,const char *buf, size_t count)
@brief Writes \a count bytes from \a buf to the filedescriptor \a fd.
@param fd The descriptor to write to.
@param buf The data buffer to write.
@param count The number of bytes to write.
*/
/**
@fn int read(int fd,char *buf,size_t count)
@brief Read bytes from a file descriptor.
@param fd The descriptor to read from.
@param buf The buffer to read into.
@param count The number of bytes to read.
*/
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef unsigned int UINT32;
int errno;
int open(const char *,int);
int close(int);
size_t write(int,const char *, size_t);
int read(int,char *,size_t);
[/cpp]
이 예제에서 알 수 있듯이 특수한 명령어들을 사용하였기 때문에 문서의 다른 위치 (예제에서는 상위에)에 코멘트 블록이 작성되어있습니다.
9. 마치며
이제, 본인의 코드에 앞에서 살펴본 내용을 바탕으로 코멘트를 작성해 보시길 바랍니다. 처음엔 귀찮은 작업이 될지는 몰라도 최종적으로 Doxygen이 생성시켜주는 문서를 보았을때는 굉장한 만족감을 느낄 수 있을 것입니다. 1부에서 언급한대로 Doxyfile의 내용을 설정하고 Graphviz를 설치 하였다면 정말 멋진 화면을 감상하실 수 있습니다. 원하는 대로 화면에 출력이 되지 않았을 경우에는 코멘트 작성법이 틀렸거나, 설정 파일의 옵션이 상황에 맞지 않는 경우입니다. 이를 잘 확인 하시고, 한줄 한줄씩 문서화를 해 나가다 보면 훌륭한 API 메뉴얼을 얻을 수 있을 것입니다.