QMLのデバッグ方法

QMLでアプリケーション開発しようと試行錯誤していると,プロパティの値が狙い通りになっているか確認したくなった。そこでQMLでのデバッグ方法を調べてまとめた。

はじめに

QMLでのデバッグ方法について調べていたら,以下の記事を発見した。

どうやら,Qt Quick 2になってからQMLのデバッグ用APIが拡充されたようだ。上記の情報を参考にQMLで利用可能なAPIの一覧を整理する。

QMLのデバッグ用API

QMLで利用可能なデバッグ用関数を以下の表にまとめた。

QMLデバッグ用API
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系の関数群を使えばよさそうだ。特に以下の関数を今後多用することになると感じた。

頻出QMLデバッグAPI
  • print
  • 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]に記入すればいい。

QtCreatorでのコマンド実行時オプションの指定場所

上記オプションをつけずに,実行した場合,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.onCompletedComponent.onDestructionイベントにデバッグ用関数を仕込めばよさそうだ。それぞれ,QMLのインスタンス生成と破棄のタイミングになる。

特に深い理由がなく,単純に値を確認したいだけであれば,Componet.onCompletedが順当だろう。

デバッグログの仕込み例
import QtQuick 2.9

QtObject {
    Component.onCompleted: {
        print("Completed")
    }

Component.onDestruction: {
print("Destructed")
}
}

動作確認

実際にQMLにデバッグ用APIを仕込んで動作を確認した。ソースコードを以下に格納した。

QtExample/QMLDebug at master · senooken/QtExample

量は多くないので全文を以下にも掲載する。

QMLDebug.pro
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
main.qml
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")
    }
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine("qrc:/main.qml");
    return app.exec();
}

このプログラムQMLDebugを実行すると以下が表示される(QMLDebug.logにも格納)。

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でのデバッグ方法をまとめた。再掲だが,特に以下の関数は今後よく使うことになるだろう。

頻出QMLデバッグAPI
  • print
  • console.exception
  • console.assert
  • console.time/console.timeEnd

QMLでデバッグするときはこれらのAPIを活用して,バグが発生しないように気をつけていきたい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です