Building the Application

The app directory and its subdirectories contain meson.build files that describe how the application is built. These are used by the Meson build tool to configure the build process.

Meson is usually run so that it creates a build directory. This is where all the resources are put so that the Ninja build tool can perform the actual process of building and installing the application.

Top-Level Build File

In the app directory itself, the meson.build file begins with a declaration of the project name, version and build system requirements:

# Define the project and its metadata.
project('ambient_light',
  version: '0.1.0',
  meson_version: '>= 0.40.0',
)

# Import the i18n module to allow other build scripts to access its features.
i18n = import('i18n')

# Declare the project's subdirectories.
subdir('data')
subdir('src')
subdir('po')

# Add a script to handle tasks that are not automatically performed by Meson.
meson.add_install_script('build-aux/meson/postinstall.py')

We also declare the data and src subdirectories, causing Meson to examine them for any meson.build files they may contain.

The last line causes a special script to be run after installation. It is not important to know what this is doing at this point.

Sources Build File

The meson.build file in the src directory describes how the source files are processed when the build occurs:

# Initialize local variables to hold installation paths.

localedir = join_paths(get_option('prefix'), get_option('localedir'))
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
moduledir = join_paths(pkgdatadir, meson.project_name())

# Find the python3 program to help define the PYTHON configuration variable
# that will be used in the ambient-light.in template.

python3 = find_program('python3')

conf = configuration_data()
conf.set('PYTHON', python3.path())
conf.set('VERSION', meson.project_version())
conf.set('localedir', localedir)
conf.set('pkgdatadir', pkgdatadir)
conf.set('project_name', meson.project_name())

# Replace placeholders in templates with the configuration data defined above
# and create the versions of these files for installation in the build
# directory.

configure_file(
  input: 'ambient-light.in',
  output: 'ambient-light',
  configuration: conf,
  install: true,
  install_dir: get_option('bindir')
)

# Declare the application's sources and their installation directory.
sources = [
  '__init__.py',
  'main.py'
]

install_data(sources, install_dir: moduledir)

In this case, we instruct Meson to take the ambient-light.in file in the src directory and copy it into the build directory as ambient-light – this is the name given as the executable in the desktop entry file.

We also declare that the file should be installed, and that its installation directory is the system location for executables (bindir).

Data Build File

The meson.build file in the data describes how the data files are processed when the build occurs:

# Initialize a local variable to hold an installation path.
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())

# Translate the desktop file template using the message catalogs from the po
# directory, found in the project's root, generating a desktop file in the
# build directory.
desktop_file = i18n.merge_file(
  input: 'com.example.ambient_light.desktop.in',
  output: 'com.example.ambient_light.desktop',
  type: 'desktop',
  po_dir: '../po',
  install: true,
  install_dir: join_paths(get_option('datadir'), 'applications')
)

# If found, use a tool to validate the desktop file.
desktop_utils = find_program('desktop-file-validate', required: false)
if desktop_utils.found()
  test('Validate desktop file', desktop_utils,
    args: [desktop_file]
  )
endif

# Also generate an AppStream file from the template.
appstream_file = i18n.merge_file(
  input: 'com.example.ambient_light.appdata.xml.in',
  output: 'com.example.ambient_light.appdata.xml',
  po_dir: '../po',
  install: true,
  install_dir: join_paths(get_option('datadir'), 'appdata')
)

# Verify the AppStream file with the appropriate tool, if found.
appstream_util = find_program('appstream-util', required: false)
if appstream_util.found()
  test('Validate appstream file', appstream_util,
    args: ['validate', appstream_file]
  )
endif

# Install the application icon to the appropriate locations for its theme.
install_data('com.example.ambient_light.svg',
  install_dir: join_paths(get_option('datadir'), 'icons', 'hicolor', 'scalable', 'apps'))

Here, we tell Meson to copy the com.example.ambient_light.desktop.in file into the build directory as com.example.ambient_light.desktop. We also declare that it should be installed, and that its installation directory is the applications subdirectory of the system location for data files (datadir).

The com.example.ambient_light.svg file is more easily described to Meson. It will be installed in the appropriate subdirectory of the system location for data files that is used for icons.

Building using Meson and Ninja

When building the application for deployment on the phone, we will use Flatpak to coordinate the build process. However, behind the scenes, we are using Meson and Ninja to perform the actual configuration and build. If you want to try and build the application for testing on your workstation, you can follow the steps below to build, install, and finally uninstall it.

To configure the build on the command line, enter the app directory and run Meson, specifying the source and build directories:

meson . _build

Build the application using Ninja, passing the build directory as an argument so that the build occurs within that directory. There is no need to specify a build rule because the default rule builds the application:

ninja -C _build

Finally, use sudo to install the application in a standard location on your system using the install build rule:

sudo ninja -C _build install

To uninstall the application, run its uninstall rule:

sudo ninja -C _build uninstall

All of the files that were installed should now have been cleanly removed from system locations.

Summary

We have examined the contents of some meson.build files to see how simple rules are used to describe the configuration process. We have also seen how Meson and Ninja are used to configure and build the application.

The application can also be packaged for more convenient installation using the Flatpak framework. This is the subject of the next part of the example.