aboutsummaryrefslogtreecommitdiff
path: root/docs/devel/build-system.rst
blob: 09caf2f8e199d67884f408a369146ae5e42b7360 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
==================================
The QEMU build system architecture
==================================

This document aims to help developers understand the architecture of the
QEMU build system. As with projects using GNU autotools, the QEMU build
system has two stages; first the developer runs the "configure" script
to determine the local build environment characteristics, then they run
"make" to build the project.  This is about where the similarities with
GNU autotools end, so try to forget what you know about them.

The two general ways to perform a build are as follows:

 - build artifacts outside of QEMU source tree entirely::

     cd ../
     mkdir build
     cd build
     ../qemu/configure
     make

 - build artifacts in a subdir of QEMU source tree::

     mkdir build
     cd build
     ../configure
     make

Most of the actual build process uses Meson under the hood, therefore
build artifacts cannot be placed in the source tree itself.


Stage 1: configure
==================

The configure script has five tasks:

 - detect the host architecture

 - list the targets for which to build emulators; the list of
   targets also affects which firmware binaries and tests to build

 - find the compilers (native and cross) used to build executables,
   firmware and tests.  The results are written as either Makefile
   fragments (``config-host.mak``) or a Meson machine file
   (``config-meson.cross``)

 - create a virtual environment in which all Python code runs during
   the build, and possibly install packages into it from PyPI

 - invoke Meson in the virtual environment, to perform the actual
   configuration step for the emulator build

The configure script automatically recognizes command line options for
which a same-named Meson option exists; dashes in the command line are
replaced with underscores.

Almost all QEMU developers that need to modify the build system will
only be concerned with Meson, and therefore can skip the rest of this
section.


Modifying ``configure``
-----------------------

``configure`` is a shell script; it uses ``#!/bin/sh`` and therefore
should be compatible with any POSIX shell. It is important to avoid
using bash-isms to avoid breaking development platforms where bash is
the primary host.

The configure script provides a variety of functions to help writing
portable shell code and providing consistent behavior across architectures
and operating systems:

``error_exit $MESSAGE $MORE...``
   Print $MESSAGE to stderr, followed by $MORE... and then exit from the
   configure script with non-zero status.

``has $COMMAND``
   Determine if $COMMAND exists in the current environment, either as a
   shell builtin, or executable binary, returning 0 on success.  The
   replacement in Meson is ``find_program()``.

``probe_target_compiler $TARGET``
  Detect a cross compiler and cross tools for the QEMU target $TARGET (e.g.,
  ``$CPU-softmmu``, ``$CPU-linux-user``, ``$CPU-bsd-user``).  If a working
  compiler is present, return success and set variables ``$target_cc``,
  ``$target_ar``, etc. to non-empty values.

``write_target_makefile``
  Write a Makefile fragment to stdout, exposing the result of the most
  ``probe_target_compiler`` call as the usual Make variables (``CC``,
  ``AR``, ``LD``, etc.).


Configure does not generally perform tests for compiler options beyond
basic checks to detect the host platform and ensure the compiler is
functioning.  These are performed using a few more helper functions:

``compile_object $CFLAGS``
   Attempt to compile a test program with the system C compiler using
   $CFLAGS. The test program must have been previously written to a file
   called $TMPC.

``compile_prog $CFLAGS $LDFLAGS``
   Attempt to compile a test program with the system C compiler using
   $CFLAGS and link it with the system linker using $LDFLAGS. The test
   program must have been previously written to a file called $TMPC.

``check_define $NAME``
   Determine if the macro $NAME is defined by the system C compiler.

``do_compiler $CC $ARGS...``
   Attempt to run the C compiler $CC, passing it $ARGS...  This function
   does not use flags passed via options such as ``--extra-cflags``, and
   therefore can be used to check for cross compilers.  However, most
   such checks are done at ``make`` time instead (see for example the
   ``cc-option`` macro in ``pc-bios/option-rom/Makefile``).

``write_c_skeleton``
   Write a minimal C program main() function to the temporary file
   indicated by $TMPC.


Python virtual environments and the build process
-------------------------------------------------

