12
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【令和元年版】Raspberry Pi 3 で Qt 5 をビルドして動かす方法

Last updated at Posted at 2019-06-05

はじめに

クロスプラットフォームのアプリケーション開発環境 Qt の最新版(と言うか開発版)を Raspberry Pi3 で動かす環境を整えてみました。

Raspberry Pi の sysroot の用意

最新イメージの取得

$ mkdir -p ~/org/raspberrypi/downloads/raspbian
$ cd $_
$ wget --content-disposition https://downloads.raspberrypi.org/raspbian_lite_latest
--2019-06-05 02:01:44--  https://downloads.raspberrypi.org/raspbian_lite_latest
Resolving downloads.raspberrypi.org... 93.93.128.230, 93.93.130.39, 93.93.130.104, ...
Connecting to downloads.raspberrypi.org|93.93.128.230|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/2019-04-08-raspbian-stretch-lite.zip [following]
--2019-06-05 02:01:45--  https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/2019-04-08-raspbian-stretch-lite.zip
Reusing existing connection to downloads.raspberrypi.org:443.
HTTP request sent, awaiting response... 302 Found
Location: http://director.downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/2019-04-08-raspbian-stretch-lite.zip [following]
--2019-06-05 02:01:46--  http://director.downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/2019-04-08-raspbian-stretch-lite.zip
Resolving director.downloads.raspberrypi.org... 93.93.128.211, 93.93.128.230, 93.93.130.39, ...
Connecting to director.downloads.raspberrypi.org|93.93.128.211|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 368729233 (368M) [application/zip]
Saving to: ‘2019-04-08-raspbian-stretch-lite.zip’

2019-04-08-raspbian-stretch-lite.zip     100%[================================================================>]   368M  4.14MB/s    in 6m 3s

2019-06-05 02:07:49 (3.02 MB/s) - ‘2019-04-08-raspbian-stretch.zip’ saved [1148149856/1148149856]

$ unzip 2019-04-08-raspbian-stretch-lite.zip
Archive:  2019-04-08-raspbian-stretch-lite.zip
  inflating: 2019-04-08-raspbian-stretch-lite.img

マウント

/sbin/fdisk -lu 2019-04-08-raspbian-stretch-lite.img

Disk 2019-04-08-raspbian-stretch-lite.img: 1.7 GiB, 1803550720 bytes, 3522560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc1dc39e5

Device                                Boot Start     End Sectors  Size Id Type
2019-04-08-raspbian-stretch-lite.img1       8192   96042   87851 42.9M  c W95 FAT32 (LBA)
2019-04-08-raspbian-stretch-lite.img2      98304 3522559 3424256  1.6G 83 Linux

$ mkdir sysroot
$ expr 98304 \* 512
$ sudo mount -t ext4 -o loop,offset=50331648 2019-04-08-raspbian-stretch-lite.img sysroot/

offset は Sector size × Start の値を指定します。

sysroot 内の相対パスの修正

$ wget https://raw.githubusercontent.com/Kukkimonsuta/rpi-buildqt/master/scripts/utils/sysroot-relativelinks.py
$ chmod +x sysroot-relativelinks.py
$ sudo ./sysroot-relativelinks.py sysroot

Raspberry Pi のクロスコンパイラの用意

$ mkdir -p ~/com/github/raspberrypi/
$ cd $_
$ git clone https://github.com/raspberrypi/tools
$ ls tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x86/bin/
arm-linux-gnueabihf-addr2line     arm-linux-gnueabihf-g++         arm-linux-gnueabihf-gprof       arm-linux-gnueabihf-pkg-config-real
arm-linux-gnueabihf-ar            arm-linux-gnueabihf-gcc         arm-linux-gnueabihf-ld          arm-linux-gnueabihf-ranlib
arm-linux-gnueabihf-as            arm-linux-gnueabihf-gcc-4.8.3   arm-linux-gnueabihf-ld.bfd      arm-linux-gnueabihf-readelf
arm-linux-gnueabihf-c++           arm-linux-gnueabihf-gcc-ar      arm-linux-gnueabihf-ld.gold     arm-linux-gnueabihf-size
arm-linux-gnueabihf-c++filt       arm-linux-gnueabihf-gcc-nm      arm-linux-gnueabihf-ldd         arm-linux-gnueabihf-strings
arm-linux-gnueabihf-cpp           arm-linux-gnueabihf-gcc-ranlib  arm-linux-gnueabihf-nm          arm-linux-gnueabihf-strip
arm-linux-gnueabihf-ct-ng.config  arm-linux-gnueabihf-gcov        arm-linux-gnueabihf-objcopy
arm-linux-gnueabihf-dwp           arm-linux-gnueabihf-gdb         arm-linux-gnueabihf-objdump
arm-linux-gnueabihf-elfedit       arm-linux-gnueabihf-gfortran    arm-linux-gnueabihf-pkg-config

