QMLのデバッグ方法
QMLでアプリケーション開発しようと試行錯誤していると,プロパティの値が狙い通りになっているか確認したくなった。そこでQMLでのデバッグ方法を調べてまとめた。
はじめに
QMLでのデバッグ方法について調べていたら,以下の記事を発見した。
どうやら,Qt Quick 2になってからQMLのデバッグ用APIが拡充されたようだ。上記の情報を参考にQMLで利用可能なAPIの一覧を整理する。
QMLのデバッグ用API
QMLで利用可能なデバッグ用関数を以下の表にまとめた。
JavaScriptの関数 | 対応するQt/C++の関数 | 説明 |
---|---|---|
print(str) | qDebug() | 引数の文字列strを表示。QtScript由来の関数。 |
console.log(str) | qDebug() | 引数の文字列strを表示。 |
console.debug(str) | qDebug() | 引数の文字列strを表示。 |
console.info(str) | qDebug() | 引数の文字列strを表示。 |
console.warn(str) | qWarning() | 引数の文字列strを表示。 |
console.error(str) | qCritical() | 引数の文字列strを表示。 |
console.count(str) | 引数の文字列strと関数の呼び出し回数を表示。 | |
console.trace() | スタックトレース(呼び出し箇所の関数名,ファイル名,行番号,列番号)を表示する。最大10個まで表示。引数を持てない。 | |
console.exception(str) | 引数の文字列strを表示した後に,スタックトレースを表示。 | |
console.assert(expr[, str]) | 式exprの結果がfalseの場合,文字列strを表示してスタックトレースを表示。strは省略可能。 | |
console.time(str) | 同じ引数の文字列strで指定したtimeとtimeEndの範囲の時間をミリ秒単位で測定し,console.timeEnd呼び出し時にstrと共に表示。 | |
console.timeEnd(str) | 同じ引数の文字列strで指定したtimeとtimeEndの範囲の時間をミリ秒単位で測定し,console.timeEnd呼び出し時にstrと共に表示。 | |
console.profile(str) | QMLとJavaScriptのプロファイラーを有効にする。プログラムの実行時にオプション-qmljsdebugger=port:ポート番号が必要。 | |
console.profileEnd(str) | QMLとJavaScriptのプロファイラーを無効にする。 |
基本的には,JavaScriptのconsole系の関数群を使えばよさそうだ。特に以下の関数を今後多用することになると感じた。
- console.exception
- console.assert
- console.time/console.timeEnd
printはconsole.logでもいいかと思ったが,printのほうが文字数が短いので,こちらでもよいだろう。
プロファイル
デバッグ用APIの中に,プロファイル関係のものがある(console.profileとconsole.profileEnd)。これらを利用する場合は,コンパイルしたバイナリーの実行時に,以下のオプションをつける必要がある。
-qmljsdebugger=port:8080
QtCreatorで実行オプションをつける場合は,[Projects]>[Build & Run]>[Run]>[Command line arguments]に記入すればいい。
上記オプションをつけずに,実行した場合,console.profileとconsole.profileEndの呼び出し時にそれぞれ以下の警告が表示されてしまう。
Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX. Ignoring console.profileEnd(): the debug service is disabled.
プロファイラー機能はよくわかっていない。解説しているページヘのリンクをひとまず掲載しておく。
デバッグ用APIの挿入場所
ここまでで,QMLのデバッグ用APIがわかった。しかし,これらの関数をどこに仕込めばいいかという問題が生じる。自分で作った関数の中に仕込む場合は簡単だ。しかし,特に関数を仕込まない場合は,どこか適当なタイミングで関数を用意してやる必要がある。
Qtの文書を眺めていると,どうやらComponet.onCompleted
やComponent.onDestruction
イベントにデバッグ用関数を仕込めばよさそうだ。それぞれ,QMLのインスタンス生成と破棄のタイミングになる。
特に深い理由がなく,単純に値を確認したいだけであれば,Componet.onCompleted
が順当だろう。
import QtQuick 2.9
QtObject {
Component.onCompleted: {
print("Completed")
}
Component.onDestruction: {
print("Destructed")
}
}
動作確認
実際にQMLにデバッグ用APIを仕込んで動作を確認した。ソースコードを以下に格納した。
量は多くないので全文を以下にも掲載する。
QT += quick
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
import QtQuick 2.9
QtObject {
Component.onCompleted: {
print("print")
console.log("log")
console.debug("debug")
console.info("info")
console.warn("warn")
console.error("error")
console.count("count")
console.trace() // stack trace
console.exception("exception: message & stack trace")
console.assert(true, "assert:true")
console.assert(false, "assert:false message & stack trace")
console.time("time")
console.timeEnd("time")
console.profile("profile")
console.profileEnd("profile")
}
}
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine("qrc:/main.qml");
return app.exec();
}
このプログラムQMLDebugを実行すると以下が表示される(QMLDebug.logにも格納)。
QML debugging is enabled. Only use this in a safe environment. QML Debugger: Waiting for connection on port 8080... qml: print qml: log qml: debug qml: info qml: warn qml: error count: 1 onCompleted (qrc:/main.qml:13) qml: exception: message & stack trace onCompleted (qrc:/main.qml:14) assert:false message & stack trace onCompleted (qrc:/main.qml:16) time: 0ms Profiling started. Profiling ended.
print系の関数は先頭に,qml:
が表示されるようだ。
おわりに
QMLでのデバッグ方法をまとめた。再掲だが,特に以下の関数は今後よく使うことになるだろう。
- console.exception
- console.assert
- console.time/console.timeEnd
QMLでデバッグするときはこれらのAPIを活用して,バグが発生しないように気をつけていきたい。