Part.1, Telegram Desktop on Raspberry Pi & Ubuntu Touch, The Story Of (2017)


Telegram does not include pre-compiled binary version of its Telegram Desktop application for ARM Linux. I decided to do two attempts today:
  1. compile Telegram Desktop on ARM from sources
  2. after running in on Raspberry Pi (Ubuntu Mate), try to also deploy it to Ubuntu Touch based phone
This could have been just a regular step-by-step tutorial for reproducing an outcome. Instead I made it a complete journal/log of the process. Complete with dead ends and failures. I wanted this post to contain the story, the logic, the rationale and to allow for extrapolating this process to other ones that you, the reader, might deal with in the future. The general grand level problem here is this:

building and deploying software across multiple architectures of Ubuntu in a workflow distributed across desktop computer, raspberry pi board and Ubuntu Touch phone.

and this is only the Part 1, as the things didn't end up well the first time around. Still, you can learn about bunch of topics from this post:

- native compilation (no cross-compilation)
- on-device compilation/building with x forwarding

- ARM native development on desktop via architectural chroot
- troubleshooting some building errors



Compiling from sources

Generally I followed the documentation at https://github.com/telegramdesktop/tdesktop/blob/dev/docs/building-cmake.md

I did all of it on Raspberry Pi board running Ubuntu Mate 16.04, but I worked entirely from my Ubuntu Desktop laptop over ssh with X forwarding so I could edit files with geany and use other GUI apps when needed. My raspberry pi uname output:

Note, that later on I was going to deploy compiled Telegram to Ubuntu phone, and ssh with X forwarding is just great for such a workflow: 3 devices are powered on, the raspberry pi board, the phone and my laptop. I just work on my laptop but I work in shells of all of these 3 devices, and when needed I use GUI apps running off all of them too!! All while on home LAN with very smooth and fast experience.

After following the steps for installing prerequisites, the final step was to go into the TBuild/tdesktop/out/Release folder of where my sources were, and running the one final make. Only during that final building I have encounter few errors, and below they are listed in the chronological order. Included are fixes I made to enable the build process to continue. To be fair, the compiler is set for a mode of operation in which all warnings are treated as errors, so some of the errors described here are actually just warnings and would have not prevented the compilation otherwise. Especially was the case with few warnings about if statement conditions that always resolve to true, which were treated by the compiler as errors.


Error #1

very soon after running the final make, an error stopped the compilation, and it was metionnig "libicutu.a", fortunately I found reference to that exact error on Telegram github here: https://github.com/telegramdesktop/tdesktop/blob/dev/docs/building-cmake.md
I solved the problem running this script:
for libname in libicutu.a libicui18n.a libicuuc.a libicudata.a; do
    sudo ln -s /usr/lib/arm-linux-gnueabihf/${libname} /usr/lib/${libname}
done

Error #2

soon a second error followed, about compiler not supporting -msse2 switch:
cc1plus: error: unrecognized command line option "-msse2"
and so I had to remove the switch from the make file at:
TBuild/tdesktop/out/Release/CMakeFiles/libtgvoip.dir/build.make

Error #3

At 47% mark I read next error log:
[ 47%] Precompiling stdafx.h for Telegram (C++)
In file included from /home/supervizor/TBuild/tdesktop/out/Release/../../Telegram/SourceFiles/core/basic_types.h:28:0,
                 from /home/supervizor/TBuild/tdesktop/out/Release/Telegram_pch/stdafx.h:78:
/home/supervizor/TBuild/tdesktop/out/Release/../../Telegram/SourceFiles/base/build_config.h:64:2: error: #error Please add support for your architecture in base/build_config.h
#error Please add support for your architecture in base/build_config.h
  ^~~~~
