当記事は、Qiitaに投稿させて頂いた「C++シリアライザTheolizerをインストールして使ってみる」をTheolizer最新版v1.1.0に対応して修正したものです。

こんにちは。田原です。

1.はじめに

Theolizer(セオライザ)を先日GitHubで正規公開としてしましたので、先ずはTheolizerを使うために必要な環境設定とTheolizer自身のセットアップ方法をまとめたいと思います。

Theolizerはクラスやポインタを含む複雑なデータ構造をファイルへ保存したり、TCP/IP等で通信したりするプログラムの開発を容易にするC++用開発ツール(シリアライザ)です。

C#にはリフレクションがあり、メンバ変数を自動的に列挙できます。だから、クラスのメンバ変数を追加/削除してもシリアライズ用のソース・コードを修正することなく自動的にシリアライズできます。

しかし、残念なことに我らがC++にはリフレクションがなく、クラスのメンバ変数の列挙を自動化できません。そのため、クラスをシリライズするにはboost::serializationのように、メンバ変数を列挙するコードをプログラマ自身が書く必要があります。
そのため、クラス定義を修正した時、メンバ変数の列挙コードの修正とデバッグが必要になります。もし、プログラムを変更する前に保存したデータを読みたい場合、旧データを回復するためのコードも書いてデバッグする必要があります。(特にデバッグ中、テスト・データを作り直したくないので頻発します。)
C#の例でも分かるようにこれらの作業は自動化することが可能であり、ミスを冒しやすい人手による変更作業をなくしたいものです

Theolizerはソース・コードをlibTooligを用いて解析しクラス・メンバのシリアライズに必要なソース・コードを自動生成します。クラス・メンバの単純な追加/削除程度ならシリアライズ用コードを修正しなくても追従しますし、それ以上の変更にも対応できる機能を提供します。

これにより、多くのケースでデータ保存/回復や通信処理の開発工数を大幅に削減できます。
そこで、できるだけ多くの方に使って頂きたく、インストール方法とユーザ・プログラムのビルド方法を解説します。

また、theolizer.comの技術解説で、C言語+αの知識の範疇で複雑な構造のデータをファイルへ保存したりTCP/IPで通信したりするサンプルを解説しています。

2.必要なツールの準備

Theolizerはマルチ・プラットフォームでC++11規格コンパイラに対応できるよう設計しており、現時点でテストできている環境は下記です。
プリビルド版もこの環境でビルドしています。これらと互換性のある環境であれば使用可能ですので、使いたいコンパイラをご用意下さい。
ここでは下記のコンパイラの準備について簡単に説明します。

OS C++コンパイラ
Windows 10 Professional 64bit Visual Studio C++ 2015 Community update 3
MinGW 5.4.0 32bit posix dwarf
MinGW 5.4.0 64bit posix seh
ubuntu 16.04 LTS 64bit gcc 5.4.0(Ubuntu 5.4.0-6ubuntu1~16.04.2)

2.1 Visual Studio 2015 Communityの準備

Visual Studio 2015 Communityは学生、オープン ソース、個人の開発者向けで無料です。
インストール手順は他のサイトに優れた解説が多数ありますので省略致します。例えばここなどが参考になります。

2.2 MinGW 5.4.0の準備

MinGWは事実上全ての人が無料で使用できます。
上表のリンク先からMinGWのインストーラがダウンロードできます。
ダウンロードしたmingw-w64-install.exeを起動して必要なMinGWを選択してインストールして下さい。

32bit版
MinGW540x32-B.png

64bit版
MinGW540x64-B.png

なお、PATHは設定されませんので使う際にPATH設定が必要になります。
32bit版は<MinGWインストール先>\mingw32\binです。
64bit版は<MinGWインストール先>\mingw64\binです。

ところで、MinGWとセットでMSYSやMSYS2もインストールするよう説明しているサイトが多いですが、Theolizerを使うためにMSYSやMSYS2をインストールする必要はありません。(もちろんインストールされていても特に問題ありません。)

2.3 ubuntu gcc 5.4.0の場合

ubuntu 16.04 LTSにはgcc 5.4.0が標準でインストールされています。

2.4 CMake 3.5.0のダウンロードとインストール方法