An important step in ``configure`` is to create a Python virtual
environment (venv) during the configuration phase.  The Python interpreter
comes from the ``--python`` command line option, the ``$PYTHON`` variable
from the environment, or the system PATH, in this order.  The venv resides
in the ``pyvenv`` directory in the build tree, and provides consistency
in how the build process runs Python code.

At this stage, ``configure`` also queries the chosen Python interpreter
about QEMU's build dependencies.  Note that the build process does  *not*
look for ``meson``, ``sphinx-build`` or ``avocado`` binaries in the PATH;
likewise, there are no options such as ``--meson`` or ``--sphinx-build``.
This avoids a potential mismatch, where Meson and Sphinx binaries on the
PATH might operate in a different Python environment than the one chosen
by the user during the build process.  On the other hand, it introduces
a potential source of confusion where the user installs a dependency but
``configure`` is not able to find it.  When this happens, the dependency
was installed in the ``site-packages`` directory of another interpreter,
or with the wrong ``pip`` program.

If a package is available for the chosen interpreter, ``configure``
prepares a small script that invokes it from the venv itself[#distlib]_.
If not, ``configure`` can also optionally install dependencies in the
virtual environment with ``pip``, either from wheels in ``python/wheels``
or by downloading the package with PyPI.  Downloading can be disabled with
``--disable-download``; and anyway, it only happens when a ``configure``
option (currently, only ``--enable-docs``) is explicitly enabled but
the dependencies are not present[#pip]_.

.. [#distlib] The scripts are created based on the package's metadata,
              specifically the ``console_script`` entry points.  This is the
              same mechanism that ``pip`` uses when installing a package.
              Currently, in all cases it would be possible to use ``python -m``
              instead of an entry point script, which makes this approach a
              bit overkill.  On the other hand, creating the scripts is
              future proof and it makes the contents of the ``pyvenv/bin``
              directory more informative.  Portability is also not an issue,
              because the Python Packaging Authority provides a package
              ``distlib.scripts`` to perform this task.

.. [#pip] ``pip`` might also be used when running ``make check-avocado``
           if downloading is enabled, to ensure that Avocado is
           available.

The required versions of the packages are stored in a configuration file
``pythondeps.toml``.  The format is custom to QEMU, but it is documented
at the top of the file itself and it should be easy to understand.  The
requirements should make it possible to use the version that is packaged
that is provided by supported distros.

When dependencies are downloaded, instead, ``configure`` uses a "known
good" version that is also listed in ``pythondeps.toml``.  In this
scenario, ``pythondeps.toml`` behaves like the "lock file" used by
``cargo``, ``poetry`` or other dependency management systems.


Bundled Python packages
-----------------------

Python packages that are **mandatory** dependencies to build QEMU,
but are not available in all supported distros, are bundled with the
QEMU sources.  Currently this includes Meson (outdated in CentOS 8
and derivatives, Ubuntu 20.04 and 22.04, and openSUSE Leap) and tomli
(absent in Ubuntu 20.04).

If you need to update these, please do so by modifying and rerunning
``python/scripts/vendor.py``.  This script embeds the sha256 hash of
package sources and checks it.  The pypi.org web site provides an easy
way to retrieve the sha256 hash of the sources.


Stage 2: Meson
==============

The Meson build system describes the build and install process for:

1) executables, which include:

   - Tools - ``qemu-img``, ``qemu-nbd``, ``qemu-ga`` (guest agent), etc

   - System emulators - ``qemu-system-$ARCH``

   - Userspace emulators - ``qemu-$ARCH``

   - Unit tests

2) documentation

3) ROMs, whether provided as binary blobs in the QEMU distributions
   or cross compiled under the direction of the configure script

4) other data files, such as icons or desktop files

All executables are built by default, except for some ``contrib/``
binaries that are known to fail to build on some platforms (for example
32-bit or big-endian platforms).  Tests are also built by default,
though that might change in the future.

The source code is highly modularized, split across many files to
facilitate building of all of these components with as little duplicated
compilation as possible. Using the Meson "sourceset" functionality,
``meson.build`` files group the source files in rules that are
enabled according to the available system libraries and to various
configuration symbols.  Sourcesets belong to one of four groups:

