パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
DoxygenとウィンドウズHTMLヘルプ

ドキュメンテーションツールとして導入されるDoxygenと、それを用いたHTMLヘルプファイルの作成を説明する。

Doxygen

DoxygenはC++を含むいくつかのプログラミング言語で書かれたソースコードを解析し、そのドキュメントをHTML形式を含む様々な書式で作成する。

Doxygenはソースコードコメント文に記述された様々なキーワードでドキュメントを修飾する。修飾機能が豊富でソースコード解析を目的としなくてもリッチなドキュメントを作成でき、例えば本サイトもDoxygenで作成している。その場合ソースコードを持たないのに全てをコメント文で記述するのは面倒だが、Doxygenはマークダウン形式ファイル(拡張子*.md)とすればプレーンなテキスト文を入力できる。

Doxygenは設定ファイルを読み込み動作する。HTML出力はさらに四つのファイルでカスタマイズされる。

ファイル 設定方法 ファイル名(例) デフォルト
設定 起動時実引数 Doxyfile カレントディレクトリのDoxyfile
ヘッダHTML 設定ファイル HTML_HEADER my_header.html 内蔵
フッタHTML HTML_FOOTER my_footer.html 内蔵
カスケードスタイルシート HTML_EXTRA_STYLESHEET my_customdoxygen.css 内蔵
レイアウト LAYOUT_FILE my_layout.xml 内蔵

Doxygen設定ファイル

設定ファイルはmsys64ターミナルで以下のコマンドでテンプレートファイルを生成し、それを編集する。フルパス名ならコマンドプロンプトでも実行できる。

$ doxygen -g Doxyfile

Doxyfile編集用にdoxywizard.exeというアプリケーションが使えるが設定オプション数が膨大で、テンプレートファイルをコメントを頼りに直接編集したほうが効率が良い。Doxyfileは自らの文字コードを設定するDOXYFILE_ENCODINGを除き設定順は問題とならず、重複は最後の設定が採用され、配列オプションの要素は+=演算子で追加できる。これらを利用しテンプレートファイルの変更箇所をまとめてファイル末尾に追加すればカスタマイズが明示され、メンテナンスが容易になる。以下に本サイトによるソースコード解析用Doxyfileのテンプレートファイルへの末尾追加部分の一例を示す。Doxyfileの文字コードはDOXYFILE_ENCODINGデフォルトに従いUTF-8とする。入力ファイル(*.cpp、*.h、*.mdなど)の文字コードもINPUT_ENCODINGデフォルトに従い全てUTF-8に統一する。

Doxyfile(追加部分)

#------------------------------------------------ [Additional Setting Start]
#---------------------------------------------------------------------------
# Customized configurations are placed here appending to those generated by
# "doxygen -g" above.
# Project
PROJECT_NAME = "パソコンでプログラミングしよう(Desktop1)"
PROJECT_NUMBER = "0.0.0.0(0)"
PROJECT_BRIEF = "金をかけずにウィンドウズC++プログラミング環境を構築する"
# C++ source
FULL_PATH_NAMES = NO
BUILTIN_STL_SUPPORT = YES
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
EXTRACT_ANON_NSPACES = YES
SOURCE_BROWSER = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
PREDEFINED = "WXUNUSED()=" \
"MY_PIMPL(smart_ptr,cls,name)=class cls;cls* name; /**<\brief smart_ptr<cls> at actual compilation, replaced with cls* when Doxygen analyzes.*/" \
"MY_CHECK_MAGIC_SELECTION()=1" \
"__attribute__()="
HAVE_DOT = YES
DOT_PATH = "C:\msys64\mingw64\bin"
CLASS_DIAGRAMS = NO
CLASS_GRAPH = NO
TEMPLATE_RELATIONS = YES
CALL_GRAPH = YES
CALLER_GRAPH = YES
# Warnings
WARN_IF_UNDOCUMENTED = NO
WARN_LOGFILE = doxygen.log
# Input files
INPUT = ../ \
./
FILE_PATTERNS = *.c \
*.cpp \
*.h \
*.hpp \
*.dox \
*.md
EXAMPLE_PATH = ../ \
./
IMAGE_PATH = ../ \
./
# Appearance
OUTPUT_LANGUAGE = Japanese
LAYOUT_FILE = my_layout.xml
HTML_HEADER = my_header.html
HTML_FOOTER = my_footer.html
HTML_EXTRA_STYLESHEET = my_customdoxygen.css
HTML_COLORSTYLE_HUE = 50
HTML_COLORSTYLE_SAT = 50
HTML_COLORSTYLE_GAMMA = 220
HTML_TIMESTAMP = YES
HTML_DYNAMIC_MENUS = NO
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 275
TOC_INCLUDE_HEADINGS = 2
SEARCHENGINE = YES
# Other outputs than html
GENERATE_LATEX = NO
# Include pages for Windows HTML help
INPUT += ./winchm/
ALIASES += "mainpage_winchm=\page mainpage_winchm"
#---------------------------------------------------------------------------
#-------------------------------------------------- [Additional Setting End]