Theolizerはビルド・ツールとしてCMake 3.5.0以上をサポートしています。CMakeがあればTheolizerを使うビルド・プロジェクト(makefileやVisual Studioのソリューション)を容易に生成できます。

OS CMake インストール方法
Windows 10 CMake 3.5.0 ダウンロードしたファイルをダブルクリック
ubuntu 16.04 LTS CMake 3.5.1 端末で”sudo apt-get install cmake”

WindowsへCMakeをインストールする場合、インストール中にPATH設定の選択肢がでてきます。例えば下記のようにPATH設定するように指示しておくとたいへん便利です。

CMake-C.png

CMakeはスクリプト機能や一通りのファイル操作機能も内蔵しており、マルチ・プラットフォーム向けにビルド・システムを構築できる優れものです。これ1つで大抵のことができますので、多数のツールをダウンロードする煩わしさを低減できます。

3.Theolizerの準備

3-1.プリビルド版のダウンロード

Theolizer自体のビルドはあまり重たくないのですが、Theolizerをビルドするために必要なClang/LLVMのビルドが大変重たいです。1セット1~3時間かかります。
そこで、下記のプリビルド版を用意していますのでお使いの環境に合わせてダウンロードして下さい。

ファイル名 内容
Theolizer-gcc540x64.tar.gz gcc 5.4.0(Ubuntu 5.4.0-6ubuntu1~16.04.2)用
Theolizer-mingw540x32.zip MinGW 5.4.0 32bits用
Theolizer-mingw540x64.zip MinGW 5.4.0 64bits用
Theolizer-msvc2015x32.zip Visual Studio C++ 2015 32bits用
Theolizer-msvc2015x64.zip Visual Studio C++ 2015 64bits用

3-2.Theolizerの動作概要

インストール手順を理解し易くするためTheolizerの動きを簡単に説明します。

冒頭で説明したようにTheolizerはユーザ・プログラムを解析して追加ソース・コードを自動生成します。
それを下記のような仕組みで実現しています。

  1. インストール時
    • 対象コンパイラを「コンパイラ名RenamedByTheolizer(.exe)」へリネームする。
    • 対象コンパイラの元のパス名へTheolizerDriverをコピーする。
  2. ビルド時
    • ビルド・システムからの要求に従い、TheolizerDriverがビルド対象のソースを解析し、
    • シリアライズ用の追加ソース・コードを自動生成する。
    • 元のコンパイラ「コンパイラ名RenamedByTheolizer(.exe)」へパススルーしてコンパイルする。

なお、ソース・コードの解析と自動生成機能はコンパイル時のコマンドライン・オプションでTHEOLIZER_ANALYZEマクロを定義(例えば、-DTHEOLIZER_ANALYZE)した時のみ機能します。
それ以外は何もせずにそのまま元のコンパイラへパス・スルーしますので、Theolizerを用いないプロジェクトへの影響は事実上ありません。
Windows 10、および、ubuntu 16.04にて、コンパイラを置き換えたままCMakeのジェネレーションやllvmのビルドができることを確認しております。

3-3.インストール

まず、ダウンロードしたTheolizerプリビルド版をお好きなフォルダへ解凍して下さい。以下、そのフォルダを<TheolizerDir>として説明します。
次に、TheolizerDriverの–theolizer-replaceコマンドにより、ドライバをリプレースします。
なお、2重にリプレースしようとしても2回目以降は何もしませんのでご安心下さい。

リプレースのテストは入念に行っておりますが、念のため、対象コンパイラをリプレースするまえにバックアップしておくことをお勧めします。

3-3-1.Visual Studio 2015の場合

環境変数VSSDK140InstallにVisual Studioのインストール先が設定されていることを利用して、ドライバをリプレースするバッチ・ファイルを用意しました。
Visual Stduioはコンパイラが下記のように複数あります。それらを全て置き換えます。

パス コンパイラの種別
%VSSDK140Install%..\VC\bin\cl.exe 32ビット・ビルド用32ビット・コンパイラ
%VSSDK140Install%..\VC\bin\amd64\cl.exe 64ビット・ビルド用64ビット・コンパイラ
%VSSDK140Install%..\VC\bin\amd64_x86\cl.exe 32ビット・ビルド用64ビット・クロス・コンパイラ
%VSSDK140Install%..\VC\bin\x86_amd64\cl.exe 64ビット・ビルド用32ビット・クロス・コンパイラ

