[Spice-devel] [PATCH spice-common v3] Add support for building with meson/ninja

Frediano Ziglio fziglio at redhat.com
Fri Jun 1 13:38:34 UTC 2018


> 
> 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>

For me,

Acked-by: Frediano Ziglio <fziglio at redhat.com>

Frediano

> ---
> Changes in v2:
>  - Rebased upstream, adding test-overflow to the tests
>  - Added files under python_modules/ as dependency of generated
>    sources, so that if any of those are changed, ninja will trigger
>    regeneration of the marshallers/demarshallers.
> 
> Changes in v3:
>  - Rebased upstream, added test-quic
>  - Strict dependency checking, not testing for deps required by other
>    projects
>  - Removed 'protocol-version' option
>  - Don't propagate cflags to other projects.
> 
>  Makefile.am                |   2 +
>  common/Makefile.am         |   1 +
>  common/meson.build         | 130 ++++++++++++++++++++++++++++++++
>  docs/.gitignore            |   1 +
>  docs/Makefile.am           |   1 +
>  docs/meson.build           |  10 +++
>  meson.build                | 182
>  +++++++++++++++++++++++++++++++++++++++++++++
>  meson_options.txt          |  32 ++++++++
>  python_modules/Makefile.am |   2 +-
>  python_modules/meson.build |   6 ++
>  tests/Makefile.am          |   1 +
>  tests/meson.build          |  52 +++++++++++++
>  12 files changed, 419 insertions(+), 1 deletion(-)
>  create mode 100644 common/meson.build
>  create mode 100644 docs/.gitignore
>  create mode 100644 docs/meson.build
>  create mode 100644 meson.build
>  create mode 100644 meson_options.txt
>  create mode 100644 python_modules/meson.build
>  create mode 100644 tests/meson.build
> 
> diff --git a/Makefile.am b/Makefile.am
> index ee0a1e2..e5630a9 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -4,6 +4,8 @@ ACLOCAL_AMFLAGS = -I m4
>  SUBDIRS = python_modules common tests docs
>  
>  EXTRA_DIST =				\
> +	meson.build			\
> +	meson_options.txt		\
>  	spice_codegen.py		\
>  	spice.proto			\
>  	spice1.proto			\
> diff --git a/common/Makefile.am b/common/Makefile.am
> index ea15039..defcb35 100644
> --- a/common/Makefile.am
> +++ b/common/Makefile.am
> @@ -129,6 +129,7 @@ generated_server_marshallers.h: $(top_srcdir)/spice.proto
> $(MARSHALLERS_DEPS)
>  EXTRA_DIST =				\
>  	$(CLIENT_MARSHALLERS)		\
>  	$(SERVER_MARSHALLERS)		\
> +	meson.build			\
>  	canvas_base.c			\
>  	canvas_base.h			\
>  	lz_compress_tmpl.c		\
> diff --git a/common/meson.build b/common/meson.build
> new file mode 100644
> index 0000000..9d46899
> --- /dev/null
> +++ b/common/meson.build
> @@ -0,0 +1,130 @@
> +#
> +# libspice-common
> +#
> +spice_common_sources = [
> +  'backtrace.c',
> +  'backtrace.h',
> +  'bitops.h',
> +  'canvas_utils.c',
> +  'canvas_utils.h',
> +  'draw.h',
> +  'lines.c',
> +  'lines.h',
> +  'log.c',
> +  'log.h',
> +  'lz.c',
> +  'lz.h',
> +  'lz_common.h',
> +  'lz_config.h',
> +  'macros.h',
> +  'marshaller.c',
> +  'marshaller.h',
> +  'mem.c',
> +  'mem.h',
> +  'messages.h',
> +  'pixman_utils.c',
> +  'pixman_utils.h',
> +  'quic.c',
> +  'quic.h',
> +  'quic_config.h',
> +  'rect.h',
> +  'region.c',
> +  'region.h',
> +  'ring.h',
> +  'rop3.c',
> +  'rop3.h',
> +  'snd_codec.c',
> +  'snd_codec.h',
> +  'spice_common.h',
> +  'verify.h'
> +]
> +
> +spice_common_lib = static_library('spice-common', spice_common_sources,
> +                                  install : false,
> +                                  include_directories :
> spice_common_include,
> +                                  dependencies : spice_common_deps)
> +
> +spice_common_dep = declare_dependency(link_with : spice_common_lib,
> +                                      include_directories :
> spice_common_include,
> +                                      dependencies : spice_common_deps)
> +
> +#
> +# libspice-common-client
> +#
> +if spice_common_generate_client_code
> +  targets = [
> +    ['client_demarshallers', spice_proto,
> 'generated_client_demarshallers.c', ['--generate-demarshallers', '--client',
> '--include', 'common/messages.h', '@INPUT@', '@OUTPUT@']],
> +    ['client_demarshallers1', spice1_proto,
> 'generated_client_demarshallers1.c', ['--generate-demarshallers',
> '--client', '--include', 'common/messages.h', '--prefix', '1', '--ptrsize',
> '8', '@INPUT@', '@OUTPUT@']],
> +    ['client_marshalers', spice_proto, 'generated_client_marshallers.c',
> ['--generate-marshallers', '-P', '--client', '--include',
> 'client_marshallers.h', '@INPUT@', '@OUTPUT@']],
> +    ['client_marshallers1', spice1_proto, 'generated_client_marshallers1.c',
> ['--generate-marshallers', '-P', '--client',  '--include',
> 'common/messages.h', '--include', 'client_marshallers.h', '--prefix', '1',
> '--ptrsize', '8', '@INPUT@', '@OUTPUT@']],
> +    ['client_marshallers_h', spice_proto, 'generated_client_marshallers.h',
> ['--generate-marshallers', '-P', '--client', '--include',
> 'common/messages.h', '-H', '@INPUT@', '@OUTPUT@']],
> +  ]
> +
> +  spice_common_client_sources = [
> +    'client_demarshallers.h',
> +    'client_marshallers.h',
> +    'ssl_verify.c',
> +    'ssl_verify.h',
> +  ]
> +
> +  foreach t : targets
> +    cmd = [python, spice_codegen] + t[3]
> +    target = custom_target(t[0], input : t[1], output : t[2], install :
> false, command : cmd, depend_files : spice_codegen_files)
> +    spice_common_client_sources += target
> +  endforeach
> +
> +  spice_common_client_lib = static_library('spice-common-client',
> spice_common_client_sources,
> +                                           install : false,
> +                                           dependencies : spice_common_dep)
> +
> +  spice_common_client_dep = declare_dependency(sources : target,
> +                                               link_with :
> spice_common_client_lib,
> +                                               dependencies :
> spice_common_dep)
> +endif
> +
> +#
> +# libspice-common-server
> +#
> +if spice_common_generate_server_code
> +  structs_args = [
> +   '-M', 'String',
> +   '-M', 'Rect',
> +   '-M', 'Point',
> +   '-M', 'DisplayBase',
> +   '-M', 'Fill',
> +   '-M', 'Opaque',
> +   '-M', 'Copy',
> +   '-M', 'Blend',
> +   '-M', 'Blackness',
> +   '-M', 'Whiteness',
> +   '-M', 'Invers',
> +   '-M', 'Rop3',
> +   '-M', 'Stroke',
> +   '-M', 'Text',
> +   '-M', 'Transparent',
> +   '-M', 'AlphaBlend',
> +   '-M', 'Composite',
> +  ]
> +
> +  targets = [
> +    ['server_demarshallers', spice_proto,
> 'generated_server_demarshallers.c', ['--generate-demarshallers', '--server',
> '--include', 'common/messages.h', '@INPUT@', '@OUTPUT@']],
> +    ['server_marshallers', spice_proto, 'generated_server_marshallers.c',
> ['--generate-marshallers', '--server'] + structs_args + ['--include',
> 'common/messages.h', '@INPUT@', '@OUTPUT@']],
> +    ['server_marshallers_h', spice_proto, 'generated_server_marshallers.h',
> ['--generate-marshallers', '--server'] + structs_args + ['--include',
> 'common/messages.h', '-H', '@INPUT@', '@OUTPUT@']],
> +  ]
> +
> +  spice_common_server_sources = []
> +
> +  foreach t : targets
> +    cmd = [python, spice_codegen] + t[3]
> +    target = custom_target(t[0], input : t[1], output : t[2], install :
> false, command : cmd, depend_files : spice_codegen_files)
> +    spice_common_server_sources += target
> +  endforeach
> +
> +  spice_common_server_lib = static_library('spice-common-server',
> spice_common_server_sources,
> +                                           install : false,
> +                                           dependencies : spice_common_dep)
> +
> +  spice_common_server_dep = declare_dependency(sources : target,
> +                                               link_with :
> spice_common_server_lib,
> +                                               dependencies :
> spice_common_dep)
> +endif
> diff --git a/docs/.gitignore b/docs/.gitignore
> new file mode 100644
> index 0000000..508590c
> --- /dev/null
> +++ b/docs/.gitignore
> @@ -0,0 +1 @@
> +spice_protocol.html
> diff --git a/docs/Makefile.am b/docs/Makefile.am
> index 20f46ef..421e5f9 100644
> --- a/docs/Makefile.am
> +++ b/docs/Makefile.am
> @@ -2,6 +2,7 @@ NULL =
>  ASCIIDOC_FLAGS = -a icons -a toc
>  
>  EXTRA_DIST =					\
> +	meson.build				\
>  	spice_protocol.txt			\
>  	$(NULL)
>  
> diff --git a/docs/meson.build b/docs/meson.build
> new file mode 100644
> index 0000000..5e10d76
> --- /dev/null
> +++ b/docs/meson.build
> @@ -0,0 +1,10 @@
> +if get_option('manual')
> +  asciidoc = find_program('asciidoc', required : false)
> +  if asciidoc.found()
> +    custom_target('spice_protocol.html',
> +                  input : files('spice_protocol.txt'),
> +                  output : 'spice_protocol.html',
> +                  build_by_default : true,
> +                  command : [asciidoc, '-n', '-a', 'icons', '-a', 'toc',
> '-o', '@OUTPUT@', '@INPUT@'])
> +  endif
> +endif
> diff --git a/meson.build b/meson.build
> new file mode 100644
> index 0000000..de777db
> --- /dev/null
> +++ b/meson.build
> @@ -0,0 +1,182 @@
> +#
> +# project definition
> +#
> +project('spice-common', 'c',
> +         meson_version : '>= 0.45.0',
> +         license : 'LGPLv2.1')
> +
> +if not meson.is_subproject()
> +  warning('This project is only intended to be used as a subproject!')
> +endif
> +
> +# some global vars
> +spice_common_global_cflags = [#'-std=c99', # fails compiling bitops.h
> +                              '-DHAVE_CONFIG_H',
> +                              '-DG_LOG_DOMAIN="Spice"',
> +                              '-Wall',
> +                              '-Wextra',
> +                              '-Werror',
> +                              '-Wno-unused-parameter']
> +
> +if get_option('alignment-checks')
> +  spice_common_global_cflags += ['-DSPICE_DEBUG_ALIGNMENT']
> +endif
> +
> +spice_common_deps = []
> +spice_common_include = include_directories('.')
> +
> +spice_proto = files('spice.proto')
> +spice1_proto = files('spice1.proto')
> +spice_codegen = files('spice_codegen.py')
> +spice_codegen_files = [spice_codegen]
> +
> +compiler = meson.get_compiler('c')
> +spice_common_config_data = configuration_data()
> +if get_option('extra-checks')
> +  spice_common_config_data.set('ENABLE_EXTRA_CHECKS', '1')
> +endif
> +
> +spice_common_generate_code = get_option('generate-code')
> +spice_common_generate_client_code = spice_common_generate_code == 'all' or
> spice_common_generate_code == 'client'
> +spice_common_generate_server_code = spice_common_generate_code == 'all' or
> spice_common_generate_code == 'server'
> +
> +#
> +# check for system headers
> +#
> +headers = ['alloca.h',
> +           'arpa/inet.h',
> +           'dlfcn.h',
> +           'inttypes.h',
> +           'malloc.h',
> +           'memory.h',
> +           'netinet/in.h',
> +           'stddef.h',
> +           'stdint.h',
> +           'stdlib.h',
> +           'strings.h',
> +           'string.h',
> +           'sys/socket.h',
> +           'sys/stat.h',
> +           'sys/types.h',
> +           'unistd.h',
> +           'vfork.h']
> +
> +foreach header : headers
> +  if compiler.has_header(header)
> +
> spice_common_config_data.set('HAVE_ at 0@'.format(header.underscorify().to_upper()),
> '1')
> +  endif
> +endforeach
> +
> +#
> +# check for system functions
> +#
> +functions = ['alloca',
> +             'dup2',
> +             'floor',
> +             'fork',
> +             'inet_ntoa',
> +             'memmove',
> +             'memset',
> +             'pow',
> +             'sqrt',
> +             'vfork']
> +
> +foreach func : functions
> +  if compiler.has_function(func)
> +    spice_common_config_data.set('HAVE_ at 0@'.format(func.to_upper()), '1')
> +  endif
> +endforeach
> +
> +
> +#
> +# check for mandatory dependencies
> +#
> +glib_version = '2.38'
> +glib_version_info = '>= @0@'.format(glib_version)
> +
> +deps = [['spice-protocol', '>= 0.12.12'],
> +        ['glib-2.0', glib_version_info],
> +        ['gio-2.0', glib_version_info],
> +        ['gthread-2.0', glib_version_info],
> +        ['pixman-1', '>= 0.17.7'],
> +        ['openssl', '>= 1.0.0']]
> +
> +foreach dep : deps
> +  spice_common_deps += dependency(dep[0], version : dep[1])
> +endforeach
> +
> +#
> +# Non-mandatory/optional dependencies
> +#
> +deps = [['opus', '>= 0.9.14', 'HAVE_OPUS'],]
> +
> +# Check deps which are optional but enabled by default. This foreach block
> only
> +# checks the option, and adds the package to the deps list, while the real
> check
> +# for the dependency is done in the foeach block below.
> +optional_deps = [['celt051', '>= 0.5.1.1', 'HAVE_CELT051'],]
> +foreach dep : optional_deps
> +  if get_option(dep[0])
> +    deps += [dep]
> +  endif
> +endforeach
> +
> +foreach dep : deps
> +  d = dependency(dep[0], required : false, version : dep[1])
> +  if d.found()
> +    spice_common_deps += d
> +    spice_common_config_data.set(dep[2], '1')
> +  endif
> +endforeach
> +
> +# Python
> +if get_option('python-checks')
> +  dependency('python3')
> +  py_module = import('python3')
> +  python = py_module.find_python()
> +  foreach module : ['six', 'pyparsing']
> +    cmd = run_command(python, '-m', module)
> +    if cmd.returncode() != 0
> +      error('Python module @0@ not found'.format(module))
> +    endif
> +  endforeach
> +endif
> +
> +# smartcard check
> +smartcard_dep = dependency('libcacard', required : false, version : '>=
> 2.5.1')
> +if smartcard_dep.found()
> +  spice_common_deps += smartcard_dep
> +  spice_common_config_data.set('USE_SMARTCARD', '1')
> +else
> +  smartcard012_dep = dependency('libcacard', required : false, version : '>=
> 0.1.2')
> +  if smartcard012_dep.found()
> +    spice_common_deps += smartcard012_dep
> +    spice_common_config_data.set('USE_SMARTCARD_012', '1')
> +  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_common_global_cflags +=
> ['-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_encoded_version),
> +
> '-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_encoded_version)]
> +
> +foreach arg : spice_common_global_cflags
> +  add_project_arguments(arg, language : 'c')
> +endforeach
> +
> +#
> +# Subdirectories
> +#
> +subdir('python_modules')
> +subdir('common')
> +subdir('tests')
> +subdir('docs')
> +
> +#
> +# write config.h
> +#
> +configure_file(output : 'config.h',
> +               install : false,
> +               configuration : spice_common_config_data)
> diff --git a/meson_options.txt b/meson_options.txt
> new file mode 100644
> index 0000000..5189f4f
> --- /dev/null
> +++ b/meson_options.txt
> @@ -0,0 +1,32 @@
> +option('alignment-checks',
> +    type : 'boolean',
> +    value : false,
> +    yield : true,
> +    description : 'Enable runtime checks for cast alignment
> (default=false)')
> +
> +option('extra-checks',
> +    type : 'boolean',
> +    value : false,
> +    yield : true,
> +    description : 'Enable extra checks on code (default=false)')
> +
> +option('celt051',
> +    type : 'boolean',
> +    value : true,
> +    description: 'Enable celt051 audio codec (default=true)')
> +
> +option('python-checks',
> +    type : 'boolean',
> +    value : true,
> +    description : 'Enable checks for Python modules needed to build from git
> (default=true)')
> +
> +option('manual',
> +    type : 'boolean',
> +    value : true,
> +    yield : true,
> +    description : 'Build SPICE manual (default=true)')
> +
> +option('generate-code',
> +    type : 'combo',
> +    choices : ['all', 'server', 'client'],
> +    description : 'Which code should be built (default=all)')
> diff --git a/python_modules/Makefile.am b/python_modules/Makefile.am
> index 50e1a71..07e1917 100644
> --- a/python_modules/Makefile.am
> +++ b/python_modules/Makefile.am
> @@ -9,7 +9,7 @@ PYTHON_MODULES =				\
>  	spice_parser.py				\
>  	$(NULL)
>  
> -EXTRA_DIST = $(PYTHON_MODULES)
> +EXTRA_DIST = meson.build $(PYTHON_MODULES)
>  
>  DISTCLEANFILES = *.pyc
>  
> diff --git a/python_modules/meson.build b/python_modules/meson.build
> new file mode 100644
> index 0000000..5ae0fd7
> --- /dev/null
> +++ b/python_modules/meson.build
> @@ -0,0 +1,6 @@
> +spice_codegen_files += files('codegen.py',
> +                             'demarshal.py',
> +                             '__init__.py',
> +                             'marshal.py',
> +                             'ptypes.py',
> +                             'spice_parser.py')
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index f03fdb4..7022808 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -85,6 +85,7 @@ generated_test_demarshallers.c:
> $(srcdir)/test-marshallers.proto $(MARSHALLERS_D
>  
>  EXTRA_DIST =				\
>  	$(TEST_MARSHALLERS)		\
> +	meson.build			\
>  	test-marshallers.proto		\
>  	$(NULL)
>  
> diff --git a/tests/meson.build b/tests/meson.build
> new file mode 100644
> index 0000000..18b03c4
> --- /dev/null
> +++ b/tests/meson.build
> @@ -0,0 +1,52 @@
> +#
> +# Build tests
> +#
> +tests = ['test-logging']
> +tests_deps = [spice_common_dep]
> +
> +if spice_common_generate_code == 'all'
> +  tests += ['test-overflow']
> +  tests_deps += [spice_common_client_dep, spice_common_server_dep]
> +endif
> +
> +foreach t : tests
> +  name = t.underscorify()
> +  exe = executable(name, '@0 at .c'.format(t),
> +                   dependencies : tests_deps,
> +                   install : false)
> +  test(name, exe)
> +endforeach
> +
> +#
> +# test_marshallers
> +#
> +test_proto = files('test-marshallers.proto')
> +
> +test_marshallers_sources = ['test-marshallers.c', 'test-marshallers.h']
> +
> +targets = [
> +    ['test_marshallers', test_proto, 'generated_test_marshallers.c',
> ['--generate-marshallers', '--server', '--include', 'test-marshallers.h',
> '@INPUT@', '@OUTPUT@']],
> +    ['test_marshallers_h', test_proto, 'generated_test_marshallers.h',
> ['--generate-marshallers', '--server', '--include', 'test-marshallers.h',
> '-H', '@INPUT@', '@OUTPUT@']],
> +    ['test_demarshallers', test_proto, 'generated_test_demarshallers.c',
> ['--generate-demarshallers', '--client', '--include', 'test-marshallers.h',
> '@INPUT@', '@OUTPUT@']],
> +]
> +
> +foreach t : targets
> +  cmd = [python, spice_codegen] + t[3]
> +  test_marshallers_sources += custom_target(t[0], input: t[1], output :
> t[2], command: cmd, depend_files : spice_codegen_files)
> +endforeach
> +
> +test('test_marshallers',
> +     executable('test_marshallers', test_marshallers_sources,
> +                dependencies : spice_common_dep,
> +                install : false))
> +
> +#
> +# test_quic
> +#
> +gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version : '>= 2.26', required
> : false)
> +if gdk_pixbuf_dep.found()
> +  test('test_quic',
> +       executable('test_quic', 'test-quic.c',
> +                  dependencies : [spice_common_dep, gdk_pixbuf_dep],
> +                  install : false))
> +endif


More information about the Spice-devel mailing list