「Boost.Regex ライブラリの導入」の版間の差分
| (同じ利用者による、間の31版が非表示) | |||
| 1行目: | 1行目: | ||
<yjavascript></script> | |||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.css"> | |||
<link rel="stylesheet" href="https://wiki.yo-net.jp/custom.css"> | |||
<script src="https://wiki.yo-net.jp/highlight/highlight.js"></script> | |||
<script src="https://wiki.yo-net.jp/custom.js"></script> | |||
<script type="text/javascript" charset="UTF-8" src="https://wiki.yo-net.jp/highlight/highlightjs-vba/dist/vba.min.js"></script> | |||
<script type="text/javascript">hljs.initHighlightingOnLoad();</script> | |||
<script></yjavascript> | |||
[[メインページ#言語と開発環境|言語と開発環境]]に戻る。 | [[メインページ#言語と開発環境|言語と開発環境]]に戻る。 | ||
== '''概要''' == | == '''概要''' == | ||
| 23行目: | 31行目: | ||
Boost. | Boost.Regexのexampleフォルダにあるコンソールアプリケーションサンプルを動かしてみます。なので、Windowsコンソールアプリケーションを作る要領で新規プロジェクトを作成します。 | ||
| 29行目: | 37行目: | ||
そしたらexampleプログラムをコピーしてmain関数が作成された「プロジェクト名.cpp」に貼り付けます。regex-developフォルダの中のexampleフォルダの中のsnippetsフォルダの中のregex_grep_example_1.cppはBoost.Regexだけで動かせるサンプルになっています。exampleフォルダの中のgrepフォルダの中にあるサンプルは動かせません。動かすにはBoost.program_optionsというリポジトリも必要になるためです。なので、Boost.Regexのリポジトリからもってきたファイル一式だからといって、exampleフォルダにある全部が動かせるとは限らないことに注意が必要です。 | |||
| 85行目: | 93行目: | ||
特定のプロジェクトにBoost.Regexを追加して、ビルドする手順は習得できたので、これで一つの使い方についてできることになったわけですからBoost. | 特定のプロジェクトにBoost.Regexを追加して、ビルドする手順は習得できたので、これで一つの使い方についてできることになったわけですからBoost.Regexを使えるようになったということです。次はICUを使う例を紹介したいですが、[[C_文字列操作#ICU導入|以前にICUを使ったとき]]からはパソコンが入れ替わっているので、また導入からになります。ICU...また後日、記事を追加することになります。今は、説明することはしばらく保留にしておきたいと思います。使えるのが大事だからね。 | ||
=== '''ライブラリを生成する場合''' === | |||
ライブラリを生成する場合はBoost_Regexだけのプロジェクト単体でダウンロードしていたのでは、割かし手順が複雑になってしまいますので、Boost全体をダウンロードした方がよいです。単体から引っ張り出す場合でも結局全部ダウンロードする感じになっている気もします。勘違いならゴメン。なのでBoostをダウンロードしよう! | |||
[https://www.boost.org/users/history/version_1_89_0.html https://www.boost.org/users/history/version_1_89_0.html] | |||
割かし大きいことに驚かされますがビビることはない。ハードディスクに空きと通信の手段と時間さえあれば、やれる。 | |||
解凍したら、コマンドプロンプトを立ち上げて解凍してできたディレクトリをカレントディレクトリにしよう。解凍したフォルダはあまり深いところに置かない方がいいです。C:¥boost_1_89_0\とかにするのもいいね。こういうboost_1_89_0までのパスを(Boostルートパス)と表現するとしよう。 | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="command prompt" class="pre-wrap"> | |||
<code class="cmd">(Boostルートパス)>bootstrap.bat</code></pre></div> | |||
<script></yjavascript> | |||
ってやると、b2っていうコマンドが使えるようになるツールを生成してくれます。したらば | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="command prompt" class="pre-wrap"> | |||
<code class="cmd">(Boostルートパス)>b2 variant=debug link=static runtime-link=shared --with-regex</code></pre></div> | |||
<script></yjavascript> | |||
のようにして、regexのdebug版のライブラリを生成し | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="command prompt" class="pre-wrap"> | |||
<code class="cmd">(Boostルートパス)>b2 variant=release link=static runtime-link=shared --with-regex</code></pre></div> | |||
<script></yjavascript> | |||
のようにして、regexのrelease版のライブラリを生成します。 | |||
以下のようなファイルが生成されます。x32の方はあまりいらないね。gdの方がデバッグ版ね。 | |||
*libboost_regex-vc143-mt-gd-x32-1_89.lib | |||
*libboost_regex-vc143-mt-gd-x64-1_89.lib | |||
*libboost_regex-vc143-mt-x32-1_89.lib | |||
*libboost_regex-vc143-mt-x64-1_89.lib | |||
(Boostルートパス)\stage\libというフォルダにlibファイルが生成されます。やったね。これとboostフォルダの中にあるincludeファイルを参照できるようにプロジェクトに設定すればboostが使えるよ。 | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Anyway.cpp" class="pre-wrap"> | |||
<code class="cpp">#include <boost\regex.hpp></code></pre></div> | |||
<script></yjavascript> | |||
のように指定して使えるようにインクルードパスの設定を追加しようね! | |||
=== '''ICU対応版スタティックライブラリを生成する場合''' === | |||
ICU対応版Boost.Regexライブラリが欲しいという稀有な人向けの記事です。ICUとBoost.Regex自体はDLLを使った動的なリンクでの利用なら、前項の方法で生成したライブラリと組み合わせて使うことができますのでこの項目の手順は不要です。 | |||
まずはICUのスタティックライブラリを生成する必要があります。*.libにはDLLでの利用を想定したライブラリファイルであるインポートライブラリと全部丸っと実行ファイルにコードを保持するためのスタティックライブラリがあります。 | |||
ICUのソースをダウンロードしてきて、スタティック版生成のためのプリプロセッサの定義をして、出力をDLL出力形式からlibファイル出力形式に切り替えて、ランタイムは必要に応じてコード生成方式を/MDや/MDd(デバッグ版)のDLL方式から/MTや/MTdに変更して、libファイルを名前を変えてlib出力ディレクトリに集約するビルド後イベントのコマンドを追加したり、makedataプロジェクトのMAKE時にスタティックオブジェクトからsicudt.libファイルを生成する処理なんかを追加します。 | |||
細かい手順は以下に記述していきます。 | |||
まずは新しいソリューション構成のStaticDebugやStaticReleaseを新規作成します。そのために、ARM64がVisualStudioでは無効であるためにソリューション構成が追加できない状態になっているので、ARM64を消します。割かし面倒な作業になります。VisualStudioのメニュー[ビルド(B)]-[構成マネージャー(O)...]を起動します。表示されたウィンドウのアクティブソリューションプラットフォームのリストから[編集]を選択します。表示されたウィンドウで[プラットフォーム]欄から[ARM64]を選択して[削除]ボタンを押します。次に[閉じる]ボタンを押します。したらば、戻ったウィンドウで各プロジェクトのプラットフォーム列の値をすべて[ARM64]にします。ARM64は消したのにまだ選べるというのは問題で、選べないようにしないといけないので、プラットフォーム列の値を選択する一覧から[編集]を選択します。表示されたウィンドウで[プラットフォーム]欄から[ARM64]を選択して[削除]ボタンを押します。次に[閉じる]ボタンを押します。これをすべてのプロジェクトのプラットフォーム列の値で繰り返し操作します。全部のプロジェクトに対して操作することでARM64を完全に消したことになります。したらば新しいソリューション構成が追加できる状態になったので、新しいソリューション構成のリストから[新規作成]を選択します。[名前]欄にStaticDebugと入力し、[設定のコピー元]欄をDebugに設定して、新しいプロジェクト構成を作成するのチェックボックスはOnのままにして[OK]ボタンを押します。おなじようにしてStaticRealeaseも作成します。新しいソリューション構成のリストから[新規作成]を選択します。[名前]欄にStaticReleaseと入力し、[設定のコピー元]欄をReleaseに設定して、新しいプロジェクト構成を作成するのチェックボックスはOnのままにして[OK]ボタンを押します。そしたら、StaticDebugとStaticReleaseの両方の構成に対して以下の設定を行います。これから何度もプロジェクトのプロパティを設定しますが、プロパティウィンドウの左上の構成欄が目的の構成に対して操作しているか確認して操作して下さい。StaticDebugとStaticReleaseについて操作します。 | |||
1.プリプロセッサの定義を追加する。makedataプロジェクト以外の全てのプロジェクトに対して。 | |||
ソリューションエクスプローラにある各プロジェクトを選択して[Alt]+[Enter]を入力して表示されるダイアログ、各プロジェクトのプロパティダイアログで項目[構成プロパティ]-[C/C++]-[プリプロセッサ]の項目[プリプロセッサの定義]に | |||
U_STATIC_IMPLEMENTATION; | |||
を追記します。最後の;(セミコロン)は区切りとしての意味があります。U_STATIC_IMPLEMENTATIONマクロを定義することによって、スタティック版ライブラリを生成するために必要な動作に切り替わる部分がいくつかあります。厳密には全部のプロジェクトに対してマクロ定義する必要は無く、U_STATIC_IMPLEMENTATIONによって動作が変化する部分を保持しているプロジェクトに対してのみマクロ定義するとよいはずです。 | |||
2.構成の種類がダイナミックライブラリ(.dll)になっているプロジェクトをスタティックライブラリ(.lib)に切り替える。 | |||
ソリューションエクスプローラにある各プロジェクトを選択して[Alt]+[Enter]を入力して表示されるダイアログ、各プロジェクトのプロパティダイアログで項目[構成プロパティ]-[全般]の項目[構成の種類]を確認して、ダイナミックライブラリ(.dll)となっている部分を | |||
スタティックライブラリ(.lib)に変更します。 | |||
に変更します。ICU77-1では | |||
*common | |||
*ctestfw | |||
*i18n | |||
*io | |||
*stubdata | |||
*testplug | |||
*toolutil | |||
の8プロジェクトがあります。 | |||
3.ランタイムもスタティックにしたい場合はコード生成がStaticDebugではマルチスレッドデバッグDLL(/MDd)になっているのをマルチスレッドデバッグ(/MTd)に変更する。StaticReleaseではマルチスレッドDLL(/MD)になっているのをマルチスレッド(/MT)に変更します。このようにICUの各プロジェクトを/MTや/MTdにした場合、ライブラリを利用するプロジェクトも/MTや/MTdにする必要があり、使いにくくなりますので、やらない方がいいと思います。ただしffftpみたいに/MTや/MTdの設定を利用するプロジェクトでboost.regexのスタティック版を使いたい時はICUもboost.regexも/MTや/MTdにしたものを作る必要があります。 | |||
ソリューションエクスプローラにある各プロジェクトを選択して[Alt]+[Enter]を入力して表示されるダイアログ、各プロジェクトのプロパティダイアログで項目[構成プロパティ]-[C/C++]-[コード生成]の項目[ランタイムライブラリ]について、 | |||
StaticDebugではマルチスレッドデバッグDLL(/MDd)になっているのをマルチスレッドデバッグ(/MTd)に変更。 | |||
StaticReleaseではマルチスレッドDLL(/MD)になっているのをマルチスレッド(/MT)に変更。 | |||
この設定によって生成されるlibを使用するプロジェクトでは、同じようにコード生成の設定を(/MTd)あるいは(/MT)にする必要があります。つまり、利用するライブラリやDLLのすべてのランタイムライブラリの設定が(/MTd)あるいは(/MT)になっている必要があります。混在はできません。ランタイムの方式だけは混在しているとリンクエラーが出るよ。つまり、いろいろなライブラリのほとんどのランタイムは規定値でDLL方式になっていることが多く。ライブラリの構築作業で疲れる方式と言えます。今やっているような作業をあらゆるライブラリのプロジェクトでやっていく覚悟が必要になるということです。これはスタティック版はどんどん容量が大きくなるということに起因していて、スタティックランタイム版は流行らないという向きが考えられます。それでもスタティック版にして、ランタイムDLLを使わないようにしたいという変態思考のプログラムを開発や小規模な開発にしていく道なのです。 | |||
では次にいきますか。 | |||
4.出力されるlibファイルを(ICUルートパス)\icu4c\lib64にコピーする処理を追加する。 | |||
ICUではlib64に生成されたlibファイルを集約して扱う習わしがあり、そのファイル名の命名規則も決まっています。例えばcommonプロジェクトではcommon.libファイルが生成されるのですが、これをデバッグ版インポートライブラリの場合icuucd.libのように命名するような規則があります。こいった変換規則にしたがったlibファイルの集約処理がビルド後に必要になります。命名規則は以下のようになっています。一部、何に使ってるかさえも理解していない命名規則はわかっていないlibファイルもあります。気が向いたら調査します。気が向かない時間は長くなりそうです。 | |||
*sicudt.lib | |||
*icudt.lib | |||
: デバッグ版とリリース版の区別もないです。ランタイムの区別もライブラリのインポートとスタティックの区別もないです。ライブラリのスタティックのときだけファイル名として先頭にsがつきます。 | |||
デバッグ版インポートライブラリ | |||
*common.lib→icuucd.lib | |||
*ctestfw.lib→icutestd.lib | |||
*i18n.lib→icuind.lib | |||
*io.lib→icuiod.lib | |||
*stubdata.lib | |||
*testplug.lib→testplugd.lib | |||
*toolutil→icutud.lib | |||
*layout.lib→iculed.lib(廃止) | |||
*layoutex.lib→iculxd.lib(廃止) | |||
リリース版インポートライブラリ | |||
*common.lib→icuuc.lib | |||
*ctestfw.lib→icutest.lib | |||
*i18n.lib→icuin.lib | |||
*io.lib→icuio.lib | |||
*stubdata.lib | |||
*testplug.lib→testplug.lib | |||
*toolutil→icutu.lib | |||
*layout.lib→icule.lib(廃止) | |||
*layoutex.lib→iculx.lib(廃止) | |||
デバッグ版スタティックライブラリ | |||
*common.lib→sicuucd.lib | |||
*ctestfw.lib→sicutestd.lib | |||
*i18n.lib→sicuind.lib | |||
*io.lib→sicuiod.lib | |||
*stubdata.lib | |||
*testplug.lib | |||
*toolutil→sicutud.lib | |||
*layout.lib→siculed.lib(廃止) | |||
*layoutex.lib→siculxd.lib(廃止) | |||
リリース版スタティックライブラリ | |||
*common.lib→sicuuc.lib | |||
*ctestfw.lib→sicutest.lib | |||
*i18n.lib→sicuin.lib | |||
*io.lib→sicuio.lib | |||
*stubdata.lib | |||
*testplug.lib | |||
*toolutil→sicutu.lib | |||
*layout.lib→sicule.lib(廃止) | |||
*layoutex.lib→siculx.lib(廃止) | |||
例えばStaticDebug構成のcommonプロジェクトの場合はソリューションエクスプローラにあるプロジェクト名[common]を選択して[Alt]+[Enter]を入力して表示されるダイアログ、プロパティダイアログで項目[構成プロパティ]-[ビルドイベント]-[ビルド後イベント]の項目[コマンドライン]の編集をクリックして表示されるウィンドウで | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Command Prompt" class="pre-wrap"> | |||
<code class="cmd">:: 出力先ディレクトリを作成 | |||
if not exist "$(SolutionDir)..\..\lib64" mkdir "$(SolutionDir)..\..\lib64" | |||
:: ビルド後の lib を移動&リネーム | |||
copy /Y "$(TargetDir)$(TargetName).lib" "$(SolutionDir)..\..\lib64\sicuucd.lib"</code></pre></div> | |||
<script></yjavascript> | |||
とします。StaticReleaseの場合は上記のコマンドラインのsicuucd.libとなっている部分をsicuuc.libとします。 | |||
これを全てのlibファイルを生成するプロジェクトで命名規則にしたがって繰り返しビルド後イベントのコマンドラインの欄に入力しています。 | |||
5.リリース版、デバッグ版共通のlibファイルsicudt.libを生成する処理を追加します。 | |||
ソリューションエクスプローラにあるプロジェクト名[makedata]を選択して[Alt]+[Enter]を入力して表示されるダイアログ、プロパティダイアログで項目[構成プロパティ]-[NMAKE]の項目[ビルドコマンドライン]の編集をクリックして表示されるウィンドウで | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Command Prompt" class="pre-wrap"> | |||
<code class="cmd">NMAKE /f makedata.mak ICUMAKE="$(ProjectDir)\" CFG=$(MakeCFG) DEBUG=$(DebugBuild) | |||
if not exist "$(SolutionDir)..\..\lib64" mkdir "$(SolutionDir)..\..\lib64" | |||
lib /nologo /out:"$(SolutionDir)..\..\lib64\sicudt.lib" "$(MSBuildProjectDirectory)\out\tmp\icudt77l_dat.obj"</code></pre></div> | |||
<script></yjavascript> | |||
とします。 | |||
6.uconvプロジェクトのmakedata.makファイルをStaticDebugを追加したことによる変更を反映する。StaticRelease対応版は作成まだです。 | |||
C:\(ICUルートパス)\icu4c\source\extra\uconv\makedata.makファイルのバックアップをとって、以下内容と差し替えます。 | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="makedata.mak" class="pre-wrap"> | |||
<code class="makefile"># Copyright (C) 2016 and later: Unicode, Inc. and others. | |||
# License & terms of use: http://www.unicode.org/copyright.html | |||
#********************************************************************** | |||
#* Copyright (C) 1999-2008, International Business Machines Corporation | |||
#* and others. All Rights Reserved. | |||
#********************************************************************** | |||
# nmake file for creating data files on win32 | |||
# invoke with | |||
# nmake /f makedata.mak icup=<path_to_icu_instalation> [Debug|Release] | |||
# | |||
# 12/10/1999 weiv Created | |||
</br> | |||
#If no config, we default to debug | |||
!IF "$(CFG)" == "" | |||
CFG=Debug | |||
!MESSAGE No configuration specified. Defaulting to common - Win32 Debug. | |||
!ENDIF | |||
</br> | |||
#Here we test if a valid configuration is given | |||
!IF "$(CFG)" != "Release" && "$(CFG)" != "release" && "$(CFG)" != "Debug" && "$(CFG)" != "debug" && "$(CFG)" != "StaticDebug" && "$(CFG)" != "staticdebug" && "$(CFG)" != "StaticRelease" && "$(CFG)" != "staticrelease" &&"$(CFG)" != "x86\Release" && "$(CFG)" != "x86\Debug" && "$(CFG)" != "x86\StaticDebug" && "$(CFG)" != "x86\StaticRelease" && "$(CFG)" != "x64\Release" && "$(CFG)" != "x64\Debug" && "$(CFG)" != "x64\StaticDebug" && "$(CFG)" != "x64\StaticRelease" && "$(CFG)" != "ARM\Release" && "$(CFG)" != "ARM\Debug" && "$(CFG)" != "ARM\StaticDebug" && "$(CFG)" != "ARM\StaticRelease" && "$(CFG)" != "ARM64\Release" && "$(CFG)" != "ARM64\Debug" && "$(CFG)" != "ARM64\StaticDebug" && "$(CFG)" != "ARM64\StaticRelease" | |||
#CFG=Debug | |||
!MESSAGE Invalid configuration "$(CFG)" specified. | |||
!MESSAGE You can specify a configuration when running NMAKE | |||
!MESSAGE by defining the macro CFG on the command line. For example: | |||
!MESSAGE | |||
!MESSAGE NMAKE /f "makedata.mak" CFG="Debug" | |||
!MESSAGE | |||
!MESSAGE Possible choices for configuration are: | |||
!MESSAGE | |||
!MESSAGE "Release" | |||
!MESSAGE "Debug" | |||
!MESSAGE "StaticDebug" | |||
!MESSAGE | |||
!ERROR An invalid configuration is specified. | |||
!ENDIF | |||
</br> | |||
#Let's see if user has given us a path to ICU | |||
#This could be found according to the path to makefile, but for now it is this way | |||
!IF "$(ICUP)"=="" | |||
!ERROR Can't find path! | |||
!ENDIF | |||
!MESSAGE ICU path is $(ICUP) | |||
</br> | |||
RESNAME=uconvmsg | |||
RESDIR=resources | |||
RESFILES=resfiles.mk | |||
ICUDATA=$(ICUP)\data | |||
</br> | |||
DLL_OUTPUT=.\$(CFG) | |||
# set the following to 'static' or 'dll' depending | |||
PKGMODE=static | |||
</br> | |||
ICD=$(ICUDATA)^\ | |||
DATA_PATH=$(ICUP)\data^\ | |||
</br> | |||
NATIVE_ARM= | |||
!IF "$(PROCESSOR_ARCHITECTURE)" == "ARM64" || "$(PROCESSOR_ARCHITEW6432)" == "ARM64" | |||
NATIVE_ARM=ARM64 | |||
!ELSE IF "$(PROCESSOR_ARCHITECTURE)" == "ARM" || "$(PROCESSOR_ARCHITEW6432)" == "ARM" | |||
NATIVE_ARM=ARM | |||
!ENDIF | |||
</br> | |||
# Use the x64 tools for building ARM and ARM64. | |||
# Note: This is similar to the TOOLS CFG PATH in source\data\makedata.mak | |||
!IF "$(NATIVE_ARM)" == "" | |||
!IF "$(CFG)" == "x64\Release" || "$(CFG)" == "x64\Debug" || "$(CFG)" == "x64\StaticDebug" || "$(CFG)" == "x64\StaticRelease" || "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" || "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease" | |||
ICUTOOLS=$(ICUP)\bin64 | |||
PATH = $(ICUP)\bin64;$(PATH) | |||
!ELSE | |||
ICUTOOLS=$(ICUP)\bin | |||
PATH = $(ICUP)\bin;$(PATH) | |||
!ENDIF | |||
!ELSE | |||
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" | |||
ICUTOOLS=$(ICUP)\binARM | |||
PATH = $(ICUP)\binARM;$(PATH) | |||
!ELSE | |||
ICUTOOLS=$(ICUP)\binARM64 | |||
PATH = $(ICUP)\binARM64;$(PATH) | |||
!ENDIF | |||
!ENDIF | |||
</br> | |||
# If building ARM/ARM, then we need to pass the arch as an argument. | |||
EXTRA_PKGDATA_ARGUMENTS= | |||
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" | |||
EXTRA_PKGDATA_ARGUMENTS=-a ARM | |||
!ENDIF | |||
!IF "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease" | |||
EXTRA_PKGDATA_ARGUMENTS=-a ARM64 | |||
!ENDIF | |||
</br> | |||
# Make sure the necessary tools exist before continuing. (This is to prevent cryptic errors from NMAKE). | |||
!IF !EXISTS($(ICUTOOLS)\pkgdata.exe) | |||
!MESSAGE Unable to find "$(ICUTOOLS)\pkgdata.exe" | |||
!ERROR The tool 'pkgdata.exe' does not exist! (Have you built all of ICU yet?). | |||
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" || "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease" | |||
!ERROR Note that the ARM and ARM64 builds require building x64 first. | |||
!ENDIF | |||
!ENDIF | |||
!IF !EXISTS($(ICUTOOLS)\genrb.exe) | |||
!MESSAGE Unable to find "$(ICUTOOLS)\genrb.exe" | |||
!ERROR The tool 'genrb.exe' does not exist! (Have you built all of ICU yet?). | |||
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" || "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease" | |||
!ERROR Note that the ARM and ARM64 builds require building x64 first. | |||
!ENDIF | |||
!ENDIF | |||
</br> | |||
# Suffixes for data files | |||
.SUFFIXES : .ucm .cnv .dll .dat .res .txt .c | |||
</br> | |||
# We're including a list of resource files. | |||
FILESEPCHAR= | |||
</br> | |||
!IF EXISTS("$(RESFILES)") | |||
!INCLUDE "$(RESFILES)" | |||
!ELSE | |||
!ERROR ERROR: cannot find "$(RESFILES)" | |||
!ENDIF | |||
RES_FILES = $(RESSRC:.txt=.res) | |||
RB_FILES = resources\$(RES_FILES:.res =.res resources\) | |||
RESOURCESDIR= | |||
</br> | |||
# This target should build all the data files | |||
!IF "$(PKGMODE)" == "dll" | |||
OUTPUT = "$(DLL_OUTPUT)\$(RESNAME).dll" | |||
!ELSE | |||
OUTPUT = "$(DLL_OUTPUT)\$(RESNAME).lib" | |||
!ENDIF | |||
</br> | |||
ALL : $(OUTPUT) | |||
@echo All targets are up to date (mode $(PKGMODE)) | |||
</br> | |||
</br> | |||
# invoke pkgdata - static | |||
"$(DLL_OUTPUT)\$(RESNAME).lib" : $(RB_FILES) $(RESFILES) | |||
@echo Building $(RESNAME).lib | |||
@"$(ICUTOOLS)\pkgdata" -f -v -m static -c -p $(RESNAME) -d "$(DLL_OUTPUT)" $(EXTRA_PKGDATA_ARGUMENTS) -s "$(RESDIR)" <<pkgdatain.txt | |||
$(RES_FILES:.res =.res | |||
) | |||
<<KEEP | |||
</br> | |||
# This is to remove all the data files | |||
CLEAN : | |||
-@erase "$(RB_FILES)" | |||
-@erase "$(CFG)\*uconvmsg*.*" | |||
-@"$(ICUTOOLS)\pkgdata" -f --clean -v -m static -c -p $(RESNAME) -d "$(DLL_OUTPUT)" $(EXTRA_PKGDATA_ARGUMENTS) -s "$(RESDIR)" pkgdatain.txt | |||
</br> | |||
# Inference rule for creating resource bundles | |||
{$(RESDIR)}.txt{$(RESDIR)}.res: | |||
@echo Making Resource Bundle files | |||
"$(ICUTOOLS)\genrb" -s $(@D) -d $(@D) $(?F) | |||
</br> | |||
$(RESSRC) : {"$(ICUTOOLS)"}genrb.exe</code></pre></div> | |||
<script></yjavascript> | |||
そしてB2ビルドでstatic版を得るためのコマンドを実行するだけです。 | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Command Prompt" class="pre-wrap"> | |||
<code class="cmd">b2 --build-type=complete --toolset=msvc cxxflags="/std:c++17" architecture=x86 address-model=64 variant=debug link=static runtime-link=shared --with-regex define=BOOST_REGEX_HAS_ICU -sICU_PATH=C:\(ICUのルートパス)\icu4c stage linkflags="Advapi32.lib"</code></pre></div> | |||
<script></yjavascript> | |||
StaticDebugに対応したBoost.Regexは上記のとおりですが、StaticReleaseの場合は上記コマンドのvariant=debugとなっているところをvariant=releaseにします。ICUのランタイムをスタティック版(/MTや/MTd設定)にしたときはlink=static runtime-link=sharedをlink=static runtime-link=staticにします。 | |||
B2ビルドは動作させると、C:¥(Boostルートパス)\bin.v2\Config.logファイルに処理結果についての記録が出力されます。最初のアーキテクチャチェックのErrorはPCに存在しないアーキテクチャーを検出する都度、Errorになりますが、問題のないエラーです。それ以外のErrorが出ていないかチェックして下さい。うまくいったように見えてErrorが出ていれば、スタティックICU版のBoost.Regexライブラリになっていないことがあります。Config.logの内容に従ってErrorを解決していけば、道は開かれます。 | |||
ちなみに生成したlibはC:¥(Boostルートパス)\stage\libに出力され、libboost_regex-vc143-mt-gd-x64-1_89.libのような名称になります。先頭にlibがついています。ICUのライブラリも内包しているスタティックライブラリになっています。ICUのランタイム設定がスタティック(/MTd)設定のデバッグ版はsgdとなります。このライブラリをライブラリディレクトリの設定とリンカの入力の追加の依存ファイルにライブラリファイル名を追加とC:¥(Boostルートパス)をインクルードディレクトリに設定して、C:¥(ICUルートパス)\icu4c\lib64へのライブラリのライブラリディレクトリの設定とリンカの入力の追加の依存ファイルにライブラリファイル名(sicudt.lib, sicuucd.lib, sicuind.lib, sicuiod.lib)とC:¥(ICUルートパス)\icu4c\includeをインクルードディレクトリに設定すればICUのDLL不要でランタイムを(/MDd)や(/MD)に設定したプロジェクトで動かすことが出来るようになります。こんな大規模なライブラリを導入しておきながらランタイムまでスタティック(ICUのコード生成設定が/MTや/MTd)なプロジェクト開発をする人がいるとは思えませんが、知識として記事にしておきました。もちろんB2でlink設定をshared設定にした場合はICUのDLLを実行ファイルが参照するパスに配置すれば動的なプロジェクト、ランタイムもDLL方式にした(/MDd)や(/MD)のプロジェクトで動かせますよ。ちなみに、b2コマンドでlink=設定でstaticを選択し、スタティックライブラリにした場合、自分のプロジェクトには、#define U_STATIC_IMPLEMENTATIONというプリプロセッサ定義が必要です。 | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Anyway.cpp" class="pre-wrap"> | |||
<code class="cpp">#define U_STATIC_IMPLEMENTATION | |||
#include <boost\regex\icu.hpp></code></pre></div> | |||
<script></yjavascript> | |||
といったインクルードファイルに書かれている関数が使えるようになるんだね。ICU版だね。 | |||
例えば、以下のようなコードが動くようになるよ。サンプルプログラムだね。[[VC PlusPlus UTF-8によるプログラミングを推進するための大切な設定]]の記事にある設定もしておこう。UTF-8の文字データを使うプログラムなのでね特に。気に留めたい。 | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Boost_Regex_ICU.cpp" class="pre-wrap"> | |||
<code class="cpp">#define U_STATIC_IMPLEMENTATION | |||
| |||
#include <boost/regex.hpp> | |||
#include <boost/regex/icu.hpp> | |||
#include <iostream> | |||
</br> | |||
int main() { | |||
SetConsoleOutputCP(CP_UTF8); | |||
SetConsoleCP(CP_UTF8); | |||
</br> | |||
boost::regex re("[A-Za-z]+"); | |||
std::string s = "Hello"; | |||
if (boost::regex_match(s, re)) { | |||
std::cout << "Match!" << std::endl; | |||
} | |||
| |||
std::cout << typeid(boost::u32regex).name() << std::endl; | |||
| |||
std::basic_string<UChar32> s4; | |||
s4.push_back('H'); | |||
s4.push_back('e'); | |||
s4.push_back('l'); | |||
s4.push_back('l'); | |||
s4.push_back('o'); | |||
| |||
boost::u32regex re4 = boost::make_u32regex("[A-Za-z]+"); | |||
| |||
if (boost::regex_match(s4, re4)) { | |||
std::cout << "Match!" << std::endl; | |||
} | |||
| |||
return 0; | |||
}</code></pre></div> | |||
<script></yjavascript> | |||
動作させると | |||
<yjavascript></script> | |||
<!-- | |||
data-line-num-start="1" | |||
data-line-highlight="3, 10-" | |||
data-max-lines="10" | |||
--> | |||
<div class="hljs-wrap"><pre data-label="Boost_Regex_ICU_Result.txt" class="pre-wrap"> | |||
<code class="text">Match! | |||
class boost::basic_regex<int,class boost::icu_regex_traits> | |||
Match!</code></pre></div> | |||
<script></yjavascript> | |||
という出力が得られます。 | |||
[[メインページ#言語と開発環境|言語と開発環境]]に戻る。 | [[メインページ#言語と開発環境|言語と開発環境]]に戻る。 | ||
2025年10月21日 (火) 18:43時点における最新版
言語と開発環境に戻る。
概要
Boost.Regexは正規表現による文字列の検索・置換の処理を高速かつ多機能にするライブラリです。標準ライブラリのstd::regexもありますが、大きな違いが認められるほどのモノで利用者も多いライブラリです。人気。ですね。Boost.RegexはBoostというライブラリの正規表現に関する部分的なライブラリで、全部を導入しなくててもBoost.Regexだけを単独で、つまりスタンドアローンモードで使うことができるとされています。
ここでは、Boost.Regexのスタンドアローンモードでの導入方法・インストール・ビルド?・設定について記述したいと思います。ただし、記事作成中にあっては、管理人も使い方をわからない手探りで進めていく感じなので、記事が完成するまでは、ただの日記です。難しそうなので、考えながらやっていく感じです。
まずは入手についてですが、github(巨大なソースコード集積siteです)から入手します。https://github.com/boostorg/regexからCodeボタンのDownload ZIPを選択すると一式を入手できます。ログインしていないと簡単にはダウンロード出来ません。
これでBoost.Regexだけを入手できたので、includeディレクトリのファイルとsrcディレクトリのファイルがあれば都度link処理は必要になりますが、Boost.Regexの各種関数が使えるようになります。あとはUnicodeの全てを司るICUライブラリを使うかとかの調整が必要になるのかな。
libファイルがあれば、includeファイルとlibファイルの組み合わせで扱うこともできますが、libファイルを作るにはBoost全体を入手して、Boostrap.batファイルを動かしたあとにb.exeを使ってlibファイルを生成するような手順が必要になります。
srcがあれば、デバッグも内部まで追いかけることができて勉強になったりもしますので、一長一短ですね。何長何短かは考え方次第です。時間があればlibファイルを使う手順もあとで追記してみたいと思います。ここではまず最初にソースとインクルードファイルだけで扱ってみたいと思います。ICUありと無しもね。まずは無しから。
特定のプロジェクトだけで使う場合
Boost.Regexを何度も使うときには、いつでも使えるように、特定のディレクトリにおいておいて、ちょっとプロジェクトを設定すれば使えるみたいにして使うのがオススメですが、特定のプロジェクトだけで使う場合はプロジェクトのフォルダの中にソースとインクルードファイルを読み込ませればよいわけです。具体的にやってみましょう。
Boost.Regexのexampleフォルダにあるコンソールアプリケーションサンプルを動かしてみます。なので、Windowsコンソールアプリケーションを作る要領で新規プロジェクトを作成します。
そしたら、プロジェクトの*.vcxprojファイルのあるフォルダにboost-regexという名前のフォルダを作って、boost.regexのファイル一式のregex-developフォルダの中にあるincludeフォルダとsrcフォルダをboost-regexの中に貼り付けましょう。
そしたらexampleプログラムをコピーしてmain関数が作成された「プロジェクト名.cpp」に貼り付けます。regex-developフォルダの中のexampleフォルダの中のsnippetsフォルダの中のregex_grep_example_1.cppはBoost.Regexだけで動かせるサンプルになっています。exampleフォルダの中のgrepフォルダの中にあるサンプルは動かせません。動かすにはBoost.program_optionsというリポジトリも必要になるためです。なので、Boost.Regexのリポジトリからもってきたファイル一式だからといって、exampleフォルダにある全部が動かせるとは限らないことに注意が必要です。
regex_grep_example_1.cppの中身をペロッと貼り付けます。
そしたら、以下のようにプロジェクトを設定します。
プロジェクトのプロパティから以下を設定します。
- [構成プロパティ]-[C/C++]-[全般]の「SDLチェック」を「いいえ(/sdl-)」を選択します。
- [構成プロパティ]-[VC++ディレクトリ]の「外部インクルードディレクトリ」の後部に「;boost-regex\include」を追記します。
- [構成プロパティ]-[デバッグ]の「コマンド引数」に「(プロジェクトファイルを作ったフォルダへのフルパス)\boost-regex\include\boost\regex\concepts.hpp」
このサンプルプログラムは、コマンド引数に与えられたファイルパスにあるファイルからclass定義を見つけてそのclass名を抽出する正規表現grepを実行するものです。なのでコマンド引数に、クラスを保持するテキストファイルへのパスを設定しました。デバッグ時はプロジェクトからの相対パスでもよいでしょう。実行ファイルから起動するときは、実行ファイルが配置されたディレクトリからの相対パスである必要があります。
Boost.Regexはstrcpyやstrcmpやstrcatなどの古い関数を使うのでSDL(Security Development Lifecycle)チェックをはずす必要もあります。
そして、ソリューションエクスプローラのソースファイルフィルタ項目の上で右クリックして表示されるメニューから[追加]-[既存の項目]を選択してプロジェクトを作成したディレクトリの中のBoost-Regexの中のsrcの中のソースファイル5つを選択してプロジェクトに追加します。
これで、準備ができたのでこのサンプルを動かすプロジェクトをビルドします。メニューの[ビルド]-[ソシューションのビルド]を実行します。ビルドがうまくいくと思います。
そしたら、ブレークポイントを設定しなくてもよいので、ローカルWindowsデバッガーボタンをおして実行してみましょう。
以下のような結果が得られます。
Processing file (プロジェクトファイルを作ったフォルダへのフルパス)\boost-regex\include\boost\regex\concepts.hpp
13 matches found
class "BaseRegexConcept" found at index: 8459
class "BitmaskConcept" found at index: 5600
class "BoostRegexConcept" found at index: 31770
class "RegexConcept" found at index: 24052
class "RegexTraitsConcept" found at index: 6054
class "allocator_architype" found at index: 2402
class "char_architype" found at index: 1279
class "functor1" found at index: 30965
class "functor1b" found at index: 31182
class "functor2" found at index: 31390
class "functor3" found at index: 31520
class "rebind" found at index: 2673
class "regex_traits_architype" found at index: 3794
(プロジェクトファイルを作ったフォルダへのフルパス)\x64\Debug\BoostSample.exe (プロセス 4908) は、コード 0 で終了しました。
デバッグが停止したときに自動的にコンソールを閉じるには、[ツール] -> [オプション] -> [デバッグ] -> [デバッグの停止時に自 動的にコンソールを閉じる] を有効にします。
このウィンドウを閉じるには、任意のキーを押してください...
特定のプロジェクトにBoost.Regexを追加して、ビルドする手順は習得できたので、これで一つの使い方についてできることになったわけですからBoost.Regexを使えるようになったということです。次はICUを使う例を紹介したいですが、以前にICUを使ったときからはパソコンが入れ替わっているので、また導入からになります。ICU...また後日、記事を追加することになります。今は、説明することはしばらく保留にしておきたいと思います。使えるのが大事だからね。
ライブラリを生成する場合
ライブラリを生成する場合はBoost_Regexだけのプロジェクト単体でダウンロードしていたのでは、割かし手順が複雑になってしまいますので、Boost全体をダウンロードした方がよいです。単体から引っ張り出す場合でも結局全部ダウンロードする感じになっている気もします。勘違いならゴメン。なのでBoostをダウンロードしよう!
https://www.boost.org/users/history/version_1_89_0.html
割かし大きいことに驚かされますがビビることはない。ハードディスクに空きと通信の手段と時間さえあれば、やれる。
解凍したら、コマンドプロンプトを立ち上げて解凍してできたディレクトリをカレントディレクトリにしよう。解凍したフォルダはあまり深いところに置かない方がいいです。C:¥boost_1_89_0\とかにするのもいいね。こういうboost_1_89_0までのパスを(Boostルートパス)と表現するとしよう。
(Boostルートパス)>bootstrap.bat
ってやると、b2っていうコマンドが使えるようになるツールを生成してくれます。したらば
(Boostルートパス)>b2 variant=debug link=static runtime-link=shared --with-regex
のようにして、regexのdebug版のライブラリを生成し
(Boostルートパス)>b2 variant=release link=static runtime-link=shared --with-regex
のようにして、regexのrelease版のライブラリを生成します。
以下のようなファイルが生成されます。x32の方はあまりいらないね。gdの方がデバッグ版ね。
- libboost_regex-vc143-mt-gd-x32-1_89.lib
- libboost_regex-vc143-mt-gd-x64-1_89.lib
- libboost_regex-vc143-mt-x32-1_89.lib
- libboost_regex-vc143-mt-x64-1_89.lib
(Boostルートパス)\stage\libというフォルダにlibファイルが生成されます。やったね。これとboostフォルダの中にあるincludeファイルを参照できるようにプロジェクトに設定すればboostが使えるよ。
#include <boost\regex.hpp>
のように指定して使えるようにインクルードパスの設定を追加しようね!
ICU対応版スタティックライブラリを生成する場合
ICU対応版Boost.Regexライブラリが欲しいという稀有な人向けの記事です。ICUとBoost.Regex自体はDLLを使った動的なリンクでの利用なら、前項の方法で生成したライブラリと組み合わせて使うことができますのでこの項目の手順は不要です。
まずはICUのスタティックライブラリを生成する必要があります。*.libにはDLLでの利用を想定したライブラリファイルであるインポートライブラリと全部丸っと実行ファイルにコードを保持するためのスタティックライブラリがあります。
ICUのソースをダウンロードしてきて、スタティック版生成のためのプリプロセッサの定義をして、出力をDLL出力形式からlibファイル出力形式に切り替えて、ランタイムは必要に応じてコード生成方式を/MDや/MDd(デバッグ版)のDLL方式から/MTや/MTdに変更して、libファイルを名前を変えてlib出力ディレクトリに集約するビルド後イベントのコマンドを追加したり、makedataプロジェクトのMAKE時にスタティックオブジェクトからsicudt.libファイルを生成する処理なんかを追加します。
細かい手順は以下に記述していきます。
まずは新しいソリューション構成のStaticDebugやStaticReleaseを新規作成します。そのために、ARM64がVisualStudioでは無効であるためにソリューション構成が追加できない状態になっているので、ARM64を消します。割かし面倒な作業になります。VisualStudioのメニュー[ビルド(B)]-[構成マネージャー(O)...]を起動します。表示されたウィンドウのアクティブソリューションプラットフォームのリストから[編集]を選択します。表示されたウィンドウで[プラットフォーム]欄から[ARM64]を選択して[削除]ボタンを押します。次に[閉じる]ボタンを押します。したらば、戻ったウィンドウで各プロジェクトのプラットフォーム列の値をすべて[ARM64]にします。ARM64は消したのにまだ選べるというのは問題で、選べないようにしないといけないので、プラットフォーム列の値を選択する一覧から[編集]を選択します。表示されたウィンドウで[プラットフォーム]欄から[ARM64]を選択して[削除]ボタンを押します。次に[閉じる]ボタンを押します。これをすべてのプロジェクトのプラットフォーム列の値で繰り返し操作します。全部のプロジェクトに対して操作することでARM64を完全に消したことになります。したらば新しいソリューション構成が追加できる状態になったので、新しいソリューション構成のリストから[新規作成]を選択します。[名前]欄にStaticDebugと入力し、[設定のコピー元]欄をDebugに設定して、新しいプロジェクト構成を作成するのチェックボックスはOnのままにして[OK]ボタンを押します。おなじようにしてStaticRealeaseも作成します。新しいソリューション構成のリストから[新規作成]を選択します。[名前]欄にStaticReleaseと入力し、[設定のコピー元]欄をReleaseに設定して、新しいプロジェクト構成を作成するのチェックボックスはOnのままにして[OK]ボタンを押します。そしたら、StaticDebugとStaticReleaseの両方の構成に対して以下の設定を行います。これから何度もプロジェクトのプロパティを設定しますが、プロパティウィンドウの左上の構成欄が目的の構成に対して操作しているか確認して操作して下さい。StaticDebugとStaticReleaseについて操作します。
1.プリプロセッサの定義を追加する。makedataプロジェクト以外の全てのプロジェクトに対して。
ソリューションエクスプローラにある各プロジェクトを選択して[Alt]+[Enter]を入力して表示されるダイアログ、各プロジェクトのプロパティダイアログで項目[構成プロパティ]-[C/C++]-[プリプロセッサ]の項目[プリプロセッサの定義]に
U_STATIC_IMPLEMENTATION;
を追記します。最後の;(セミコロン)は区切りとしての意味があります。U_STATIC_IMPLEMENTATIONマクロを定義することによって、スタティック版ライブラリを生成するために必要な動作に切り替わる部分がいくつかあります。厳密には全部のプロジェクトに対してマクロ定義する必要は無く、U_STATIC_IMPLEMENTATIONによって動作が変化する部分を保持しているプロジェクトに対してのみマクロ定義するとよいはずです。
2.構成の種類がダイナミックライブラリ(.dll)になっているプロジェクトをスタティックライブラリ(.lib)に切り替える。
ソリューションエクスプローラにある各プロジェクトを選択して[Alt]+[Enter]を入力して表示されるダイアログ、各プロジェクトのプロパティダイアログで項目[構成プロパティ]-[全般]の項目[構成の種類]を確認して、ダイナミックライブラリ(.dll)となっている部分を
スタティックライブラリ(.lib)に変更します。
に変更します。ICU77-1では
- common
- ctestfw
- i18n
- io
- stubdata
- testplug
- toolutil
の8プロジェクトがあります。
3.ランタイムもスタティックにしたい場合はコード生成がStaticDebugではマルチスレッドデバッグDLL(/MDd)になっているのをマルチスレッドデバッグ(/MTd)に変更する。StaticReleaseではマルチスレッドDLL(/MD)になっているのをマルチスレッド(/MT)に変更します。このようにICUの各プロジェクトを/MTや/MTdにした場合、ライブラリを利用するプロジェクトも/MTや/MTdにする必要があり、使いにくくなりますので、やらない方がいいと思います。ただしffftpみたいに/MTや/MTdの設定を利用するプロジェクトでboost.regexのスタティック版を使いたい時はICUもboost.regexも/MTや/MTdにしたものを作る必要があります。
ソリューションエクスプローラにある各プロジェクトを選択して[Alt]+[Enter]を入力して表示されるダイアログ、各プロジェクトのプロパティダイアログで項目[構成プロパティ]-[C/C++]-[コード生成]の項目[ランタイムライブラリ]について、
StaticDebugではマルチスレッドデバッグDLL(/MDd)になっているのをマルチスレッドデバッグ(/MTd)に変更。
StaticReleaseではマルチスレッドDLL(/MD)になっているのをマルチスレッド(/MT)に変更。
この設定によって生成されるlibを使用するプロジェクトでは、同じようにコード生成の設定を(/MTd)あるいは(/MT)にする必要があります。つまり、利用するライブラリやDLLのすべてのランタイムライブラリの設定が(/MTd)あるいは(/MT)になっている必要があります。混在はできません。ランタイムの方式だけは混在しているとリンクエラーが出るよ。つまり、いろいろなライブラリのほとんどのランタイムは規定値でDLL方式になっていることが多く。ライブラリの構築作業で疲れる方式と言えます。今やっているような作業をあらゆるライブラリのプロジェクトでやっていく覚悟が必要になるということです。これはスタティック版はどんどん容量が大きくなるということに起因していて、スタティックランタイム版は流行らないという向きが考えられます。それでもスタティック版にして、ランタイムDLLを使わないようにしたいという変態思考のプログラムを開発や小規模な開発にしていく道なのです。
では次にいきますか。
4.出力されるlibファイルを(ICUルートパス)\icu4c\lib64にコピーする処理を追加する。
ICUではlib64に生成されたlibファイルを集約して扱う習わしがあり、そのファイル名の命名規則も決まっています。例えばcommonプロジェクトではcommon.libファイルが生成されるのですが、これをデバッグ版インポートライブラリの場合icuucd.libのように命名するような規則があります。こいった変換規則にしたがったlibファイルの集約処理がビルド後に必要になります。命名規則は以下のようになっています。一部、何に使ってるかさえも理解していない命名規則はわかっていないlibファイルもあります。気が向いたら調査します。気が向かない時間は長くなりそうです。
- sicudt.lib
- icudt.lib
- デバッグ版とリリース版の区別もないです。ランタイムの区別もライブラリのインポートとスタティックの区別もないです。ライブラリのスタティックのときだけファイル名として先頭にsがつきます。
デバッグ版インポートライブラリ
- common.lib→icuucd.lib
- ctestfw.lib→icutestd.lib
- i18n.lib→icuind.lib
- io.lib→icuiod.lib
- stubdata.lib
- testplug.lib→testplugd.lib
- toolutil→icutud.lib
- layout.lib→iculed.lib(廃止)
- layoutex.lib→iculxd.lib(廃止)
リリース版インポートライブラリ
- common.lib→icuuc.lib
- ctestfw.lib→icutest.lib
- i18n.lib→icuin.lib
- io.lib→icuio.lib
- stubdata.lib
- testplug.lib→testplug.lib
- toolutil→icutu.lib
- layout.lib→icule.lib(廃止)
- layoutex.lib→iculx.lib(廃止)
デバッグ版スタティックライブラリ
- common.lib→sicuucd.lib
- ctestfw.lib→sicutestd.lib
- i18n.lib→sicuind.lib
- io.lib→sicuiod.lib
- stubdata.lib
- testplug.lib
- toolutil→sicutud.lib
- layout.lib→siculed.lib(廃止)
- layoutex.lib→siculxd.lib(廃止)
リリース版スタティックライブラリ
- common.lib→sicuuc.lib
- ctestfw.lib→sicutest.lib
- i18n.lib→sicuin.lib
- io.lib→sicuio.lib
- stubdata.lib
- testplug.lib
- toolutil→sicutu.lib
- layout.lib→sicule.lib(廃止)
- layoutex.lib→siculx.lib(廃止)
例えばStaticDebug構成のcommonプロジェクトの場合はソリューションエクスプローラにあるプロジェクト名[common]を選択して[Alt]+[Enter]を入力して表示されるダイアログ、プロパティダイアログで項目[構成プロパティ]-[ビルドイベント]-[ビルド後イベント]の項目[コマンドライン]の編集をクリックして表示されるウィンドウで
:: 出力先ディレクトリを作成
if not exist "$(SolutionDir)..\..\lib64" mkdir "$(SolutionDir)..\..\lib64"
:: ビルド後の lib を移動&リネーム
copy /Y "$(TargetDir)$(TargetName).lib" "$(SolutionDir)..\..\lib64\sicuucd.lib"
とします。StaticReleaseの場合は上記のコマンドラインのsicuucd.libとなっている部分をsicuuc.libとします。
これを全てのlibファイルを生成するプロジェクトで命名規則にしたがって繰り返しビルド後イベントのコマンドラインの欄に入力しています。
5.リリース版、デバッグ版共通のlibファイルsicudt.libを生成する処理を追加します。
ソリューションエクスプローラにあるプロジェクト名[makedata]を選択して[Alt]+[Enter]を入力して表示されるダイアログ、プロパティダイアログで項目[構成プロパティ]-[NMAKE]の項目[ビルドコマンドライン]の編集をクリックして表示されるウィンドウで
NMAKE /f makedata.mak ICUMAKE="$(ProjectDir)\" CFG=$(MakeCFG) DEBUG=$(DebugBuild)
if not exist "$(SolutionDir)..\..\lib64" mkdir "$(SolutionDir)..\..\lib64"
lib /nologo /out:"$(SolutionDir)..\..\lib64\sicudt.lib" "$(MSBuildProjectDirectory)\out\tmp\icudt77l_dat.obj"
とします。
6.uconvプロジェクトのmakedata.makファイルをStaticDebugを追加したことによる変更を反映する。StaticRelease対応版は作成まだです。
C:\(ICUルートパス)\icu4c\source\extra\uconv\makedata.makファイルのバックアップをとって、以下内容と差し替えます。
# Copyright (C) 2016 and later: Unicode, Inc. and others.
# License & terms of use: http://www.unicode.org/copyright.html
#**********************************************************************
#* Copyright (C) 1999-2008, International Business Machines Corporation
#* and others. All Rights Reserved.
#**********************************************************************
# nmake file for creating data files on win32
# invoke with
# nmake /f makedata.mak icup=<path_to_icu_instalation> [Debug|Release]
#
# 12/10/1999 weiv Created
#If no config, we default to debug
!IF "$(CFG)" == ""
CFG=Debug
!MESSAGE No configuration specified. Defaulting to common - Win32 Debug.
!ENDIF
#Here we test if a valid configuration is given
!IF "$(CFG)" != "Release" && "$(CFG)" != "release" && "$(CFG)" != "Debug" && "$(CFG)" != "debug" && "$(CFG)" != "StaticDebug" && "$(CFG)" != "staticdebug" && "$(CFG)" != "StaticRelease" && "$(CFG)" != "staticrelease" &&"$(CFG)" != "x86\Release" && "$(CFG)" != "x86\Debug" && "$(CFG)" != "x86\StaticDebug" && "$(CFG)" != "x86\StaticRelease" && "$(CFG)" != "x64\Release" && "$(CFG)" != "x64\Debug" && "$(CFG)" != "x64\StaticDebug" && "$(CFG)" != "x64\StaticRelease" && "$(CFG)" != "ARM\Release" && "$(CFG)" != "ARM\Debug" && "$(CFG)" != "ARM\StaticDebug" && "$(CFG)" != "ARM\StaticRelease" && "$(CFG)" != "ARM64\Release" && "$(CFG)" != "ARM64\Debug" && "$(CFG)" != "ARM64\StaticDebug" && "$(CFG)" != "ARM64\StaticRelease"
#CFG=Debug
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "makedata.mak" CFG="Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Release"
!MESSAGE "Debug"
!MESSAGE "StaticDebug"
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
#Let's see if user has given us a path to ICU
#This could be found according to the path to makefile, but for now it is this way
!IF "$(ICUP)"==""
!ERROR Can't find path!
!ENDIF
!MESSAGE ICU path is $(ICUP)
RESNAME=uconvmsg
RESDIR=resources
RESFILES=resfiles.mk
ICUDATA=$(ICUP)\data
DLL_OUTPUT=.\$(CFG)
# set the following to 'static' or 'dll' depending
PKGMODE=static
ICD=$(ICUDATA)^\
DATA_PATH=$(ICUP)\data^\
NATIVE_ARM=
!IF "$(PROCESSOR_ARCHITECTURE)" == "ARM64" || "$(PROCESSOR_ARCHITEW6432)" == "ARM64"
NATIVE_ARM=ARM64
!ELSE IF "$(PROCESSOR_ARCHITECTURE)" == "ARM" || "$(PROCESSOR_ARCHITEW6432)" == "ARM"
NATIVE_ARM=ARM
!ENDIF
# Use the x64 tools for building ARM and ARM64.
# Note: This is similar to the TOOLS CFG PATH in source\data\makedata.mak
!IF "$(NATIVE_ARM)" == ""
!IF "$(CFG)" == "x64\Release" || "$(CFG)" == "x64\Debug" || "$(CFG)" == "x64\StaticDebug" || "$(CFG)" == "x64\StaticRelease" || "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" || "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease"
ICUTOOLS=$(ICUP)\bin64
PATH = $(ICUP)\bin64;$(PATH)
!ELSE
ICUTOOLS=$(ICUP)\bin
PATH = $(ICUP)\bin;$(PATH)
!ENDIF
!ELSE
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease"
ICUTOOLS=$(ICUP)\binARM
PATH = $(ICUP)\binARM;$(PATH)
!ELSE
ICUTOOLS=$(ICUP)\binARM64
PATH = $(ICUP)\binARM64;$(PATH)
!ENDIF
!ENDIF
# If building ARM/ARM, then we need to pass the arch as an argument.
EXTRA_PKGDATA_ARGUMENTS=
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease"
EXTRA_PKGDATA_ARGUMENTS=-a ARM
!ENDIF
!IF "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease"
EXTRA_PKGDATA_ARGUMENTS=-a ARM64
!ENDIF
# Make sure the necessary tools exist before continuing. (This is to prevent cryptic errors from NMAKE).
!IF !EXISTS($(ICUTOOLS)\pkgdata.exe)
!MESSAGE Unable to find "$(ICUTOOLS)\pkgdata.exe"
!ERROR The tool 'pkgdata.exe' does not exist! (Have you built all of ICU yet?).
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" || "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease"
!ERROR Note that the ARM and ARM64 builds require building x64 first.
!ENDIF
!ENDIF
!IF !EXISTS($(ICUTOOLS)\genrb.exe)
!MESSAGE Unable to find "$(ICUTOOLS)\genrb.exe"
!ERROR The tool 'genrb.exe' does not exist! (Have you built all of ICU yet?).
!IF "$(CFG)" == "ARM\Release" || "$(CFG)" == "ARM\Debug" || "$(CFG)" == "ARM\StaticDebug" || "$(CFG)" == "ARM\StaticRelease" || "$(CFG)" == "ARM64\Release" || "$(CFG)" == "ARM64\Debug" || "$(CFG)" == "ARM64\StaticDebug" || "$(CFG)" == "ARM64\StaticRelease"
!ERROR Note that the ARM and ARM64 builds require building x64 first.
!ENDIF
!ENDIF
# Suffixes for data files
.SUFFIXES : .ucm .cnv .dll .dat .res .txt .c
# We're including a list of resource files.
FILESEPCHAR=
!IF EXISTS("$(RESFILES)")
!INCLUDE "$(RESFILES)"
!ELSE
!ERROR ERROR: cannot find "$(RESFILES)"
!ENDIF
RES_FILES = $(RESSRC:.txt=.res)
RB_FILES = resources\$(RES_FILES:.res =.res resources\)
RESOURCESDIR=
# This target should build all the data files
!IF "$(PKGMODE)" == "dll"
OUTPUT = "$(DLL_OUTPUT)\$(RESNAME).dll"
!ELSE
OUTPUT = "$(DLL_OUTPUT)\$(RESNAME).lib"
!ENDIF
ALL : $(OUTPUT)
@echo All targets are up to date (mode $(PKGMODE))
# invoke pkgdata - static
"$(DLL_OUTPUT)\$(RESNAME).lib" : $(RB_FILES) $(RESFILES)
@echo Building $(RESNAME).lib
@"$(ICUTOOLS)\pkgdata" -f -v -m static -c -p $(RESNAME) -d "$(DLL_OUTPUT)" $(EXTRA_PKGDATA_ARGUMENTS) -s "$(RESDIR)" <<pkgdatain.txt
$(RES_FILES:.res =.res
)
<<KEEP
# This is to remove all the data files
CLEAN :
-@erase "$(RB_FILES)"
-@erase "$(CFG)\*uconvmsg*.*"
-@"$(ICUTOOLS)\pkgdata" -f --clean -v -m static -c -p $(RESNAME) -d "$(DLL_OUTPUT)" $(EXTRA_PKGDATA_ARGUMENTS) -s "$(RESDIR)" pkgdatain.txt
# Inference rule for creating resource bundles
{$(RESDIR)}.txt{$(RESDIR)}.res:
@echo Making Resource Bundle files
"$(ICUTOOLS)\genrb" -s $(@D) -d $(@D) $(?F)
$(RESSRC) : {"$(ICUTOOLS)"}genrb.exe
そしてB2ビルドでstatic版を得るためのコマンドを実行するだけです。
b2 --build-type=complete --toolset=msvc cxxflags="/std:c++17" architecture=x86 address-model=64 variant=debug link=static runtime-link=shared --with-regex define=BOOST_REGEX_HAS_ICU -sICU_PATH=C:\(ICUのルートパス)\icu4c stage linkflags="Advapi32.lib"
StaticDebugに対応したBoost.Regexは上記のとおりですが、StaticReleaseの場合は上記コマンドのvariant=debugとなっているところをvariant=releaseにします。ICUのランタイムをスタティック版(/MTや/MTd設定)にしたときはlink=static runtime-link=sharedをlink=static runtime-link=staticにします。
B2ビルドは動作させると、C:¥(Boostルートパス)\bin.v2\Config.logファイルに処理結果についての記録が出力されます。最初のアーキテクチャチェックのErrorはPCに存在しないアーキテクチャーを検出する都度、Errorになりますが、問題のないエラーです。それ以外のErrorが出ていないかチェックして下さい。うまくいったように見えてErrorが出ていれば、スタティックICU版のBoost.Regexライブラリになっていないことがあります。Config.logの内容に従ってErrorを解決していけば、道は開かれます。
ちなみに生成したlibはC:¥(Boostルートパス)\stage\libに出力され、libboost_regex-vc143-mt-gd-x64-1_89.libのような名称になります。先頭にlibがついています。ICUのライブラリも内包しているスタティックライブラリになっています。ICUのランタイム設定がスタティック(/MTd)設定のデバッグ版はsgdとなります。このライブラリをライブラリディレクトリの設定とリンカの入力の追加の依存ファイルにライブラリファイル名を追加とC:¥(Boostルートパス)をインクルードディレクトリに設定して、C:¥(ICUルートパス)\icu4c\lib64へのライブラリのライブラリディレクトリの設定とリンカの入力の追加の依存ファイルにライブラリファイル名(sicudt.lib, sicuucd.lib, sicuind.lib, sicuiod.lib)とC:¥(ICUルートパス)\icu4c\includeをインクルードディレクトリに設定すればICUのDLL不要でランタイムを(/MDd)や(/MD)に設定したプロジェクトで動かすことが出来るようになります。こんな大規模なライブラリを導入しておきながらランタイムまでスタティック(ICUのコード生成設定が/MTや/MTd)なプロジェクト開発をする人がいるとは思えませんが、知識として記事にしておきました。もちろんB2でlink設定をshared設定にした場合はICUのDLLを実行ファイルが参照するパスに配置すれば動的なプロジェクト、ランタイムもDLL方式にした(/MDd)や(/MD)のプロジェクトで動かせますよ。ちなみに、b2コマンドでlink=設定でstaticを選択し、スタティックライブラリにした場合、自分のプロジェクトには、#define U_STATIC_IMPLEMENTATIONというプリプロセッサ定義が必要です。
#define U_STATIC_IMPLEMENTATION
#include <boost\regex\icu.hpp>
といったインクルードファイルに書かれている関数が使えるようになるんだね。ICU版だね。
例えば、以下のようなコードが動くようになるよ。サンプルプログラムだね。VC PlusPlus UTF-8によるプログラミングを推進するための大切な設定の記事にある設定もしておこう。UTF-8の文字データを使うプログラムなのでね特に。気に留めたい。
#define U_STATIC_IMPLEMENTATION
#include <boost/regex.hpp>
#include <boost/regex/icu.hpp>
#include <iostream>
int main() {
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
boost::regex re("[A-Za-z]+");
std::string s = "Hello";
if (boost::regex_match(s, re)) {
std::cout << "Match!" << std::endl;
}
std::cout << typeid(boost::u32regex).name() << std::endl;
std::basic_string<UChar32> s4;
s4.push_back('H');
s4.push_back('e');
s4.push_back('l');
s4.push_back('l');
s4.push_back('o');
boost::u32regex re4 = boost::make_u32regex("[A-Za-z]+");
if (boost::regex_match(s4, re4)) {
std::cout << "Match!" << std::endl;
}
return 0;
}
動作させると
Match!
class boost::basic_regex
Match!
という出力が得られます。
言語と開発環境に戻る。