Doxygenカスタマイズファイル

ヘッダHTMLファイル、フッタHTMLファイル、カスケードスタイルシートファイルのテンプレートファイルは以下で生成する。

$ doxygen -w html my_header.html my_footer.html my_customdoxygen.css

レイアウトファイルのテンプレートファイルは以下で生成されるはずだが、30MiBクラスの役に立たない破損ファイルを出力するので代わりにWeb上のソースを用いる。

$ doxygen -l my_layout.xml

バッチファイル

本サイト運用においてDoxygenはmingw64サブシステムにインストールされるが、ウィンドウズ環境からそのまま使用できる。Doxyfileの置かれたディレクトリで実行するバッチファイルをソースコード解析用として示すが、mingw64サブシステムウィンドウズパスを加えるだけの単純なものである。

k_doxygen.bat

C:\msys64\mingw64\bin\doxygen.exe

日本語ソースコードコメントの問題点

本サイトは国際化機能の利用でソースコードを英語(ASCII)で記述するがコメントのみ日本語(UTF-8)とすることも可能である。しかしDoxygenによるドキュメンテーションに以下の問題がある。

/**
/* 日本語文字列で1行におさまる。<BR>
/* 日本語文字列で
/* 2行にわたる。
*/

日本語文字列で1行におさまる。
日本語文字列で 2行にわたる。

"2行"の前に空白(半角空白)が挿入される。英語であれば複数行にわたる文字列を空白で連結して自然だが日本語は異なる。プレーンテキスト(*.md)ならエディタ折り返しを設定し改行せずに打ち続ければ良いが、Doxygenコメント形式(*.cppなど)でこれをやるとソースコードは酷く見づらい。

ウィンドウズHTMLヘルプファイル

ウィンドウズHTMLヘルプファイルはウィンドウズが標準としたヘルプファイル形式で、ウィンドウズに標準添付されるHTMLヘルプビューアで表示される。登場以来20年以上が経過、マイクロソフトはその更新を放棄し最近のアプリケーションでこれを利用するものは少なくなった。しかし本サイトの開発アプリケーションは今なおこれを使用する。

HTMLヘルプファイルの作成は、HTMLエディタとHTMLヘルプオーサリングとHTMLヘルプコンパイラを必要とする。アプリケーションDesktop1のヘルプファイルを作成するとして通常の手順を以下に説明する。

  1. 任意のHTMLエディタでHTMLヘルプページの元となる複数のHTMLファイル(*.html)を作成する。
  2. HTML Help Workshop(hhw.exe)などのHTMLヘルプオーサリングでプロジェクトファイル(Desktop1.hhp)、目次ファイル(Desktop1.hhc)、索引ファイル(Desktop1.hhk)を作成する。
  3. HTMLヘルプコンパイラ(hhc.exe)は複数のHTMLファイルをプロジェクトファイル、目次ファイル、索引ファイルを用いて一つのHTMLヘルプファイル(Desktop1.chm)へ合成する。

Doxygenはオプション設定により自らプロジェクトファイル(index.hhp)、目次ファイル(index.hhc)、索引ファイル(index.hhk)を生成し、HTMLヘルプコンパイラをコールしてHTMLヘルプファイルを出力する機能を持つ。ただし文字コードに関しては大きな問題が存在し、Doxygenが出力するHTMLファイルの文字コードはUTF-8であるにもかかわらず、HTMLヘルプファイル(*.chm)はシステムロケール(ウィンドウズスタートメニューから[設定|時刻と言語|地域|日付、時刻、地域の追加設定|地域|管理|システムロケールの変更])のコードページ(手法)が扱う文字コードに限定され日本語対応はシフトJISとなる。すなわちHTMLヘルプビューアはインターネットエクスプローラをエンジンとしてUTF-8の記述ページを問題なく表示するのに、プロジェクトファイル、目次ファイル、索引ファイルはシフトJISでなければならない。のみならずページ内容を検索可能とするには、元となるHTMLファイル自体もシフトJISで記述しておく必要がある。

