How to Build Things on Fedora
Tags: linux, fedora
Published: 2020-11-03 00:41:32

I am here to provide you an overview to build things on Fedora. I mean, yes, you can also implement these general ideas in other distributions. It is highly recommended that you understand what the [build actually does](https://stackoverflow.com/a/2650423/8791891). Let's start the story.

# A Background

Once upon a time, I was wondering how to get [Dialect](https://github.com/gi-lom/dialect), a translation application for GNOME based on Google Translate, on my beloved machine. Dialect was relatively new at that day, so I have doubt that this application is available in the official Fedora's repository. Then I went to GNOME Terminal, typed `dnf search dialect` and glared at the output.

```bash
$ dnf search dialect
Last metadata expiration check: 1:46:27 ago on Mon 02 Nov 2020 15:44:00 WIB.
====================================================== Name Exactly Matched: dialect =======================================================
dialect.noarch : A translation app for GNOME based on Google Translate
========================================================= Summary Matched: dialect =========================================================
golang-starlark.x86_64 : Dialect of Python intended for use as a configuration language
golang-starlark-devel.noarch : Dialect of Python intended for use as a configuration language
owl-lisp.x86_64 : Owl Lisp is a purely functional dialect of Scheme
...
```

I was so shocked! It was officially there! I was pinching my cheek to realize it was not a dream! So, I continued my finding by typed `dnf info dialect` and read the output carefully.

```bash
$ dnf info dialect
Last metadata expiration check: 2:59:21 ago on Mon 02 Nov 2020 15:44:00 WIB.
Available Packages
Name         : dialect
Version      : 1.0.0
Release      : 1.fc33
Architecture : noarch
Size         : 37 k
Source       : dialect-1.0.0-1.fc33.src.rpm
Repository   : updates
Summary      : A translation app for GNOME based on Google Translate
URL          : https://github.com/gi-lom/dialect
License      : GPLv3+
Description  : A translation app for GNOME based on Google Translate.
             : 
             : Features:
             : * Text translation up to 5000 chars
             : * Text to speech
             : * History
             : * Automatic language detection
             : * Clipboard buttons
```

Terrific, the packaging already provided the URL information to [the project homepage](https://github.com/gi-lom/dialect). I had expected this was the latest version.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4fo5gu29gv7rdbtvupim.png)

Sadly, nope. I have drop behind one minor version. So, what were the possible solutions? I thought, I will wait for the official update. This was like the best option, but do I have to wait until the next Fedora release? No, please don't.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vk8k7xr7363ncwp07u38.png)

I want to install it through Flatpak then. It looked promising, but I had pretended not to like Flatpak at the moment. Otherwise, this post will end here. LOL. Let's assume that Dialect was never available on Flatpak and never will be.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/26j13hhb6p2apogsslo2.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vebqy2t3lx3tazwgx2m4.png)

What were the remaining options? It was building by myself. Alright, let's dive into it and go back to the present! I am tired of using past sentences. LOL.

# Installing the Requirements

Dialect is one well-documented example of software development. It already includes the procedure for building along with the requirements. But consider a situation when we found nothing documented. It is encountered fairly often for many small projects.

Now, let's try installing all the requirements described in [the repository page](https://github.com/gi-lom/dialect).

```bash
$ sudo dnf install python python-gobject gtk3 libhandy gstreamer meson ninja python-googletrans python-gtts python-dbus
Last metadata expiration check: 1:25:05 ago on Mon 02 Nov 2020 19:39:09 WIB.
Package python-unversioned-command-3.9.0-1.fc33.noarch is already installed.
Package python3-gobject-3.38.0-2.fc33.x86_64 is already installed.
Package gtk3-3.24.23-1.fc33.x86_64 is already installed.
Package libhandy-0.0.13-6.fc33.x86_64 is already installed.
No match for argument: gstreamer
No match for argument: ninja
Package python3-dbus-1.2.16-3.fc33.x86_64 is already installed.
Error: Unable to find a match: gstreamer ninja
```

What does the output mean? We do not need to install the `python`, `python-gobject`, `gtk3`, `libhandy` and `python-dbus` packages, since they are already installed. Meanwhile, the `meson`, `python-googletrans` and `python-gtts` packages were found but not installed.

The error above has stated that we could not find `gstreamer` and `ninja` packages. There are two possibilities: 1) they are not already in the repository which is rare or 2) the maintainers have named it differently. So, what we need to do next is search them manually.

```bash
$ dnf search gstreamer
Last metadata expiration check: 5:46:28 ago on Mon 02 Nov 2020 15:44:00 WIB.
==================================================== Name & Summary Matched: gstreamer =====================================================
...
gstreamer1.x86_64 : GStreamer streaming media framework runtime
gstreamer1.i686 : GStreamer streaming media framework runtime
gstreamer1-devel.i686 : Libraries/include files for GStreamer streaming media framework
gstreamer1-devel.x86_64 : Libraries/include files for GStreamer streaming media framework
gstreamer1-doc.noarch : GStreamer documentation
...
```

By looking at the output, we could see that the correct package is `gstreamer1`. Before installing it, let's find another one.

```bash
$ dnf search ninja
Last metadata expiration check: 5:54:13 ago on Mon 02 Nov 2020 15:44:00 WIB.
=========================================================== Name Matched: ninja ============================================================
backupninja.noarch : Lightweight, extensible backup system
ninja-build.x86_64 : Small build system with a focus on speed
sqlninja.noarch : A tool for SQL server injection and takeover
========================================================== Summary Matched: ninja ==========================================================
lugaru.x86_64 : Ninja rabbit fighting game
samurai.x86_64 : ninja-compatible build tool written in C
```

So, it turns out to be `ninja-build`. Hereafter, let's try installing both of them and the other three packages.

```bash
$ sudo dnf install --assumeyes gstreamer1 ninja-build meson python-googletrans python-gtts
```

Next, we need to verify the versions of the packages required. As said in the documentation, Dialect requires a specific version of `libhandy` package, it must be greater than or equal to `0.90.0`. Let's check what version is available in the repository.

```bash
$ dnf search libhandy
Last metadata expiration check: 0:24:28 ago on Mon 02 Nov 2020 21:43:29 WIB.
====================================================== Name Exactly Matched: libhandy ======================================================
libhandy.x86_64 : Library with GTK+ widgets for mobile phones
libhandy.i686 : Library with GTK+ widgets for mobile phones
===================================================== Name & Summary Matched: libhandy =====================================================
libhandy-devel.i686 : Development files for libhandy
libhandy-devel.x86_64 : Development files for libhandy
libhandy1-devel.i686 : Development files for libhandy1
libhandy1-devel.x86_64 : Development files for libhandy1
========================================================== Name Matched: libhandy ==========================================================
libhandy1.x86_64 : Building blocks for modern adaptive GNOME apps
libhandy1.i686 : Building blocks for modern adaptive GNOME apps
```

This means there are two different versions of the `libhandy` package. The `libhandy1` is supposed to be the one we are looking for. But let's see if they are both installed.

```bash
$ dnf info --installed libhandy libhandy1
Installed Packages
Name         : libhandy
Version      : 0.0.13
Release      : 6.fc33
Architecture : x86_64
Size         : 468 k
Source       : libhandy-0.0.13-6.fc33.src.rpm
Repository   : @System
From repo    : anaconda
Summary      : Library with GTK+ widgets for mobile phones
URL          : https://source.puri.sm/Librem5/libhandy/
License      : LGPLv2+
Description  : libhandy provides GTK+ widgets and GObjects to ease developing
             : applications for mobile phones.

Name         : libhandy1
Version      : 1.0.0
Release      : 2.fc33
Architecture : x86_64
Size         : 634 k
Source       : libhandy1-1.0.0-2.fc33.src.rpm
Repository   : @System
From repo    : anaconda
Summary      : Building blocks for modern adaptive GNOME apps
URL          : https://gitlab.gnome.org/GNOME/libhandy
License      : LGPLv2+
Description  : libhandy provides GTK+ widgets and GObjects to ease developing
             : applications for mobile phones.
```

As it turns out, the latter is what we are looking for and it is already installed.

# Preparing to Compile

Now, we are going to download the source code from the repository. I used to put any source code into the Downloads directory.

```bash
$ cd Downloads

$ git clone https://github.com/gi-lom/dialect.git
Cloning into 'dialect'...
remote: Enumerating objects: 209, done.
remote: Counting objects: 100% (209/209), done.
remote: Compressing objects: 100% (154/154), done.
remote: Total 1446 (delta 128), reused 102 (delta 52), pack-reused 1237
Receiving objects: 100% (1446/1446), 515.58 KiB | 534.00 KiB/s, done.
Resolving deltas: 100% (915/915), done.

$ cd dialect

$ ls
build-aux  data  LICENSE  meson.build  po  preview-2.png  preview-mobile.png  preview.png  README.md  src
```

After that, we move onto the easiest step, which is preparing to compile.

```bash
$ meson builddir --prefix=/usr/local
The Meson build system
Version: 0.55.3
Source dir: /home/naru/Downloads/dialect
Build dir: /home/naru/Downloads/dialect/builddir
Build type: native build
Project name: dialect
Project version: 1.1.0
Host machine cpu family: x86_64
Host machine cpu: x86_64
Program python3 found: YES (/usr/bin/python3)
Message: Looking for dependencies
Program python3 found: YES (/usr/bin/python3)
Message: Found python3 binary
Found pkg-config: /usr/bin/pkg-config (1.7.3)
Did not find CMake 'cmake'
Found CMake: NO
Run-time dependency gobject-introspection-1.0 found: NO (tried pkgconfig)

meson.build:29:0: ERROR: Dependency "gobject-introspection-1.0" not found, tried pkgconfig

A full log can be found at /home/naru/Downloads/dialect/builddir/meson-logs/meson-log.txt
```

Unfortunately, we faced an error! What went wrong in the previous steps?

> Please note, building something also requires the development files of all the requirements. Fedora uses the suffix `-devel` for its development packages, while some distros use the suffix `-dev`.

Let's try installing the requirements again, but we excluded the `python3-devel`, `meson-devel` and `ninja-devel` packages because they are not required dependencies.

```bash
$ sudo dnf install -y python3-gobject-devel gtk3 libhandy1-devel gstreamer1-devel python3-googletrans python3-gtts python3-dbus
```

Then, let's rerun the previous command.

```bash
$ meson builddir --prefix=/usr/local
The Meson build system
Version: 0.55.3
Source dir: /home/naru/Downloads/dialect
Build dir: /home/naru/Downloads/dialect/builddir
Build type: native build
Project name: dialect
Project version: 1.1.0
Host machine cpu family: x86_64
Host machine cpu: x86_64
Program python3 found: YES (/usr/bin/python3)
Message: Looking for dependencies
Program python3 found: YES (/usr/bin/python3)
Message: Found python3 binary
Found pkg-config: /usr/bin/pkg-config (1.7.3)
Run-time dependency gobject-introspection-1.0 found: YES 1.66.1
Run-time dependency gtk+-3.0 found: YES 3.24.23
Run-time dependency glib-2.0 found: YES 2.66.2
Run-time dependency pygobject-3.0 found: YES 3.38.0
Found pkg-config: /usr/bin/pkg-config (1.7.3)
Program desktop-file-validate found: YES
Program appstream-util found: YES
Program glib-compile-schemas found: YES
Configuring dialect using configuration
Configuring com.github.gi_lom.dialect.SearchProvider.service using configuration
Configuring search_provider using configuration
Program build-aux/meson/postinstall.py found: YES (/home/naru/Downloads/dialect/build-aux/meson/postinstall.py)
Build targets in project: 6

Found ninja-1.10.1 at /usr/bin/ninja
```

Looks like everything is going well! Before we go, let's take a look at the `meson builddir --prefix=/usr/local` command. The `builddir` argument tells `meson` to prepare the target files to be built in a separate directory named `builddir` from the source files. If we run the `ls` command now, we can see a new directory named `builddir` has just been created by the `meson builddir` command.

```bash
$ ls
build-aux  builddir  data  LICENSE  meson.build  po  preview-2.png  preview-mobile.png  preview.png  README.md  src

$ ls builddir
build.ninja  compile_commands.json  data  meson-info  meson-logs  meson-private  po  src
```

Whilst, the `--prefix=/usr/local` argument tells `meson` to install the compiled files into `/usr/local` directory.

# Installing Dialect

Finally, when everything goes well in advance, we can install Dialect by simply running a command. But for study purposes, I suggest to include the `-v` or `--verbose` argument as well. So, we can see all the things behind the installation.

```bash
$ sudo ninja -C builddir --verbose install
ninja: Entering directory `builddir'
[0/1] /usr/bin/meson install --no-rebuild
Installing data/resources/dialect.gresource to /usr/local/share/dialect
Installing data/com.github.gi_lom.dialect.desktop to /usr/local/share/applications
Installing data/com.github.gi_lom.dialect.metainfo.xml to /usr/local/share/metainfo
Installing /home/naru/Downloads/dialect/data/com.github.gi_lom.dialect.gschema.xml to /usr/local/share/glib-2.0/schemas
Installing /home/naru/Downloads/dialect/data/com.github.gi_lom.dialect.svg to /usr/local/share/icons/hicolor/scalable/apps
Installing /home/naru/Downloads/dialect/data/com.github.gi_lom.dialect-symbolic.svg to /usr/local/share/icons/hicolor/scalable/apps
Installing /home/naru/Downloads/dialect/builddir/src/dialect to /usr/local/bin
Installing /home/naru/Downloads/dialect/src/search_provider/com.github.gi_lom.dialect.SearchProvider.ini to /usr/local/share/gnome-shell/search-providers
Installing /home/naru/Downloads/dialect/builddir/src/search_provider/com.github.gi_lom.dialect.SearchProvider.service to /usr/local/share/dbus-1/services
Installing /home/naru/Downloads/dialect/builddir/src/search_provider/search_provider to /usr/local/share/dialect
Installing /home/naru/Downloads/dialect/src/__init__.py to /usr/local/share/dialect/dialect
Installing /home/naru/Downloads/dialect/src/main.py to /usr/local/share/dialect/dialect
Installing /home/naru/Downloads/dialect/src/define.py to /usr/local/share/dialect/dialect
Installing /home/naru/Downloads/dialect/src/window.py to /usr/local/share/dialect/dialect
Installing /home/naru/Downloads/dialect/src/preferences.py to /usr/local/share/dialect/dialect
Installing /home/naru/Downloads/dialect/src/lang_selector.py to /usr/local/share/dialect/dialect
Running custom install script '/usr/bin/meson --internal gettext install --subdir=po --localedir=share/locale --pkgname=dialect'
Installing /home/naru/Downloads/dialect/builddir/po/de.gmo to /usr/local/share/locale/de/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/es.gmo to /usr/local/share/locale/es/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/fa.gmo to /usr/local/share/locale/fa/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/hu.gmo to /usr/local/share/locale/hu/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/id.gmo to /usr/local/share/locale/id/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/it.gmo to /usr/local/share/locale/it/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/pt_BR.gmo to /usr/local/share/locale/pt_BR/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/ru.gmo to /usr/local/share/locale/ru/LC_MESSAGES/dialect.mo
Installing /home/naru/Downloads/dialect/builddir/po/tr.gmo to /usr/local/share/locale/tr/LC_MESSAGES/dialect.mo
Running custom install script '/home/naru/Downloads/dialect/build-aux/meson/postinstall.py'
Updating icon cache...
Updating desktop database...
Compiling GSettings schemas...
```

Once the installation has done, we can find Dialect in the Application Launcher. Congratulations!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cber5tlbodhe6y0627d4.png)

Run it and see if it works!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h7wmfyulmlr0wnopdje1.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1l9v2exfbk93z6f9b2cq.png)

# Tips

Let's take a look back at the error message we got earlier.

```bash
...
meson.build:29:0: ERROR: Dependency "gobject-introspection-1.0" not found, tried pkgconfig
...
```

Sometimes, we could not find any development packages that provide the `gobject-introspection-1.0` package which in our case is provided by the `python3-gobject-devel` package. If you are curious to check whether the `python3-gobject-devel` package provides the `gobject-introspection-1.0` package or not, you can simply run `dnf repoquery --deplist python3-gobject-devel`.

```bash
$ dnf repoquery --deplist python3-gobject-devel
...
package: python3-gobject-devel-3.38.0-2.fc33.x86_64
  dependency: /usr/bin/pkg-config
   provider: pkgconf-pkg-config-1.7.3-5.fc33.x86_64
   provider: pkgconf-pkg-config-1.7.3-2.fc33.i686
  dependency: gobject-introspection-devel(x86-64)
   provider: gobject-introspection-devel-1.66.1-1.fc33.x86_64
  dependency: pkgconfig(gobject-2.0)
   provider: glib2-devel-2.66.2-1.fc33.i686
   provider: glib2-devel-2.66.2-1.fc33.x86_64
  dependency: pkgconfig(libffi)
   provider: libffi-devel-3.1-26.fc33.i686
   provider: libffi-devel-3.1-26.fc33.x86_64
  dependency: python3-gobject(x86-64) = 3.38.0-2.fc33
   provider: python3-gobject-3.38.0-2.fc33.x86_64

$ dnf repoquery --deplist gobject-introspection-devel
...
package: gobject-introspection-devel-1.66.1-1.fc33.x86_64
  dependency: (python(abi) = 3.9 if python3)
   provider: python3-3.9.0-1.fc33.i686
   provider: python3-3.9.0-1.fc33.x86_64
  dependency: /usr/bin/pkg-config
   provider: pkgconf-pkg-config-1.7.3-5.fc33.x86_64
   provider: pkgconf-pkg-config-1.7.3-2.fc33.i686
  dependency: /usr/bin/python3
   provider: python3-3.9.0-1.fc33.i686
   provider: python3-3.9.0-1.fc33.x86_64
  dependency: gobject-introspection(x86-64) = 1.66.1-1.fc33
   provider: gobject-introspection-1.66.1-1.fc33.x86_64
...
```

If the `python3-gobject-devel` package is not in the repository, which actually we do not need it, we can directly install `gobject-introspection-devel`. Sometimes, however, the development package does not have the name `<package-name>-devel` or it does not have the exact version we needed. If so, search for `pkgconfig(gobject-introspection-1.0)` on a site like [rpmfind](https://rpmfind.net/). It will give you the exact package name to be installed.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gwf2d318vo8fwdkfpjzi.png)

That's all. I hope this post will be of use to you.