リプレース時のコマンドは以下の通りです。

 > <TheolizerDir>\replace.bat

リネーム後のcl.exeのファイル名はclRenamedByTheolizer.exeです。

MinGW(Windows)の場合

 > <TheolizerDir>/bin/TheolizerDriver "--theolizer-replace=<g++のフル・パス>"

リネーム後のg++.exeのファイル名はg++RenamedByTheolizer.exeです。

gcc(ubuntu)の場合

 > sudo <TheolizerDir>/bin/TheolizerDriver "--theolizer-replace=/usr/bin/g++-5"

リネーム後のg++-5のファイル名はg++-5RenamedByTheolizerです。

なお、リプレースを指示する先はg++-5へのシンボリックリンクでも大丈夫です。
シンポリックリンクを追跡して、対象のコンパンラ実体を置き換えます。

リプレース確認
リプレース後、PATHを通して下記コマンドを入力するとTheolizerを導入できたことを確認できます。

Visual Studio> cl  --theolizer-version
MinGW        > g++ --theolizer-version
gcc          $ g++ --theolizer-version

Theolizer version 0.3.0 
Copyright (C) 2016 Yohinori Tahara (Theoride Technology)
    SourcesHash : 2555e35a9599a7df4b713672c74d52ca

SourceHashはソース・コードのMD5値です。gitリポジトリ上のどのバージョンか特定できるよう実験的に付けてみました。

4.Theolizerを使うプロジェクトを生成し、ビルド、実行

お試し用のソースを<TheolizerDir>/samples/exampleに置いてます。
CMakeを使ってこれのビルド用プロジェクトを生成できます。

適当に空のフォルダを1つ用意してください。例えばexample_buildフォルダを作ります。

 > mkdir example_build
 > cd example_build

下記操作でプロジェクトを生成し、ビルド、実行できます。

注意
この時、下記のようなエラーが出た場合、ドライバのリプレースができていません。
「3-3.インストール」のドライバのリプレース作業を忘れていないか確認して下さい。

example.cpp(11): fatal error C1083: include ファイルを開けません。
‘example.cpp.theolizer.hpp’:No such file or directory

Visual Studio 2015の32bitの場合
TheolizerはTheolizer-msvc2015x32.zipを使って下さい。

 > cmake -G "Visual Studio 14" <TheolizerDir>/samples/example -DTHEOLIZER_DIR=<TheolizerDir>
 > cmake --build . --config Release --target BuildTest

Visual Studio 2015の64bitの場合
TheolizerはTheolizer-msvc2015x64.zipを使って下さい。

 > cmake -G "Visual Studio 14 Win64" <TheolizerDir>/samples/example -DTHEOLIZER_DIR=<TheolizerDir>
 > cmake --build . --config Release --target BuildTest

MinGW 5.4.0の32bitの場合
TheolizerはTheolizer-mingw540x32.zipを使って下さい。
また、MinGW 5.4.0 32bit posix dwarfmingw32\binフォルダへPATHを通しておいて下さい。

 > cmake -G "MinGW Makefiles" <TheolizerDir>/samples/example -DCMAKE_BUILD_TYPE=Release -DTHEOLIZER_DIR=<TheolizerDir>
 > mingw32-make BuildTest

MinGW 5.4.0の64bitの場合
TheolizerはTheolizer-mingw540x64.zipを使って下さい。
また、MinGW 5.4.0 64bit posix sehmingw64\binフォルダへPATHを通しておいて下さい。

 > cmake -G "MinGW Makefiles" <TheolizerDir>/samples/example -DCMAKE_BUILD_TYPE=Release -DTHEOLIZER_DIR=<TheolizerDir>
 > mingw32-make BuildTest

gcc 5.4.0(ubuntu)の場合
TheolizerはTheolizer-gcc540x64.tar.gzを使って下さい。

 $ cmake -G "Unix Makefiles" <TheolizerDir>/samples/example -DCMAKE_BUILD_TYPE=Release -DTHEOLIZER_DIR=<TheolizerDir>
 $ make BuildTest

