메뉴 건너뛰기


Developer > Development Tools

Doxygen 4장. Doxygen 응용 3/3

2013.11.16 01:36

푸우 조회 수:8734

이번에는 저번 강좌에 이어 클래스에 문서화 주석 다는 법을 알아보도록 하겠습니다.
 
 
4장. Doxygen 응용 3/3
 
이번에는 클래스에 주석 다는 것을 해볼텐데요. 클래스, 구조체, ENUM 등 블록 지어질 수 있는 것들은 모두 마찬가지가 될 것입니다.
 
1. 클래스에 문서화 주석 달기
 
hello.h파일에 선언한 Hello 클래스를 다음과 같이 바꾸세요.
/** * Hello 클래스. * * 인사를 하기 위한 사용자의 이름과 count값을 관리합니다. */ class Hello { private: char *username; //!< 사용자이름을 저장하는 비공개 멤버 변수 */ public: int count; public: Hello(char *user); ~Hello(void); ///< Hello 클래스의 소멸자 char *getUserName(void); void setCount(int num); int getCount(void); };
 
그리고 hello.cpp에서 다음과 같이 Hello()함수와 ~Hello()함수 위에 다음과 같은 주석을 추가하세요.
 
/** * Hello 클래스의 생성자. * * Hello 객체의 멤버변수들을 초기화 합니다. * @see Hello::~Hello */ Hello::Hello( char *user ///<[in] 사용자의 이름 ) { this->username=NULL; this->count=0; this->username=strdup(user); } /** * Hello 객체 멤버변수에 할당된 메모리를 해제합니다. * @see Hello::Hello */ Hello::~Hello(void)
 
말씀을 안드렸는데 위의 Hello()함수의 매개변수 부분에도 주석을 추가했습니다.
위와 같이 했다면 doxygen을 돌리고 html문서를 보세요.
다음은 상단의 "데이터 구조" 탭을 클릭한 화면입니다.
 
1.png
 
Hello 클래스에 간단한 설명이 달렸군요. 이번엔 Hello 클래스 이름을 클릭해서 Hello 클래스 문서를 보세요.
2.png
 
생성자와 소멸자에 모두 간단한 설명이 붙었네요. 주석을 되돌아 보면 생성자 주석은 함수 위에 간단한 설명을 달았지만 소멸자는 헤더 파일에 간단한 설명을 달았었습니다.
데이터 필드에는 클래스내의 공개 멤버 변수인 count 만 표시가 되고 있습니다.
즉, 비공개(private) 멤버 변수 및 함수는 문서화에서 빠진다는 거죠. 만약 이 부분이 맘에 안든다면 환경변수 중 "EXTRACT_PRIVATE"를 YES로 지정하세요. 그러면 다음과 같이 보실 수 있습니다.
3.png
 
같은 맥락에서 static 함수나 static 전역 변수도 파일외부에는 노출이 안되는 함수 혹은 변수 이므로 기본 문서화에서 제외 됩니다. 이걸 문서화에 포함시키고 싶다면 "EXTRACT_STATIC" 환경변수를 YES로 설정하세요.
 
이번에는 문서화 주석을 했던 생성자와 소멸자 함수를 보겠습니다.
 
4.png  
 
 뭐 예상대로 되어 있죠? (ㅎㅎ..)
생성자 함수에서 좀 눈여겨 봐야 할 부분은 매개변수가 @param 명령어를 사용하지 않았는데도 추출되었다는 것 입니다. 바로 매개변수 바로 옆에 "///<"와 같은 주석을 달아서 입니다.
또 소멸자 함수를 보면 헤더파일에 적은 간단한 주석과 소스파일에 적은 상세한 주석이 모두 한곳에 정리되어 있네요.
 
2. 그룹(모듈) 만들기
 
지금의 예제와는 좀 어울리지는 않지만 doxygen을 이용해서 함수들을 그룹지어 모듈로서 분류할 수 있습니다.
 
 
1) @defgroup <name> (group title)
 
함수들을 그룹 짓기 위해서는 먼저 그룹을 정의해야 합니다.
그룹을 정의하는 함수가 @defgroup명령어입니다. <name>에 그룹의 이름을 지정하면 되구요. (group title)에는 그룹의 제목에 해당하는 글을 적으면 됩니다. 물론 블록지어서 내부에 그룹을 설명하는 글을 적을 수도 있습니다.
 
그룹에 멤버들을 등록하는 방법은 두가지가 있는데요.
첫번째는 방법은 그룹을 정의할때 @{ ... @}에 의해 그룹 멤버들을 감싸는 것입니다.
hello.h 파일에서 아직 문서화 하지 않은 부분을 다음과 같이 바꿔보세요.
/** @defgroup get_group 프로퍼티 Get * Get 프로퍼티 함수 모음. * 클래스의 멤버변수의 값을 가져오는 함수그룹입니다. * @{ */ char *getUserName(void); int getCount(void); // end of get_group
 
좀 복잡해 보이지만 getUserName()함수와 getCount()함수를 get_group이라는 그룹에 포함시키는 예입니다.
 
2) @ingroup (<groupname> [<groupname> <groupname>])
 
