Qt 4.8.5 ソースのコンパイルエラー ( Visual C++ 2012) への対処


Qt 4.8.5 を VC++ 2012 でコンパイルするとエラー

Qt 4.8.5 を Visual C++ 2012 でコンパイルする際に、以下のエラーが発生しました。

.wtf/HashSet.h(180) : error C2664: ‘std::pair<_Ty1,_Ty2>::pair(const std::pair< _Ty1,_Ty2> &)’ : 1 番目の引数を ‘std::pair<_Ty1,_Ty2>’ から ‘const std::pair<_Ty 1,_Ty2> &’ に変換できません。(新しい機能 ; ヘルプを参照)
.
.
.

まず、エラーを起こした HashSet.h を特定する必要があります。探してみると、wtfHashSet.h に該当するのは、

  1. src3rdpartyjavascriptcoreJavaScriptCorewtfHashSet.h
  2. src3rdpartywebkitSourceJavaScriptCorewtfHashSet.h
  3. src3rdpartywebkitSourceWebCoreForwardingHeaderswtfHashSet.h

の3つあります。180行目に該当するコードがあるのは 2番目で、以下の箇所です。

実際には、その下の add 関数も問題がありそうです。

add 関数の返り値の暗黙の型変換が原因

どうやら、これらの関数の return が返す pair の第一パラメータの型が関数の宣言と一致しない事が原因のようです。VC++ 2010 では暗黙の型変換でうまく解決できていたようですが、VC++ 2012 ではうまく解決できないようです。Building Qt 4.8.2 with Visual Studio 2012 RC | Qt Project forums | Qt Project で詳しい議論がされていて、解決方法が 2つあがっています。

これらを整理して、よりわかりやすくしたものが [#QTBUG-28335] Build Webkit with MSVC 2012 – Qt Bug Tracker の msvc2012_WebKit_HashSet.patch です。私は、git apply でこのパッチを適用しようとしてうまくいかなかったので、以下の様に手書きで修正しました。

  1. src3rdpartywebkitSourceJavaScriptCorewtfHashSet.h をエディタで開く
  2. 180 行目と、189 行目の return 文の中身を、後で作成する iterator_const_cast() で囲う (以下、行番号は修正前の値)
    180行目 

    189行目
  3. 93行目の friend 文の後に、以下の様に iterator_const_cast を定義する (パッチに含まれるコメントを全て入れてあります。)

以上の修正が済んだら、再び nmake を実行することでコンパイルを進めることができます。(修正済の HashSet.h を こちらに用意しました。)

また、この後 platformDefaultLocalizationStrategy.cpp でコンパイルエラーが出た場合はマルチバイト環境特有の問題で、VC++ 2010 でコンパイルした場合にも発生します。これは、Qt 4.8.5 のコンパイルエラー ( Visual C++) 対処 | DeVlog – 銀の翼で翔べ – の方法で解決できます。

[関連記事]
Qt 4.8.5 のコンパイルエラー ( Visual C++) 対処 | DeVlog – 銀の翼で翔べ –

[関連サイト]
junfs-qt in Jun Funada – Qt by Digia

[参考サイト]

  1. Building Qt 4.8.2 with Visual Studio 2012 RC | Qt Project forums | Qt Project
  2. [#QTBUG-28335] Build Webkit with MSVC 2012 – Qt Bug Tracker

Qt 4.8.5 ソースのコンパイルエラー ( Visual C++ ) への対処


Qt 4.8.5 を Visual C++ でコンパイルするとエラー発生

Qt 4.8.5 のソースを Visual C++ 2010 でコンパイルする際に、以下のエラーが発生することがあります。

DefaultLocalizationStrategy.cpp
C:Program Files (x86)Microsoft Visual Studio 10.0VCINCLUDEyvals.h(21) : warning C4005: ‘_HAS_TR1’ : macro redefinition
command-line arguments : see previous definition of ‘_HAS_TR1’
platformDefaultLocalizationStrategy.cpp(327) : error C2001: newline in constant
.
.
NMAKE : fatal error U1077: ‘”C:Program Files (x86)Microsoft Visual Studio 10.0
VCBinamd64cl.EXE”‘ : return code ‘0x2’
Stop.

情報量が多すぎてエラーの起きたファイルを特定しにくい場合は、エラーが起きた後に再度 nmake を実行すると、不要なメッセージが消えるので見つけやすいです。

原因は文字コードの誤判定

今回のエラーの原因は、
src3rdpartywebkitSourceWebCoreplatformDefaultLocalizationStrategy.cpp
の 327 行目です。

Web 上では正しく表現できないのですが、実は <selection> を囲っているダブルクォーテーションが多バイト文字です。( xE2809C と xE2809D ) UTF-8N に対応したエディタでソースを開いて確認してください。

これがなぜ問題になるのかというと、

このファイルに BOM が無いため VC++ コンパイラは、このファイルを CP932(SJIS) とみなす

ためです。VC++ は、BOM の有り無しで UTF-8 かどうか判断しているようです。そのため、このファイルは ( UTF-8 であるにも関わらず ) CP932(SJIS) とみなされます。(Visual C++ と gcc 共有ソースでの文字コードについて | DeVlog – 銀の翼で翔べ – を参照してください。)

xE2809C → xE2 + x80 + x9C (漢字第一バイト)
xE2809D → xE2 + x80 + x9D (漢字第一バイト)

と解釈されるため、直後の 1バイトは漢字第二バイトと解釈されて文字化けします。特に問題となるのは後の方のダブルクォーテーションで、その後の ( 文字列の終端である ) 半角のダブルクォーテーションを無効化してしまいます。その結果コンパイルエラーが発生するわけです。

BOM 付き UTF-8 で保存すれば解決

これらの問題を解決するには、上記の多バイトのダブルクォーテーションを半角に変えるとか (半角ダブルクォーテーションにする場合は、” とする必要があります。)、多バイト文字の後にダミーで半角スペースを加えるといった方法も考えられますが、

このファイルを、BOM 付き UTF-8 で再保存

によって、ソースを改変することなくコンパイルが可能になります。

おそらく、海外の多くの方々の環境では、BOM 無し UTF-8 は Latine1 等の単バイトの文字コードとして解釈されるのではないかと思います。その場合、不要な文字が挿入されはするものの、半角ダブルクォーテーション (x22) が無視されることはなく、正常にコンパイルが終了するのではないでしょうか? そのため、この問題は見過ごされてきているような気がします。

もしかしたら、他にも多バイト文字を含む UTF-8 ソースがあるのかもしれません。その場合、コンパイルは終了しても、実行時にメッセージの文字化けが発生する可能性はあり得ます。ざっと調べたところでは、他バイト文字を含む多くのソースは冒頭コメントの著作者名が多バイトになっているだけのようですので無問題です。

なお、Visual C++ 2012 でコンパイルする際には、この問題の他に別のエラーも発生します。これについては、次回の記事で報告します。

[関連記事]

  1. Visual C++ と gcc 共有ソースでの文字コードについて | DeVlog – 銀の翼で翔べ –
  2. Qt 4.8.5 のコンパイルエラー ( VC++ 2012) 対処 | DeVlog – 銀の翼で翔べ –

[参考にしたサイト]
Qt4.8.xをWindows(Desktop)向けにビルドする – 理ろぐ