参考リンクはHTMLヘルプファイルの作成表示はシステムロケールを合わせる必要があるとする。しかし現在(ウィンドウズ10で確認)のHTMLヘルプビューアは異なるシステムロケールで作成されたHTMLヘルプファイルも正常に表示するため、多言語対応(マルチリンガル)アプリケーションに対応できる。一方で作成側のHTML Help Workshop(hhw.exe)とHTMLヘルプコンパイラ(hhc.exe)の実行はターゲットに合わせたシステムロケールを設定する必要がある。

覚え書き
現在のHTMLヘルプビューアはユニコード(手法)アプリケーションでシステムロケールを変更してもメニュー項目やコントロールラベルは文字化けしないが、読み込むHTMLヘルプファイルをユニコード(UTF-16、UTF-8)とする事ができない。HTML Help WorkshopとHTMLヘルプコンパイラはコードページ(手法)アプリケーションのままにある。

Doxygenの設定

以下に本サイトがHTMLヘルプファイルを作成する設定ファイルを示す。ソースコード解析用Doxyfileと同一ディレクトリに配置するためDoxyfile_winchmという異なった名称を与える。@INCLUDEタグでDoxyfileをインクルードし必要なカスタマイズを追加する。オプションCHM_INDEX_ENCODING=CP932によりプロジェクトファイル、目次ファイル、索引ファイルはシフトJISで出力される。

Doxyfile_winchm

@INCLUDE = Doxyfile
# CHM_FILE path is relative to "./html_winchm" where index.hhp is in.
# It is not relateve to "." where this file is in.
WARN_LOGFILE = doxygen_winchm.log
HTML_OUTPUT = ./html_winchm/
INPUT = ./winchm/
GENERATE_HTMLHELP = YES
GENERATE_TREEVIEW = NO
SEARCHENGINE = NO
CHM_FILE = ../../bin/Desktop1.chm
HHC_LOCATION = "C:\Program Files (x86)\HTML Help Workshop\hhc.exe"
CHM_INDEX_ENCODING = CP932
ALIASES += "mainpage_winchm=\mainpage"

生成されるHTMLヘルプファイルはHTMLヘルプビューアで正常に表示されるが、[検索]が機能せず、[お気に入り|現在のトピック]が文字化けする。

バッチファイル

検索機能などを正常に機能させるため、Doxygenが生成したファイル(*.html、*.js、*.css)全てをUTF-8からシフトJISへ変換して、改めてHTMLヘルプコンパイラでHTMLヘルプファイルへ結合する。以下はこれを自動化するバッチファイルで、Doxyfile_winchmの置かれたディレクトリで実行する。このバッチファイルは結果的にHTMLヘルプコンパイラを二度起動し、最初に作成されたHTMLヘルプファイルは上書きされる。シフトJISへの変換はmsys2サブシステムのsedとiconvを使用する。iconvの-cオプションで元のファイルに含まれるシフトJIS外文字は無視される。コマンドラインバージョンのHTMLヘルプコンパイラ(hcc.exe)は終了コードに成功で1、エラーで0を返すが、通常と反対なので最終行で修正する。

k_doxygen_winchm.bat

@SETLOCAL
@SET PATH=C:\msys64\usr\bin;%PATH%
@CHCP 437
C:\msys64\mingw64\bin\doxygen.exe Doxyfile_winchm
@echo:
@for %%i in (html_winchm\*.html html_winchm\*.js html_winchm\*.css) do @(
echo Converting %%i from UTF-8 to Shift-JIS...
sed -e 's/UTF-8/Shift-JIS/gI' < %%i | iconv -f UTF-8 -t CP932 -c > temp.dat
move /Y temp.dat %%i
)
@echo:
"C:\Program Files (x86)\HTML Help Workshop\hhc.exe" html_winchm\index.hhp
if not errorlevel 1 exit /b 1
覚え書き
iconvの-cオプションを外し、シフトJIS外文字はエラーとした方が良いかもしれない。しかし生成されるJavaスクリプトファイルの一つであるjquery.jsはコメントにシフトJIS外(ASCII外)のUTF-8符号(U+2013、EN DASH)を含み、この対処として安直に-cオプションを加えた。

HTML Help Workshopインストール時の不具合