그룹을 정의하는 또 다른 방법은 일단 그룹을 정의해 놓고 @ingroup 명령어를 사용하는 것입니다.
@ingroup명령어는 지정한 <groupname>에 주석을 다는 함수나 변수를 멤버로 추가하는 명령입니다.
<groupname>은 여러개를 적어서 여러 그룹에 속하도록 할 수 있습니다.
 
hello.cpp를 다음과 같이 수정하세요.
/** * @defgroup set_group 프로퍼티 Set * Set 프로퍼티 함수 모음. * 클래스의 멤버변수의 값을 설정하는 함수그룹입니다. */ /** * @ingroup set_group * count에 값을 설정함. * * Hello 클래스의 count값을 설정합니다. * @param num 숫자를 입력으로 받음 * @see Hello::getCount */ void Hello::setCount(int num) { this-&gt;count=num; } /** * count에 값을 가져옴. * * Hello 클래스의 count값을 읽어서 리턴합니다. * @return count 숫자를 리턴함. * @see Hello::setCount */ int Hello::getCount(void) { return this-&gt;count; }
 
제일 윗 부분에 set_group이라는 그룹을 정의하였습니다. 그리고 setCount()함수를 @ingroup명령어를 이용하여 set_group이라는 그룹에 참여 시키고 있습니다. 다른 부분은 이미 get_group에 속한 멤버들에 문서화 주석을 단 것 뿐입니다.
 
여기까지 했으면 doxygen을 실행해서 html문서를 보세요.
 
먼저 상단에 "모듈"이라는 못 보던 탭이 하나 생겼네요. 
 
5.png
 
모듈을 클릭해 보면 우리가 정의한 두개의 모듈의 목록이 나타납니다.
 
6.png
 
각 모듈로 들어가 보면 우리가 문서화 한 그룹에 대한 설명과 멤버로 참가시킨 함수들에 대한 상세한 정보들이 나타납니다.
 
3. 예제 파일 포함하기
 
만약 여러분이 API를 제공할 목적으로 dll파일을 만든다면 메뉴얼에 API 사용 예제를 넣고 싶은 경우가 있겠죠? 이럴 때 사용하는 명령이 @example 입니다.
 
@example <file-name>
 
실습을 위해 우리가 이미 만들었던 example  폴더에 test.cpp라는 파일을 만드세요. 내용은 음~
아무거나 넣으세요.
여기서 예제로 사용할 test.cpp 파일을 exaple 폴더에 넣는 이유는 환경변수 "EXAMPLE_PATH"에 "../example/"이라고 지정했기 때문입니다.
src와 같은 폴더에 두면 test.cpp도 문서화 대상이 됨으로 우리가 원하는 바가 아닐 수 있습니다.
이런 이유로 example 폴더를 별도로 두는 것이 더 바람직합니다.
test.cpp를 만드셨다면 hello.cpp 파일의 Usage()함수의 주석 위에 다음과 같이 입력하세요.
 