CMakeFiles/Telegram.dir/build.make:75: recipe for target 'Telegram_pch/stdafx.h.gch/.c++' failed
make[2]: *** [Telegram_pch/stdafx.h.gch/.c++] Error 1
CMakeFiles/Makefile2:485: recipe for target 'CMakeFiles/Telegram.dir/all' failed
make[1]: *** [CMakeFiles/Telegram.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
so in the file /TBuild/tdesktop/Telegram/SourceFiles/base/build_config.h
I had to add definitions for ARM family of architectures. Below a line  saying: 
"// Processor architecture detection."  
There was a list of definitions, and before the final "#else" I pasted the missing ones for ARM architecture:
(...)
#elif defined(__ARMEL__)
#define ARCH_CPU_ARM_FAMILY 1
#define ARCH_CPU_ARMEL 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__aarch64__)
#define ARCH_CPU_ARM_FAMILY 1
#define ARCH_CPU_ARM64 1
#define ARCH_CPU_64_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
(...)

Error #4

Next error stopped the building process at 54% mark:
so I editte the file TBuild/tdesktop/Telegram/SourceFiles/history/history_media_types.cpp at line 1355 had to change the codefrom:
   } else if (wf->at(0) < 0) {
    wf = nullptr;
   } else {
    norm_value = _data->voice()->wavemax;
   }
to: } else {wf = nullptr;}

Error #5

Next stop at 58%, very similar error to the previous one:
so I editted the TBuild/tdesktop/Telegram/SourceFiles/storage/localstorage.cpp, line 3157, from:
   } else if (voice->waveform[0] < 0) {
    voice->waveform[0] = -2;
    voice->wavemax = 0;
   }
to:
   } else {
    voice->waveform[0] = -2;
    voice->wavemax = 0;
   }

Error #6

Next stop at 49%, somehow earlier in the overall progress then the previous error:
I Googled similar error reported by someone at: https://github.com/telegramdesktop/tdesktop/issues/2205

and supposedly some patch was released, but I went the other way and in the file
/usr/local/tdesktop/Qt-5.6.2/include/QtGui/qtextlayout.h, line 188 we have:
private:
    QTextLayout(QTextEngine *e) : d(e) {}
    Q_DISABLE_COPY(QTextLayout)

    friend class QPainter;
    friend class QGraphicsSimpleTextItemPrivate;
    friend class QGraphicsSimpleTextItem;
    friend void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *, const QString& str,
                               QRectF *brect, int tabstops, int* tabarray, int tabarraylen,
                               QPainter *painter);
    QTextEngine *d;
};
so I made the definition public:
private:
    Q_DISABLE_COPY(QTextLayout)

    friend class QPainter;
    friend class QGraphicsSimpleTextItemPrivate;
    friend class QGraphicsSimpleTextItem;
    friend void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *, const QString& str,
                               QRectF *brect, int tabstops, int* tabarray, int tabarraylen,
                               QPainter *painter);
    QTextEngine *d;
public:    
    QTextLayout(QTextEngine *e) : d(e) {}
}; 
and that allowed me to move forward.


Error #7

Next stop at 71%, a familiar error again:
so editted the file TBuilt/tdesktop/Telegram/SourceFiles/logs.cpp, and commented the condition that always returns true:


Error #8

Again always-true conditon:
And a quick fix at TBuilt/tdesktop/Telegram/SourceFiles/structs.cpp:

Crash (cc1plus)

What happened next was not an ordinary error:
I restarted the compilation and my worries got confirmed:
while at qrc_telegram.o the memory ran out! twice ! I turned off graphical x session via raspi-config tool as decribed here. I rebooted my pi board and did not start xserver. Then I re-run make again this time on the pi itself, to also save any ssh session resources. It crashed again, same thing.
It became obvious, that I nede more memory. Since I could not add RAM I had to create some good bit of SWAP for my pi system.  For adding SWAP I followed instructions found here: https://raspberrypi.stackexchange.com/questions/70/how-to-set-up-swap-space
so I added 4G swapfile , and to keep my sd card in good shape I decided to turn that extra swap off after I'm done:
and just as I continue building again, I can see that the swap is being eaten, so I guess it works now:
Adding swap was definitely the way to go, just look how much of it was being used:
only to find out that the next element in the queue maxed the swap usage even further:
why emoji so big??? Anyways, it only proves that swap was absolutely essential for this entire process.


More Crashing...

turns out that telegram building is huge on RAM, and it continued crashing me due to memory allocation exception:
so I just kept restarting the makescript hoping that memory will be enough to compile one object file at a time. In the meantime while sharing my progress with users on Telegrams UB Ports Supergroup I was pointed (thank you Dalton @UniversalSuperBox) to make's utility -j switch that can limit number of jobs ran in parallel. I remembered that qt sources were built with -j4 switch, so I decided at this moment, that if the building crashes again I will use this switch to try again.
So 2 minutes after I wrote the previous sentence, it crashed, I restarted make with -j4 switch and I immediately moved forward in the make queue:
you live and you learn :D Anyways, I was soon to learn that this entire task was just too much to handle by the pi board which only has 1G RAM. So what do you do when your RAM is just not enough? You buy more right? Not on pi board, no.

