torutkのブログ

ソフトウェア・エンジニアのブログ

BoostとVisual C++

Visual C++ 10(Visual Studio 2010)に、Boost 1.51を使ってプログラムを作ろうとして躓きました。

Boostは、次のサイトからビルド済みバイナリをインストールします。

で、program_optionsライブラリを使用したプログラムをビルドした際に、リンクエラーが発生しました。プログラムはWin32コンソールアプリケーションとしてプロジェクトを生成したものをベースに書いたものです。

LINK : fatal error LNK1104: ファイル 'libboost_program_options-vc100-mt-gd-1_51.lib' を開くことができません。

プログラムのプロジェクト設定は、Win32コンソールアプリケーションで生成したもので、ランタイムライブラリの種類はデフォルトのままで、「マルチスレッドデバッグDLL(/MDd)」が指定されています。

Boostのライブラリ種類は、インストール時に次の種類から選択できます。

  • Multithreaded debug DLL
  • Multithreaded DLL
  • Multithreaded
  • Multithreaded debug
  • Multithreaded static runtime
  • Multithreaded debug static runtime
  • Single threaded static runtime
  • Single threaded debug static runtime

最初の2つはDLLとあるように、実行時にDLLファイルを必要とする動的リンク、残りは実行時にDLLファイルを必要としない静的リンクです。

最後の4つはstatic runtimeとあるように、Cランタイムライブラリと静的リンクしたライブラリです。

最後の2つはSingle threadedとあるように、シングルスレッド版です。

それぞれライブラリファイル名が異なります。たとえば、program_optionライブラリの場合

  • Multithreaded debug DLL
    • boost_program_options-vc100-mt-gd-1_51.dll
    • boost_program_options-vc100-mt-gd-1_51.lib
  • Multithreaded DLL
    • boost_program_options-vc100-mt-1_51.dll
    • boost_program_options-vc100-mt-1_51.lib
  • Multithreaded
    • libboost_program_options-vc100-mt-1_51.lib
  • Multithreaded debug
    • libboost_program_options-vc100-mt-gd-1_51.lib
  • Multithreaded static runtime
    • libboost_program_options-vc100-mt-s-1_51.lib
  • Multithreaded debug static runtime
    • libboost_program_options-vc100-mt-sgd-1_51.lib
  • Single threaded static runtime
    • libboost_program_options-vc100-s-1_51.lib
  • Single threaded debug static runtime
    • libboost_program_options-vc100-sgd-1_51.lib

となります。

さらに、通常リンクするライブラリはプロジェクトの設定でファイル名を指定しますが、Boostの場合、Boostのヘッダーファイル*1VC++固有の記述でリンク指示が定義されます。

#pragma comment(lib, "xxx.lib")

xxx.libの部分は、複雑なプリプロセッサの条件分岐の結果が適用されます。詳細を次に述べます。

リンクするライブラリファイル名の決定

まず、動的リンクか静的リンクかは、次の条件で判断されます。

  1. プリプロセッサ定義_DLLが指定されている
  2. プリプロセッサ定義BOOST_DYN_LINKが指定されている
条件1 条件2 判断結果
動的リンク
N/C × 静的リンク
× コンパイルエラー
  • N/C: Not Care.

条件の制御方法は、

  1. プロジェクトの設定でC/C++コード生成のランタイムライブラリを/MDまたは/MDdにする
  2. プロジェクトの設定でC/C++プリプロセッサの定義にBOOST_ALL_DYN_LINKを指定する(注:BOOST_DYN_LINKではなく)

次に、スレッド種類がMultithreadedかSingle threadedかは、次の条件で判断されます。

  1. プリプロセッサ定義_MTまはた__MT__が指定されている
条件1 判断結果
Multithreaded
× Single threaded

条件の制御方法は、

  1. VC++ 10では、かならず_MTが定義される(シングルスレッドを指定するオプションがない、省略時は/MT扱い)

次にdebug, static runtimeかは次の条件で判断されます。

  1. プリプロセッサ定義_DLLが指定されている
  2. プリプロセッサ定義_DEBUGが指定されている
条件1 条件2 判断結果
debug
× debug static runtime
×
× × static runtime

条件の制御方法は、プロジェクトの設定でC/C++コード生成のランタイムライブラリを

  1. /MDd に指定すると、_DLLと_DEBUGがともに指定
  2. /MTd に指定すると、_DEBUGが指定
  3. /MD に指定すると、_DLLが指定
  4. /MT に指定すると、指定なし
    • プロジェクト設定では、ランタイムライブラリにシングルスレッドの選択肢が用意されていない

以上を整理すると、次のように単純化できます。

コンパイル指定 BOOST_ALL_DYN_LINK定義 使用するライブラリ種類
/MD Multithreaded DLL
/MD × Multithreaded
/MDd Multithreaded debug DLL
/MDd × Multithreaded debug
/MT × Multithreaded static runtime
/MT コンパイルエラー
/MTd × Multithreaded debug static runtime
/MTd コンパイルエラー

ということで、Visual C++のWin32コンソールアプリケーションで生成したプロジェクトのデフォルト設定(/MDや/MDdが指定される)でBoostを使用すると、MultithreadやMultithreaded debugがリンクされるので、

  • libboost_program_options-vc100-mt-gd-1_51.lib

を探し、なければエラーとなります。

コンパイルオプションとプリプロセッサ定義については、次のURLに解説があります(日本語)。

この問題に一日はまってました。実は昔この問題に対処していましたが(次のWebにその対処を書いてます)、まったく覚えていませんでした。

同じ落とし穴に二度落ちたことになります・・・

*1:boost/config/auto_link.hpp