/// @example test.cpp /** * 사용법을 출력합니다. * * Hello프로그램의 사용법을 출력합니다.\n * 실제 출력 내용은 다음과 같습니다.\n * @code * Usage: hello &lt;yourname&gt; * @endcode * @see main */ void Usage(void)
 
여러줄을 보여드리긴 했지만 진짜로 추가한 거는 맨 첫줄 한 줄입니다. @example명령어는 위치가 중요합니다.  어디에 정의했냐에 따라 어떤 함수의 예제이냐가 구분됩니다.
아무튼 위와 같이 했다면 다시 doxygen을 실행하고 html문서를 열어보세요.
 
"예제"라는 또하나의 새로운 탭이 생겼군요.
 7.png
 
Usage()함수의 문서화된 내용을 보면 다음의 부분이 추가되어 있습니다.
8.png
 
이번에는 예제탭을 클릭해서 보면 test.cpp 파일에 대한 링크가 있는 걸 확인하실 수 있을 겁니다.
 
 
4. todo, test, bug, deprecated
 
이번에는 일반적으로 문서화를 하긴 하는데 특별히 나중에 별도로 참조할 목적으로 적어 놓는 주석에 대한 처리에 대해 이야기 해 보겠습니다.
 
이런 류의 명령어로는 다음과 같은 것들이 있습니다.
 
1) @todo { paragraph describing what is to be done }
 
앞으로 해야할 일을 적어 둡니다.
 
2) @test { paragraph describing a test case }
 
테스트한 결과나 방법에 관한 내용을 적어 둡니다.
 
3) @bug { bug description }
 
문제점에 대해서 적어 둡니다.
 
4) @deprecated { description }
 
반대(?)되는 점을 적어 둡니다.
 
위의 내용을 각각이 보이기 보다는 한꺼번에 예제를 보도록 하겠습니다.
hello.cpp에서 다음과 같이 수정해 보세요.
int main(int argc, char *argv[]) { /** * @todo 아큐먼트를 좀 더 세밀히 체크해야 함. * @bug 100번 수행하면 101번째 프로그램이 죽음 * @test 100번 출력하는데 10ms가 걸림 * @deprecated 이건 뭐라 적어야 할지 */ if(argc&lt;2) {
 
 그냥 주저리 주저리 글을 적는 부분들이다 보니깐  \n을 이용해서 여러 줄에 걸쳐 작성하거나 html tag를 사용해도 됩니다. 여기서는 그냥 귀차니즘에 의해 그냥 한 주로 썼습니다.
 
이렇게 한 다음 doxygen을 돌리고 html문서에서 "관련된 페이지"를 보면 다음과 같은 항목들이 새로 생겼음을 아실 수 있습니다.
9.png
 
물론 "새 페이지 예"는 page.dox 파일에 의해 만들어 진거죠. 각 항목을 클릭하면 해당 내용을 볼 수 있습니다.
 
5. def, var, enum, fn, class ...
 
지금까지 작업을 잘 따라 오셨다면 아마 소스가 난잡하게 되어 버렸을 것 입니다. (생각하기 따라 다르겠지만...) 그래도 문서화는 별도로 할 필요없이 모두 정리가 되었으니 감안해야 할 수도 있겠죠...
doxygen에서는 이러한 문제를 해결(?)하기 위해서 함수나 변수에 직접 주석을 달지 않고 별도로 적을 수 있도록 명령어들을 준비하고 있습니다.
 
예를 들면 다음과 같은 매크로 함수가 있다고 할때
#define MAX(a,b) (((a)&gt;(b))?(a):(b))
 
이 매크로 함수에 직접 주석을 달지 않고 별도의 파일이나 별도의 영역에 다음과 같은 형식으로 주석을 달아도 같은 기능을 갖습니다.
/** * @def MAX(a,b) * 더 큰값을 리턴. * * a와 b 중 더 큰값을 리턴하는 매크로 함수입니다. */
 
즉, 매크로(#define)의 주석이니깐 @def 명령어를 사용한다는 것입니다.
이런 류의 것들을 정리하면 다음과 같습니다. (Object C, Java용 명령어는 뺐습니다.)
 
1) @class <name> [<header-file>] [<header-name>]
2) @def <name>
3) @enum <name>
4) @fn (function declaration)
5) @var (variable declaration)
6) @typedef (typedef declaration)
7) @union <name> [<header-file>] [<header-name>]
8) @struct <name> [<header-file>] [<header-name>]
9) @namespace <name>
 
