Clazy (Clang Lazy) is a new Qt oriented static analyzer implemented as a clang plugin that helps to improve the performance of your Qt applications and libraries. Clang is a C/C++ frontend for the LLVM compiler infrastructure that is not used in the Sailfish OS SDK but can be used by it to at least perform the code analysis.
The Sailfish OS SDK uses GCC by default as compiler for the standard build targets/kits MerSDK i486 and MerSDK armv7hl. But because it is a normal Qt Creator with some Sailfish specific additions you can also use it for building desktop apps. MerSDK also has LLVM in its repositories, but unfortunately Clazy requires at least LLVM version 3.6 and MerSDK only provides version 3.3. So you can not use it directly in the SDK but the SDK can still use the version installed on your host OS (together with the Qt development files on your host).
Clazy source code is available via the KDE git repos. Precompiled packages for openSUSE can be found in my openSUSE Build Service repository. Some more information about Clazy are available in this two blog posts: How to use static analysis to improve performance and New C++/Qt code checks in clazy static analyzer.
It is also simply possible to use calzy outside of Qt Creator / Sailfish SDK, but integrating it gives some comfort. For performing the checks you only have to switch the build kit and the warnings are shown in the Issues tab where you can easily click on the entries to jump to the code part that is responsible for the warning.
Adding new kit for Clazy
Open Tools » Options in Qt Creator and select Build & Run where you will find the settings for the kits, compilers, debuggers etc. If you have installed LLVM/clang and Qt on your host before starting the SDK they should show up in the tabs automatically, otherwise you can add them manually. There should also already exist a Desktop Kit to build software for desktop environments. Easiest way is to clone the Desktop kit and simply change the compiler to Clang like shown in the following screenshot.
Build settings for Clazy
After the new kit has been successfully setup, you can add a new build target on the project page. Choose your new Clazy kit and you are only a few steps away from checking your code. When the new kit has been added you need to modify the qmake call and add some additional arguments to include clazy into the build process. Add the following statement to the Additional arguments input:
QMAKE_CXXFLAGS="-Xclang -load -Xclang ClangLazy.so -Xclang -add-plugin -Xclang clang-lazy"
When using the Qt environment on your host system the sailfish libraries and settings will be missing there. Normally you will have an entry like CONFIG += sailfishapp
in you project’s pro file. That config automatically adds some defines, includes and libraries to your project configuration. This will not be available on your host system, so you have to add some configs manually. You can add them to the pro file, but you can also add them to the qmake call. Mostly this will be the Qt components qml and quick. So, add another statement to the Additional arguments:
"QT+=qml quick"
There will be parts in the code, like calling SailfishApp static functions, that are not available on the host system. You need them for running the app, but not for checking the code via clazy. For me the easiest workaround seems to be to use preprocessor conditionals to not include them when checking the code for example via a #ifndef CLAZY
. Therefor I added "DEFINES+=CLAZY"
to the Additional arguments.
The complete line in Additional arguments should now look like this:
"QT+=qml quick" "DEFINES+=CLAZY" QMAKE_CXXFLAGS="-Xclang -load -Xclang ClangLazy.so -Xclang -add-plugin -Xclang clang-lazy"
You can choose the tests that clazy should perform via the environment variable CLAZY_CHECKS. The clazy README provides information about the available checks and levels. To select the tests, add a new environment variable to the Build Environment with the name CLAZY_CHECKS
and for example the value level0,level1,level2
. This will order clazy to perform all checks of the first three levels.
Now your build steps should look like this:
You might wonder why there are still disabled Start SDK entries. Sailfish SDK seems to readd them automatically even when you remove them. So disabling them is the solution to get rid of these steps when building your app with clazy.
Preparing the code
As mentioned before, you will miss some parts when building a Sailfish App on your host system like libsailfishapp
. So we need to exclude such parts from compiling with the Clazy kit. This can be achieved easily by using preprocessor conditionals, for that we already added the CLAZY
define to the qmake call.
I also added an additional make clean
step in front of the qmake
call to get a clean build dir on every run and have all warnings shown up, otherwise for not changed code the cached results will be used and the warnings are not shown. (You have to disable it on the first run, because not makefile will be present.)
#ifndef CLAZY #include <sailfishapp.h> #endif #include <QGuiApplication> #include <QQmlEngine> #include <QQuickView> #include <QtQml> int main(int argc, char *argv[]) { #ifndef CLAZY QGuiApplication* app = SailfishApp::application(argc, argv); #else QGuiApplication* app = new QGuiApplication(argc, argv); #endif app->setOrganizationName(QStringLiteral("Buschtrommel")); app->setOrganizationDomain(QStringLiteral("buschmann23.de")); app->setApplicationName(QStringLiteral("harbour-clazy-test")); app->setApplicationDisplayName(QStringLiteral("Clazy Test")); app->setApplicationVersion(QStringLiteral("0.0.1")); #ifndef CLAZY QString locale = QLocale::system().name(); QTranslator* translator = new QTranslator; if (translator->load(locale, SailfishApp::pathTo("translations").toString(QUrl::RemoveScheme))) { app->installTranslator(translator); } #endif return app->exec(); }
Getting the results
Now, when everything has been setup, hit Ctrl+b to build your project and let clang and clazy do their work. When clazy finds stuff that should be fixed it will be shown to you in the issues tab like this.