(Ubuntu とかの場合は build-essential libncurses-dev git git-core あたりが必要かもしれないけれど、僕は Gentoo 大好きなので細かいことは知らない)

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

$ mkdir -p ~/io/qt/code/qt/
$ cd $_
$ git clone git://code.qt.io/qt/qt5/ --branch dev
$ cd qt5
$ ./init-repository -f --module-subset=qtbase,qtdeclarative
...

Qt のビルドの詳細は、Qt のソースコードを取得してビルドをする方法について という記事を以前に書いたので、こちらを参考にしてください。

最近の環境では OpenGL ES2 と EGL のライブラリの名前が変わっている らしいので、qtbase/mkspecs/device/linux-rasp-pi3-g++/ 以下の設定をちょっと変更

diff --git a/mkspecs/devices/linux-rasp-pi3-g++/qmake.conf b/mkspecs/devices/linux-rasp-pi3-g++/qmake.conf
index b215833486..ba0e2d9226 100644
--- a/mkspecs/devices/linux-rasp-pi3-g++/qmake.conf
+++ b/mkspecs/devices/linux-rasp-pi3-g++/qmake.conf
@@ -26,12 +26,12 @@ QMAKE_INCDIR_EGL        = \

 QMAKE_INCDIR_OPENGL_ES2 = $${QMAKE_INCDIR_EGL}

-QMAKE_LIBS_OPENGL_ES2   = $${VC_LINK_LINE} -lGLESv2
+QMAKE_LIBS_OPENGL_ES2   = $${VC_LINK_LINE} -lbrcmGLESv2

 # The official opt vc EGL references GLESv2 symbols: need to link it
-QMAKE_LIBS_EGL          = $${VC_LINK_LINE} -lEGL -lGLESv2
+QMAKE_LIBS_EGL          = $${VC_LINK_LINE} -lbrcmEGL -lbrcmGLESv2

-QMAKE_LIBDIR_BCM_HOST   = $$VC_LIBRARY_PATH
+QMAKE_LIBDIR_BCM_HOST   = $$[QT_SYSROOT]$$VC_LIBRARY_PATH
 QMAKE_INCDIR_BCM_HOST   = $$VC_INCLUDE_PATH

Qt のビルド

$ mkdir -p ~/io/qt/code/qt/rpi
$ cd $_
$ ../qt5/configure -opensource -confirm-license -release -make libs -no-widgets -no-pch -prefix /opt/qt -ccache -opengl es2 -no-use-gold-linker -device linux-rasp-pi3-g++ -device-option CROSS_COMPILE=~/com/github/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf- -sysroot ~/org/raspberrypi/downloads/raspbian/sysroot
...
Option Description
-opensource オープンソース版を選択しました。商用ライセンスの場合は -commercial を設定しましょう。
-confirm-license 上記のライセンスに合意したことを示します。これを指定しない場合はライセンスに同意するか否かを聞かれます。
-release リリースモードでビルドをします。
-make libs ライブラリのみをビルドする。ようにします。これにより examples, tools, tests はビルド対象から外れます。
-no-widgets QtWidgets をビルド対象から外します。組み込み向けでは Qt Quick を利用しましょう。
-no-pch 諸事情により指定しましたが、必須ではありません。
-prefix /opt/qt sysroot 内で Qt がどこにインストールされるかを指定します。
-ccache 諸事情により指定しましたが、必須ではありません。
-opengl es2 OpenGL ES2 を明示的に指定します。
-no-use-gold-linker どうやら必要らしいので設定しました。
-device linux-rasp-pi3-g++ mkspecs/devices/linux-rasp-pi3-g++ の設定でビルドをすることを伝えます。
-device-option CROSS_COMPILE=... クロスコンパイラの設定です。
-sysroot sysrootを指定します。
config.summary
Building on: linux-g++ (x86_64, CPU features: mmx sse sse2)
Building for: devices/linux-rasp-pi3-g++ (arm, CPU features: neon)
Target compiler: gcc 4.8.3
Configuration: cross_compile ccache compile_examples enable_new_dtags largefile neon shared rpath release c++11 concurrent dbus reduce_exports stl no-widgets
Build options:
  Mode ................................... release
  Optimize release build for size ........ no
  Building shared libraries .............. yes
  Using C standard ....................... C11
  Using C++ standard ..................... C++11
  Using ccache ........................... yes
  Using new DTAGS ........................ yes
  Using precompiled headers .............. no
  Using LTCG ............................. no
  Target compiler supports:
    NEON ................................. yes
  Build parts ............................ libs
