Visual Studio 2010でQtのビルド

2011/03/22更新:Qtが更新されたので新しいのを書きました
http://d.hatena.ne.jp/rofi/20110321/1300741573

はじめに

Qtはマルチプラットフォームフレームワークです。
詳細はQtでググッてください。

Qtはオープンソース版ではMinGWしか使えません。
(多分。フレームワークだけならばVC++版もあるみたい・・・)
そこでVisual Studioコンパイルを行おうとするならばQt自体を自分でビルドする必要があります。
以下は私が行った記録です。
注意:これは私が試行錯誤して行った記録でありこの方法が正しい保証はありません。

環境

概要

  1. Qtのソースを落としてくる
  2. Qt Frameworkのビルド
  3. Microsoft Windows SDKのインストール
  4. cdbが使えるように少しいじる
  5. Qt Creatorのビルド
  6. jom.exeの設定
  7. (゚д゚)ウマー

ソースコードのダウンロード

http://qt.nokia.com/
Qtの本家からソースコードをダウンロードしてきます。
落としてくるソースは以下の2つです。

qt-everywhere-opensource-src-4.7.1.zipを適当な場所(C:\Qt\4.7.1など)に解凍します。
パスにスペースが入ると問題らしいのでスペースがないところに置いておくほうが無難かもしれません(未確認)

フレームワークのビルド

Qtフレームワークをビルドします。
スタート→Visual Studioの中にあるコマンドプロンプトから行います。
通常のコマンドプロンプトではビルドツールにパスが通らないのでここから起動したものを使用します。

また、使用するのはx86の方を使用してください。
x64の方でもビルドは通りましたがその後起動すると例外が発生して全く起動しませんでした。
誰かx64でビルドしたときのこの原因、対処の方法を教えてください><

コマンドプロンプトを立ち上げたら先ほど展開した位置までカレントディレクトリを移動させます。
その後Qtへのパスを通しビルド環境の指定を行った後configureを実行し、nmakeでビルドします。


ここで商用版かオープンソース版か聞かれるのでオープンソース(o)を指定
さらにライセンスに同意するか聞かれるのでyを指定


一番ここが時間がかかるので気長に待ちましょう


>

以上でQtのビルドは終わりです。

Windows SDK

次にWindows SDKを入れます。
これはQt Creatorでcdb(デバッガ)を使う場合に必要です。
さらにこれはQt Creatorのビルドの前にしておかなければQt Creatorでは有効になりません。
Qt Creatorのオプションの項目にすら出てきませんでした。。。


デバッガに関する詳細は本家URLへ。
http://doc.trolltech.com/qtcreator-1.2/creator-debugging.html
Debugging Tools for Windowsに関する情報はこちら。
http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx
日本語版:http://www.microsoft.com/japan/whdc/devtools/debugging/installx86.mspx


Debugging Tools for Windowsに書いてあるように現在はWindows SDKに含まれているらしいのでWindows SDKを入れます。
このときx86の人は[Common Utilities] の下の [Debugging Tools for Windows]を、x64の人は[Redistributable Packages] の下の [Debugging Tools]を有効にすればいいようです。
#自分は面倒なのでフルインストールしました。

少しいじる

もしかしたらここは必要ないかもしれませんが、何度もビルドするのが大変なのでこれを行いました。
でもQtがx86である以上必要だと思われます。

x64の人はインストールが終わるとC:\Program Files\Microsoft SDKs\Windows\v7.1\Redist\Debugging Tools for Windowsにdbg_x86.msiというファイルが出来ているのでこれを実行しインストールします。
するとC:\Program Files (x86)\Debugging Tools for Windows (x86)というところにインストールされるのでこの「Debugging Tools for Windows (x86)」を「Debugging Tools for Windows」にリネームしておきます。

x86の人は多分何もしなくてもいいかと思います。
x86環境では今回何も行ってないのでわかりません。

Qt Creatorのビルド

ここからQt Creatorのビルドを行います。
qt-creator-2.0.1-src.zipを適当な場所(C:\Qt\qt-creator-2.0.1-srcなど)に解凍します。

