[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