Qt modules and options:
  Qt Concurrent .......................... yes
  Qt D-Bus ............................... yes
  Qt D-Bus directly linked to libdbus .... no
  Qt Gui ................................. yes
  Qt Network ............................. yes
  Qt Sql ................................. yes
  Qt Testlib ............................. yes
  Qt Widgets ............................. no
  Qt Xml ................................. yes
Support enabled for:
  Using pkg-config ....................... yes
  udev ................................... no
  Using system zlib ...................... yes
  Zstandard support ...................... no
Qt Core:
  DoubleConversion ....................... yes
    Using system DoubleConversion ........ no
  GLib ................................... no
  iconv .................................. yes
  ICU .................................... no
  Built-in copy of the MIME database ..... yes
  Tracing backend ........................ <none>
  Logging backends:
    journald ............................. no
    syslog ............................... no
    slog2 ................................ no
  PCRE2 .................................. yes
    Using system PCRE2 ................... no
Qt Network:
  getifaddrs() ........................... yes
  IPv6 ifname ............................ yes
  libproxy ............................... no
  Linux AF_NETLINK ....................... yes
  OpenSSL ................................ no
    Qt directly linked to OpenSSL ........ no
  OpenSSL 1.1 ............................ no
  DTLS ................................... no
  OCSP-stapling .......................... no
  SCTP ................................... no
  Use system proxies ..................... yes
  GSSAPI ................................. no
Qt Gui:
  Accessibility .......................... yes
  FreeType ............................... yes
    Using system FreeType ................ yes
  HarfBuzz ............................... yes
    Using system HarfBuzz ................ no
  Fontconfig ............................. no
  Image formats:
    GIF .................................. yes
    ICO .................................. yes
    JPEG ................................. yes
      Using system libjpeg ............... no
    PNG .................................. yes
      Using system libpng ................ yes
  Text formats:
    HtmlParser ........................... yes
    CssParser ............................ yes
    OdfWriter ............................ yes
    MarkdownReader ....................... yes
      Using system libmd4c ............... no
    MarkdownWriter ....................... yes
  EGL .................................... yes
  OpenVG ................................. no
  OpenGL:
    Desktop OpenGL ....................... no
    OpenGL ES 2.0 ........................ yes
    OpenGL ES 3.0 ........................ no
    OpenGL ES 3.1 ........................ no
    OpenGL ES 3.2 ........................ no
  Vulkan ................................. no
  Session Management ..................... yes
Features used by QPA backends:
  evdev .................................. yes
  libinput ............................... no
  INTEGRITY HID .......................... no
  mtdev .................................. no
  tslib .................................. no
  xkbcommon .............................. no
  X11 specific:
    XLib ................................. no
    XCB Xlib ............................. no
    EGL on X11 ........................... no
QPA backends:
  DirectFB ............................... no
  EGLFS .................................. yes
  EGLFS details:
    EGLFS OpenWFD ........................ no
    EGLFS i.Mx6 .......................... no
    EGLFS i.Mx6 Wayland .................. no
    EGLFS RCAR ........................... no
    EGLFS EGLDevice ...................... no
    EGLFS GBM ............................ no
    EGLFS VSP2 ........................... no
    EGLFS Mali ........................... no
    EGLFS Raspberry Pi ................... yes
    EGLFS X11 ............................ no
  LinuxFB ................................ yes
  VNC .................................... yes
Qt Sql:
  SQL item models ........................ yes
Qt Widgets:
  GTK+ ................................... no
  Styles ................................. Fusion Windows