下記のようなメッセージが最後の方で出力されたら、正常にビルドでき、実行されています。

 test 1
      Start 1: example

  1: Test command: L:\Data\DataOrig\3.Projects\3.Serializer\5.OpenBeta\Theolizer\source\samples\example\msvc\Release\example.exe
  1: Test timeout computed to be: 9.99988e+006
  1: {
  1:     "SerialzierName":"JsonTheolizer",
  1:     "GlobalVersionNo":1,
  1:     "TypeInfoList":[1]
  1: }
  1: {
  1:     "name":"Taro Yamada",
  1:     "age":22
  1: }
  1/1 Test #1: example ..........................   Passed    0.04 sec

  100% tests passed, 0 tests failed out of 1

  Total Test time (real) =   0.05 sec

淡赤色の部分(”1:”除く)がプログラムの出力です。

5. ソース・コードの説明

exampleはクラスをJson形式で保存/回復するサンプルです。

5-1.サンプル・プログラム example.cpp

使用するTheolizerのヘッダをインクルードします。このサンプルではJsonシリアラザを使うのでtheolizer/serializer_json.hをインクルードしています。

#include <iostream>
#include <fstream>
#include <string>
#include <theolizer/serializer_json.h>

struct Foo
{
    std::string name;
    int age;
};

#include "example.cpp.theolizer.hpp"            // Theolizer自動生成先

int main(int argc, char* argv[])
{
    // 保存
    {
        Foo foo;
        foo.name="Taro Yamada";
        foo.age=22;

        std::ofstream ofs("sample.txt");
        theolizer::JsonOSerializer<> jos(ofs);  // シリアライザを生成
        THEOLIZER_PROCESS(jos, foo);            // ファイルへfooを保存
    }

    // 回復
    {
        Foo foo;
        std::ifstream ifs("sample.txt");
        theolizer::JsonISerializer<> jis(ifs);  // デシリアライザを生成
        THEOLIZER_PROCESS(jis, foo);            // ファイルからfooを回復

        theolizer::JsonOSerializer<> jos(std::cout);
        THEOLIZER_PROCESS(jos, foo);            // 回復結果の簡易表示
    }
}
5-1-1.自動生成ファイルのインクルード

Theolzier®は、あなたのプログラムを解析してシリアライス処理のために必要なクラスのメンバ・リストやenum型のシンボル・リストを生成します。
その生成先のファイルは<コンパイル対象ファイル名>.theolizer.hppです。example.cppの場合example.cpp.theolizer.hppとなります。

自動生成ファイルのインクルード場所について
自動生成ファイルには、シリアライズするクラス、enum型に対する追加定義を行います。
ですので、シリアライズ対象のクラスやenum型の宣言部(ヘッダ)と、実際にシリアライズ処理する処理部(THEOLIZER_PROCESSマクロの呼び出し)の間でインクルードして下さい。

5-1-2.保存処理

保存処理は下記の4ステップです。

  1. std::ofstream aStream(“example.json”);
    example.logファイルを書き込みオープンします。

  2. theolizer::JsonOSerializer<> js(aStream);
    Theolizerに対して上記でオープンしたファイルへシリアライズします。

  3. THEOLIZER_PROCESS(js, aStructType);
    事前に設定していたaStructType変数の内容をexample.logファイルへ出力します。

  4. {…}
    ブロックから抜けた時にファイルがクローズされて書き込みが完了します。

以上により出力されるJsonファイルです。

{
    "SerialzierName":"JsonTheolizer",
    "GlobalVersionNo":1,
    "TypeInfoList":[1]
}
{
    "name":"Taro Yamada",
    "age":22
}
5-1-3.回復処理

回復処理も下記の4ステップです。

  1. std::ifstream aStream(“example.json”);
    example.logファイルを読み出しオープンします。

  2. theolizer::JsonISerializer<> js(aStream);
    Theolizerに対して上記でオープンしたファイルからデシリアライズします。

  3. THEOLIZER_PROCESS(js, aStructType);
    事前に確保していたaStructType変数へexample.logファイルの内容を回復します。

  4. {…}
    ブロックから抜けた時にファイルがクローズされて読み出しが完了します。

5-2.自動生成ファイル example.cpp.theolizer.hpp

Theolizerがexample.cppと同じフォルダに自動生成します。これはクラス定義やenum型定義を保持します。

Theolizerでは、バージョンを上げた時に古いクラス定義やenum型定義をここに残しておくことで、古いシリアライズ・データを回復できるようにしています。
そのため、このファイルをお使いのバージョン管理システム(gitやsvn等)へ登録することを想定しています。

