Building stuff from sources on Steam Deck
My previous article about Steam Deck has exploded in size, so I decided to move the part about installing packages and building stuff into a separate article.
But it’s not just already published parts, there are some new things too: in particular, I’ve managed to build Qt (both shared and static configurations) and used it to build my own applications.
But first, continuing the trend, here’s a photo with Deadpool:
And now to the actual stuff.
Y tho
Aside from being a “video game machine”, Steam Deck is also a quite powerful PC with a common x86_64 / AMD64 architecture - the same that you (most likely) have on your desktop PC. So you can use it for software development the same way as your main machine.
In some situations it might even be the only computer that you have available, so isn’t it handy that you can perform all your regular software development tasks on it.
Finally, certain software might not be available in a form of pre-built binaries in neither of the repositories/storages/stores, and to get it running on Steam Deck you’d need to build it from sources right on the device (of course, you can also build it on another GNU/Linux host and copy the binaries to Steam Deck, but that won’t be as exciting, would it, plus you might stumble upon a mismatch in some dependencies versions, such as ICU).
Is it convenient/viable/feasible
Display
The device screen is certainly not big enough, so I’d recommend docking to an external display (shown on the left):
I mean, Steam Deck screen size is rather okay, you can read from it and work with code, but probably not for a long periods of time, if you value your eyesight.
Keyboard/mouse
Instead of docking to an external display you can also connect to Steam Deck via SSH from your main machine (that’s what is happenning on the right display on the photo above), where you have both normal display and proper mouse/keyboard.
If even SSH isn’t an option, then at least do get a decent keyboard, because I most definitely can recommend neither the one from the photo above (Microsoft Wireless Universal Foldable, which has no F1-F12 keys) nor the one from the very first photo in the article (Microsoft Arc 1392, which has awful arrow keys). If we are talking about portable keyboards specifically, the best option I’ve found so far is iClever BK08:
It is not perfect either, as the keyboard layout could certainly be better (at the very least, the ESC
should have been a one-key thing, not the fn-ESC
combo). But for the most part it is very good, especially the typing experience, plus it has a touchpad, so you won’t need a mouse.
Overall
Software-wise, SteamOS (Arch Linux) environment is good enough for software development, despite its limitations of having a read-only wipeable filesystem. You’ll see how that works in the next section.
As for computing power, on Steam Deck it is more than decent. Hell, it is far more powerful than my desktop PC. Later in the article there will be a section about Qt build times, which can be used as a good real-life compilation benchmark.
So, while (undocked) Steam Deck is not the most convenient workstation in the world, it is powerful enough for software development tasks. As a bonus, it is a portable device that is rather easy to carry around, although compiling big projects without being connected to a power supply isn’t a particularly bright idea.
Homebrew
As I already described in the previous article, it might be wise not to install system-wide packages via pacman and use a different package manager instead, specifically one that would keep its packages “isolated” somewhere and not getting in the way or “contaminating” the system environment.
Nix package manager will likely do the job, but I don’t have any experience with it. Also, its installation involves certain trickery with symlinks and system services for persisting those, so I decided not to try that one.
Homebrew package manager, on the other hand, I know very well, as I use it every day on my Mac. Conveniently enough it also has GNU/Linux support, so that is what I’ll be using on Steam Deck too. It does not require sudo
elevation and installs stuff into /home/linuxbrew/
, where it is nicely contained.
Some say that Homebrew is a bad choice, because there is already a bazillion of package managers for GNU/Linux distributions. But how many of those are easy enough to install and, most importantly, how many of them allow to install to /home/
or other specified folder without affecting system environment? Yeah, I’ll stick to Homebrew for now.
There is a guide for installing Homebrew on Steam Deck from some guy over here, and he says not to put stuff into ~/.bash_profile
, otherwise it “it will break Steam”, but he doesn’t say how exactly it will break Steam. He probably means that Homebrew environment variables/paths will be prepended to they system ones, and while that’s what is desired for the whole purpose of using Homebrew, the default SteamOS stuff (Steam itself, Gamescope, etc) might get “unexpected” paths/libraries/etc, which will affect the way system works. That I can only agree with, that is exactly why I am trying to avoid using pacman for installing additional software.
There is also this thread on Steam Community forums, where people also mention that the system environment should not be affected if Homebrew environment is activated manually (not added to the ~/.bash_profile
).
Finally, here’s Homebrew own instructions where they tell to add stuff to ~/.bash_profile
, but most likely these instructions do not account for SteamOS environment.
So, in the end, it probably really is a good idea not to add Homebrew environment stuff to ~/.bash_profile
and instead explicitly activate it every time you’d like to use it.
Let’s proceed with the installation then. First create a user for it:
$ sudo useradd --system --user-group --create-home linuxbrew
$ grep linuxbrew /etc/passwd
linuxbrew:x:966:966::/home/linuxbrew:/usr/sbin/nologin
$ ls -l /home
drwx------ 17 deck deck 4096 Jan 27 12:29 deck
drwx------ 3 linuxbrew linuxbrew 4096 Jan 27 15:18 linuxbrew
drwx------ 2 root root 16384 Aug 26 09:39 lost+found
-rw------- 1 root root 1073741824 Jan 22 21:55 swapfile
If linuxbrew
user didn’t get nologin
, set it explicitly to prevent logging-in as that user:
$ sudo usermod -s /usr/sbin/nologin linuxbrew
$ sudo --login --user linuxbrew
This account is currently not available.
Then execute the Homebrew installation script as linuxbrew
user. Yes, it is a horrible idea to execute shell scripts downloaded from the internet, but I couldn’t comprehend individual steps in the script, so I decided to take the risk:
$ sudo -u linuxbrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
==> Checking for `sudo` access (which may request your password)...
==> This script will install:
/home/linuxbrew/.linuxbrew/bin/brew
/home/linuxbrew/.linuxbrew/share/doc/homebrew
/home/linuxbrew/.linuxbrew/share/man/man1/brew.1
/home/linuxbrew/.linuxbrew/share/zsh/site-functions/_brew
/home/linuxbrew/.linuxbrew/etc/bash_completion.d/brew
/home/linuxbrew/.linuxbrew/Homebrew
Press RETURN/ENTER to continue or any other key to abort:
Sorry, user linuxbrew may not run sudo on HOSTNAME.
==> /bin/chown -R linuxbrew:linuxbrew /home/linuxbrew/.linuxbrew/Homebrew
==> Downloading and installing Homebrew...
remote: Enumerating objects: 224720, done.
remote: Counting objects: 100% (232/232), done.
remote: Compressing objects: 100% (163/163), done.
remote: Total 224720 (delta 85), reused 175 (delta 67), pack-reused 224488
Receiving objects: 100% (224720/224720), 63.74 MiB | 2.73 MiB/s, done.
Resolving deltas: 100% (165343/165343), done.
From https://github.com/Homebrew/brew
* [new branch] less-agressive-core-tap -> origin/less-agressive-core-tap
* [new branch] master -> origin/master
* [new tag] 0.1 -> 0.1
* [new tag] 0.2 -> 0.2
* [new tag] 0.3 -> 0.3
...
* [new tag] 3.6.6 -> 3.6.6
* [new tag] 3.6.7 -> 3.6.7
* [new tag] 3.6.8 -> 3.6.8
* [new tag] 3.6.9 -> 3.6.9
HEAD is now at 10845a112 Merge pull request #14444 from dduugg/resolve-rubocop-todo
==> Tapping homebrew/core
remote: Enumerating objects: 1404036, done.
remote: Counting objects: 100% (194/194), done.
remote: Compressing objects: 100% (99/99), done.
remote: Total 1404036 (delta 112), reused 169 (delta 95), pack-reused 1403842
Receiving objects: 100% (1404036/1404036), 536.53 MiB | 1.42 MiB/s, done.
Resolving deltas: 100% (978676/978676), done.
From https://github.com/Homebrew/homebrew-core
* [new branch] master -> origin/master
HEAD is now at b14bb200024 eksctl: update 0.127.0 bottle.
==> Downloading https://ghcr.io/v2/homebrew/portable-ruby/portable-ruby/blobs/sha256:fc45ee6eddf4c7a17f4373dde7b1bc8a58255ea61e6847d3bf895225b28d072a
######################################################################## 100.0%
==> Pouring portable-ruby-2.6.8_1.x86_64_linux.bottle.tar.gz
Warning: /home/linuxbrew/.linuxbrew/bin is not in your PATH.
Instructions on how to configure your shell for Homebrew
can be found in the 'Next steps' section below.
==> Installation successful!
==> Homebrew has enabled anonymous aggregate formulae and cask analytics.
Read the analytics documentation (and how to opt-out) here:
https://docs.brew.sh/Analytics
No analytics data has been sent yet (nor will any be during this install run).
==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
https://github.com/Homebrew/brew#donations
==> Next steps:
- Run these three commands in your terminal to add Homebrew to your PATH:
echo '# Set PATH, MANPATH, etc., for Homebrew.' >> /home/linuxbrew/.bash_profile
echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/linuxbrew/.bash_profile
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
- Install Homebrew's dependencies if you have sudo access:
sudo pacman -S base-devel
For more information, see:
https://docs.brew.sh/Homebrew-on-Linux
- We recommend that you install GCC:
brew install gcc
- Run brew help to get started
- Further documentation:
https://docs.brew.sh
Do not follow these instructions in the end of the output (except for the one about installing base-devel
, but we’ll get to that later). Do not add anything to ~/.bash_profile
. Like I said, Homebrew environment will be activated manually.
If you get permission errors, check that you’ve run the commands as linuxbrew
user. Also just in case check who is the owner of /home/linuxbrew
, and if it’s not linuxbrew
, then change to it:
$ sudo chown -R linuxbrew:linuxbrew /home/linuxbrew
Now the Homebrew is installed, but you might still get permission problems, this time for your deck
user to access linuxbrew
stuff. So maybe the step with creating linuxbrew
user was actually redundant, but they do say not to use a sudo-capable user for that. Anyway, I unfortunately don’t exactly remember what I did to resolve this, but I found the following in my history of commands:
$ sudo usermod -a -G linuxbrew deck
$ sudo chmod -R g+rx /home/linuxbrew
$ grep linuxbrew /etc/group
linuxbrew:x:966:deck
$ groups
wheel deck
So I added brew
user to linuxbrew
group and changed the group permissions for /home/linuxbrew
folder. Reboot (or restart the session) to refresh the deck
user groups and check what you got:
$ whoami
deck
$ id
uid=1000(deck) gid=1000(deck) groups=1000(deck),966(linuxbrew),998(wheel)
$ groups
linuxbrew wheel deck
Now you should be able to activate Homebrew environment (as deck
user):
$ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
$ brew --version
But when I tried to verify the installation with brew doctor
, I got lots of problems reported, such as no Git origin, non-writable folders and so on. Again, this is still likely because of the linuxbrew
access rights, and so probably one should execute everything as deck
from the begining, but since I am already where I am, the fix was to grant the following rights:
$ sudo chown -R deck \
/home/linuxbrew/.linuxbrew/Homebrew \
/home/linuxbrew/.linuxbrew/etc/bash_completion.d \
/home/linuxbrew/.linuxbrew/share/doc \
/home/linuxbrew/.linuxbrew/share/man \
/home/linuxbrew/.linuxbrew/share/man/man1 \
/home/linuxbrew/.linuxbrew/share/zsh \
/home/linuxbrew/.linuxbrew/share/zsh/site-functions \
/home/linuxbrew/.linuxbrew/var/homebrew/locks
$ chmod u+w \
/home/linuxbrew/.linuxbrew/Homebrew \
/home/linuxbrew/.linuxbrew/etc/bash_completion.d \
/home/linuxbrew/.linuxbrew/share/doc \
/home/linuxbrew/.linuxbrew/share/man \
/home/linuxbrew/.linuxbrew/share/man/man1 \
/home/linuxbrew/.linuxbrew/share/zsh \
/home/linuxbrew/.linuxbrew/share/zsh/site-functions \
/home/linuxbrew/.linuxbrew/var/homebrew/locks
Now everything should be in order:
$ brew doctor
Warning: No developer tools installed.
Install Clang or run `brew install gcc`.
The warning about no developer tools installed is okay, we’ll get to it.
Disable analytics, if you wish:
$ brew analytics off
$ brew analytics
Analytics are disabled.
Out of the box with no packages installed yet, Homebrew takes almost 750 MB of disk space:
$ du -hs /home/linuxbrew/
746M /home/linuxbrew/
Run an update just in case and check the version:
$ brew update
==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
https://github.com/Homebrew/brew#donations
Updated 1 tap (homebrew/core).
$ brew --version
Homebrew 3.6.20
Homebrew/homebrew-core (git revision 7c064c30a3d; last commit 2023-01-27)
The final step: make an alias in ~/.bashrc
for activating Homebrew environment:
$ nano ~/.bashrc
alias brewsome="eval \"$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)\""
If you’ll add it to ~/.bash_profile
instead, then this alias will be available only when you connect over SSH, but Konsole sessions won’t have it.
To test the alias, restart the Konsole (or reconnect via SSH) and run brew --version
. It should fail, then you activate Homebrew environment and try again:
$ brew --version
-bash: brew: command not found
$ brewsome
$ brew --version
Homebrew 3.6.20
Homebrew/homebrew-core (git revision 7c064c30a3d; last commit 2023-01-27)
Installing GCC
The first thing you need to install with Homebrew is developer tools. To be specific - GCC:
$ brew install gcc
==> Pouring gcc--12.2.0.x86_64_linux.bottle.2.tar.gz
Warning: The post-install step did not complete successfully
You can try again using:
brew postinstall gcc
==> Summary
� /home/linuxbrew/.linuxbrew/Cellar/gcc/12.2.0: 1,623 files, 306.6MB
==> Running `brew cleanup gcc`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Aw, something failed. At the same time, it did install something, because the folder size has doubled:
$ du -hs /home/linuxbrew/
1.6G /home/linuxbrew/
Trying to do what it says to fails as well:
$ brew postinstall gcc
==> Postinstalling gcc
Warning: The post-install step did not complete successfully
You can try again using:
brew postinstall gcc
Adding --debug
does output more details:
$ brew postinstall --debug gcc
==> Postinstalling gcc
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/brew.rb (Formulary::FromPathLoader): loading /home/linuxbrew/.linuxbrew/opt/gcc/.brew/gcc.rb
Warning: The post-install step did not complete successfully
You can try again using:
brew postinstall gcc
==> An exception occurred within a child process:
ErrorDuringExecution: Failure while executing; `/usr/bin/cc -print-file-name=crti.o` exited with 127. Here's the output:
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/utils/popen.rb:12:in `popen_read'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/utils/popen.rb:16:in `safe_popen_read'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/gcc.rb:173:in `post_install'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/formula.rb:1161:in `block (2 levels) in run_post_install'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/formula.rb:968:in `with_logging'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/formula.rb:1160:in `block in run_post_install'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/utils.rb:605:in `with_env'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/formula.rb:1149:in `run_post_install'
/home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/postinstall.rb:24:in `<main>'
I don’t remember how I got to the actual reason, but I discovered that installing GCC with Homebrew requires… GCC being already available in the system! What is the actual fuck.
That is one of those exceptions to the rule of not installing system-wide packages with pacman, which I mentioned earlier. There is simply no other way to proceed without installing GCC with pacman. At least I didn’t find any other way.
Using these instructions, GCC can be installed like this:
$ sudo steamos-readonly disable
$ sudo pacman-key --init
$ sudo pacman-key --populate archlinux
==> Appending keys from archlinux.gpg...
==> Updating trust database...
gpg: next trustdb check due at 2023-07-12
$ sudo pacman -Syu
:: Synchronizing package databases...
jupiter-rel is up to date
holo-rel is up to date
core-rel is up to date
extra-rel is up to date
community-rel is up to date
multilib-rel is up to date
:: Starting full system upgrade...
there is nothing to do
$ sudo pacman -S base-devel
:: There are 26 members in group base-devel:
:: Repository holo-rel
1) archlinux-keyring
:: Repository core-rel
2) autoconf 3) automake 4) binutils 5) bison 6) debugedit 7) fakeroot 8) file 9) findutils 10) flex 11) gawk 12) gcc 13) gettext 14) grep 15) groff
16) gzip 17) libtool 18) m4 19) make 20) pacman 21) patch 22) pkgconf 23) sed 24) sudo 25) texinfo 26) which
Enter a selection (default=all):
resolving dependencies...
looking for conflicting packages...
Packages (28) libisl-0.25-1 libmpc-1.2.1-2 archlinux-keyring-20221123-1.1 autoconf-2.71-1 automake-1.16.5-1 binutils-2.39-3 bison-3.8.2-4 debugedit-5.0-4
fakeroot-1.29-1 file-5.43-1 findutils-4.9.0-1 flex-2.6.4-3 gawk-5.2.0-3 gcc-12.2.0-1 gettext-0.21.1-1 grep-3.8-2 groff-1.22.4-7 gzip-1.12-1
libtool-2.4.7-5 m4-1.4.19-1 make-4.3-3 pacman-6.0.1-8 patch-2.7.6-8 pkgconf-1.8.0-1 sed-4.8-1 sudo-1.9.11.p3-1 texinfo-6.8-2 which-2.21-5
Total Installed Size: 275.34 MiB
Net Upgrade Size: 185.29 MiB
:: Proceed with installation? [Y/n] Y
(28/28) checking keys in keyring [###########################################################] 100%
(28/28) checking package integrity [###########################################################] 100%
(28/28) loading package files [###########################################################] 100%
(28/28) checking for file conflicts [###########################################################] 100%
error: failed to commit transaction (conflicting files)
fakeroot: /etc/ld.so.conf.d/fakeroot.conf exists in filesystem
Errors occurred, no packages were upgraded.
When I installed it for the first time, it just worked. But when it all seemingly got wiped after one of the system updates and I tried to install it again, then, as you can see, I got this error about fakeroot
, which can be worked around by adding --overwrite '*'
:
$ sudo pacman -S base-devel --overwrite '*'
One other time after another system update I got errors about signing keys. Tried changing key servers and also re-initializing and re-populating keyrings:
$ mv /home/deck/.gnupg /home/deck/Downloads/gnupg.home.backup
$ sudo mv /etc/pacman.d/gnupg /home/deck/Downloads/gnupg.etc.backup
# one of these might be redundant
$ sudo dirmngr </dev/null
$ dirmngr </dev/null
$ sudo pacman-key --init
$ sudo pacman-key --populate archlinux
…but nothing helped (or did help, but not entirely?), as any attempt to update anything was still failing like this:
downloading required keys...
:: Import PGP key AF1D2199EF0A3CCF, "GitLab CI Package Builder <ci-package-builder-1@steamos.cloud>"? [Y/n] y
error: key "AF1D2199EF0A3CCF" could not be looked up remotely
error: required key missing from keyring
error: failed to commit transaction (unexpected error)
Errors occurred, no packages were upgraded.
or like this:
downloading required keys...
:: Import PGP key AF1D2199EF0A3CCF, "David Runge <dvzrv@archlinux.org>"? [Y/n] y
error: key "AF1D2199EF0A3CCF" could not be looked up remotely
error: required key missing from keyring
error: failed to commit transaction (unexpected error)
Errors occurred, no packages were upgraded.
or with some other key.
And then I realized that it might be root
keyring that has troubles, so I did almost the same but for root
:
$ sudo rm -R /etc/pacman.d/gnupg
$ sudo rm -R /root/.gnupg
$ sudo gpg --refresh-keys
$ gpg --refresh-keys # might be redundant
$ sudo pacman-key --init
$ sudo pacman-key --populate
And after that I could progress further to get this error about fakeroot
again:
$ sudo pacman -S base-devel
resolving dependencies...
looking for conflicting packages...
Packages (16) autoconf-2.71-4 automake-1.16.5-2 bison-3.8.2-5 debugedit-5.0-5 fakeroot-1.31-2 flex-2.6.4-5 gcc-13.1.1-1 groff-1.22.4-10 libisl-0.26-1
libmpc-1.3.1-1 m4-1.4.19-3 make-4.4.1-2 patch-2.7.6-10 pkgconf-1.8.1-1 texinfo-7.0.3-1 base-devel-1-1
Total Installed Size: 216.44 MiB
:: Proceed with installation? [Y/n] y
(16/16) checking keys in keyring [#############################################################] 100%
(16/16) checking package integrity [#############################################################] 100%
(16/16) loading package files [#############################################################] 100%
(16/16) checking for file conflicts [#############################################################] 100%
error: failed to commit transaction (conflicting files)
fakeroot: /etc/ld.so.conf.d/fakeroot.conf exists in filesystem
Errors occurred, no packages were upgraded.
which can be resolved by adding --overwrite '*'
:
$ sudo pacman -S base-devel --overwrite '*'
:: There are 26 members in group base-devel:
:: Repository holo-rel
1) archlinux-keyring
:: Repository core-rel
2) autoconf 3) automake 4) binutils 5) bison 6) debugedit 7) fakeroot 8) file 9) findutils 10) flex 11) gawk 12) gcc 13) gettext 14) grep 15) groff
16) gzip 17) libtool 18) m4 19) make 20) pacman 21) patch 22) pkgconf 23) sed 24) sudo 25) texinfo 26) which
Enter a selection (default=all):
resolving dependencies...
looking for conflicting packages...
Packages (28) libisl-0.25-1 libmpc-1.2.1-2 archlinux-keyring-20221123-1.1 autoconf-2.71-1 automake-1.16.5-1 binutils-2.39-3 bison-3.8.2-4 debugedit-5.0-4
fakeroot-1.29-1 file-5.43-1 findutils-4.9.0-1 flex-2.6.4-3 gawk-5.2.0-3 gcc-12.2.0-1 gettext-0.21.1-1 grep-3.8-2 groff-1.22.4-7 gzip-1.12-1
libtool-2.4.7-5 m4-1.4.19-1 make-4.3-3 pacman-6.0.1-8 patch-2.7.6-8 pkgconf-1.8.0-1 sed-4.8-1 sudo-1.9.11.p3-1 texinfo-6.8-2 which-2.21-5
Total Installed Size: 275.34 MiB
Net Upgrade Size: 185.29 MiB
:: Proceed with installation? [Y/n] Y
(28/28) checking keys in keyring [###########################################################] 100%
(28/28) checking package integrity [###########################################################] 100%
(28/28) loading package files [###########################################################] 100%
(28/28) checking for file conflicts [###########################################################] 100%
(28/28) checking available disk space [###########################################################] 100%
warning: could not get file information for usr/include/
warning: could not get file information for usr/include/autosprintf.h
warning: could not get file information for usr/include/gettext-po.h
...
warning: could not get file information for usr/share/man/
warning: could not get file information for usr/share/man/man1/
warning: could not get file information for usr/share/man/man1/which.1.gz
:: Processing package changes...
( 1/28) reinstalling gettext [###########################################################] 100%
( 2/28) reinstalling gawk [###########################################################] 100%
( 3/28) reinstalling grep [###########################################################] 100%
( 4/28) reinstalling findutils [###########################################################] 100%
( 5/28) reinstalling pacman [###########################################################] 100%
( 6/28) reinstalling archlinux-keyring [###########################################################] 100%
==> Appending keys from archlinux.gpg...
==> Updating trust database...
gpg: next trustdb check due at 2023-07-12
==> Updating trust database...
gpg: next trustdb check due at 2023-07-12
( 7/28) installing m4 [###########################################################] 100%
( 8/28) installing autoconf [###########################################################] 100%
( 9/28) installing automake [###########################################################] 100%
(10/28) reinstalling binutils [###########################################################] 100%
(11/28) installing bison [###########################################################] 100%
(12/28) installing debugedit [###########################################################] 100%
(13/28) reinstalling sed [###########################################################] 100%
(14/28) reinstalling file [###########################################################] 100%
(15/28) installing fakeroot [###########################################################] 100%
(16/28) installing flex [###########################################################] 100%
(17/28) installing libmpc [###########################################################] 100%
(18/28) installing libisl [###########################################################] 100%
(19/28) installing gcc [###########################################################] 100%
Optional dependencies for gcc
lib32-gcc-libs: for generating code for 32-bit ABI [installed]
(20/28) reinstalling groff [###########################################################] 100%
(21/28) reinstalling gzip [###########################################################] 100%
(22/28) reinstalling libtool [###########################################################] 100%
(23/28) reinstalling texinfo [###########################################################] 100%
(24/28) installing make [###########################################################] 100%
(25/28) installing patch [###########################################################] 100%
Optional dependencies for patch
ed: for patch -e functionality
(26/28) reinstalling pkgconf [###########################################################] 100%
(27/28) reinstalling sudo [###########################################################] 100%
warning: directory permissions differ on /etc/sudoers.d/
filesystem: 755 package: 750
warning: directory permissions differ on /var/db/
filesystem: 711 package: 755
warning: directory permissions differ on /var/db/sudo/lectured/
filesystem: 711 package: 700
(28/28) reinstalling which [###########################################################] 100%
:: Running post-transaction hooks...
(1/4) Reloading system manager configuration...
(2/4) Creating temporary files...
/usr/lib/tmpfiles.d/steamos.conf:24: Duplicate line for path "/var/empty", ignoring.
/usr/lib/tmpfiles.d/tmp.conf:12: Duplicate line for path "/var/tmp", ignoring.
/usr/lib/tmpfiles.d/var.conf:19: Duplicate line for path "/var/cache", ignoring.
(3/4) Arming ConditionNeedsUpdate...
(4/4) Updating the info directory file...
$ echo $?
0
So everything got installed successfully:
$ which gcc
/usr/bin/gcc
$ gcc --version
gcc (GCC) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Don’t forget to enable read-only mode back:
$ sudo steamos-readonly enable
$ sudo steamos-readonly status
enabled
Now we can proceed with installing GCC for Homebrew:
$ brew postinstall gcc
==> Postinstalling gcc
==> Creating the GCC specs file: /home/linuxbrew/.linuxbrew/Cellar/gcc/12.2.0/bin/../lib/gcc/current/gcc/x86_64-pc-linux-gnu/12/specs
$ ls -l /home/linuxbrew/.linuxbrew/bin/{gcc*,g++*}
lrwxrwxrwx 1 deck deck 31 Jan 27 16:50 /home/linuxbrew/.linuxbrew/bin/g++-12 -> ../Cellar/gcc/12.2.0/bin/g++-12
lrwxrwxrwx 1 deck deck 31 Jan 27 16:50 /home/linuxbrew/.linuxbrew/bin/gcc-12 -> ../Cellar/gcc/12.2.0/bin/gcc-12
lrwxrwxrwx 1 deck deck 34 Jan 27 16:50 /home/linuxbrew/.linuxbrew/bin/gcc-ar-12 -> ../Cellar/gcc/12.2.0/bin/gcc-ar-12
lrwxrwxrwx 1 deck deck 34 Jan 27 16:50 /home/linuxbrew/.linuxbrew/bin/gcc-nm-12 -> ../Cellar/gcc/12.2.0/bin/gcc-nm-12
lrwxrwxrwx 1 deck deck 38 Jan 27 16:50 /home/linuxbrew/.linuxbrew/bin/gcc-ranlib-12 -> ../Cellar/gcc/12.2.0/bin/gcc-ranlib-12
$ which gcc-12
/home/linuxbrew/.linuxbrew/bin/gcc-12
$ gcc-12 --version
gcc-12 (Homebrew GCC 12.2.0) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
So these are the tools that Homebrew will (apparently) be using for building its stuff.
But let’s try to build a simple C++ program with either of compilers (the system one and the Homebrew’s one):
$ cd /tmp
$ nano ./some.cpp
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "ololo" << std::endl;
return EXIT_SUCCESS;
}
It will likely fail to compile like this:
$ g++ ./some.cpp -o some
In file included from /usr/include/c++/12.2.0/x86_64-pc-linux-gnu/bits/c++config.h:655,
from /usr/include/c++/12.2.0/iostream:38,
from ./some.cpp:1:
/usr/include/c++/12.2.0/x86_64-pc-linux-gnu/bits/os_defines.h:39:10: fatal error: features.h: No such file or directory
39 | #include <features.h>
| ^~~~~~~~~~~~
compilation terminated.
That is because glibc is missing in the system (why isn’t it included in base-devel
?). Do not install it with Homebrew, that should be done with pacman:
$ sudo steamos-readonly disable
$ sudo pacman -S glibc
$ sudo steamos-readonly enable
Try to compile again, and if it fails like this:
$ g++ ./some.cpp -o some
In file included from /usr/include/errno.h:28,
from /usr/include/c++/12.2.0/cerrno:42,
from /usr/include/c++/12.2.0/ext/string_conversions.h:44,
from /usr/include/c++/12.2.0/bits/basic_string.h:3960,
from /usr/include/c++/12.2.0/string:53,
from /usr/include/c++/12.2.0/bits/locale_classes.h:40,
from /usr/include/c++/12.2.0/bits/ios_base.h:41,
from /usr/include/c++/12.2.0/ios:42,
from /usr/include/c++/12.2.0/ostream:38,
from /usr/include/c++/12.2.0/iostream:39,
from ./some.cpp:1:
/usr/include/bits/errno.h:26:11: fatal error: linux/errno.h: No such file or directory
26 | # include <linux/errno.h>
| ^~~~~~~~~~~~~~~
compilation terminated.
then this time it is missing linux-api-headers, which you also need to install with pacman (again, why isn’t it included in base-devel
?):
$ sudo steamos-readonly disable
$ sudo pacman -S linux-api-headers
$ sudo steamos-readonly enable
Now it should compile without problems with both compilers:
$ which g++-12
/home/linuxbrew/.linuxbrew/bin/g++-12
$ g++-12 --version
g++-12 (Homebrew GCC 12.2.0) 12.2.0
$ g++-12 ./some.cpp -o some-gcc-homebrew
$ ./some-gcc-homebrew
ololo
$ which g++
/usr/bin/g++
$ g++ --version
g++ (GCC) 12.2.0
$ g++ ./some.cpp -o some-gcc-system
$ ./some-gcc-system
ololo
$ du -b ./some-gcc-*
21232 ./some-gcc-homebrew
21144 ./some-gcc-system
It’s interesting that even though the compilers versions are the same, resulting binaries differ in size.
Anyway, now it’s all finally sorted, but do remember that system GCC (and related packages) will likely get wiped once again on the next system update, so you will need to be install them with pacman again.
Building from sources
Now that you have Homebrew and GCC, you can install additional build tools (without contaminating the system environment), such as:
$ brew install cmake ninja
A simple application
For example, I can try to build my GLFW Dear ImGui sample application:
$ mkdir ~/code && cd $_
$ git clone git@github.com:retifrav/glfw-imgui-example.git
$ cd ./glfw-imgui-example/
This project has several dependencies, which I could install via Homebrew as well, but for resolving libraries dependencies it might be a better idea to use vcpkg instead, especially that vcpkg also is contained within the user home folder and does not “spam” to system environment.
But when I tried to configure the project, it will fail to find OpenGL:
...
CMake Error at /home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
Could NOT find OpenGL (missing: OPENGL_INCLUDE_DIR)
Call Stack (most recent call first):
/home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE)
/home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.1/share/cmake/Modules/FindOpenGL.cmake:443 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
CMakeLists.txt:71 (find_package)
So it says that a GNU/Linux based gaming OS does not have developer libraries for OpenGL. Well, I guess it wasn’t expected that someone will actually build something directly on Steam Deck. Okay, we can install it with Homebrew then:
$ brew install mesa
That will (should) also install libx11
dependency, which we’ll need in a moment.
Let’s now try to build the project:
$ cmake --preset vcpkg-default-triplet
But it will likely fail on resolving GLFW dependency:
...
-- Using X11 for window creation
CMake Error at /home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
Could NOT find X11 (missing: X11_X11_INCLUDE_PATH)
Call Stack (most recent call first):
/home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.1/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE)
/home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.1/share/cmake/Modules/FindX11.cmake:481 (find_package_handle_standard_args)
/home/deck/programs/vcpkg/scripts/buildsystems/vcpkg.cmake:852 (_find_package)
CMakeLists.txt:208 (find_package)
Here it says that it couldn’t find exactly the X11 library, which has been just installed together with Mesa.
It would be correct to assume that one needs to provide the Homebrew prefix path, so CMake could find the dependencies there, but in case of vcpkg it won’t be enough to just give it -DCMAKE_PREFIX_PATH="/home/linuxbrew/.linuxbrew"
, because it’s vcpkg who can’t find it, not the project. And I didn’t find a better way to resolve this but to edit ~/programs/vcpkg/scripts/buildsystems/vcpkg.cmake
and add this line to the end of the file:
list(APPEND CMAKE_PREFIX_PATH "/home/linuxbrew/.linuxbrew")
Now the project configuration succeeds:
$ cmake --preset vcpkg-default-triplet
Preset CMake variables:
CMAKE_BUILD_TYPE:STRING="Release"
CMAKE_INSTALL_PREFIX:PATH="/home/deck/code/glfw-imgui-example/install/vcpkg-default-triplet"
CMAKE_TOOLCHAIN_FILE:FILEPATH="/home/deck/programs/vcpkg/scripts/buildsystems/vcpkg.cmake"
USING_PACKAGE_MANAGER_VCPKG:BOOL="TRUE"
-- Running vcpkg install
Fetching registry information from git@github.com:retifrav/vcpkg-registry.git (HEAD)...
Detecting compiler hash for triplet x64-linux...
The following packages will be built and installed:
dear-imgui[backend-glfw,core]:x64-linux -> 1.88.0 -- /home/deck/.cache/vcpkg/registries/git-trees/fda742f0dd720fcd2af3cb8e946173069d70435f
* decovar-vcpkg-cmake[core]:x64-linux -> 2022-10-15 -- /home/deck/.cache/vcpkg/registries/git-trees/71a584c17648c10b4c515cfb980d644ce8486bbe
glad[core]:x64-linux -> 0.1.36 -- /home/deck/.cache/vcpkg/registries/git-trees/2341f5144ce8e76a256289517d61abb4ab9fb72c
glfw[core]:x64-linux -> 3.3.8 -- /home/deck/.cache/vcpkg/registries/git-trees/ff428db2871ef4e409c2ea9f29a866b63ba5b90b
* vcpkg-cmake[core]:x64-linux -> 2022-08-18 -- /home/deck/.cache/vcpkg/registries/git-trees/84c200e8e625d4d99b1649525fcdf81a73197078
* vcpkg-cmake-config[core]:x64-linux -> 2022-02-06 -- /home/deck/.cache/vcpkg/registries/git-trees/e23b39e21f0dd42ecc615262640d211c39696aa1
Additional packages (*) will be modified to complete this operation.
Restored 0 package(s) from /home/deck/.cache/vcpkg/archives in 50.7 us. Use --debug to see more details.
Installing 1/6 vcpkg-cmake-config:x64-linux...
Building vcpkg-cmake-config[core]:x64-linux...
-- Installing port from location: /home/deck/.cache/vcpkg/registries/git-trees/e23b39e21f0dd42ecc615262640d211c39696aa1
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake-config_x64-linux/share/vcpkg-cmake-config/vcpkg_cmake_config_fixup.cmake
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake-config_x64-linux/share/vcpkg-cmake-config/vcpkg-port-config.cmake
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake-config_x64-linux/share/vcpkg-cmake-config/copyright
-- Performing post-build validation
Stored binary cache: "/home/deck/.cache/vcpkg/archives/ca/ca9825c42848d6276fd7e99fcdba804bee900f94a2b30e25e8f7bf3b2112aeeb.zip"
Elapsed time to handle vcpkg-cmake-config:x64-linux: 44.1 ms
Installing 2/6 vcpkg-cmake:x64-linux...
Building vcpkg-cmake[core]:x64-linux...
-- Installing port from location: /home/deck/.cache/vcpkg/registries/git-trees/84c200e8e625d4d99b1649525fcdf81a73197078
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake_x64-linux/share/vcpkg-cmake/vcpkg_cmake_configure.cmake
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake_x64-linux/share/vcpkg-cmake/vcpkg_cmake_build.cmake
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake_x64-linux/share/vcpkg-cmake/vcpkg_cmake_install.cmake
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake_x64-linux/share/vcpkg-cmake/vcpkg-port-config.cmake
-- Installing: /home/deck/programs/vcpkg/packages/vcpkg-cmake_x64-linux/share/vcpkg-cmake/copyright
-- Performing post-build validation
Stored binary cache: "/home/deck/.cache/vcpkg/archives/f1/f1cf145f5b84d9cc4327ee8e27c01cd269058869ec23bf3040cb3db9d31cae88.zip"
Elapsed time to handle vcpkg-cmake:x64-linux: 48.8 ms
Installing 3/6 decovar-vcpkg-cmake:x64-linux...
Building decovar-vcpkg-cmake[core]:x64-linux...
-- Installing port from location: /home/deck/.cache/vcpkg/registries/git-trees/71a584c17648c10b4c515cfb980d644ce8486bbe
-- Installing: /home/deck/programs/vcpkg/packages/decovar-vcpkg-cmake_x64-linux/share/decovar-vcpkg-cmake/Installing.cmake
-- Installing: /home/deck/programs/vcpkg/packages/decovar-vcpkg-cmake_x64-linux/share/decovar-vcpkg-cmake/Config.cmake.in
-- Installing: /home/deck/programs/vcpkg/packages/decovar-vcpkg-cmake_x64-linux/share/decovar-vcpkg-cmake/decovar_vcpkg_cmake_ololo.cmake
-- Installing: /home/deck/programs/vcpkg/packages/decovar-vcpkg-cmake_x64-linux/share/decovar-vcpkg-cmake/vcpkg-port-config.cmake
-- Installing: /home/deck/programs/vcpkg/packages/decovar-vcpkg-cmake_x64-linux/share/decovar-vcpkg-cmake/copyright
-- Performing post-build validation
Stored binary cache: "/home/deck/.cache/vcpkg/archives/5b/5bc820e411604043dfd9f73645b718b9860cfac802616fee91c12360a7174690.zip"
Elapsed time to handle decovar-vcpkg-cmake:x64-linux: 48 ms
Installing 4/6 glfw:x64-linux...
Building glfw[core]:x64-linux...
-- Installing port from location: /home/deck/.cache/vcpkg/registries/git-trees/ff428db2871ef4e409c2ea9f29a866b63ba5b90b
-- Using cached /home/deck/programs/vcpkg/downloads/glfw-7482de6071d21db77a7236155da44c172a7f6c9e.tar.gz
-- Cleaning sources at /home/deck/programs/vcpkg/buildtrees/glfw/src/172a7f6c9e-ac9aaa482e.clean. Use --editable to skip cleaning for the packages you specify.
-- Extracting source /home/deck/programs/vcpkg/downloads/glfw-7482de6071d21db77a7236155da44c172a7f6c9e.tar.gz
-- Applying patch disable-pkgconfig.patch
-- Using source at /home/deck/programs/vcpkg/buildtrees/glfw/src/172a7f6c9e-ac9aaa482e.clean
-- Found external ninja('1.11.1').
-- Configuring x64-linux
-- Building x64-linux-dbg
-- Building x64-linux-rel
-- Installing: /home/deck/programs/vcpkg/packages/glfw_x64-linux/share/glfw/copyright
-- Performing post-build validation
Stored binary cache: "/home/deck/.cache/vcpkg/archives/6a/6a6b5672bee1fb07fe9454ba0dd6d2cf991d154131a14e7cdad4ad0fe3e5217f.zip"
Elapsed time to handle glfw:x64-linux: 3 s
Installing 5/6 dear-imgui:x64-linux...
Building dear-imgui[backend-glfw,core]:x64-linux...
-- Installing port from location: /home/deck/.cache/vcpkg/registries/git-trees/fda742f0dd720fcd2af3cb8e946173069d70435f
-- Using cached /home/deck/programs/vcpkg/downloads/dear-imgui-9aae45eb4a05a5a1f96be1ef37eb503a12ceb889.tar.gz
-- Cleaning sources at /home/deck/programs/vcpkg/buildtrees/dear-imgui/src/3a12ceb889-c011915ee6.clean. Use --editable to skip cleaning for the packages you specify.
-- Extracting source /home/deck/programs/vcpkg/downloads/dear-imgui-9aae45eb4a05a5a1f96be1ef37eb503a12ceb889.tar.gz
-- Using source at /home/deck/programs/vcpkg/buildtrees/dear-imgui/src/3a12ceb889-c011915ee6.clean
-- Found external ninja('1.11.1').
-- Configuring x64-linux
-- Building x64-linux-dbg
-- Building x64-linux-rel
-- Installing: /home/deck/programs/vcpkg/packages/dear-imgui_x64-linux/share/dear-imgui/copyright
-- ololo
-- Performing post-build validation
Stored binary cache: "/home/deck/.cache/vcpkg/archives/91/919da7bde86d29184e2fad379ef3b8064542bf1390ff6113090a11f7d8e32502.zip"
Elapsed time to handle dear-imgui:x64-linux: 11 s
Installing 6/6 glad:x64-linux...
Building glad[core]:x64-linux...
-- Installing port from location: /home/deck/.cache/vcpkg/registries/git-trees/2341f5144ce8e76a256289517d61abb4ab9fb72c
-- Using cached /home/deck/programs/vcpkg/downloads/glad-1ecd45775d96f35170458e6b148eb0708967e402.tar.gz
-- Cleaning sources at /home/deck/programs/vcpkg/buildtrees/glad/src/708967e402-a791cb9077.clean. Use --editable to skip cleaning for the packages you specify.
-- Extracting source /home/deck/programs/vcpkg/downloads/glad-1ecd45775d96f35170458e6b148eb0708967e402.tar.gz
-- Using source at /home/deck/programs/vcpkg/buildtrees/glad/src/708967e402-a791cb9077.clean
-- Found external ninja('1.11.1').
-- Configuring x64-linux
-- Building x64-linux-dbg
-- Building x64-linux-rel
-- Installing: /home/deck/programs/vcpkg/packages/glad_x64-linux/share/glad/copyright
-- Performing post-build validation
Stored binary cache: "/home/deck/.cache/vcpkg/archives/8b/8ba6bfc9ece2fd756e5818f78d2bd968ec282e85b520deddca37beaa17b3cc3b.zip"
Elapsed time to handle glad:x64-linux: 3.2 s
Total install time: 17 s
glfw provides CMake targets:
# this is heuristically generated, and may not be correct
find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(main PRIVATE glfw)
dear-imgui provides CMake targets:
# this is heuristically generated, and may not be correct
find_package(DearImGui CONFIG REQUIRED)
target_link_libraries(main PRIVATE DearImGui)
glad provides CMake targets:
# this is heuristically generated, and may not be correct
find_package(glad CONFIG REQUIRED)
target_link_libraries(main PRIVATE glad::glad)
-- Running vcpkg install - done
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found OpenGL: /usr/lib/libOpenGL.so
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Found X11: /home/linuxbrew/.linuxbrew/include
-- Looking for XOpenDisplay in /home/linuxbrew/.linuxbrew/lib/libX11.so;/home/linuxbrew/.linuxbrew/lib/libXext.so
-- Looking for XOpenDisplay in /home/linuxbrew/.linuxbrew/lib/libX11.so;/home/linuxbrew/.linuxbrew/lib/libXext.so - found
-- Looking for gethostbyname
-- Looking for gethostbyname - found
-- Looking for connect
-- Looking for connect - found
-- Looking for remove
-- Looking for remove - found
-- Looking for shmat
-- Looking for shmat - found
-- Looking for IceConnectionNumber in ICE
-- Looking for IceConnectionNumber in ICE - found
-- Configuring done (21.2s)
-- Generating done (0.0s)
-- Build files have been written to: /home/deck/code/glfw-imgui-example/build/vcpkg-default-triplet
Interesting that according to this output it has found system OpenGL (/usr/lib/libOpenGL.so
), while not that long ago it was complaining that it can’t find one, and I needed to install Mesa with Homebrew. So which one is used/needed then?
Anyway, the project can finally build and run:
$ cmake --build --preset vcpkg-default-triplet
$ ./install/vcpkg-default-triplet/bin/glfw-imgui/glfw-imgui
And here it goes:
The 717
window height apparently reports the canvas height without the height of window decoration bar on top (which leaves it 83
pixels then).
The Qt Framework
Of course, let’s build Qt! First of all, because we can, but also to see how good Steam Deck hardware is for compiling really big projects.
Some information about the build environment:
- Qt 6.5.1 sources;
- Homebrew environment is activated (to find CMake and Ninja executables, although
CMAKE_PREFIX_PATH
still needs to be set, as you’ll see in a second); VCPKG_ROOT
environment variable is unset (just in case, as Qt seems to be using it for some purposes when it is set).
And here we go:
$ pwd
/home/deck/programs/qt/src/6.5.1/build
$ ../configure -static -release -no-pch \
-prefix "/home/deck/programs/qt/6.5.1-static" \
-skip qtwebengine -nomake tests -nomake examples \
-- \
-DCMAKE_PREFIX_PATH="/home/linuxbrew/.linuxbrew"
Without pointing it to Homebrew prefix in CMAKE_PREFIX_PATH
the configuration will fail to even find OpenGL. With the prefix set, however, I almost immediately got another error:
CMake Error at /home/linuxbrew/.linuxbrew/lib/cmake/zstd/zstdTargets.cmake:42 (message):
Some (but not all) targets in this export set were already defined.
Targets Defined: zstd::libzstd_static
Targets not yet defined: zstd::libzstd_shared
From what I understood, what’s wrong is that in /home/linuxbrew/.linuxbrew/lib/cmake/zstd/zstdTargets.cmake
there is this line:
foreach(_cmake_expected_target IN ITEMS zstd::libzstd_shared zstd::libzstd_static)
And that is somehow problematic for static Qt (because dynamic Qt configured and built fine without complaining about zstd). So I just removed zstd::libzstd_shared
from that foreach()
, leaving only zstd::libzstd_static
.
That did help once, but later at some point, probably after one of the system or/and Homebrew or/and Qt updates, the configuration started to fail like this:
Qt is now configured for building. Just run 'cmake --build . --parallel'
Once everything is built, you must run 'cmake --install .'
Qt will be installed into '/home/deck/programs/qt/6.6.2-static'
To configure and build other Qt modules, you can use the following convenience script:
/home/deck/programs/qt/6.6.2-static/bin/qt-configure-module
If reconfiguration fails for some reason, try removing 'CMakeCache.txt' from the build directory
Alternatively, you can add the --fresh flag to your CMake flags.
-- Configuring incomplete, errors occurred!
CMake Error at /home/deck/programs/qt/src/6.6.2/qtbase/cmake/QtProcessConfigureArgs.cmake:1040 (message):
CMake exited with code 1.
As you can see, even though it says “Qt is now configured for building” and prints the usual build commands, in the very end it says that there was some unspecified CMake error. And the line 1040
in QtProcessConfigureArgs.cmake
isn’t particularly helpful either:
1039 if(NOT exit_code EQUAL 0)
1040 message(FATAL_ERROR "CMake exited with code ${exit_code}.")
1041 endif()
Only having scrolled up the configuration output I saw the actual errors:
-- Configuring submodule 'qtimageformats'
-- Found the following ICU libraries:
-- i18n (required): /home/linuxbrew/.linuxbrew/lib/libicui18n.so
-- uc (required): /home/linuxbrew/.linuxbrew/lib/libicuuc.so
-- data (required): /home/linuxbrew/.linuxbrew/lib/libicudata.so
CMake Error at /home/linuxbrew/.linuxbrew/lib/cmake/zstd/zstdTargets.cmake:60 (add_library):
add_library cannot create imported target "zstd::libzstd_shared" because
another target with the same name already exists.
Call Stack (most recent call first):
/home/linuxbrew/.linuxbrew/lib/cmake/zstd/zstdConfig.cmake:1 (include)
qtbase/cmake/FindWrapZSTD.cmake:24 (find_package)
/home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.3/share/cmake/Modules/CMakeFindDependencyMacro.cmake:76 (find_package)
qtbase/cmake/QtPublicDependencyHelpers.cmake:36 (find_dependency)
build/qtbase/lib/cmake/Qt6Core/Qt6CoreDependencies.cmake:30 (_qt_internal_find_third_party_dependencies)
build/qtbase/lib/cmake/Qt6Core/Qt6CoreConfig.cmake:41 (include)
build/qtbase/lib/cmake/Qt6/Qt6Config.cmake:164 (find_package)
qtimageformats/CMakeLists.txt:14 (find_package)
So the trick with removing zstd::libzstd_shared
target from foreach()
apparently wasn’t enough anymore(?), and I also had to comment that target out in /home/linuxbrew/.linuxbrew/lib/cmake/zstd/zstdTargets.cmake
:
# Create imported target zstd::libzstd_shared
#add_library(zstd::libzstd_shared SHARED IMPORTED)
#
#set_target_properties(zstd::libzstd_shared PROPERTIES
# INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
#)
and in /home/linuxbrew/.linuxbrew/lib/cmake/zstd/zstdTargets-release.cmake
:
# Import target "zstd::libzstd_shared" for configuration "Release"
#set_property(TARGET zstd::libzstd_shared APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
#set_target_properties(zstd::libzstd_shared PROPERTIES
# IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libzstd.so.1.5.5"
# IMPORTED_SONAME_RELEASE "libzstd.so.1"
# )
#
#list(APPEND _cmake_import_check_targets zstd::libzstd_shared )
#list(APPEND _cmake_import_check_files_for_zstd::libzstd_shared "${_IMPORT_PREFIX}/lib/libzstd.so.1.5.5" )
Which is most certainly not a great idea, as these files aren’t meant to be modified. And I really can’t tell where this problem actually needs to be “fixed”: on Qt side (in FindWrapZSTD.cmake
?) or in the Homebrew’s formula/recipe. By the way, the current package in AUR has this the other way around - with zstd::libzstd_shared
and without zstd::libzstd_static
.
Either way, after I left only the zstd::libzstd_static
target, Qt was able to configure without complaining about zstd. If anything, after the build is done, you should probably revert these changes in zstd CMake configs.
Related to that, there is this bugreport and this commit, which apparently isn’t part of Qt 6.5.1 as of now, but eventually it probably will appear in one of the next versions. It won’t resolve the problem still, but it will make you delete zstd::libzstd_static
instead of zstd::libzstd_shared
, which means that you’ll end up with zstd being a shared/dynamic library dependency of your Qt build (or you can modify Qt’s FindWrapZSTD.cmake
to make static zstd to be the preferred option again).
But okay, zstd is sorted, Qt has successfully configured, so it can be built now:
$ time cmake --build . --parallel
But very soon building failed with this error:
/home/deck/programs/qt/src/6.5.1/qtgrpc/src/tools/qtprotoccommon/generatorbase.h:8:10: fatal error: google/protobuf/compiler/code_generator.h: No such file or directory
8 | #include <google/protobuf/compiler/code_generator.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Fortunately, this is just a missing dependency, which can be installed with Homebrew:
$ brew install protobuf
After that it built some more, but then failed with another problem:
/home/deck/programs/qt/src/6.5.1/qtbase/src/corelib/text/qdoublescanprint_p.h:115:14: fatal error: double-conversion/double-conversion.h: No such file or directory
115 | # include <double-conversion/double-conversion.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
This one is strange, because Qt sources do contain this library in /home/deck/programs/qt/src/6.5.1/qtbase/src/3rdparty/double-conversion/
. But okay, this one also can be installed with Homebrew:
$ brew install double-conversion
That helped for a while, but then the build failed with another one:
/home/deck/programs/qt/src/6.5.1/qtbase/src/gui/text/qtextmarkdownimporter.cpp:16:10: fatal error: md4c.h: No such file or directory
16 | #include <md4c.h>
| ^~~~~~~~
compilation terminated.
And again, Qt sources do have this library in /home/deck/programs/qt/src/6.5.1/qtbase/src/3rdparty/md4c/
, so what’s going on then? But alright, Homebrew has this one too:
$ brew install md4c
After that the build was going fine for quite some time, but then still failed with another problem:
FAILED: qtbase/plugins/multimedia/libgstreamermediaplugin.so
/usr/bin/ld: cannot find -lgstphotography-1.0: No such file or directory
collect2: error: ld returned 1 exit status
So it says that it’s missing a GStreamer plugin called photography
, which I indeed didn’t have:
$ gst-inspect-1.0 photography
No such element or plugin 'photography'
It is a part of a package called gst-plugins-bad
, so I installed this one:
$ brew install gst-plugins-bad
But surprisingly the build still failed (even after removing everything from the build folder and re-configuring Qt). Then I realized that Qt actually doesn’t need GStreamer anymore - starting from Qt 6.5.1 the default multimedia backend is FFmpeg. So I just uninstalled GStreamer:
$ brew uninstall gstreamer
and re-configured Qt. This time it didn’t discover GStreamer and didn’t enable related features. And then the build finally succeeded, and I could install Qt:
$ cmake --install .
To verify that it’s a proper working build, I tried to use it to compile an application (my world-famous Color Corners):
$ cd ~/code
$ git clone git@github.com:retifrav/color-corners.git
$ cd ./color-corners
$ mkdir build && cd $_
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="/home/deck/programs/qt/6.5.1-static" \
..
…but it failed, although with a harmless error first:
CMake Warning at /home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6/Qt6Config.cmake:157 (find_package):
Found package configuration file:
/home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6Core/Qt6CoreConfig.cmake
but it set Qt6Core_FOUND to FALSE so package "Qt6Core" is considered to be
NOT FOUND. Reason given by package:
Qt6Core could not be found because dependency WrapZLIB could not be found.
or, in case of a shared Qt build:
CMake Warning at /home/linuxbrew/.linuxbrew/Cellar/cmake/3.26.2/share/cmake/Modules/CMakeFindDependencyMacro.cmake:76 (find_package):
Found package configuration file:
/home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6Gui/Qt6GuiConfig.cmake
but it set Qt6Gui_FOUND to FALSE so package "Qt6Gui" is considered to be
NOT FOUND. Reason given by package:
Qt6Gui could not be found because dependency WrapOpenGL could not be found.
That is because the path to Homebrew prefix needs to be provided too:
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="/home/linuxbrew/.linuxbrew;/home/deck/programs/qt/6.5.1-static" \
..
Then the project configures further, but shortly after either fails like this (if it is a static Qt):
/home/deck/programs/qt/6.5.1-static/./libexec/qmlimportscanner: error while loading shared libraries: libb2.so.1: cannot open shared object file: No such file or directory
CMake Error at /home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6Qml/Qt6QmlMacros.cmake:2837 (message):
Failed to scan target color-corners for QML imports: 127
Call Stack (most recent call first):
/home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6Qml/Qt6QmlMacros.cmake:2872 (_qt_internal_scan_qml_imports)
/home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6Qml/Qt6QmlMacros.cmake:2944 (qt6_import_qml_plugins)
CMakeLists.txt:159 (qt_import_qml_plugins)
or configures fine but fails to build (if it is a shared Qt):
$ cmake --build .
[1/7] Running qmlimportscanner for color-corners
FAILED: .qt_plugins/Qt6_QmlPlugins_Imports_color-corners.cmake /home/deck/code/color-corners/build/.qt_plugins/Qt6_QmlPlugins_Imports_color-corners.cmake
cd /home/deck/code/color-corners && /home/deck/programs/qt/6.5.1/./libexec/qmlimportscanner @/home/deck/code/color-corners/build/.qt_plugins/Qt6_QmlPlugins_Imports_color-corners.rsp
/home/deck/programs/qt/6.5.1/./libexec/qmlimportscanner: error while loading shared libraries: libicui18n.so.72: cannot open shared object file: No such file or directory
ninja: build stopped: subcommand failed.
This is because one also needs to provide path (in LD_LIBRARY_PATH
) to shared libraries that are required for Qt tools (such as qmlimportscanner
) on project configuration:
$ LD_LIBRARY_PATH="/home/linuxbrew/.linuxbrew/lib" cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="/home/linuxbrew/.linuxbrew;/home/deck/programs/qt/6.5.1-static" \
..
or for building:
$ LD_LIBRARY_PATH="/home/linuxbrew/.linuxbrew/lib" cmake --build .
Then I was able to build my application, but it failed to run:
$ ./color-corners
qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in ""
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: wayland, wayland-egl, eglfs, minimal, vnc, offscreen, linuxfb, minimalegl.
If I paid attention to the Qt configuration output, I would have noticed that XCB backend feature wasn’t enabled. Fortunately, this is again just a matter of installing missing dependencies, which in case of Homebrew are these:
$ brew install xcb-util xcb-util-image xcb-util-renderutil xcb-proto xcb-util-cursor xcb-util-keysyms xcb-util-wm \
libxinerama libxi libxkbcommon libxrandr libxrender libxt libxv \
mesa mesa-glu \
xinput xorgproto
…even though all of these (and some more) were already available in system’s /usr/lib/
, but for some reason aren’t picked up, so one needs to install them via Homebrew. I am actually not sure if all of these are needed, plus there might be more that are required, so just in case here’s a full list of Homebrew packages that I had installed back then.
Anyway, after that Qt configuration successfully discovered XCB:
Qt Gui:
Accessibility .......................... yes
FreeType ............................... yes
Using system FreeType ................ yes
HarfBuzz ............................... yes
Using system HarfBuzz ................ yes
Fontconfig ............................. yes
Image formats:
GIF .................................. yes
ICO .................................. yes
JPEG ................................. yes
Using system libjpeg ............... yes
PNG .................................. yes
Using system libpng ................ yes
Text formats:
HtmlParser ........................... yes
CssParser ............................ yes
OdfWriter ............................ yes
MarkdownReader ....................... yes
Using system libmd4c ............... yes
MarkdownWriter ....................... yes
EGL .................................... yes
OpenVG ................................. no
OpenGL:
Desktop OpenGL ....................... yes
OpenGL ES 2.0 ........................ no
OpenGL ES 3.0 ........................ no
OpenGL ES 3.1 ........................ no
OpenGL ES 3.2 ........................ no
Vulkan ................................. yes
Session Management ..................... yes
Features used by QPA backends:
evdev .................................. yes
libinput ............................... no
HiRes wheel support in libinput ........ no
INTEGRITY HID .......................... no
mtdev .................................. no
tslib .................................. no
xkbcommon .............................. yes
X11 specific:
XLib ................................. yes
XCB Xlib ............................. yes
EGL on X11 ........................... yes
xkbcommon-x11 ........................ yes
xcb-sm ............................... yes
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 ...................... yes
EGLFS GBM ............................ yes
EGLFS VSP2 ........................... no
EGLFS Mali ........................... no
EGLFS Raspberry Pi ................... no
EGLFS X11 ............................ yes
LinuxFB ................................ yes
VNC .................................... yes
VK_KHR_display ......................... yes
QNX:
lgmon ................................ no
IMF .................................. no
XCB:
Using system-provided xcb-xinput ..... no
GL integrations:
GLX Plugin ......................... yes
XCB GLX .......................... yes
EGL-X11 Plugin ..................... yes
Before that the xcb-sm
feature was set to no
, and XCB
section in QPA backends
also had no
on all items.
Having re-built Qt again, I finally got the XCB plugin built too:
$ ls -L1 /home/deck/programs/qt/6.5.1-static/plugins/platforms/*.a
libqeglfs.a
libqlinuxfb.a
libqminimal.a
libqminimalegl.a
libqoffscreen.a
libqvkkhrdisplay.a
libqvnc.a
libqwayland-egl.a
libqwayland-generic.a
libqxcb.a
And then the application built and ran just fine:
What’s a bit weird is the amount of dependencies reported by ldd
:
$ ldd ./color-corners
linux-vdso.so.1 (0x00007ffc5fb30000)
libSM.so.6 => /home/linuxbrew/.linuxbrew/lib/libSM.so.6 (0x00007f2ab197d000)
libICE.so.6 => /home/linuxbrew/.linuxbrew/lib/libICE.so.6 (0x00007f2ab195b000)
libX11.so.6 => /home/linuxbrew/.linuxbrew/lib/libX11.so.6 (0x00007f2ab1838000)
libXext.so.6 => /home/linuxbrew/.linuxbrew/lib/libXext.so.6 (0x00007f2ab1821000)
libdrm.so.2 => /home/linuxbrew/.linuxbrew/lib/libdrm.so.2 (0x00007f2ab1805000)
libgbm.so.1 => /home/linuxbrew/.linuxbrew/lib/libgbm.so.1 (0x00007f2ab17f2000)
libjpeg.so.8 => /home/linuxbrew/.linuxbrew/lib/libjpeg.so.8 (0x00007f2ab1747000)
libtiff.so.6 => /home/linuxbrew/.linuxbrew/lib/libtiff.so.6 (0x00007f2ab16be000)
libwebpdemux.so.2 => /home/linuxbrew/.linuxbrew/lib/libwebpdemux.so.2 (0x00007f2ab16b6000)
libwebpmux.so.3 => /home/linuxbrew/.linuxbrew/lib/libwebpmux.so.3 (0x00007f2ab16a8000)
libwebp.so.7 => /home/linuxbrew/.linuxbrew/lib/libwebp.so.7 (0x00007f2ab15ff000)
libsharpyuv.so.0 => /home/linuxbrew/.linuxbrew/lib/libsharpyuv.so.0 (0x00007f2ab15f4000)
libxcb-glx.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-glx.so.0 (0x00007f2ab15d1000)
libX11-xcb.so.1 => /home/linuxbrew/.linuxbrew/lib/libX11-xcb.so.1 (0x00007f2ab15cb000)
libxkbcommon-x11.so.0 => /home/linuxbrew/.linuxbrew/lib/libxkbcommon-x11.so.0 (0x00007f2ab15be000)
libxkbcommon.so.0 => /home/linuxbrew/.linuxbrew/lib/libxkbcommon.so.0 (0x00007f2ab1575000)
libxcb-cursor.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-cursor.so.0 (0x00007f2ab156b000)
libxcb-icccm.so.4 => /home/linuxbrew/.linuxbrew/lib/libxcb-icccm.so.4 (0x00007f2ab1561000)
libxcb-image.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-image.so.0 (0x00007f2ab1559000)
libxcb-keysyms.so.1 => /home/linuxbrew/.linuxbrew/lib/libxcb-keysyms.so.1 (0x00007f2ab1553000)
libxcb-randr.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-randr.so.0 (0x00007f2ab153c000)
libxcb-render-util.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-render-util.so.0 (0x00007f2ab1534000)
libxcb-shm.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-shm.so.0 (0x00007f2ab152c000)
libxcb-sync.so.1 => /home/linuxbrew/.linuxbrew/lib/libxcb-sync.so.1 (0x00007f2ab1521000)
libxcb-xfixes.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-xfixes.so.0 (0x00007f2ab1515000)
libxcb-render.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-render.so.0 (0x00007f2ab1503000)
libxcb-shape.so.0 => /home/linuxbrew/.linuxbrew/lib/libxcb-shape.so.0 (0x00007f2ab14fc000)
libxcb-xkb.so.1 => /home/linuxbrew/.linuxbrew/lib/libxcb-xkb.so.1 (0x00007f2ab14d8000)
libxcb.so.1 => /home/linuxbrew/.linuxbrew/lib/libxcb.so.1 (0x00007f2ab14a5000)
libEGL.so.1 => /home/linuxbrew/.linuxbrew/lib/libEGL.so.1 (0x00007f2ab145a000)
libGLX.so.0 => /usr/lib/libGLX.so.0 (0x00007f2ab140a000)
libOpenGL.so.0 => /usr/lib/libOpenGL.so.0 (0x00007f2ab13df000)
libpng16.so.16 => /home/linuxbrew/.linuxbrew/lib/libpng16.so.16 (0x00007f2ab13a6000)
libharfbuzz.so.0 => /home/linuxbrew/.linuxbrew/lib/libharfbuzz.so.0 (0x00007f2ab127e000)
libmd4c.so.0 => /home/linuxbrew/.linuxbrew/lib/libmd4c.so.0 (0x00007f2ab1000000)
libfreetype.so.6 => /home/linuxbrew/.linuxbrew/lib/libfreetype.so.6 (0x00007f2ab0f46000)
libfontconfig.so.1 => /home/linuxbrew/.linuxbrew/lib/libfontconfig.so.1 (0x00007f2ab122d000)
libgobject-2.0.so.0 => /home/linuxbrew/.linuxbrew/lib/libgobject-2.0.so.0 (0x00007f2ab0edb000)
libgio-2.0.so.0 => /home/linuxbrew/.linuxbrew/lib/libgio-2.0.so.0 (0x00007f2ab0cc8000)
libdbus-1.so.3 => /home/linuxbrew/.linuxbrew/lib/libdbus-1.so.3 (0x00007f2ab0c69000)
libz.so.1 => /home/linuxbrew/.linuxbrew/lib/libz.so.1 (0x00007f2ab0c4e000)
libdouble-conversion.so.3 => /home/linuxbrew/.linuxbrew/lib/libdouble-conversion.so.3 (0x00007f2ab1217000)
libb2.so.1 => /home/linuxbrew/.linuxbrew/lib/libb2.so.1 (0x00007f2ab0a00000)
libicui18n.so.72 => /home/linuxbrew/.linuxbrew/lib/libicui18n.so.72 (0x00007f2ab0639000)
libicuuc.so.72 => /home/linuxbrew/.linuxbrew/lib/libicuuc.so.72 (0x00007f2ab0409000)
libicudata.so.72 => /home/linuxbrew/.linuxbrew/lib/libicudata.so.72 (0x00007f2aae638000)
libpcre2-16.so.0 => /home/linuxbrew/.linuxbrew/lib/libpcre2-16.so.0 (0x00007f2aae5a7000)
libglib-2.0.so.0 => /home/linuxbrew/.linuxbrew/lib/libglib-2.0.so.0 (0x00007f2aae44d000)
libgthread-2.0.so.0 => /home/linuxbrew/.linuxbrew/lib/libgthread-2.0.so.0 (0x00007f2ab0c48000)
libbrotlidec.so.1 => /home/linuxbrew/.linuxbrew/lib/libbrotlidec.so.1 (0x00007f2aae200000)
libgssapi_krb5.so.2 => /home/linuxbrew/.linuxbrew/lib/libgssapi_krb5.so.2 (0x00007f2aae1a9000)
libstdc++.so.6 => /home/linuxbrew/.linuxbrew/lib/libstdc++.so.6 (0x00007f2aadef3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f2aade0b000)
libgcc_s.so.1 => /home/linuxbrew/.linuxbrew/lib/libgcc_s.so.1 (0x00007f2ab0c21000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f2aadc24000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f2ab3399000)
libwayland-server.so.0 => /home/linuxbrew/.linuxbrew/opt/wayland/lib/libwayland-server.so.0 (0x00007f2aae433000)
libexpat.so.1 => /home/linuxbrew/.linuxbrew/opt/expat/lib/libexpat.so.1 (0x00007f2aadbf2000)
libzstd.so.1 => /home/linuxbrew/.linuxbrew/opt/zstd/lib/libzstd.so.1 (0x00007f2aadadf000)
libxcb-util.so.1 => /home/linuxbrew/.linuxbrew/opt/xcb-util/lib/libxcb-util.so.1 (0x00007f2aae429000)
libXau.so.6 => /home/linuxbrew/.linuxbrew/opt/libxau/lib/libXau.so.6 (0x00007f2aae420000)
libXdmcp.so.6 => /home/linuxbrew/.linuxbrew/opt/libxdmcp/lib/libXdmcp.so.6 (0x00007f2aae417000)
libglapi.so.0 => /home/linuxbrew/.linuxbrew/Cellar/mesa/22.3.6_1/lib/libglapi.so.0 (0x00007f2aadaa3000)
libxcb-dri2.so.0 => /home/linuxbrew/.linuxbrew/opt/libxcb/lib/libxcb-dri2.so.0 (0x00007f2aae40f000)
libwayland-client.so.0 => /home/linuxbrew/.linuxbrew/opt/wayland/lib/libwayland-client.so.0 (0x00007f2aada8d000)
libxcb-dri3.so.0 => /home/linuxbrew/.linuxbrew/opt/libxcb/lib/libxcb-dri3.so.0 (0x00007f2aada85000)
libxcb-present.so.0 => /home/linuxbrew/.linuxbrew/opt/libxcb/lib/libxcb-present.so.0 (0x00007f2aada7f000)
libxshmfence.so.1 => /home/linuxbrew/.linuxbrew/opt/libxshmfence/lib/libxshmfence.so.1 (0x00007f2aada79000)
libGLdispatch.so.0 => /usr/lib/libGLdispatch.so.0 (0x00007f2aad9c1000)
libgraphite2.so.3 => /home/linuxbrew/.linuxbrew/opt/graphite2/lib/libgraphite2.so.3 (0x00007f2aad600000)
libbz2.so.1.0 => /home/linuxbrew/.linuxbrew/opt/bzip2/lib/libbz2.so.1.0 (0x00007f2aad9a9000)
libffi.so.8 => /home/linuxbrew/.linuxbrew/opt/libffi/lib/libffi.so.8 (0x00007f2aad998000)
libgmodule-2.0.so.0 => /home/linuxbrew/.linuxbrew/Cellar/glib/2.74.6/lib/libgmodule-2.0.so.0 (0x00007f2aad990000)
libmount.so.1 => /home/linuxbrew/.linuxbrew/opt/util-linux/lib/libmount.so.1 (0x00007f2aad926000)
libgomp.so.1 => /home/linuxbrew/.linuxbrew/lib/libgomp.so.1 (0x00007f2aad8d1000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f2aad8cc000)
libpcre2-8.so.0 => /home/linuxbrew/.linuxbrew/opt/pcre2/lib/libpcre2-8.so.0 (0x00007f2aad82d000)
libbrotlicommon.so.1 => /home/linuxbrew/.linuxbrew/Cellar/brotli/1.0.9/lib/libbrotlicommon.so.1 (0x00007f2aad200000)
libkrb5.so.3 => /home/linuxbrew/.linuxbrew/Cellar/krb5/1.20.1/lib/libkrb5.so.3 (0x00007f2aad51f000)
libk5crypto.so.3 => /home/linuxbrew/.linuxbrew/Cellar/krb5/1.20.1/lib/libk5crypto.so.3 (0x00007f2aad4ee000)
libcom_err.so.3 => /home/linuxbrew/.linuxbrew/Cellar/krb5/1.20.1/lib/libcom_err.so.3 (0x00007f2aad4e7000)
libkrb5support.so.0 => /home/linuxbrew/.linuxbrew/Cellar/krb5/1.20.1/lib/libkrb5support.so.0 (0x00007f2aad4d6000)
libblkid.so.1 => /home/linuxbrew/.linuxbrew/Cellar/util-linux/2.38.1/lib/libblkid.so.1 (0x00007f2aad47a000)
libresolv.so.2 => /usr/lib/libresolv.so.2 (0x00007f2aad468000)
But I guess that’s okay, especially that there is no Qt in the list, as I linked against static build.
Build times
Out of curiosity I’ve built the same static Qt 6.5.1 configuration on several other hosts that I have, and here are the build times for each (from fastest to slowest):
Device | OS | CPU | Cores | Time (minutes) | |
---|---|---|---|---|---|
1 | MacBook Pro | Mac OS 13.6 | Apple M2 Pro | 12 | 12 |
2 | Office desktop PC | Windows 10 | Intel Core i9-9900K | 8/16 | 30 |
3 | MacBook Pro | Mac OS 13.4 | Intel Core i7-8850H | 6/12 | 40 |
4 | Steam Deck | SteamOS 3.4.6 | AMD Zen 2 | 4/8 | 75 |
5 | Laptop | Ubuntu 22.04 | Intel Core i7-4710MQ | 4/8 | 87 |
6 | Home desktop PC | Windows 11 | Intel Core i5-4670k | 4/4 | 108 |
Quite not bad, is it. Especially considering the price of each device (Steam Deck is the cheapest).
The temperature reported by sensors
during all 75 minutes of the build time was on a level of 84°C with rare spikes to 88°C.
It would also be interesting to measure how fast the battery goes from 100% to 0%, but I guess it will be the same as with demanding games, so about 1.5 hours at best. I tried it once when I had 71% of charge, and that lasted only to build a bit more than a half, so I think 100% might not be enough either. Still, I’ll try it with a fully charged battery at some point later.
Problem with VAAPI in Qt Multimedia static build
I have an application that uses Qt Multimedia, and while building it with shared Qt goes fine, it fails to build with static Qt:
CMake Error at /home/deck/programs/qt/6.5.1-static/lib/cmake/Qt6Multimedia/Qt6QFFmpegMediaPluginTargets.cmake:61 (set_target_properties):
The link interface of target "Qt6::QFFmpegMediaPlugin" contains:
VAAPI::VAAPI
but the target was not found. Possible reasons include:
* There is a typo in the target name.
* A find_package call is missing for an IMPORTED target.
* An ALIAS target is missing.
Since it builds fine with shared Qt, this probably means that static Qt expects a static build of that VAAPI thing? But where should it come from, is it a FFmpeg/VAAPI thing or is it something else?
I tried building FFmpeg from sources using Qt’s Coin script in /path/to/qt/src/6.5.1/coin/provisioning/qtci-linux-Ubuntu-22.04-x86_64/90-install-ffmpeg.sh
and then configuring Qt with -- -DFFMPEG_DIR="/path/to/ffmpeg/install"
(that build looked static to me, because it had .a
libraries), but still my application failed to configure even with that Qt build.
I couldn’t figure out this problem yet.
Inspecting applications with RenderDoc
If you work with something that puts pixels on a screen, you’ll probably want to inspect your application/game with RenderDoc. It does support GNU/Linux hosts, and in fact renderdoccmd
is already available on Steam Deck out of the box (unless it was me who installed it at some point):
$ renderdoccmd --version
renderdoccmd x64 v1.22 built from NO_GIT_COMMIT_HASH_DEFINED
Packaged for SteamOS (1.22) - joshua@froggi.es
APIs supported at compile-time: Vulkan, GL, GLES.
Windowing systems supported at compile-time: xlib, XCB, Vulkan KHR_display.
$ which renderdoccmd
/usr/bin/renderdoccmd
Either way, you can also download it from its website; and you’ll have to do that if you need the GUI application (qrenderdoc
), as, unlike renderdoccmd
, it isn’t available in the system by default. Once you download it, keep in mind that you might need to register that one for Vulkan capture instead of the default one. I kept the default one, just in case (I only needed the GUI anyway).
Let’s try to inspect an OpenGL application, such as this one:
$ renderdoccmd capture "/path/to/glfw-imgui"
The application will launch and you’ll see RenderDoc’s info in the top left corner:
If you press F12, it will make a capture and save it to /tmp/RenderDoc/glfw-imgui_2023.07.30_15.20_frame6983.rdc
file. That file can now be openned in RenderDoc GUI (File → Open Capture):
You can inspect Vulkan applications as well, here’s an example with a default vkcube
sample:
$ renderdoccmd capture "vkcube"
Alternatively, in case of Vulkan applications, you can just set the ENABLE_VULKAN_RENDERDOC_CAPTURE
environment variable:
$ ENABLE_VULKAN_RENDERDOC_CAPTURE=1 vkcube
It will again launch the application with RenderDoc info in the top-left corner:
If you’d like to inspect captures in RenderDoc GUI application right on Steam Deck, then you better do that with an external display, because the GUI is rather packed with controls and widgets to be viewed on Steam Deck’s own screen.
You can also move the capture file over to your main machine with a big screen and open it there, but chances are you have a different GPU on it, and so the capture will fail to load:
To be able to view it on that host, you’ll need to run renderdoccmd
on Steam Deck in server mode:
$ renderdoccmd remoteserver -p 4321
then discover it on your main host:
and then you’ll be able to choose Remote option:
and that will work:
You should also be able to launch applications remotely, which should eliminate the step of manually transferring capture files from Steam Deck to you main host. I could indeed launch an application remotely, but then I didn’t find a way to remotely trigger a capture and view captured results.
Capturing a Windows application running with Proton
In general, it should be just a matter of running that application/game with Proton and wrapping that call into renderdoccmd capture
:
$ STEAM_COMPAT_CLIENT_INSTALL_PATH=/home/deck/.steam/steam \
STEAM_COMPAT_DATA_PATH=/home/deck/.local/share/Steam/steamapps/compatdata/2718988064 \
renderdoccmd capture /home/deck/.local/share/Steam/compatibilitytools.d/GE-Proton8-4/proton waitforexitandrun \
/run/media/mmcblk0p1/games/diablo-2-resurrected/D2R.exe -launch
But for me that just ran the game without RenderDoc capturing it. And I didn’t find a way to make it work with renderdoccmd capture
, but fortunately this game is using Vulkan (or rather DirectX via Vulkan?), and so the variant with setting environment variable works fine:
$ ENABLE_VULKAN_RENDERDOC_CAPTURE=1 \
STEAM_COMPAT_CLIENT_INSTALL_PATH=/home/deck/.steam/steam \
STEAM_COMPAT_DATA_PATH=/home/deck/.local/share/Steam/steamapps/compatdata/2718988064 \
/home/deck/.local/share/Steam/compatibilitytools.d/GE-Proton8-4/proton waitforexitandrun \
/run/media/mmcblk0p1/games/diablo-2-resurrected/D2R.exe -launch
Obviously, if that game/application is already added to your Steam library, then you can just set this variable in its launch options instead of running it from bare CLI.
What about IDEs
I reckon, it’s the same as with any other GNU/Linux hosts - whatever you can install there, most likely can be installed on Steam Deck too. And if you are connecting to it via SSH, then you probably will use IDEs that you have on your main machine anyway.
Personally, I do not care much about IDEs, because, as you might have noticed, I prefer to build stuff from CLI. The code editing is a different story, of course, but even then I do not like full-blown IDEs, as they are too “slow” and “clumsy” for me.
My absolute favorite text/code editor is Sublime Text. It can be installed on Steam Deck either with pacman or via direct download of a portable archive (64 bit .tar.xz
option). There is also a version published on Flathub, but it is quite old and isn’t official, so it is not recommended to install that one. Speaking about C++ development in particular, LSP and clangd make it almost as good as a “proper” IDE without getting as bloated:
If video doesn’t play in your browser, you can download it here.
If you prefer text editors based on web-browsers, then you can download and run Visual Studio Code. This one provides a portable archive option too, and LSP support goes without saying.
For Qt development one might want to use Qt Creator, and that one can be installed with an official installer. There is one issue with it, though - out of the box the text and background colors of application menu items are set to something unreadable (probably can be fixed somewhere in Plasma theme settings):
If video doesn’t play in your browser, you can download it here.
Lastly, there is a default(?) Kate editor, which is quite good too and seems to support LSP as well.
So, is it worth it
In my opinion, Steam Deck makes a rather decent development host. As a matter of fact, I plan to publish one of my applications on Flathub with Steam Deck being one of the target platforms, and I am currently building and testing that application right on the device.
It gets even better if you are don’t have enough money to purchase a proper computer and just want something affordable that is capable of building stuff with acceptable performance.
When I was a student, I’d be more than happy to get it, especially remembering how I had ASUS Eee 1025C back in my days. It would be like a dream come true: an affordable portable computer for making notes on lectures/seminars at the university, which at the same time is powerful enough for working on assignments, and you can also play games on it.
Social networks
Zuck: Just ask
Zuck: I have over 4,000 emails, pictures, addresses, SNS
smb: What? How'd you manage that one?
Zuck: People just submitted it.
Zuck: I don't know why.
Zuck: They "trust me"
Zuck: Dumb fucks