HTML Help Workshopのインストールを日本語のユーザー名で行うと、恐らく"Couldn't load C:\windows\????.tmp Library files needed to run this can't be found."というメッセージで失敗する。インストーラは一時フォルダにファイルを展開してインストールする。一時フォルダは環境変数TMPに設定されてデフォルトはC:\Users\<ユーザー名>\AppData\Local\Tempなので日本語を含む可能性がある。インストーラは英語ロケールで作成されたコードページ(手法)アプリケーションと思われ日本語を含むパスを正しく取得できない。コマンドプロンプトでTMPを変更してからインストーラを起動すれば良いが、インストーラは管理者権限で実行されるためコマンドプロンプトも管理者権限を必要とする。

以下で対処する。

  • スタートメニュー[Windows システム ツール|コマンド プロンプト]の右クリック[その他|管理者として実行]で管理者権限を持つコマンドプロンプトを起動する。
  • 日本語を含まない(英数字のみからなる)パスをもつ一時フォルダ(例えばC:\Temp)をSETコマンドで環境変数TMPに設定する。
  • コマンドプロンプトからインストーラを実行する。

ウィンドウズデスクトップアプリケーション

wxWidgetsライブラリによるウィンドウズデスクトップアプリケーションにおける運用について説明する。ソースコード解析用HTMLファイルはプロジェクトディレクトリ階層下のdoxygen\htmlディレクトリに出力され、開発者への参考に供される。HTMLヘルプファイル用HTMLファイルはdoxygen\html_winchmディレクトリに出力され、これからHTMLヘルプファイルが作成される。ソースコード解析用HTMLファイルはHTMLヘルプファイル用HTMLファイルのコピーを参考用に含む。HTMLヘルプファイルだけが実行形式ファイルと共に配布される。

ドキュメンテーションファイルの配置

開発時にドキュメンテーションファイルは以下に配置されているものとする。doxygen\html_winchmディレクトリを除き全てのテキストファイル文字コードはUTF-8とする。doxygen\html_winchmディレクトリ内のテキストファイルのみシフトJISで出力されるかシフトJISへ変換される。

ディレクトリ ファイル 内容
[プロジェクトディレクトリ] Desktop1.cbp Code::Blocksプロジェクト
*.cpp, *.h ソースコード、インクルード
resource.rc ウィンドウズリソース
├ bin Desktop1.chm HTMLヘルプ
│├ Debug32 Desktop1.exe 32ビット実行形式デバッグ版
│├ Release32 Desktop1.exe 32ビット実行形式リリース版
│├ Debug64 Desktop1.exe 64ビット実行形式デバッグ版
│└ Release64 Desktop1.exe 64ビット実行形式リリース版
├ obj
│├ Debug32 *.o 32ビットオブジェクトデバッグ版
│├ Release32 *.o 32ビットオブジェクトリリース版
│├ Debug64 *.o 64ビットオブジェクトデバッグ版
│└ Release64 *.o 64ビットオブジェクトリリース版
├ wxsmith *.wxs wxSmithリソース
└ doxygen Doxyfile ソースコード解析用Doxygen設定
 │ Doxyfile_winchm HTMLヘルプファイル用Doxygen設定
 │ my_header.html ヘッダHTML
 │ my_footer.html フッタHTML
 │ my_customstylesheet.css カスケードスタイルシート
 │ my_layout.xml レイアウト
 │ doxygen.log ソースコード解析用ログ出力
 │ doxygen_winchm.log HTMLヘルプファイル用ログ出力
 │ k_doxygen.bat ソースコード解析用Doxygen実行バッチ
 │ k_doxygen_winchm.bat HTMLヘルプファイル用Doxygen実行バッチ
 ├ html index.html ソースコード解析用HTMLトップページ
 │ *.html, *.js, *.cssなど ソースコード解析用HTML
 ├ html_winchm index.html HTMLヘルプファイル用HTMLトップページ
 │ *.html, *.js, *.cssなど HTMLヘルプファイル用HTML
 │ index.hhp HTMLヘルププロジェクト
 │ index.hhc HTMLヘルプ目次
 │ index.hhk HTMLヘルプ索引
 └ winchm *.md HTMLヘルプファイル用原稿

配布時はインストーラが以下に配置する。

ディレクトリ ファイル 内容
[インストールディレクトリ] Desktop1.exe 実行形式
Desktop1.chm HTMLヘルプ

HTMLヘルプファイルのトップページ

ソースコード解析用HTMLファイルはHTMLヘルプファイル用HTMLファイルのコピーを参考用に含む。これを目的としてDoxyfileのINPUTオプションにHTMLヘルプファイル用原稿を収納するディレクトリ(.\winchm\)を追加する。HTMLヘルプファイル用HTMLファイルのトップページはソースコード解析用HTMLにコピーとして含まれる場合は通常ページとしなければならないが、これをDoxygenのアライアス機能で実現する。すなわち以下mainpage_winchm.mdに示すようにトップページをアライアス\mainpage_winchmで定義し、これをDoxyfileおよびDoxyfile_winchmのALIASESオプションで\pageまたは\mainpageに切り替える。

