mirror of https://github.com/mpv-player/mpv
200 lines
8.5 KiB
ReStructuredText
200 lines
8.5 KiB
ReStructuredText
|
Build system overview
|
||
|
=====================
|
||
|
|
||
|
mpv's new build system is based on Python and completely replaces the previous
|
||
|
./waf build system.
|
||
|
|
||
|
This file describes internals. See the README in the top level directory for
|
||
|
user help.
|
||
|
|
||
|
User help (to be moved to README.md)
|
||
|
====================================
|
||
|
|
||
|
Compiling with full features requires development files for several
|
||
|
external libraries. Below is a list of some important requirements.
|
||
|
|
||
|
For a list of the available build options use `./configure --help`. If
|
||
|
you think you have support for some feature installed but configure fails to
|
||
|
detect it, the file `build/config.log` may contain information about the
|
||
|
reasons for the failure.
|
||
|
|
||
|
NOTE: To avoid cluttering the output with unreadable spam, `--help` only shows
|
||
|
one of the many switches for each option. If the option is autodetected by
|
||
|
default, the `--disable-***` switch is printed; if the option is disabled by
|
||
|
default, the `--enable-***` switch is printed. Either way, you can use
|
||
|
`--enable-***` or `--disable-***` regardless of what is printed by `--help`.
|
||
|
By default, most features are auto-detected. You can use ``--with-***=option``
|
||
|
to get finer control over whether auto-detection is used for a feature.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
./configure && make -j20
|
||
|
|
||
|
If everything goes well, the mpv binary is created in the ``build`` directory.
|
||
|
|
||
|
`make` alone can be used to rebuild parts of the player. On update, it's
|
||
|
recommended to run `make dist-clean` and to rerun configure.
|
||
|
|
||
|
See `./configure --help` for advanced usage.
|
||
|
|
||
|
Motivation & Requirements
|
||
|
=========================
|
||
|
|
||
|
It's unclear what the fuck the author of the new build system was thinking.
|
||
|
|
||
|
Big picture
|
||
|
===========
|
||
|
|
||
|
The configure script is written in Python. It generates config.h and config.mak
|
||
|
files (and possibly more). By default these are written to a newly created
|
||
|
"build" directory. It also writes a build.log.
|
||
|
|
||
|
The "actual" build system is based on GNU make (other make variants probably
|
||
|
won't work). The Makefile in the project root is manually created by the build
|
||
|
system "user" (i.e. the mpv developers), and is fixed and not changed by
|
||
|
configure. It includes the configured-generated build/config.mak file for the
|
||
|
variable parts. It also includes Header file dependencies are handled
|
||
|
automatically with the ``-MD`` option (which the compiler must support).
|
||
|
|
||
|
For out-of-tree builds, a small Makefile is generated that includes the one
|
||
|
from the source directory. Simply call configure from another directory.
|
||
|
(Note: this is broken, fails at generated files, and is also ugly.)
|
||
|
|
||
|
By default, it attempts not to write any build output to the source tree, except
|
||
|
to the "build" directory.
|
||
|
|
||
|
Comparison to previous waf build system
|
||
|
=======================================
|
||
|
|
||
|
The new configure uses the same concept as our custom layer above waf, which
|
||
|
made the checks generally declarative. In fact, most checks were ported
|
||
|
straight, changing only to the new syntax.
|
||
|
|
||
|
Some of the internal and user-visible conventions are extremely similar. For
|
||
|
example, the new system creates a build dir and writes to it by default.
|
||
|
|
||
|
The choice of Python as implementation language is unfortunate. Shell was
|
||
|
considered, but discarded for being too fragile, error prone, and PITA-ish.
|
||
|
Lua would be reasonable, but is too fragmented, and requires external
|
||
|
dependencies to do meaningful UNIX scripting. There is nothing else left that
|
||
|
is widely supported enough, does not require external dependencies, and which
|
||
|
isn't something that I would not touch without gloves. Bootstrapping a system
|
||
|
implemented in C was considered, but deemed too problematic.
|
||
|
|
||
|
mpv's custom configure
|
||
|
======================
|
||
|
|
||
|
All of the configuration process is handled with a mostly-declarative approach.
|
||
|
Each configure check is a call to a "check" function, which takes various named
|
||
|
arguments. The check function is obviously always called, even if the
|
||
|
corresponding feature is disabled.
|
||
|
|
||
|
A simple example using pkg-config would be::
|
||
|
|
||
|
check("-vdpau*",
|
||
|
desc = "VDPAU acceleration",
|
||
|
deps = "x11",
|
||
|
fn = lambda: check_pkg_config("vdpau >= 0.2"),
|
||
|
sources = ["video/filter/vf_vdpaupp.c",
|
||
|
"video/out/vo_vdpau.c",
|
||
|
"video/vdpau.c",
|
||
|
"video/vdpau_mixer.c"])
|
||
|
|
||
|
This defines a feature called ``vdpau`` which can be enabled or disabled by
|
||
|
the users with configure flags (that's the meaning of ``-``). This feature
|
||
|
depends on another feature whose name is ``x11``, and the autodetection check
|
||
|
consists of running ``pkg-config`` and looking for ``vdpau`` with version
|
||
|
``>= 0.2``. If the check succeeds a ``#define HAVE_VDPAU 1`` will be added to
|
||
|
``config.h``, if not ``#define HAVE_VDPAU 0`` will be added (the ``*`` on the
|
||
|
feature name triggers emitting of such defines).
|
||
|
|
||
|
The defines names are automatically prepended with ``HAVE_``, capitalized, and
|
||
|
some special characters are replaced with underscores.
|
||
|
|
||
|
If the test succeeds, the listed source files are added to the build.
|
||
|
|
||
|
Read the inline-documentation on the check function in configure_common.py for
|
||
|
details. The following text only gives a crude overview.
|
||
|
|
||
|
Configure tests
|
||
|
---------------
|
||
|
|
||
|
The check function has a ``fn`` parameter. This function is called when it's
|
||
|
time to perform actual configure checks. Most check calls in configure make
|
||
|
this a lambda, so the actual code to run can be passed inline as a function
|
||
|
argument. (This is similar to the old waf based system, just that functions
|
||
|
like check_pkg_config returned a function as result, which hid the indirection.)
|
||
|
|
||
|
One central function is ``check_cc``. It's quite similar to the waf-native
|
||
|
function with the same name. One difference is that there is no ``mandatory``
|
||
|
option - instead it always returns a bool for success. On success, the passed
|
||
|
build flags are appended to the check's build flags. This makes it easier to
|
||
|
compose checks. For example::
|
||
|
|
||
|
check(desc = "C11/C99",
|
||
|
fn = lambda: check_cc(flags = "-std=c11") or
|
||
|
check_cc(flags = "-std=c99"),
|
||
|
required = "No C11 or C99 support.")
|
||
|
|
||
|
This tries to use -std=c11, but allows a fallback to -std=c99.
|
||
|
|
||
|
If the entire check fails, none of the added build flags are added. For example,
|
||
|
you could chain multiple tests like this::
|
||
|
|
||
|
check("-vapoursynth*",
|
||
|
fn = lambda: check_pkg_config("vapoursynth >= 24") and
|
||
|
check_pkg_config("vapoursynth-script >= 23"))
|
||
|
|
||
|
If the second check fails, the final executable won't link to ``vapoursynth``.
|
||
|
(Note that this test could just make a single check_pkg_config call, and pass
|
||
|
each dependency as separate argument.)
|
||
|
|
||
|
Source files
|
||
|
------------
|
||
|
|
||
|
configure generates the list of source files and writes it to config.mak. You
|
||
|
can add source files at any point in configure, but normally they're added with
|
||
|
the ``sources`` parameter in each feature check. This is done because a larger
|
||
|
number of source files depend on configure options, so having it all in the same
|
||
|
place as the check is slightly nicer than having a separate conditional mess in
|
||
|
the fixed Makefile.
|
||
|
|
||
|
Configure phases, non-declarative actions
|
||
|
-----------------------------------------
|
||
|
|
||
|
configure was written to be as single-pass as possible. It doesn't even put the
|
||
|
checks in any lists or so (except for the outcome). Handling of ``--enable-...``
|
||
|
etc. options is done while running configure. If you pass e.g.
|
||
|
``--enable-doesntexist``, configure will complain about an unknown
|
||
|
``doesntexist`` feature only once all checks have been actually run.
|
||
|
|
||
|
Although this is slightly weird, it is done so that the ``configure`` file
|
||
|
itself can be a flat file with simple top-down execution. It enables you to add
|
||
|
arbitrary non-declarative checks and such between the ``check`` calls.
|
||
|
|
||
|
One thing you need to be aware of is that if ``--help`` was passed to configure,
|
||
|
it will run in "help mode". You may have to use ``is_running()`` to check
|
||
|
whether it's in a mode where checks are actually executed. Outside of this mode,
|
||
|
``dep_enabled()`` will fail.
|
||
|
|
||
|
Makefile
|
||
|
--------
|
||
|
|
||
|
Although most source files are added from configure, this build system still
|
||
|
may require you to write some make. In particular, generated files are not
|
||
|
handled by configure.
|
||
|
|
||
|
make is bad. It's hard to use, hard to debug, and extremely fragile. It may be
|
||
|
replaced by something else in the future, including the possibility of turning
|
||
|
configure into waf-light.
|
||
|
|
||
|
Variables:
|
||
|
|
||
|
``BUILD``
|
||
|
The directory for build output. Can be a relative path, usually set to
|
||
|
``build``.
|
||
|
``ROOT``
|
||
|
The directory that contains ``configure``. Usually the root directory
|
||
|
of the repository. Source files need to be addressed relative to this
|
||
|
path. Can be a relative path, usually set to ``.``.
|