1# This file is part of libsigc++.
2
3project('libsigc++', 'cpp',
4  version: '3.0.7',
5  license: 'LGPLv2.1+',
6  default_options: [
7    'cpp_std=c++17',
8    'warning_level=0',
9  ],
10  meson_version: '>= 0.51.0', # required for dep.get_variable()
11)
12#TODO: Require meson_version: '>= 0.54.0' when it's available
13# in GitHub's CI (continuous integration).
14# meson_version() >= 0.54.0 is necessary if sigc++ is a subproject,
15# or if mm-common is a subproject of sigc++.
16
17sigcxx_api_version = '3.0'
18sigcxx_pcname = 'sigc++-' + sigcxx_api_version
19
20sigcxx_version_array = meson.project_version().split('.')
21sigcxx_major_version = sigcxx_version_array[0].to_int()
22sigcxx_minor_version = sigcxx_version_array[1].to_int()
23sigcxx_micro_version = sigcxx_version_array[2].to_int()
24
25# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
26# The relation between libtool's current:revison:age interface versioning
27# and the .so filename, .so.x.y.z, is
28# x = current - age
29# y = age
30# z = revision
31# If libtool_soversion is updated as described in libtool's documentation,
32# x.y.z will usually *not* be equal to meson.project_version().
33libtool_soversion = [0, 0, 0]
34sigcxx_libversion = '@0@.@1@.@2@'.format(
35  libtool_soversion[0] - libtool_soversion[2],
36  libtool_soversion[2],
37  libtool_soversion[1])
38darwin_versions = [libtool_soversion[0] + 1, '@0@.@1@'.format(libtool_soversion[0] + 1, libtool_soversion[1])]
39
40# Use these instead of meson.source_root() and meson.build_root() in subdirectories.
41# source_root() and build_root() are not useful, if this is a subproject.
42project_source_root = meson.current_source_dir()
43project_build_root = meson.current_build_dir()
44
45cpp_compiler = meson.get_compiler('cpp')
46is_msvc = cpp_compiler.get_id() == 'msvc'
47python3 = import('python').find_installation()
48
49python_version = python3.language_version()
50python_version_req = '>= 3.5'
51if not python_version.version_compare(python_version_req)
52  error('Requires Python @0@, found @1@.'.format(python_version_req, python_version))
53endif
54
55# Do we build from a git repository?
56# Suppose we do if and only if a '.git' directory or file exists.
57cmd_py = '''
58import os
59import sys
60sys.exit(os.path.isdir("@0@") or os.path.isfile("@0@"))
61'''.format(project_source_root / '.git')
62is_git_build = run_command(python3, '-c', cmd_py).returncode() != 0
63
64# Are we testing a dist tarball while it's being built?
65# There ought to be a better way. https://github.com/mesonbuild/meson/issues/6866
66is_dist_check = project_source_root.contains('dist-unpack') and \
67                project_build_root.contains('dist-build')
68
69# Options.
70maintainer_mode_opt = get_option('maintainer-mode')
71maintainer_mode = maintainer_mode_opt == 'true' or \
72                 (maintainer_mode_opt == 'if-git-build' and is_git_build)
73if is_dist_check
74  message('Looks like a tarball is being tested. ' + \
75          'Option "dist-warnings" is used instead of "warnings".')
76  warning_level = get_option('dist-warnings')
77else
78  warning_level = get_option('warnings')
79endif
80build_deprecated_api = get_option('build-deprecated-api')
81build_documentation_opt = get_option('build-documentation')
82build_documentation = build_documentation_opt == 'true' or \
83                     (build_documentation_opt == 'if-maintainer-mode' and maintainer_mode)
84build_examples = get_option('build-examples')
85do_benchmark = get_option('benchmark')
86
87# Installation directories are relative to {prefix}.
88install_prefix = get_option('prefix')
89install_includedir = get_option('includedir')
90install_libdir = get_option('libdir')
91install_datadir = get_option('datadir')
92install_pkgconfigdir = install_libdir / 'pkgconfig'
93
94# Dependencies.
95# sigcxx_build_dep: Dependencies when building the libsigc++ library.
96# sigcxx_dep (created in sigc++/meson.build):
97#   Dependencies when using the libsigc++ library.
98sigcxx_build_dep = [] # No dependencies
99
100benchmark_dep = dependency('boost', modules: ['system', 'timer'],
101                           version: '>=1.20.0', required: do_benchmark)
102can_benchmark = benchmark_dep.found()
103
104if is_msvc
105  # We must have Visual Studio 2017 15.7 or later...
106  assert(cpp_compiler.version().split('.')[0].to_int() >= 19 and \
107         cpp_compiler.version().split('.')[1].to_int() >= 15,
108         'Visual Studio 2017 15.7 or later is required')
109endif
110
111# Some dependencies are required only in maintainer mode and/or
112# if documentation shall be built.
113mm_common_get = find_program('mm-common-get', required: false)
114
115if maintainer_mode and not mm_common_get.found()
116  message('Maintainer mode requires the \'mm-common-get\' command. If it is not found,\n' +
117          'use \'-Dmaintainer-mode=false\' or install the \'mm-common\' package, version 1.0.0 or higher.')
118  # If meson --wrap-mode != forcefallback, Meson falls back to the mm-common
119  # subproject only if mm-common-get is required.
120  mm_common_get = find_program('mm-common-get', required: true)
121endif
122
123perl = find_program('perl', required: build_documentation)
124doxygen = find_program('doxygen', required: build_documentation)
125dot = find_program('dot', required: build_documentation) # Used by Doxygen
126xsltproc = find_program('xsltproc', required: build_documentation)
127
128script_dir = project_source_root / 'untracked' / 'build_scripts'
129doc_reference = script_dir / 'doc-reference.py'
130dist_changelog = script_dir / 'dist-changelog.py'
131dist_build_scripts = script_dir / 'dist-build-scripts.py'
132tutorial_custom_cmd = project_source_root / 'tools' / 'tutorial-custom-cmd.py'
133
134if maintainer_mode
135  # Copy files to untracked/build_scripts and untracked/docs/docs.
136  run_command(mm_common_get, '--force', script_dir,
137    project_source_root / 'untracked' / 'docs' / 'docs')
138else
139  cmd_py = '''
140import os
141import sys
142sys.exit(os.path.isfile("@0@"))
143'''.format(doc_reference)
144  file_exists = run_command(python3, '-c', cmd_py).returncode() != 0
145  if not file_exists
146    warning('Missing files in untracked/. ' + \
147    'Enable maintainer-mode if you want to build documentation or create a dist tarball.')
148  endif
149endif
150
151# Set compiler warnings.
152warning_flags = []
153if warning_level == 'min'
154  if is_msvc
155    warning_flags = ['/W3']
156  else
157    warning_flags = ['-Wall']
158  endif
159elif warning_level == 'max' or warning_level == 'fatal'
160  if is_msvc
161    warning_flags = ['/W4']
162  else
163    warning_flags = '-pedantic -Wall -Wextra -Wsuggest-override -Wshadow -Wzero-as-null-pointer-constant -Wformat-security'.split()
164  endif
165  if warning_level == 'fatal'
166    if is_msvc
167      warning_flags += ['/WX']
168    else
169      warning_flags += ['-Werror']
170    endif
171  endif
172endif
173
174warning_flags = cpp_compiler.get_supported_arguments(warning_flags)
175add_project_arguments(warning_flags, language: 'cpp')
176
177# MSVC: Ignore warnings that aren't really harmful, but make those
178#       that should not be overlooked stand out.
179if is_msvc
180  foreach wd : ['/FImsvc_recommended_pragmas.h', '/EHsc', '/wd4267', '/utf-8']
181    disabled_warning = cpp_compiler.get_supported_arguments(wd)
182    add_project_arguments(disabled_warning, language: 'cpp')
183  endforeach
184endif
185
186# Configure files
187pkg_conf_data = configuration_data()
188pkg_conf_data.set('prefix', install_prefix)
189pkg_conf_data.set('exec_prefix', '${prefix}')
190pkg_conf_data.set('libdir', '${exec_prefix}' / install_libdir)
191pkg_conf_data.set('datarootdir', '${prefix}' / install_datadir)
192pkg_conf_data.set('datadir', '${datarootdir}')
193pkg_conf_data.set('includedir', '${prefix}' / install_includedir)
194pkg_conf_data.set('top_srcdir', project_source_root)
195pkg_conf_data.set('PACKAGE_VERSION', meson.project_version())
196pkg_conf_data.set('SIGCXX_API_VERSION', sigcxx_api_version)
197
198if not build_deprecated_api
199  pkg_conf_data.set('SIGCXX_DISABLE_DEPRECATED', true)
200endif
201pkg_conf_data.set('SIGCXX_MAJOR_VERSION', sigcxx_major_version)
202pkg_conf_data.set('SIGCXX_MINOR_VERSION', sigcxx_minor_version)
203pkg_conf_data.set('SIGCXX_MICRO_VERSION', sigcxx_micro_version)
204
205configure_file(
206  input: 'sigc++.pc.in',
207  output: sigcxx_pcname + '.pc',
208  configuration: pkg_conf_data,
209  install_dir: install_pkgconfigdir,
210)
211
212configure_file(
213  input: 'sigc++-uninstalled.pc.in',
214  output: sigcxx_pcname + '-uninstalled.pc',
215  configuration: pkg_conf_data,
216)
217
218install_includeconfigdir = install_libdir / sigcxx_pcname / 'include'
219sigcxxconfig_h = configure_file(
220  input: 'sigc++config.h.meson',
221  output: 'sigc++config.h',
222  configuration: pkg_conf_data,
223  install_dir: install_includeconfigdir,
224)
225
226# add_dist_script() is not allowed in a subproject if meson.version() < 0.58.0.
227can_add_dist_script = not meson.is_subproject() or meson.version().version_compare('>= 0.58.0')
228
229#subdir('cmake')
230subdir('MSVC_NMake')
231subdir('sigc++')
232subdir('examples')
233subdir('tests')
234subdir('docs/docs/reference')
235subdir('docs/docs/manual')
236
237if can_add_dist_script
238  # Add a ChangeLog file to the distribution directory.
239  meson.add_dist_script(
240    python3.path(), dist_changelog,
241    project_source_root,
242  )
243  # Add build scripts to the distribution directory, and delete .gitignore
244  # files and an empty $MESON_PROJECT_DIST_ROOT/build/ directory.
245  meson.add_dist_script(
246    python3.path(), dist_build_scripts,
247    project_source_root,
248    'untracked' / 'build_scripts',
249  )
250endif
251
252if meson.is_subproject()
253  pkgconfig_vars = {
254    'htmlrefdir': install_prefix / install_docdir / 'reference' / 'html',
255    'htmlrefpub': 'http://library.gnome.org/devel/libsigc++/unstable/'
256  }
257  if build_documentation
258    pkgconfig_vars += {'doxytagfile': tag_file.full_path()}
259    # May be used in a main project.
260    global_tag_file_target = tag_file
261  endif
262  sigcxx_dep = declare_dependency(
263    dependencies: sigcxx_own_dep,
264    variables: pkgconfig_vars,
265  )
266
267  # A main project that looks for sigcxx_pcname.pc shall find sigcxx_dep.
268  meson.override_dependency(sigcxx_pcname, sigcxx_dep)
269endif
270
271# Print a summary.
272real_maintainer_mode = ''
273if maintainer_mode_opt == 'if-git-build'
274  real_maintainer_mode = ' (@0@)'.format(maintainer_mode)
275endif
276
277real_build_documentation = ''
278if build_documentation_opt == 'if-maintainer-mode'
279  real_build_documentation = ' (@0@)'.format(build_documentation)
280endif
281
282validate = get_option('validation') and can_parse_and_validate
283explain_val = ''
284if get_option('validation') and not validate
285  explain_val = ' (requires xmllint)'
286endif
287
288build_pdf = build_pdf_by_default and can_build_pdf
289explain_pdf = ''
290if build_pdf_by_default and not build_pdf
291  explain_pdf = ' (requires dblatex or (xmllint and docbook2pdf))'
292endif
293
294
295
296summary = [
297  '',
298  '------',
299  meson.project_name() + ' ' + meson.project_version(),
300  '',
301  '         Maintainer mode: @0@@1@'.format(maintainer_mode_opt, real_maintainer_mode),
302  '       Compiler warnings: @0@'.format(warning_level),
303  '    Build deprecated API: @0@'.format(build_deprecated_api),
304  'Build HTML documentation: @0@@1@'.format(build_documentation_opt, real_build_documentation),
305  '          XML validation: @0@@1@'.format(validate, explain_val),
306  '               Build PDF: @0@@1@'.format(build_pdf, explain_pdf),
307  '  Build example programs: @0@'.format(build_examples),
308  '               Benchmark: @0@'.format(do_benchmark),
309  'Directories:',
310  '                  prefix: @0@'.format(install_prefix),
311  '              includedir: @0@'.format(install_prefix / install_includedir),
312  '        includesigcxxdir: @0@'.format(install_prefix / install_includedir / sigcxx_pcname),
313  '                  libdir: @0@'.format(install_prefix / install_libdir),
314  '        includeconfigdir: @0@'.format(install_prefix / install_includeconfigdir),
315  '            pkgconfigdir: @0@'.format(install_prefix / install_pkgconfigdir),
316  '                 datadir: @0@'.format(install_prefix / install_datadir),
317  '                  docdir: @0@'.format(install_prefix / install_docdir),
318  '              devhelpdir: @0@'.format(install_prefix / install_devhelpdir),
319  '             tutorialdir: @0@'.format(install_prefix / install_tutorialdir),
320  '------'
321]
322
323message('\n'.join(summary))
324