Qt PrintSupport:
  CUPS ................................... no
Qt Sql Drivers:
  DB2 (IBM) .............................. no
  InterBase .............................. no
  MySql .................................. no
  OCI (Oracle) ........................... no
  ODBC ................................... no
  PostgreSQL ............................. no
  SQLite2 ................................ no
  SQLite ................................. yes
    Using system provided SQLite ......... no
  TDS (Sybase) ........................... no
Qt Testlib:
  Tester for item models ................. yes
Qt QML:
  QML network support .................... yes
  QML debugging and profiling support .... yes
  QML just-in-time compiler .............. yes
  QML sequence object .................... yes
  QML XML http request ................... yes
  QML Locale ............................. yes
Qt QML Models:
  QML list model ......................... yes
  QML delegate model ..................... yes
Qt Quick:
  Direct3D 12 ............................ no
  AnimatedImage item ..................... yes
  Canvas item ............................ yes
  Support for Qt Quick Designer .......... yes
  Flipable item .......................... yes
  GridView item .......................... yes
  ListView item .......................... yes
  TableView item ......................... yes
  Path support ........................... yes
  PathView item .......................... yes
  Positioner items ....................... yes
  Repeater item .......................... yes
  ShaderEffect item ...................... yes
  Sprite item ............................ yes

Note: Also available for Linux: linux-clang linux-icc

Note: PKG_CONFIG_LIBDIR automatically set to ~/org/raspberrypi/downloads/raspbian/sysroot/usr/lib/pkgconfig:~/org/raspberrypi/downloads/raspbian/sysroot/usr/share/pkgconfig:~/org/raspberrypi/downloads/raspbian/sysroot/usr/lib/arm-linux-gnueabihf/pkgconfig

Note: PKG_CONFIG_SYSROOT_DIR automatically set to ~/org/raspberrypi/downloads/raspbian/sysroot

ビルドをしましょう。

$ make -j4
...

もう一つバグの修正

In file included from ~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/qvarlengtharray.h:1:0,
                 from ~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/kernel/qmetatype.h:48,
                 from ~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/qmetatype.h:1,
                 from ~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/kernel/qobject.h:54,
                 from ~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/qobject.h:1,
                 from ../../include/QtQml/5.14.0/QtQml/private/../../../../../../../qt5/qtdeclarative/src/qml/qml/qqmltypeloader_p.h:55,
                 from ../../include/QtQml/5.14.0/QtQml/private/qqmltypeloader_p.h:1,
                 from ~/io/qt/code/qt/qt5/dev/qt5/qtdeclarative/src/qml/compiler/qqmltypecompiler_p.h:56,
                 from ~/io/qt/code/qt/qt5/dev/qt5/qtdeclarative/src/qml/compiler/qqmltypecompiler.cpp:40:
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h: In instantiation of ‘QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator, InputIterator) [with InputIterator = const QV4::CompiledData::Alias* const*; typename std::enable_if<std::is_convertible<typename std::iterator_traits<_II1>::iterator_category, std::input_iterator_tag>::value, bool>::type <anonymous> = 1u; T = const QV4::CompiledData::Alias*; int Prealloc = 4]’:
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:72:51:   required from ‘QVarLengthArray<T, Prealloc>::QVarLengthArray(std::initializer_list<_Tp>) [with T = const QV4::CompiledData::Alias*; int Prealloc = 4]’
../../include/QtQml/5.14.0/QtQml/private/../../../../../../../qt5/qtdeclarative/src/qml/compiler/qqmlpropertycachecreator_p.h:705:85:   required from ‘QQmlCompileError QQmlPropertyCacheAliasCreator<T>::propertyDataForAlias(const CompiledObject&, const QV4::CompiledData::Alias&, int*, int*, QQmlPropertyData::Flags*) [with ObjectContainer = QQmlTypeCompiler; QQmlPropertyCacheAliasCreator<T>::CompiledObject = QmlIR::Object]’
../../include/QtQml/5.14.0/QtQml/private/../../../../../../../qt5/qtdeclarative/src/qml/compiler/qqmlpropertycachecreator_p.h:813:110:   required from ‘QQmlCompileError QQmlPropertyCacheAliasCreator<T>::appendAliasesToPropertyCache(const CompiledObject&, int) [with ObjectContainer = QQmlTypeCompiler; QQmlPropertyCacheAliasCreator<T>::CompiledObject = QmlIR::Object]’
~/io/qt/code/qt/qt5/dev/qt5/qtdeclarative/src/qml/compiler/qqmltypecompiler.cpp:1032:133:   required from here
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:78:27: error: no matching function for call to ‘QVarLengthArray<const QV4::CompiledData::Alias*, 4>::QVarLengthArray()         : QVarLengthArray()
                           ^
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:78:27: note: candidates are:
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:77:12: note: template<class InputIterator, typename std::enable_if<std::is_convertible<typename std::iterator_traits<_Iterator>::iterator_category, std::input_iterator_tag>::value, bool>::type <anonymous> > QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator, InputIterator)
     inline QVarLengthArray(InputIterator first, InputIterator last)
            ^
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:77:12: note:   template argument deduction/substitution failed:
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:78:27: note:   candidate expects 2 arguments, 0 provided
         : QVarLengthArray()
                           ^
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:71:5: note: QVarLengthArray<T, Prealloc>::QVarLengthArray(std::initializer_list<_Tp>) [with T = const QV4::CompiledData::Alias*; int Prealloc = 4]
     QVarLengthArray(std::initializer_list<T> args)
     ^
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:71:5: note:   candidate expects 1 argument, 0 provided
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:65:12: note: QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc>&) [with T = const QV4::CompiledData::Alias*; int Prealloc = 4]
     inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
            ^