예를 묶어서 보여드리겠습니다.
 
hello.h파일에 다음과 같은 내용을 추가합니다.
/** @def MAX(a,b) * 더 큰값을 리턴. * a와 b 중 더 큰값을 리턴하는 매크로 함수입니다. */ /** @var typedef unsigned int UINT32 * 32비트 정수 타입 정의. * 32비트 부호없는 정수 타입을 UINT32로 정의합니다. */ /** @var int errno * 에러 코드 저장. * 마지막 에러 코드를 저장합니다. * @warning 쓰레드에 안전하지 않습니다.! */ /** @fn int open(const char *pathname,int flags) * 파일을 개방합니다. * 지정된 파일을 개방하여 파일 기술자를 리턴합니다. * @param pathname 개방하고하는 파일의 경로. * @param flags 개방 모드를 지정. */ /** @enum COLOR_NAME * 색깔 상수. * 빛의 삼원색의 이름을 정의합니다. */ /** @struct _MyStruct * 더미 구조체. * 예제를 위해 만든 구조체입니다. */ #define MAX(a,b) (((a)&gt;(b))?(a):(b)) typedef unsigned int UINT32; int errno; int open(const char *,int); enum COLOR_NAME { COLOR_RED = 0, COLOR_GREEN, COLOR_BLUE }; struct _MyStruct { int i; };
 
 위와 같은 소스를 doxygen으로 돌려서 보면 다음과 같은 결과가 나타납니다.
10.png
 
상세설명은 캡쳐하지 않겠습니다. 뭐 어떻게 사용하는지는 아시겠죠?
 
6. 기타 명령어들
 
문서화를 위한 중요 주석 명령어에 대해서는 어느 정도 설명한 것 같습니다.
이제는 부가적인(?) 기능을 하는 명령어들을 알아 보겠습니다.
 
먼저 HTML의 모양을 조금 바꿔주는 그런 명령어들입니다. 사실 거의 폰트를 변경하는 것에 해당하지만....
 
@a   단어 앞에 사용하며 해당 단어를 스페셜체로 바꿔줍니다. 
@b   단어 앞에 사용하며 해당 단어를 강조체로 바꿔줍니다.
@p   단어 앞에 사용하며 해당 단어를 타이프라이터체로 바꿔줍니다.
@c   @p명령어와 같습니다.
@e   단어 앞에 사용하며 해당 단어를 이탤릭체로 바꿔줍니다.
@em @e명령어와 같습니다.
@li    한 문장 앞에 사용하며 항목화 시킵니다. 
@arg  @li명령어와 같습니다.
@code / @endcode  코드블록을 만듭니다. 
 
 
예로 다음의 코드를 적당한 위치에 놓으세요.
 * 이것은 @a 스페셜체 입니다.\n
 * 이것은 @b 강조체 입니다.\n
 * 이것은 @p 타이프라이터체 입니다.\n
 * 이것은 @e 이탤릭체 입니다.\n
 * @code
 * @li 항목1 입니다.
 * @li 항목1 입니다.
 * @li 항목1 입니다.
 * @endcode
 
그렇게 하면 다음과 같은 화면을 보실 수 있습니다.
 
11.png
 
 
 이밖에도 매우 많은 명령어들이 있습니다.
 
 
를 참조하여 그때 그때 사용하세요.
 
 
 
 
 
Creative Commons License
Creative Commons License이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Copyright 조희창(Nicholas Jo). Some rights reserved. http://bbs.nicklib.com