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

Eduardo Lima (Etrunko) etrunko at redhat.com
Fri Jul 27 11:41:10 UTC 2018


On 27/07/18 06:52, Frediano Ziglio wrote:
>>
>> 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?
> 

Agreed, will change this in order to keep using the template file.

> Frediano
> 


-- 
Eduardo de Barros Lima (Etrunko)
Software Engineer - RedHat
etrunko at redhat.com


More information about the Spice-devel mailing list