5-3.CMakeLists.txt

CMake用の設定ファイルです。

theolizerを組み込むためには、CMakeでジェネレートする際に<TheolizerDir>をTHEOLIZER_DIRにて指定して下さい。これはfind_package(THEOLIZER)でTheolizerを組み込むために使用されます。

そして、Theolizerをプログラムに組み込むためには通常のインクルード・パス指定、ライブラリ指定以外にTHEOLIZER_ANALYZEマクロの指定等が必要です。それらをsetup_theolizer()で行います。

最後の「テスト実行」の部分で、BuildTestターゲットを定義しています。
CMakeはテストとビルドが独立しています。CTestしてもそれに必要なプログラムは自動的にビルドされません。
そこで、テスト用のカスタム・ターゲットを作って、その中でCTestを起動しています。
そして、そのカスタム・ターゲットをビルド・ターゲットに依存させることで、コマンド一発でビルド→テストできるようにしています。

#[[###########################################################################
        Theolizer紹介用サンプルCMakeLists.txt
]]############################################################################

if("${CMAKE_VERSION}" STREQUAL "")
    set(CMAKE_VERSION, 3.5.0)
endif()
cmake_minimum_required(VERSION ${CMAKE_VERSION})

message(STATUS "BOOST_ROOT=${BOOST_ROOT}")

#-----------------------------------------------------------------------------
#       プロジェクト設定
#-----------------------------------------------------------------------------

set(TARGET_NAME example)
set(SOURCE_LIST example.cpp)

project(${TARGET_NAME}  VERSION 1.0.0)

#-----------------------------------------------------------------------------
#       ビルド設定
#-----------------------------------------------------------------------------

# MSVCの通常使わないビルド・モードとZERO_CHECKプロジェクトの削除
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
set(CMAKE_SUPPRESS_REGENERATION TRUE)

# Theolizer
find_package(THEOLIZER)

# Options
if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
    add_definitions(-D_UNICODE -DUNICODE)
    set(CMAKE_DEBUG_POSTFIX "d")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

    # MinGWの不具合(https://sourceforge.net/p/mingw-w64/discussion/723797/thread/c6b70624/#7f0a)暫定対処
    if((CMAKE_COMPILER_IS_MINGW) AND (CMAKE_SIZEOF_VOID_P EQUAL 8))
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
    endif()
endif()

# example
add_executable(${TARGET_NAME} ${SOURCE_LIST})
setup_theolizer(${TARGET_NAME} StaticWithBoost)

#-----------------------------------------------------------------------------
#       テスト実行
#-----------------------------------------------------------------------------

enable_testing()
add_test(NAME ${TARGET_NAME} COMMAND $<TARGET_FILE:${TARGET_NAME}>)

add_custom_target(BuildTest COMMAND "ctest" "-V" "-C" $<CONFIG>)
add_dependencies(BuildTest ${TARGET_NAME})

6.アンインストール

最後にアンインストール方法を説明します。インストールの逆の操作を行います。
まずドライバをリストア・コマントによりリストアし、次にTheolizerを保存したフォルダを削除します。

リストア・コマンドは対象のコンパイラ・パス名でコピーしていたTheolizerDriverを削除し、元のコンパイラの名前を元に戻します。
リストア・コマンドは、replacerestoreへ置き換えて起動します。下記の通りです。
なお、2重にリストアしようとしても2回目以降は何もしませんのでご安心下さい。

Visual Studio 2015の場合

 > <TheolizerDir>\restore.bat

MinGW(Windows)の場合

 > <TheolizerDir>/bin/TheolizerDriver "--theolizer-restore=<g++のフル・パス>"

gcc(ubuntu)の場合

 $ sudo <TheolizerDir>/bin/TheolizerDriver "--theolizer-restore=/usr/bin/g++-5"

7.最後に

example.hのFooの定義を変更してもシリアライズ処理の変更が不要なことを確認頂き、Theolizerのパワーを感じて頂けると嬉しいです。そして、もし、うまく行かなかったら遠慮なくご質問下さい

なお、Fooの値を設定したり、表示したりする部分はご自身で修正する必要が有ります。この部分はアプリケーション部分です。プログラマがアプリション・ロジックの開発に注力できることがTheolizerを使うメリットです。