~/io/qt/code/qt/qt5/dev/rpi/qtbase/include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:65:12: note:   candidate expects 1 argument, 0 provided
make[3]: *** [Makefile:15237: .obj/qqmltypecompiler.o] Error 1
make[2]: *** [Makefile:57: sub-qml-make_first-ordered] Error 2
make[1]: *** [Makefile:50: sub-src-make_first] Error 2
make: *** [Makefile:73: module-qtdeclarative-make_first] Error 2

というエラーが出たので、以下の変更をしました。

diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 01fc63b677..12383deb14 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -75,7 +75,7 @@ public:

     template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
     inline QVarLengthArray(InputIterator first, InputIterator last)
-        : QVarLengthArray()
+        : QVarLengthArray(0)
     {
         QtPrivate::reserveIfForwardIterator(this, first, last);
         std::copy(first, last, std::back_inserter(*this));

今回はこれでビルド&インストールが完了しました。

$ make -j4
...
$ sudo make install
...

実機で動作確認

SD カードの準備

まず、最新イメージの取得 で取得したイメージを SD カードにコピーします。

$ cd ~/org/raspberrypi/downloads/raspbian
$ dd if=2019-04-08-raspbian-stretch.img of=/dev/sd? bs=16M

次に、sysroot 以下の Qt の部分を SD カードにコピーします。

$ mkdir sdcard
$ sudo mount -t ext4 /dev/sd?2 sdcard
$ sudo cp -r sysroot/opt/qt sdcard/opt/
$ sudo umount sdcard

Raspberry Pi3 の設定変更

raspberrypi login: pi
Password: (raspberry)
$ sudo raspi-config
(WiFi の設定とか、ssh を有効にするとか、GPU メモリを256に変更するとか)
$ sudo raspi-update
$ vi main.qml

とっても簡単な QtQuick アプリケーションを QML で書いてみましょう。

main.qml
import QtQuick 2.12

Item {
    id: root
    width: 1920
    height: 1080
    Rectangle {
        anchors.centerIn: parent
        width: 200
        height: 200
        color: 'blue'
        NumberAnimation on rotation {
            from: 0
            to: 360
            duration: 5000
            easing.type: Easing.SineCurve
            loops: Animation.Infinite
        }
    }
}

テスト用の qml のビューアーで実行してみましょう。

$ /opt/qt/bin/qmlscene main.qml

image.png

終わりに

Raspberry Pi3 で Qt5 を動かす方法をまとめました。

今回は、Raspbian の Stretch の中の Lite という軽量なイメージを利用した関係で、/usr/share/fonts が存在せず、FontConfig も未サポートとなっています。

この Qt を利用してアプリケーションを開発する際には、フォントの用意と、アプリケーション内部でフォントの設定をする必要があります。

具体的には、 QFontDatabase::addApplicationFont("フォントのパス")QGuiApplication のインスタンス生成後に 呼び出してください。

参考情報

12
14
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?