Subsystem sourcesets:
  Various subsystems that are common to both tools and emulators have
  their own sourceset, for example ``block_ss`` for the block device subsystem,
  ``chardev_ss`` for the character device subsystem, etc.  These sourcesets
  are then turned into static libraries as follows::

    libchardev = static_library('chardev', chardev_ss.sources(),
                                name_suffix: 'fa',
                                build_by_default: false)

    chardev = declare_dependency(link_whole: libchardev)

  As of Meson 0.55.1, the special ``.fa`` suffix should be used for everything
  that is used with ``link_whole``, to ensure that the link flags are placed
  correctly in the command line.

Target-independent emulator sourcesets:
  Various general purpose helper code is compiled only once and
  the .o files are linked into all output binaries that need it.
  This includes error handling infrastructure, standard data structures,
  platform portability wrapper functions, etc.

  Target-independent code lives in the ``common_ss``, ``system_ss`` and
  ``user_ss`` sourcesets.  ``common_ss`` is linked into all emulators,
  ``system_ss`` only in system emulators, ``user_ss`` only in user-mode
  emulators.

Target-dependent emulator sourcesets:
  In the target-dependent set lives CPU emulation, some device emulation and
  much glue code. This sometimes also has to be compiled multiple times,
  once for each target being built.  Target-dependent files are included
  in the ``specific_ss`` sourceset.

  Each emulator also includes sources for files in the ``hw/`` and ``target/``
  subdirectories.  The subdirectory used for each emulator comes
  from the target's definition of ``TARGET_BASE_ARCH`` or (if missing)
  ``TARGET_ARCH``, as found in ``default-configs/targets/*.mak``.

  Each subdirectory in ``hw/`` adds one sourceset to the ``hw_arch`` dictionary,
  for example::

    arm_ss = ss.source_set()
    arm_ss.add(files('boot.c'), fdt)
    ...
    hw_arch += {'arm': arm_ss}

  The sourceset is only used for system emulators.

  Each subdirectory in ``target/`` instead should add one sourceset to each
  of the ``target_arch`` and ``target_system_arch``, which are used respectively
  for all emulators and for system emulators only.  For example::

    arm_ss = ss.source_set()
    arm_system_ss = ss.source_set()
    ...
    target_arch += {'arm': arm_ss}
    target_system_arch += {'arm': arm_system_ss}

Module sourcesets:
  There are two dictionaries for modules: ``modules`` is used for
  target-independent modules and ``target_modules`` is used for
  target-dependent modules.  When modules are disabled the ``module``
  source sets are added to ``system_ss`` and the ``target_modules``
  source sets are added to ``specific_ss``.

  Both dictionaries are nested.  One dictionary is created per
  subdirectory, and these per-subdirectory dictionaries are added to
  the toplevel dictionaries.  For example::

    hw_display_modules = {}
    qxl_ss = ss.source_set()
    ...
    hw_display_modules += { 'qxl': qxl_ss }
    modules += { 'hw-display': hw_display_modules }

Utility sourcesets:
  All binaries link with a static library ``libqemuutil.a``.  This library
  is built from several sourcesets; most of them however host generated
  code, and the only two of general interest are ``util_ss`` and ``stub_ss``.

  The separation between these two is purely for documentation purposes.
  ``util_ss`` contains generic utility files.  Even though this code is only
  linked in some binaries, sometimes it requires hooks only in some of
  these and depend on other functions that are not fully implemented by
  all QEMU binaries.  ``stub_ss`` links dummy stubs that will only be linked
  into the binary if the real implementation is not present.  In a way,
  the stubs can be thought of as a portable implementation of the weak
  symbols concept.


The following files concur in the definition of which files are linked
into each emulator:

``default-configs/devices/*.mak``
  The files under ``default-configs/devices/`` control the boards and devices
  that are built into each QEMU system emulation targets. They merely contain
  a list of config variable definitions such as::

    include arm-softmmu.mak
    CONFIG_XLNX_ZYNQMP_ARM=y
    CONFIG_XLNX_VERSAL=y

``*/Kconfig``
  These files are processed together with ``default-configs/devices/*.mak`` and
  describe the dependencies between various features, subsystems and
  device models.  They are described in :ref:`kconfig`

``default-configs/targets/*.mak``
  These files mostly define symbols that appear in the ``*-config-target.h``
  file for each emulator [#cfgtarget]_.  However, the ``TARGET_ARCH``
  and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
  ``target/`` subdirectories that are compiled into each target.

.. [#cfgtarget] This header is included by ``qemu/osdep.h`` when
                compiling files from the target-specific sourcesets.

These files rarely need changing unless you are adding a completely
new target, or enabling new devices or hardware for a particular
system/userspace emulation target


Adding checks
-------------

Compiler checks can be as simple as the following::

  config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h'))

A more complex task such as adding a new dependency usually
comprises the following tasks:

 - Add a Meson build option to meson_options.txt.

 - Add code to perform the actual feature check.

 - Add code to include the feature status in ``config-host.h``

 - Add code to print out the feature status in the configure summary
   upon completion.

Taking the probe for SDL2_Image as an example, we have the following
in ``meson_options.txt``::

  option('sdl_image', type : 'feature', value : 'auto',
         description: 'SDL Image support for icons')

Unless the option was given a non-``auto`` value (on the configure
command line), the detection code must be performed only if the
dependency will be used::

  sdl_image = not_found
  if not get_option('sdl_image').auto() or have_system
    sdl_image = dependency('SDL2_image', required: get_option('sdl_image'),
                           method: 'pkg-config')
  endif

This avoids warnings on static builds of user-mode emulators, for example.
Most of the libraries used by system-mode emulators are not available for
static linking.

The other supporting code is generally simple::

  # Create config-host.h (if applicable)
  config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found())

  # Summary
  summary_info += {'SDL image support': sdl_image.found()}

For the configure script to parse the new option, the
``scripts/meson-buildoptions.sh`` file must be up-to-date; ``make
update-buildoptions`` (or just ``make``) will take care of updating it.


Support scripts
---------------

Meson has a special convention for invoking Python scripts: if their
first line is ``#! /usr/bin/env python3`` and the file is *not* executable,
find_program() arranges to invoke the script under the same Python
interpreter that was used to invoke Meson.  This is the most common
and preferred way to invoke support scripts from Meson build files,
because it automatically uses the value of configure's --python= option.

In case the script is not written in Python, use a ``#! /usr/bin/env ...``
line and make the script executable.

Scripts written in Python, where it is desirable to make the script
executable (for example for test scripts that developers may want to
invoke from the command line, such as tests/qapi-schema/test-qapi.py),
should be invoked through the ``python`` variable in meson.build. For
example::

  test('QAPI schema regression tests', python,
       args: files('test-qapi.py'),
       env: test_env, suite: ['qapi-schema', 'qapi-frontend'])

This is needed to obey the --python= option passed to the configure
script, which may point to something other than the first python3
binary on the path.

By the time Meson runs, Python dependencies are available in the virtual
environment and should be invoked through the scripts that ``configure``
places under ``pyvenv``.  One way to do so is as follows, using Meson's
``find_program`` function::

  sphinx_build = find_program(
       fs.parent(python.full_path()) / 'sphinx-build',
       required: get_option('docs'))


Stage 3: Make
=============

The next step in building QEMU is to invoke make.  GNU Make is required
to build QEMU, and may be installed as ``gmake`` on some hosts.

The output of Meson is a ``build.ninja`` file, which is used with the
Ninja build tool.  However, QEMU's build comprises other components than
just the emulators (namely firmware and the tests in ``tests/tcg``) which
need different cross compilers.  The QEMU Makefile wraps both Ninja and
the smaller build systems for firmware and tests; it also takes care of
running ``configure`` again when the script changes.  Apart from invoking
these sub-Makefiles, the resulting build is largely non-recursive.

Tests, whether defined in ``meson.build`` or not, are also ran by the
Makefile with the traditional ``make check`` phony target, while benchmarks
are run with ``make bench``.  Meson test suites such as ``unit`` can be ran
with ``make check-unit``, and ``make check-tcg`` builds and runs "non-Meson"
tests for all targets.

If desired, it is also possible to use ``ninja`` and ``meson test``,
respectively to build emulators and run tests defined in meson.build.
The main difference is that ``make`` needs the ``-jN`` flag in order to
enable parallel builds or tests.

Useful make targets
-------------------

``help``
  Print a help message for the most common build targets.

``print-VAR``
  Print the value of the variable VAR. Useful for debugging the build
  system.


Important files for the build system
====================================

Statically defined files
------------------------

The following key files are statically defined in the source tree, with
the rules needed to build QEMU. Their behaviour is influenced by a
number of dynamically created files listed later.

``Makefile``
  The main entry point used when invoking make to build all the components
  of QEMU. The default 'all' target will naturally result in the build of
  every component.

``*/meson.build``
  The meson.build file in the root directory is the main entry point for the
  Meson build system, and it coordinates the configuration and build of all
  executables.  Build rules for various subdirectories are included in
  other meson.build files spread throughout the QEMU source tree.