ソースツリー上でビルドするのはよくないらしい(今更)ので別のフォルダを作ってその上(ここではC:\Qt\qt-creator)で作業します。
やり方はqmakeした後nmakeするだけです。
・・・が、ビルドが通りません。
のでソースコードに修正を加えました。
以下が修正を加えたパッチです。
※これ書いてる途中で気づいたのですがREADMEを読むとこんなことしなくてもいいのかもしれませんね。もう面倒なのでやりませんが・・・(ぁ


まずQt Creatorのフォルダ内で以下のパッチを当ててください。
#パッチってどうやって当てるんだろうね? ←

--- src/plugins/qmldesigner/designercore/instances/qmlpropertychangesnodeinstance.cpp	2010-08-24 09:46:08.000000000 +0900
+++ ../qt-creator-2.0.1-src_patched/src/plugins/qmldesigner/designercore/instances/qmlpropertychangesnodeinstance.cpp	2011-01-22 16:20:25.070053100 +0900
@@ -341,7 +341,7 @@
         QMutableListIterator<QDeclarativeSimpleAction> simpleActionIterator(statePrivate()->revertList);
         while (simpleActionIterator.hasNext()) {
             QDeclarativeSimpleAction &qmlSimpleAction = simpleActionIterator.next();
-            if (qmlSimpleAction.specifiedProperty == propertyName && qmlSimpleAction.specifiedObject == targetObject()) {
+            if (qmlSimpleAction.specifiedProperty() == propertyName && qmlSimpleAction.specifiedObject() == targetObject()) {
                 simpleActionIterator.remove();
             }
         }
@@ -366,13 +366,13 @@
         QMutableListIterator<QDeclarativeSimpleAction> simpleActionIterator(statePrivate()->revertList);
         while(simpleActionIterator.hasNext()) {
             QDeclarativeSimpleAction &simpleAction = simpleActionIterator.next();
-            if (simpleAction.specifiedObject == targetObject()) {
-                if (simpleAction.property.isValid()) {
-                    if (simpleAction.binding) {
-                        QDeclarativePropertyPrivate::setBinding(simpleAction.property, simpleAction.binding);
-                    } else if (simpleAction.value.isValid()) {
-                        QDeclarativePropertyPrivate::setBinding(simpleAction.property, 0);
-                        simpleAction.property.write(simpleAction.value);
+            if (simpleAction.specifiedObject() == targetObject()) {
+                if (simpleAction.property().isValid()) {
+                    if (simpleAction.binding()) {
+                        QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+                    } else if (simpleAction.value().isValid()) {
+                        QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+                        simpleAction.property().write(simpleAction.value());
                     }
                 }
                 simpleActionIterator.remove();
@@ -388,8 +388,8 @@
         while (actionIterator.hasNext()) {
             const QDeclarativeAction &qmlAction = actionIterator.next();
             QDeclarativeSimpleAction simpleAction(qmlAction);
-            simpleAction.binding = qmlAction.fromBinding;
-            simpleAction.value = qmlAction.fromValue;
+            simpleAction.setBinding(qmlAction.fromBinding);
+            simpleAction.setValue(qmlAction.fromValue);
             statePrivate()->revertList.append(simpleAction);
             if (qmlAction.toBinding)
                 QDeclarativePropertyPrivate::setBinding(qmlAction.property, qmlAction.toBinding);
@@ -409,14 +409,14 @@
             ++actionIterator) {
                 //simple action defines values and bindings to revert current state
                 QDeclarativeSimpleAction &simpleAction = *actionIterator;
-                if (simpleAction.specifiedObject == targetObject()
-                    && simpleAction.specifiedProperty == name) {
+                if (simpleAction.specifiedObject() == targetObject()
+                    && simpleAction.specifiedProperty() == name) {
                     const QDeclarativeAction &qmlAction = qmlActionForProperty(name);
-                    simpleAction.value = qmlAction.fromValue;
-                    simpleAction.binding = qmlAction.fromBinding;
-                    simpleAction.specifiedObject = qmlAction.specifiedObject;
-                    simpleAction.specifiedProperty = qmlAction.specifiedProperty;
-                    simpleAction.property = qmlAction.property;
+                    simpleAction.setValue(qmlAction.fromValue);
+                    simpleAction.setBinding(qmlAction.fromBinding);
+                    simpleAction.setSpecifiedObject(qmlAction.specifiedObject);
+                    simpleAction.setSpecifiedProperty(qmlAction.specifiedProperty);
+                    simpleAction.setProperty(qmlAction.property);
                     return; //return since we just had to update exisisting simple action
                 }
             }
@@ -426,8 +426,8 @@
 
         const QDeclarativeAction &qmlAction = qmlActionForProperty(name);
         QDeclarativeSimpleAction simpleAction(qmlAction);
-        simpleAction.binding = qmlAction.fromBinding;
-        simpleAction.value = qmlAction.fromValue;
+        simpleAction.setBinding(qmlAction.fromBinding);
+        simpleAction.setValue(qmlAction.fromValue);
         statePrivate()->revertList.append(simpleAction);
     }
 }
@@ -523,13 +523,13 @@
         QMutableListIterator<QDeclarativeSimpleAction> simpleActionIterator(statePrivate()->revertList);
         while (simpleActionIterator.hasNext()) {
             QDeclarativeSimpleAction &qmlSimpleAction = simpleActionIterator.next();
-            if (qmlSimpleAction.specifiedProperty == name && qmlSimpleAction.specifiedObject == targetObject()) {
-                if (qmlSimpleAction.binding) {
-                    qDebug() << qmlSimpleAction.binding->expression();
-                    QDeclarativePropertyPrivate::setBinding(qmlSimpleAction.property, qmlSimpleAction.binding);
+            if (qmlSimpleAction.specifiedProperty() == name && qmlSimpleAction.specifiedObject() == targetObject()) {
+                if (qmlSimpleAction.binding()) {
+                    qDebug() << qmlSimpleAction.binding()->expression();
+                    QDeclarativePropertyPrivate::setBinding(qmlSimpleAction.property(), qmlSimpleAction.binding());
                 } else {
-                    QDeclarativePropertyPrivate::setBinding(qmlSimpleAction.property, 0);
-                    qmlSimpleAction.property.write(qmlSimpleAction.value);
+                    QDeclarativePropertyPrivate::setBinding(qmlSimpleAction.property(), 0);
+                    qmlSimpleAction.property().write(qmlSimpleAction.value());
                 }
             }
         }


次にQtのライブラリ側も書き換えます。
先ほどビルドを行ったフォルダに入り以下のパッチを当てます。

--- src/declarative/util/qdeclarativestate_p_p.h	2010-11-06 11:55:24.000000000 +0900
+++ ../4.7.1/src/declarative/util/qdeclarativestate_p_p.h	2011-01-22 16:19:26.678713300 +0900
@@ -148,11 +148,21 @@
         return m_binding.data();
     }
 
+    void setSpecifiedObject(QObject *specifiedObject)
+    {
+        m_specifiedObject = specifiedObject;
+    }
+
     QObject *specifiedObject() const
     {
         return m_specifiedObject;
     }
 
+    void setSpecifiedProperty(const QString &specifiedProperty)
+    {
+        m_specifiedProperty = specifiedProperty;
+    }
+
     const QString &specifiedProperty() const
     {
         return m_specifiedProperty;


以上で準備は整ったのでビルドを行います。
ビルドはqmakeしてnmakeでできます。

>qmake ..\qt-creator-2.0.1-src\qtcreator.pro
>nmake

これでQt Creatorができました。

jom.exe

Qt CreatorなどのQtのプログラムを立ち上げるにはQtのライブラリにパスを通しておく必要があります。
環境変数の設定などでパスを通しておきましょう。

さて、Qt Creatorができたのでビルドしようとするとjom.exeがないと怒られます。
設定で外すこともできるようですが、jom.exeを入れてしまうのもひとつの手です。

jom.exeに関してはこちらも方も書かれています。
http://www.ebatech.jp/archives/1561
jom.exeのソースコードの入手先はこちら。
http://qt.gitorious.org/qt-labs/jom
jom.exeのバイナリはこちらから手に入ります。
ftp://ftp.qt.nokia.com/jom/

これをQtのbinに入れれば動作します。

(゚д゚)ウマー

開発頑張りましょう! (