The bottom line is that it kept crashing with the same memory allocation problem multiple times over. I kept restarting the compilation thought, because since I was using make with -j4 switch, there were still 4 jobs going on simultaneously, and while one was struggling other ones were still going on. So by running the compilation over and over as it continued to crash, some jobs were actually going through and out of the compilation pipeline. Until one remained. One job that was just too much for pi board with all that swap to handle: qrc_telegram_emoji.o  WHY ARE YOU SO BIG EMOJI ?! So where do you even go from here...


Booting raspberry pi SD card on desktop via architectural chroot

Clearly I was not goign to build Telgram on pi board, due to... emoji! So I had to start thinking out of the box. My first thought was to quickly set up qemu-system-arm container to build inside it on an emulated ARM system. Just that it wasn't a quick way to go. Nor was it a good way either. It was a slow way because I'd need to prep all the prerequisites again, all the downloading, configuring, and pre-building.... while on the pi board it was almost all good except for the emoji part. Neither it was a good way, because qemu-system-arm had a design limitation of only being able to supply 256MB of RAM to the emulated container, effectively making the emulated ARM slower from the actual ARM even on the core i5 laptop.
The better way was what some call an architectural chroot. It actually was going to allow me to emulate ARM system booted off my actual SD card taken off my pi board, with all the stuff there ready for typing "make" and hitting enter. Actually, I used dd to ghost my pi board SD card into an image file, that I put on my laptop's SSD hard drive. Much faster to work in chroot that way. I mounted the image and I just needed a tiny bit of preparation. I needed to add into that image a special kind of magic: qemu-user-static. It will sit in front of the kernel and emulate machine code calls between x86 and ARM architectures on the fly. A great read about this is here: http://sentryytech.blogspot.tw/2013/02/faster-compiling-on-emulated-raspberry.html
Interestingly the linked article shows a failed plan A and an alternative plan B scenarios, which are basically my first and my second thoughts about qemu-system-arm container and about architectural root. Anyways, I was now up and running my pi board's ghosted SD card real-time emulated on my core i5 laptop, and in the make pipeline only the emoji were left, now about to go down:
in the background is the system manager showing CPU usage, which was going crazy on all of my 4 cores. But it was going, and it actually did crack the emoji, unitl this happened:
after all of these work-arounds, after literally entire night awake and entire following day (24 hrs no sleep) I was stuck in the building of Telegram on ARM because of fcitx and hime input plugins... let's just give up.


Undoing fcitx and Hime

just that I am not really good at giving up. So I went back to the official building documentation of Telegram Desktop, and to the beginning of the QT part. It was qt that has introduced the fcitx and hime plugins. So what I did, I deleted the TBuild/Libraries/qt5_6_2 folder entirely. Then I followed the steps for qt AGAIN, but skipping the part about fcitix and hime plugins. I had to recompile qt AGAIN, so I just went to sleep. It was approx 6 pm, and I left it at building qt 2nd time, and finally went to sleep.

Tuesday, October 7th 2017. I woke up at 7:30 am, after 13+ hours sleep. Qt was built and I directly went back to bulding Telegram: 
$ cd ~/TBuild/tdesktop/out/Release
$ make
and so i was trying again, this time it was a lot of rebuilding of previously built parts, because of entirely new qt version:
all of my four cores were running crazy again and I was waiting to see what was going to happen this time over...

3:15 PM, Nov 7th 2017, the process failed at the previously reported error #6 (scroll up to find it), so I just applied the fix to the file  /usr/local/tdesktop/Qt-5.6.2/include/QtGui/qtextlayout.h  again and continued. That file got updated when I recompiled and reinstalled QT, so repeating this step was expected.