``python/scripts/mkvenv.py``
  A wrapper for the Python ``venv`` and ``distlib.scripts`` packages.
  It handles creating the virtual environment, creating scripts in
  ``pyvenv/bin``, and calling ``pip`` to install dependencies.

``tests/Makefile.include``
  Rules for external test harnesses. These include the TCG tests
  and the Avocado-based integration tests.

``tests/docker/Makefile.include``
  Rules for Docker tests. Like ``tests/Makefile.include``, this file is
  included directly by the top level Makefile, anything defined in this
  file will influence the entire build system.

``tests/vm/Makefile.include``
  Rules for VM-based tests. Like ``tests/Makefile.include``, this file is
  included directly by the top level Makefile, anything defined in this
  file will influence the entire build system.

Dynamically created files
-------------------------

The following files are generated at run-time in order to control the
behaviour of the Makefiles. This avoids the need for QEMU makefiles to
go through any pre-processing as seen with autotools, where configure
generates ``Makefile`` from ``Makefile.in``.

Built by configure:

``config-host.mak``
  When configure has determined the characteristics of the build host it
  will write the paths to various tools to this file, for use in ``Makefile``
  and to a smaller extent ``meson.build``.

  ``config-host.mak`` is also used as a dependency checking mechanism. If make
  sees that the modification timestamp on configure is newer than that on
  ``config-host.mak``, then configure will be re-run.

