// Connect の方にフィードバックとしてだすかどうか悩んだのですが
// なにか大きな勘違いをしているだけかもしれないので、まずみなさんにも確認していただけたらと思います。
ICU (International Components for Unicode) (http://site.icu-project.org/) の 4.8.1 をダウンロードしました。
ソリューションファイルが Visual Studio 2010 のタイプしか用意されていない為、
Visual C++ 2010 Express でソリューションを開き、Visual C++ 9.0 (2008) でビルドするため、
makedata プロジェクト以外のすべてのプロジェクトについてプロジェクトプロパティの「全般」から
「プラットフォームツールセット」を v90 に変更し、ビルドしたところ、intltest プロジェクトにて
stringpiece::npos の外部参照を解決できないエラーがでます。
dumpbin /exports icuuc48.dll (icu 4.8.1 内の common プロジェクトで生成されるファイル)でエクスポートされている内容を調べたところ、
vc100 (2010) でビルドしたものは、2378 number of names であるのにたいし、
vc90 (2008) でビルドしたものは、2377 number of names となっており、
stringpiece::npos のエクスポートだけが抜け落ちているようでした。
// ここで、2008 と 2010 では c++ の名前修飾は同じだし、2010 でビルドされた dll を 2008 でコンパイルされたものとリンクできるので
// わざわざ 2008 でビルドする必要なんてないというつっこみはなしでお願いします。
// そういう話ではありません。
理由をしらべてみたところ、stringpiece.cpp において以下のようなコードがあったためでした。
#if (!defined(_MSC_VER) || (_MSC_VER > 1500)) && !defined(CYGWINMSVC)const int32_t StringPiece::npos; #endif
Visual C++ 9.0 (2008) の _MSC_VER は 1500 なので、
const int32_t StringPiece::npos;
はコード化されず、npos がエクスポートされないということのようです。
実際に、このコード部分をコメントアウトすると、vc100 (2010) でビルドしても
2377 number of names となり、StringPiece::npos だけがエクスポートされなくなります。
ここで、stringpiece.h をみると、
public:<省略>staticconst int32_t npos = 0x7fffffff;
と、public メンバとしてクラス内で初期化も行われています。
整数型な static const メンバ以外はクラス内で初期化できない為、クラス外で初期化する必要があり、
クラス外で宣言初期化を行わなかった場合変数が作成されず(?)、エクスポートもされないということはわかります。
しかし、 ここでの int32_t は typedef で signed int の別名となっている為問題はないはずです(そもそもコンパイルが通ります)。
自分で dll プロジェクトを作成し、クラス定義内で初期化される static const int な public メンバを用意し(クラス外で宣言しない)、ビルドしても
きちんとエクスポート出来ています。
当然それを別のプロジェクトからリンクすることもできます。
ICU 4.8.1 内のの別プロジェクト(i18n) に同様に 整数型で public な static const メンバがあったので
そちらでも確認してみました。
tzrule.h で定義されている AnnualTimeZoneRule で以下の定義があります。
staticconst int32_t MAX_YEAR;
そして、tzrule.cpp で以下の宣言が行われています。
const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
そこで、このコードをコメントアウトし(クラス定義外で初期化も宣言もしない)、tzrule.h 内での定義を以下のようにして MAX_YEAR をクラス定義内で初期化することにします。
staticconst int32_t MAX_YEAR = 0x7FFFFFFF;
これで先ほどの stringpiece::npos とコード上では同様の状態になっていると思います。
しかし、これをビルドし、dumpbin /exports icuin48.dll で確認すると、MAX_YEAR はエクスポートされたままです。
この状況をどう理解すればいいのかわかりません。
ICU を使用するという点ではどうでもいいことです。名前修飾の方法がかわらないかぎり、最新のコンパイラで生成されたバイナリでも
2008 からリンクできるからです。
また、sringpiece 内での初期化を避け、クラス外宣言で初期化しそのコードを #if ~ #endif で囲むのをやめてもらえば済むことです。
が、それで終わっていいものかどうかもわかりません。
もしバグなら修正されるべき内容かと思います。回避策はあるので修正してもらえないと思いますけど。
一番いいのは自分の勘違いで終わることなんですけど。
もしなにか御存じのことがあれば返信下さい。お願いします。