5:00 am, Nov 8th 2017: failed at the exactly same stage. And also it was when I realized that all the QT rebuilding was totally unneccesary, because it did not affect in any way the build configuration. The libfcitxplatforminputcontextplugin.so was being defined somewhere in the main build configuration. I really should not have thought that repeating steps for QT building but skipping the plugins steps will change the build command line. Unless off course some further setps after building QT, that I did not do. Anyways, I started to think, and also I found this page that talks just that very library problem in Telegram on Linux: 
https://github.com/telegramdesktop/tdesktop/issues/375
I started suspecting that somehow the library was build but not on LD_LIBRARY_PATH. I searched the filesystem and I found that  it was in:
 /usr/lib/arm-linux-gnueabihf/qt5/plugins/platforminputcontexts
I just copied it to/usr/lib. Then I run make again and:
YAY! we finally moved past the fcitx plugin problem, now we only left with hime plugin. 
Unfortunately my system does not have libhimeplatforminputcontextplugin.so, so...
quick apt-cache search found me this:  
hime-qt5-immodule - Qt5 input method module with HIME as backend
so: sudo apt-get install hime-qt5-immodule , and it did install a bunch of things...
And so after installing I went to list libraries under /usr/lib/arm-linux-gnueabihf/qt5/plugins/platforminputcontexts only to find out that installed library was not what I expected, instead it was called im-hime.so, and it was then that I felt inspired to just give it a rename-makeover and try if it would work. I honestly didn't believe it was a high chance of success, but I was curious, and so I re-ran make and lo and behold... it went into building far beyond the time that it has previously ran for before stopping on the input plugin library linking error. Is it possible that simply renaming the library worked?

17:15 PM Nov 8th, 2017, I am now at Taipei Songshan Airport about to board flight to Chengdu while Telegram is still compiling:
This story will continue in China. But I am very optimistic this time, because the compilation didn't fail for much longer than previously, so it just might moved past he input plugins. We shall see...

23:03, Nov 8th, 2017, Chengdu - I finally let the building to continue only to find out that it failed in the end with both fcitx and hime modules:
 I reckon that the .so libraries were not compiled form the same sources that are used in Telegram, so .cpp and .h files were not compatible with the compiled libraries.

That's it, I give up
although, not with the Telegram, just with the fcitx and hime plugins. Will try to disable these plugins and just go with ibus. If I succeed that way, I will take a step back and try to at least make fcitx work. The only reference to a compiler command line with switches for linking fcitx and hime plugins are in the file ~/TBuild/tdesktop/out/Release/CMakeFiles/Telegram.dir/link.txt - I did not expect to find compilation command in a .txt file, but what do I know about makefile... I removed two switches: "-lfcitxplatforminputcontextplugin -lhimeplatforminputcontextplugin" entirely from the command line. Then went again to run make.

==>> Observation <<==
when hanging around filesystem on my UT phone, I found that there was this file: /usr/lib/arm-linux-gnueabihf/qt5/plugins/platforminputcontexts/libmaliitphabletplatforminputcontextplugin.so, so... 
yeah, it makes sense, since UT uses maliit OSK, and this finding (the context input plugin) will be very important later on for running telegram desktop on UT once compiled for ARM. When we put this finally built telegram desktop on the phone and call it via ssh with x forwarding, then we will use ibus, or fcitx, but if we will start it on the phone directly, we will want to use it with phone's OSK, so we will need the maliit plugin to work with it. At some point I will have to consider compiling telegram again with linking to that plugin. Possibly with some extra param line switch like -lmaliitplatforminputcontextplugin. Unless telegram can just detect it at runtime and link it dynamically, which currently I don't know if it will be the case. But it is important to look around, and notice things that seem related. Even if you cannot make sense of it right away, keeping it in mind will possibly speed you up later on, when you can deduce some things that can fix your problems along the way.


To Be Continued...

it is now 10 am, Nov. 16th, Taipei. Telegram compiling on ARM failed, and I recently was too busy with my daytime job to put extra thoughts into it. I still want to re-approach this, but will have to take a break. In the meantime, I decided to publish this article as is, because I believe that it contains lot of value for people who just wish to explore lots of alternative workflows with Ubuntu Touch.

Comments

Popular posts from this blog

Lazarus IDE on ARM Ubuntu (Raspberry Pi, Ubuntu Touch, etc)

SSH and Ubuntu Touch - everything you want to ask but are afraid to ask

Desktop Apps on Ubuntu Phone