``config-meson.cross``

  A Meson "cross file" (or native file) used to communicate the paths to
  the toolchain and other configuration options.

``config.status``

  A small shell script that will invoke configure again with the same
  environment variables that were set during the first run.  It's used to
  rerun configure after changes to the source code, but it can also be
  inspected manually to check the contents of the environment.

``Makefile.prereqs``

  A set of Makefile dependencies that order the build and execution of
  firmware and tests after the container images and emulators that they
  need.

``pc-bios/*/config.mak``, ``tests/tcg/config-host.mak``, ``tests/tcg/*/config-target.mak``

  Configuration variables used to build the firmware and TCG tests,
  including paths to cross compilation toolchains.

``pyvenv``

  A Python virtual environment that is used for all Python code running
  during the build.  Using a virtual environment ensures that even code
  that is run via ``sphinx-build``, ``meson`` etc. uses the same interpreter
  and packages.

Built by Meson:

``config-host.h``
  Used by C code to determine the properties of the build environment
  and the set of enabled features for the entire build.

``${TARGET-NAME}-config-devices.mak``
  TARGET-NAME is the name of a system emulator. The file is
  generated by Meson using files under ``configs/devices`` as input.

``${TARGET-NAME}-config-target.mak``
  TARGET-NAME is the name of a system or usermode emulator. The file is
  generated by Meson using files under ``configs/targets`` as input.

``$TARGET_NAME-config-target.h``, ``$TARGET_NAME-config-devices.h``
  Used by C code to determine the properties and enabled
  features for each target.  enabled.  They are generated from
  the contents of the corresponding ``*.mak`` files using Meson's
  ``configure_file()`` function; each target can include them using
  the ``CONFIG_TARGET`` and ``CONFIG_DEVICES`` macro respectively.

``build.ninja``
  The build rules.


Built by Makefile:

``Makefile.ninja``
  A Makefile include that bridges to ninja for the actual build.  The
  Makefile is mostly a list of targets that Meson included in build.ninja.

``Makefile.mtest``
  The Makefile definitions that let "make check" run tests defined in
  meson.build.  The rules are produced from Meson's JSON description of
  tests (obtained with "meson introspect --tests") through the script
  scripts/mtest2make.py.