mainpage_winchm.md

\mainpage_winchm ヘルプファイル
これはヘルプファイルのメインページです。

ソースコードの修正

ウィンドウズデスクトップアプリケーションはHTMLヘルプファイルの表示にwxWidgetsライブラリのwxHelpControllerクラスを利用する。例として動作確認(1)で作成したDesktop1プロジェクトにHTMLヘルプファイル表示機能を加える。Desktop1Frameクラス(Desktop1Frame.hとDesktop1Frame.cpp)を以下に修正してビルドする。メニューアイテムの実行でHTMLヘルプファイルが表示される。

Desktop1Frame.h

  • wxWidgetsライブラリwx/help.hをインクルードする。
  • Desktop1Frameクラスのプライベートメンバ変数にwxHelpController型のhelpController_を追加する。
#ifndef DESKTOP1MAIN_H
#define DESKTOP1MAIN_H
//(*Headers(Desktop1Frame)
#include <wx/frame.h>
#include <wx/menu.h>
#include <wx/statusbr.h>
//*)
#include <wx/help.h>
class Desktop1Frame: public wxFrame
{
public:
Desktop1Frame(wxWindow* parent,wxWindowID id = -1);
virtual ~Desktop1Frame();
private:
//(*Handlers(Desktop1Frame)
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnHelp(wxCommandEvent& event);
//*)
//(*Identifiers(Desktop1Frame)
static const long idMenuQuit;
static const long idMenuHelp;
static const long idMenuAbout;
static const long ID_STATUSBAR1;
//*)
//(*Declarations(Desktop1Frame)
wxStatusBar* StatusBar1;
//*)
wxHelpController helpController_;
DECLARE_EVENT_TABLE()
};
#endif // DESKTOP1MAIN_H

Desktop1Frame.cpp

  • HTMLヘルプファイルフルパス名を構築するためwxStandardPathsクラスとwxFileNameクラスを利用するので、wx/stdpaths.hとwx/filename.hをインクルードする。
  • コンストラクタ内でhelpController_のInitializeメンバ関数をHTMLヘルプファイルフルパス名を実引数としてコールする。
  • 適当なメニューアイテムのハンドラ関数でhelpController_のDisplayContentsメンバ関数をコールする。
#include "wx_pch.h"
#include "Desktop1Frame.h"
#include <wx/msgdlg.h>
#include <wx/stdpaths.h>
#include <wx/filename.h>
//(*InternalHeaders(Desktop1Frame)
#include <wx/intl.h>
#include <wx/string.h>
//*)
...
//(*IdInit(Desktop1Frame)
const long Desktop1Frame::idMenuQuit = wxNewId();
const long Desktop1Frame::idMenuHelp = wxNewId();
const long Desktop1Frame::idMenuAbout = wxNewId();
const long Desktop1Frame::ID_STATUSBAR1 = wxNewId();
//*)
BEGIN_EVENT_TABLE(Desktop1Frame,wxFrame)
//(*EventTable(Desktop1Frame)
//*)
END_EVENT_TABLE()
Desktop1Frame::Desktop1Frame(wxWindow* parent,wxWindowID id)
:helpController_{this}
{
//(*Initialize(Desktop1Frame)
...
Connect(idMenuQuit,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&Desktop1Frame::OnQuit);
Connect(idMenuHelp,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&Desktop1Frame::OnHelp);
Connect(idMenuAbout,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&Desktop1Frame::OnAbout);
//*)
helpController_.Initialize
(wxFileName{wxStandardPaths::Get().GetDataDir(),"Desktop1.chm"}
.GetFullPath());
}
...
void Desktop1Frame::OnHelp(wxCommandEvent& event)
{
helpController_.DisplayContents();
}

HTMLヘルプファイルのディレクトリをwxStandardPaths::GetDataDirメンバ関数で取得するが、これは開発時と配布時でHTMLヘルプファイルの実行形式ファイルに対する相対位置が異なるためで、アプリケーションクラスインスタンスの初期化関数(Desktop1App:OnInitメンバ関数)で適切にwxStandardPaths::IgnoreAppSubDirメンバ関数がコールされていることを前提とする。この件については国際化機能サンプルソースコードも参考いただきたい。