[Spice-devel] [PATCH spice-server v4 1/2] Add support for building with meson/ninja

Frediano Ziglio fziglio at redhat.com
Fri Jul 27 09:52:49 UTC 2018


> 
> On 26/07/18 08:46, Frediano Ziglio wrote:
> >>
> >> In a comparison with current autotools build system, meson/ninja
> >> provides a huge improvement in build speed, while keeping the same
> >> functionalities currently available and being considered more user
> >> friendly.
> >>
> >> The new system coexists within the same repository with the current one,
> >> so we can do more extensive testing of its functionality before deciding
> >> if the old system can be removed, or for some reason, has to stay for
> >> good.
> >>
> >> - Meson: https://mesonbuild.com
> >>
> >>   This is the equivalent of autogen/configure step in autotools. It
> >>   generates the files that will be used by ninja to actually build the
> >>   source code.
> >>
> >>   The project has received lots of traction recently, with many GNOME
> >>   projects willing to move to this new build system. The following wiki
> >>   page has more details of the status of the many projects being ported:
> >>
> >>     https://wiki.gnome.org/Initiatives/GnomeGoals/MesonPorting
> >>
> >>   Meson has a python-like syntax, easy to read, and the documentation
> >>   on the project is very complete, with a dedicated page on how to port
> >>   from autotools, explaining how most common use cases can be
> >>   implemented using meson.
> >>
> >>     http://mesonbuild.com/Porting-from-autotools.html
> >>
> >>   Other important sources of information:
> >>
> >>     http://mesonbuild.com/howtox.html
> >>     http://mesonbuild.com/Syntax.html
> >>     http://mesonbuild.com/Reference-manual.html
> >>
> >> - Ninja: https://ninja-build.org
> >>
> >>   Ninja is the equivalent of make in an autotools setup, which actually
> >>   builds the source code. It has being used by large and complex
> >>   projects such as Google Chrome, Android and LLVM. There is not much to
> >>   say about ninja (other than it is much faster than make) because we
> >>   won't interact directly with it as much, as meson does the middle man
> >>   job here. The reasoning for creating ninja in the first place is
> >>   explained on the following post:
> >>
> >>     http://neugierig.org/software/chromium/notes/2011/02/ninja.html
> >>
> >>   Also its manual provides more in-depth information about the design
> >>   principles:
> >>
> >>     https://ninja-build.org/manual.html
> >>
> >> - Basic workflow:
> >>
> >>   Meson package is available for most if not all distros, so, taking
> >>   Fedora as an example, we only need to run:
> >>
> >>     # dnf -y install meson ninja-build.
> >>
> >>   With Meson, building in-tree is not possible at all, so we need to
> >>   pass a directory as argument to meson where we want the build to be
> >>   done. This has the advantage of creating builds with different options
> >>   under the same parent directory, e.g.:
> >>
> >>     $ meson ./build --prefix=/usr
> >>     $ meson ./build-extra -Dextra-checks=true -Dalignment-checks=true
> >>
> >>   After configuration is done, we call ninja to actually do the build.
> >>
> >>     $ ninja -C ./build
> >>     $ ninja -C ./build install
> >>
> >>   Ninja defaults to parallel builds, and this can be changed with the -j
> >>   flag.
> >>
> >>     $ ninja -j 10 -C ./build
> >>
> >> - Hacking:
> >>
> >>   * meson.build: Mandatory for the project root and usually found under
> >>                  each directory you want something to be built.
> >>
> >>   * meson_options.txt: Options that can interfere with the result of the
> >>                        build.
> >>
> >> Signed-off-by: Eduardo Lima (Etrunko) <etrunko at redhat.com>
> >> Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
> >> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> >> ---
> >>  Makefile.am                        |   3 +
> >>  build-aux/meson/check-spice-common |   5 +
> >>  docs/Makefile.am                   |   1 +
> >>  docs/manual/Makefile.am            |   1 +
> >>  docs/manual/meson.build            |  18 +++
> >>  docs/meson.build                   |  14 +++
> >>  meson.build                        | 219
> >>  +++++++++++++++++++++++++++++++++++++
> >>  meson_options.txt                  |  52 +++++++++
> >>  server/Makefile.am                 |   1 +
> >>  server/meson.build                 | 188 +++++++++++++++++++++++++++++++
> >>  server/tests/Makefile.am           |   1 +
> >>  server/tests/meson.build           |  85 ++++++++++++++
> >>  subprojects/spice-common           |   2 +-
> >>  tools/Makefile.am                  |   4 +
> >>  tools/meson.build                  |   4 +
> >>  15 files changed, 597 insertions(+), 1 deletion(-)
> >>  create mode 100755 build-aux/meson/check-spice-common
> >>  create mode 100644 docs/manual/meson.build
> >>  create mode 100644 docs/meson.build
> >>  create mode 100644 meson.build
> >>  create mode 100644 meson_options.txt
> >>  create mode 100644 server/meson.build
> >>  create mode 100644 server/tests/meson.build
> >>  create mode 100644 tools/meson.build
> >>
> > 
> > ....
> > 
> >> diff --git a/docs/meson.build b/docs/meson.build
> >> new file mode 100644
> >> index 00000000..82864bb8
> >> --- /dev/null
> >> +++ b/docs/meson.build
> >> @@ -0,0 +1,14 @@
> >> +if get_option('manual')
> >> +  asciidoc = find_program('asciidoc', required : false)
> >> +  if asciidoc.found()
> >> +    asciidoc_args = ['-a', 'data-uri', '-a', 'icons', '-a', 'toc']
> >> +    foreach doc : ['style', 'threading_model']
> >> +      custom_target('spice_ at 0@.html'.format(doc),
> >> +                    input : 'spice_ at 0@.txt'.format(doc),
> >> +                    output : 'spice_ at 0@.html'.format(doc),
> >> +                    build_by_default: true,
> >> +                    command : [asciidoc, '-n', asciidoc_args, '-o',
> >> '@OUTPUT@', '@INPUT@'])
> >> +    endforeach
> >> +  endif
> >> +  subdir('manual')
> >> +endif
> >> diff --git a/meson.build b/meson.build
> >> new file mode 100644
> >> index 00000000..b7b7fee7
> >> --- /dev/null
> >> +++ b/meson.build
> >> @@ -0,0 +1,219 @@
> >> +#
> >> +# project definition
> >> +#
> >> +project('spice', 'c',
> >> +        version : run_command('build-aux/git-version-gen',
> >> '${MESON_SOURCE_ROOT}/.tarball-version').stdout().strip(),
> >> +        license : 'LGPLv2.1',
> >> +        meson_version : '>= 0.47.0')
> >> +
> >> +# double check meson.project_version()
> >> +# we can not use 'check' keyword in run_command() for git-version-gen
> >> above
> >> +# https://github.com/mesonbuild/meson/issues/3944
> >> +version = run_command('build-aux/git-version-gen',
> >> '${MESON_SOURCE_ROOT}/.tarball-version', check : true).stdout().strip()
> >> +if meson.project_version() != version
> >> +  error('Wrong project version')
> >> +endif
> >> +
> >> +message('Updating submodules')
> >> +run_command('build-aux/meson/check-spice-common', check : true)
> >> +
> >> +# some global vars
> >> +spice_server_so_version = '1.12.4'
> >> +
> >> +spice_server_global_cflags = ['-fvisibility=hidden',
> >> +                              '-DSPICE_SERVER_INTERNAL',
> >> +                              '-DG_LOG_DOMAIN="Spice"',
> >> +                              '-DHAVE_CONFIG_H',
> >> +                              #'-Werror',
> >> +                              '-Wall',
> >> +                              '-Wextra',
> >> +                              '-Wno-sign-compare',
> >> +                              '-Wno-unused-parameter']
> >> +
> >> +compiler = meson.get_compiler('c')
> >> +spice_server_config_data = configuration_data()
> >> +spice_server_include = [include_directories('.')]
> >> +spice_server_deps = []
> >> +spice_server_link_args = []
> >> +spice_server_requires = ''
> >> +
> >> +#
> >> +# Spice common subproject
> >> +#
> >> +spice_common = subproject('spice-common', default_options :
> >> 'generate-code=server')
> >> +spice_server_config_data.merge_from(spice_common.get_variable('spice_common_config_data'))
> >> +spice_server_deps += spice_common.get_variable('spice_common_server_dep')
> >> +
> >> +#
> >> +# check for system headers
> >> +#
> >> +headers = ['sys/time.h',
> >> +           'execinfo.h',
> >> +           'linux/sockios.h',
> >> +           'pthread_np.h']
> >> +
> >> +foreach header : headers
> >> +  if compiler.has_header(header)
> >> +
> >> spice_server_config_data.set('HAVE_ at 0@'.format(header.underscorify().to_upper()),
> >> '1')
> >> +  endif
> >> +endforeach
> >> +
> >> +# TCP_KEEPIDLE definition in netinet/tcp.h
> >> +if compiler.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE')
> >> +  spice_server_config_data.set('HAVE_TCP_KEEPIDLE', '1')
> >> +endif
> >> +
> >> +#
> >> +# check for mandatory dependencies
> >> +#
> >> +spice_protocol_version='>= 0.12.15'
> >> +
> >> +glib_version = '2.38'
> >> +glib_version_info = '>= @0@'.format(glib_version)
> >> +
> >> +deps = [['spice-protocol', spice_protocol_version],
> >> +        ['glib-2.0', glib_version_info],
> >> +        ['gio-2.0', glib_version_info],
> >> +        ['gobject-2.0', glib_version_info],
> >> +        ['pixman-1', '>= 0.17.7'],
> >> +        ['openssl', '>= 1.0.0']]
> >> +
> >> +foreach dep : deps
> >> +  spice_server_deps += dependency(dep[0], version : dep[1])
> >> +endforeach
> >> +
> >> +# TODO: specify minimum version for jpeg and zlib?
> >> +foreach dep : ['libjpeg', 'zlib']
> >> +  spice_server_deps += dependency(dep)
> >> +endforeach
> >> +
> >> +foreach dep : ['librt', 'libm']
> >> +  spice_server_deps += compiler.find_library(dep)
> >> +endforeach
> >> +
> >> +#
> >> +# Non-mandatory/optional dependencies
> >> +#
> >> +optional_deps = [
> >> +                  ['celt051', '>= 0.5.1.1'],
> >> +                  ['opus', '>= 0.9.14'],
> >> +                ]
> >> +foreach dep : optional_deps
> >> +  option_value = get_option(dep[0])
> >> +  if option_value != 'false'
> >> +    d = dependency(dep[0], required: (option_value == 'true'), version :
> >> dep[1])
> >> +    if d.found()
> >> +      spice_server_deps += d
> >> +
> >> spice_server_config_data.set('HAVE_ at 0@'.format(dep[0].underscorify().to_upper()),
> >> '1')
> >> +    endif
> >> +  endif
> >> +endforeach
> >> +
> >> +# gstreamer
> >> +spice_server_has_gstreamer = false
> >> +spice_server_gst_version = get_option('gstreamer')
> >> +if spice_server_gst_version != 'no'
> >> +  gst_deps = ['gstreamer', 'gstreamer-base', 'gstreamer-app',
> >> 'gstreamer-video']
> >> +  foreach dep : gst_deps
> >> +    dep = '@0 at -@1@'.format(dep, spice_server_gst_version)
> >> +    spice_server_deps += dependency(dep)
> >> +  endforeach
> >> +  spice_server_deps += dependency('orc-0.4')
> >> +
> >> +  gst_def = 'HAVE_GSTREAMER'
> >> +  if spice_server_gst_version == '1.0'
> >> +    gst_def = 'HAVE_GSTREAMER_1_0'
> >> +  endif
> >> +
> >> +  spice_server_config_data.set(gst_def, '1')
> >> +  spice_server_has_gstreamer = true
> >> +endif
> >> +
> >> +# lz4
> >> +spice_server_has_lz4 = false
> >> +if get_option('lz4')
> >> +  lz4_dep = dependency('liblz4', required : false, version : '>= 129')
> >> +  if not lz4_dep.found()
> >> +    lz4_dep = dependency('liblz4', version : '>= 1.7.3')
> >> +  endif
> >> +
> >> +  if compiler.has_function('LZ4_compress_fast_continue', dependencies :
> >> lz4_dep)
> >> +    spice_server_config_data.set('HAVE_LZ4_COMPRESS_FAST_CONTINUE', '1')
> >> +  endif
> >> +
> >> +  spice_server_deps += lz4_dep
> >> +  spice_server_config_data.set('USE_LZ4', '1')
> >> +  spice_server_has_lz4 = true
> >> +endif
> >> +
> >> +# sasl
> >> +spice_server_has_sasl = false
> >> +if get_option('sasl')
> >> +  spice_server_deps += dependency('libsasl2')
> >> +  spice_server_config_data.set('HAVE_SASL', '1')
> >> +  spice_server_has_sasl = true
> >> +endif
> >> +
> >> +# smartcard check
> >> +spice_server_has_smartcard = false
> >> +if get_option('smartcard')
> >> +  smartcard_dep = dependency('libcacard', required : false, version : '>=
> >> 2.5.1')
> >> +  if smartcard_dep.found()
> >> +    spice_server_deps += smartcard_dep
> >> +    spice_server_config_data.set('USE_SMARTCARD', '1')
> >> +  else
> >> +    smartcard012_dep = dependency('libcacard', required : false, version
> >> :
> >> '>= 0.1.2')
> >> +    if smartcard012_dep.found()
> >> +      spice_server_deps += smartcard012_dep
> >> +      spice_server_config_data.set('USE_SMARTCARD_012', '1')
> >> +    endif
> >> +  endif
> >> +
> >> +  spice_server_has_smartcard = smartcard_dep.found() or
> >> smartcard012_dep.found()
> >> +  if not spice_server_has_smartcard
> >> +    error('Building with smartcard support but dependency not found')
> >> +  endif
> >> +endif
> >> +
> >> +#
> >> +# global C defines
> >> +#
> >> +glib_major_minor = glib_version.split('.')
> >> +glib_encoded_version = 'GLIB_VERSION_ at 0@_ at 1@'.format(glib_major_minor[0],
> >> glib_major_minor[1])
> >> +spice_server_global_cflags +=
> >> ['-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_encoded_version),
> >> +
> >> '-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_encoded_version)]
> >> +
> >> +foreach arg : spice_server_global_cflags
> >> +  add_project_arguments(arg, language : 'c')
> >> +endforeach
> >> +
> >> +#
> >> +# Subdirectories
> >> +#
> >> +subdir('server')
> >> +subdir('tools')
> >> +subdir('docs')
> >> +
> >> +#
> >> +# write config.h
> >> +#
> >> +spice_server_config_data.set_quoted('VERSION', meson.project_version())
> >> +spice_server_config_data.set('SPICE_USE_SAFER_CONTAINEROF', '1')
> >> +
> >> +if get_option('statistics')
> >> +  spice_server_config_data.set('RED_STATISTICS', '1')
> >> +endif
> >> +
> >> +configure_file(output : 'config.h',
> >> +               install : false,
> >> +               configuration : spice_server_config_data)
> >> +
> >> +#
> >> +# write spice-server.pc
> >> +#
> >> +pkgconfig = import('pkgconfig')
> >> +pkgconfig.generate(spice_server_shared_lib,
> >> +                   description : 'SPICE server library',
> >> +                   requires : 'spice-protocol
> >> @0@'.format(spice_protocol_version),
> >> +                   variables : 'exec_prefix=${prefix}',
> >> +                   subdirs : 'spice-server')
> > 
> > Was testing the difference in installed files. From autoconf:
> > 
> > -----
> > prefix=/home/freddy/qemu
> > exec_prefix=${prefix}
> > libdir=${exec_prefix}/lib
> > includedir=${prefix}/include
> > 
> > Name: spice
> > Description: SPICE server library
> > Version: 0.14.0.292-aad0-dirty
> > 
> > Requires: spice-protocol >= 0.12.15
> > Requires.private:  libcacard >= 0.1.2 glib-2.0 >= 2.32 gio-2.0 >= 2.32
> > gobject-2.0 >= 2.32 pixman-1 >= 0.17.7 openssl
> > Libs: -L${libdir} -lspice-server
> > Libs.private:  -pthread -lm -lrt
> > Cflags: -I${includedir}/spice-server
> > ----
> > 
> > From Meson:
> > -----
> > prefix=/usr/local
> > libdir=${prefix}/lib64
> > includedir=${prefix}/include
> > 
> > exec_prefix=${prefix}
> > 
> > Name: spice-server
> > Description: SPICE server library
> > Version: 0.14.0.292-aad0-dirty
> > Requires: spice-protocol >=  0.12.15, spice-protocol >=  0.12.12
> > Requires.private: glib-2.0 >=  2.38, gio-2.0 >=  2.38, gthread-2.0 >=
> > 2.38, pixman-1 >=  0.17.7, openssl >=  1.0.0, celt051 >=  0.5.1.1, opus
> > >=  0.9.14, libcacard >=  0.1.2, gobject-2.0 >=  2.38, libjpeg, zlib,
> > gstreamer-1.0, gstreamer-base-1.0, gstreamer-app-1.0, gstreamer-video-1.0,
> > orc-0.4, liblz4 >=  1.7.3, libsasl2
> > Libs: -L${libdir} -lspice-server
> > Libs.private: -lm -L${libdir} -lspice-common -lm -lm -lspice-common-server
> > -lm /usr/lib64/librt.so /usr/lib64/libm.so
> > Cflags: -I${includedir}/spice-server
> > -----
> > 
> > Beside directories that is up to the setup:
> > - Name is spice for autotools, spice-server for Meson, seems more correct
> > Meson
> > - Requires in Meson specify 2 times spice-protocol, should not be an issue
> > - Requires.private in Meson contains a lot of more libraries, this cause
> > pkg-config --cflags to add a lot of include directories which are not
> > required to link to spice library and IMHO should be avoided
> > - Libs.private contains duplications, direct shared library names (why?)
> > and libraries (spice-common) which should not be there. Not clear where
> > this directive is used, pkg-config --libs seems not to consider these
> > libraries.
> > I don't know how to solve these, maybe the spice-common library should be
> > more a static library (in libtool they are called convenience libraries).
> > 
> 
> Basically meson uses the dependencies to build the pkgconfig file. In
> the case of two spice-protocol in 'Requires', the second one comes from
> spice-common, which explains the different version. The duplication in
> 'Libs.private' seems to be the same.
> 
> If you think it is necessary, we can of course keep using the
> spice.pc.in instead of the built-in pkgconfig module for meson. This
> will give exact same results as in autotools build.
> 

I'll explain why this module in Meson is buggy.

Let's say I'm building libc using Meson. libc uses kernel headers to use
some feature and expose a more or less plain C interface.
Do you think all code using libc have to include kernel headers or have
these include in their path list? Surely no, but Meson include directory
paths for all dependencies! Unless the libc headers include kernel headers
but is up to libc to tell the build system this.

In recent systems for dynamic object (.so/.dll/.whatever) loading the same
is true so the Libs directive is correct.

The Libs.private however is expected to be used for static library, now:
1- the library passed is only dynamic, no reason to provide option for
   a library that won't be installed;
2- the directive include a mix of system libraries (-lm), convenience
   libraries (-lspice-common) and dynamic libraries (/usr/lib64/libm.so)
   but if you want static library you usually want static linking so why
   to include dynamic ones?
5- why libm is specified 5 times?

Frediano


More information about the Spice-devel mailing list