1# Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot org>
2#
3# This file is part of Zrythm
4#
5# Zrythm is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Affero General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Zrythm is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU Affero General Public License for more details.
14#
15# You should have received a copy of the GNU Affero General Public License
16# along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
17
18project (
19  'zrythm', ['c', 'cpp'],
20  version: files ('VERSION'),
21  license: 'AGPL-3-or-later',
22  meson_version: '>= 0.57.0',
23  default_options: [
24    'warning_level=2',
25    'buildtype=debugoptimized',
26    'c_std=gnu11',
27    'b_lto=true',
28    'b_lto_threads=2',
29    ],
30  )
31
32# --- Import/configure required modules ---
33
34gnome = import ('gnome')
35fs = import ('fs')
36cmake = import ('cmake')
37cmake_opts = cmake.subproject_options ()
38cmake_opts.add_cmake_defines ({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'})
39
40# --- Check for programs ---
41
42find_program ('sed')
43find_program ('gettext')
44msgattrib = find_program ('msgattrib')
45msguniq = find_program ('msguniq')
46msggrep = find_program ('msggrep')
47msgfmt = find_program ('msgfmt', required: false)
48bash = find_program ('bash')
49grep = find_program ('grep')
50dot_bin = find_program ('dot', required: false)
51rubberband = find_program (
52  'rubberband', required: false)
53cppcheck = find_program (
54  'cppcheck', required: false)
55clang_tidy = find_program (
56  'clang-tidy', required: false)
57jq = find_program ('jq', required: false)
58sphinx_build = find_program (
59  ['sphinx-build', 'sphinx-build-3'],
60  required: get_option ('user_manual'))
61sphinx_intl = find_program (
62  'sphinx-intl',
63  required: get_option ('user_manual'))
64sass = find_program (
65  'sass', required: get_option ('user_manual'))
66help2man = find_program (
67  ['help2man'],
68  required: get_option ('manpage'))
69find_program (
70  'flex', required: get_option ('completions'))
71stoat = find_program (
72  ['stoat'], required: false)
73python3 = find_program (
74  ['python3', 'python'])
75guile = find_program (
76  ['guile2.2', 'guile'])
77guild = find_program (
78  ['guild2.2', 'guild'], required: false)
79guile_snarf = find_program (
80  ['guile-snarf2.2', 'guile-snarf'], required: false)
81pandoc = find_program (
82  ['pandoc'], required: false)
83texi2html = find_program (
84  ['texi2html'], required: false)
85ulimit = find_program (
86  'tools/check_have_unlimited_memlock.sh')
87lv2ls_bin = find_program ('lv2ls', required: false)
88lv2info_bin = find_program (
89  'lv2info', required: false)
90get_lv2_bundle_uri_bin = find_program (
91  'tools/get_lv2_bundle_uri.sh')
92get_vst_path_bin = find_program (
93  'tools/get_vst_path.sh')
94manpage_completions_run_sh = find_program (
95  'ext/sh-manpage-completions/run.sh')
96
97# --- Set common variables ---
98
99cc = meson.get_compiler ('c')
100is_gcc = cc.get_id() == 'gcc'
101
102meson_src_root = meson.current_source_dir ()
103meson_build_root = meson.current_build_dir ()
104
105prog_name = get_option ('program_name')
106prog_name_lowercase = prog_name.to_lower()
107copyright_name = 'The ' + prog_name + ' contributors'
108copyright_years = '2018-2021'
109
110prefix = get_option ('prefix')
111bindir = prefix / get_option ('bindir')
112libdir = prefix / get_option ('libdir')
113libexecdir = prefix / get_option ('libexecdir')
114includedir = prefix / get_option ('includedir')
115datadir = prefix / get_option ('datadir')
116sysconfdir = get_option ('sysconfdir')
117mandir = datadir / 'man' / 'man1'
118schemasdir = datadir / 'glib-2.0/schemas'
119fontsdir = datadir / 'fonts' / prog_name_lowercase
120zrythm_libdir = prefix / 'lib/zrythm'
121zrythmdatadir = datadir / prog_name_lowercase
122themesdir = zrythmdatadir / 'themes'
123themes_css_dir = themesdir / 'css'
124samplesdir = zrythmdatadir / 'samples'
125scriptsdir = zrythmdatadir / 'scripts'
126docdir = datadir / 'doc' / prog_name_lowercase
127sourceviewstylesdir = zrythmdatadir / 'sourceview-styles'
128
129resources_dir = meson_src_root / 'resources'
130data_dir = meson_src_root / 'data'
131
132# Used for building manpages, manual, etc., using
133# foreach.
134# The actual languages to use are specified in
135# po/LINGUAS.
136language_mappings = {
137  'af_ZA': 'Afrikaans',
138  'ar': 'اَلْعَرَبِيَّةُ‎',
139  'cs': 'Czech',
140  'da': 'Dansk',
141  'de': 'Deutsch',
142  'en': 'English',
143  'en_GB': 'English UK',
144  'el': 'Ελληνικά',
145  'es': 'Español',
146  'et': 'Eeti',
147  'fa': 'فارسی',
148  'fi': 'Suomi',
149  'fr': 'Français',
150  'gd': 'Gaelic',
151  'gl': 'Galego',
152  'hi': 'हिन्दी',
153  'id': 'bahasa Indonesia',
154  'it': 'Italiano',
155  'ja': '日本語',
156  'ko': '한국어',
157  'nb_NO': 'Bokmål',
158  'nl': 'Nederlands',
159  'pl': 'Polski',
160  'pt': 'Português',
161  'pt_BR': 'Português BR',
162  'ru': 'Русский',
163  'sv': 'Svenska',
164  'th': 'ภาษาไทย',
165  'tr': 'Türkiye',
166  'uk': 'Українська',
167  'vi': 'Tiếng Việt',
168  'zh_CN': '简体中文',
169  'zh_TW': '繁體中文',
170  }
171locales_str = run_command ('cat', 'po/LINGUAS').stdout ().strip ()
172locales = {}
173foreach locale : locales_str.split (' ')
174  locales += { locale: language_mappings[locale] }
175  if locale == 'de'
176    locales += { 'en': language_mappings['en'], }
177  endif
178endforeach
179locales_str = ' '.join (locales.keys())
180
181# get host system and library suffix
182os_darwin = false
183os_gnu = false
184os_freebsd = false
185os_windows = false
186bin_suffix = ''
187lib_suffix = '.so'
188
189if host_machine.system() == 'darwin'
190  os_darwin = true
191  lib_suffix = '.dylib'
192elif host_machine.system() == 'linux'
193  os_gnu = true
194elif host_machine.system() == 'freebsd' or host_machine.system() == 'dragonfly'
195  os_freebsd = true
196elif host_machine.system() == 'windows'
197  os_windows = true
198  bin_suffix = '.exe'
199  lib_suffix = '.dll'
200else
201  error ('unknown host system ' + host_machine.system ())
202endif
203
204have_custom_name = prog_name != 'Zrythm'
205have_custom_logo_and_splash = get_option ('custom_logo_and_splash')
206
207# include dirs
208root_inc = include_directories ('.')
209inc_inc = include_directories ('inc')
210ext_inc = include_directories ('ext')
211midilib_inc = include_directories ('ext/midilib')
212whereami_inc = include_directories ('ext/whereami')
213zix_inc = include_directories ('ext/zix')
214weakjack_inc = include_directories ('ext/weakjack')
215suil_inc = include_directories ('inc/plugins/lv2')
216all_inc = [
217  root_inc,
218  inc_inc,
219  ext_inc,
220  midilib_inc,
221  whereami_inc,
222  zix_inc,
223  weakjack_inc,
224  suil_inc,
225  ]
226
227all_static = get_option ('static_deps')
228
229# plugins for testing
230ext_lv2_plugins = {
231  'ams_lfo': [
232    'AMS LFO',
233    'http://github.com/blablack/ams-lv2/lfo'],
234  'calf_monosynth': [
235    'Calf Monosynth',
236    'http://calf.sourceforge.net/plugins/Monosynth'],
237  'helm': [
238    'Helm', 'http://tytel.org/helm'],
239  'sherlock_atom_inspector': [
240    'Sherlock Atom Inspector',
241    'http://open-music-kontrollers.ch/lv2/sherlock#atom_inspector'],
242  'lsp_compressor': [
243    'LSP Compressor',
244    'http://lsp-plug.in/plugins/lv2/compressor_stereo'],
245  'lsp_sidechain_compressor': [
246    'LSP Sidechain Compressor',
247    'http://lsp-plug.in/plugins/lv2/sc_compressor_stereo'],
248  'lsp_multisampler_24_do': [
249    'LSP MultiSampler x24 Direct Out',
250    'http://lsp-plug.in/plugins/lv2/multisampler_x24_do'],
251  'carla_rack': [
252    'Carla Rack',
253    'http://kxstudio.sf.net/carla/plugins/carlarack'],
254  'no_delay_line': [
255    'No Delay Line',
256    'http://gareus.org/oss/lv2/nodelay'],
257  'mda_ambience': [
258    'mda Ambience',
259    'http://drobilla.net/plugins/mda/Ambience'],
260  'midi_cc_map': [
261    'MIDI CC Map',
262    'http://gareus.org/oss/lv2/midifilter#mapcc'],
263  'noize_maker': [
264    'NoizeMak3r',
265    'http://kunz.corrupt.ch/products/tal-noisemaker'],
266  'tal_filter': [
267    'TAL Filter',
268    'urn:juce:TalFilter'],
269  'geonkick': [
270    'Geonkick',
271    'http://geontime.com/geonkick/single'],
272  'chipwave': [
273    'ChipWave',
274    'https://github.com/linuxmao-org/shiru-plugins/chipwave'],
275  'calf_compressor': [
276    'Calf Compressor',
277    'http://calf.sourceforge.net/plugins/Compressor'],
278  'mverb': [
279    'MVerb',
280    'http://distrho.sf.net/plugins/MVerb'],
281  'sfizz': [
282    'Sfizz',
283    'http://sfztools.github.io/sfizz'],
284  'drops': [
285    'Drops',
286    'http://github.com/clearly-broken-software/drops'],
287  'test_signal': [
288    'Test Signal',
289    'http://gareus.org/oss/lv2/testsignal'],
290  }
291have_ext_lv2_plugins = {}
292ext_lv2_plugin_bundles = {}
293ext_vst_plugins = {
294  'noizemaker': 'TAL-NoiseMaker.so',
295  }
296have_ext_vst_plugins = {}
297ext_vst_plugin_paths = {}
298if get_option ('tests')
299  # get lv2 bundle paths
300  if lv2ls_bin.found () and lv2info_bin.found ()
301    lv2ls_res = run_command (
302      lv2ls_bin, check: true).stdout ()
303    foreach name, info : ext_lv2_plugins
304      uri = info[1]
305      have_ext_lv2 = lv2ls_res.contains (uri)
306      have_ext_lv2_plugins += {
307        name: have_ext_lv2
308        }
309      if have_ext_lv2
310        ext_lv2_plugin_bundles += {
311          name: run_command (
312            get_lv2_bundle_uri_bin, lv2info_bin,
313            uri, check: true).stdout ().strip ()
314          }
315      endif
316    endforeach
317  endif
318  # get vst plugin paths
319  if get_vst_path_bin.found ()
320    foreach name, filename : ext_vst_plugins
321      have_ext_vst = run_command (
322        get_vst_path_bin,
323        filename).returncode () == 0
324      have_ext_vst_plugins += {
325        name: have_ext_vst
326        }
327      if have_ext_vst
328        ext_vst_plugin_paths += {
329          name: run_command (
330            get_vst_path_bin, filename,
331            check: true).stdout ().strip ()
332          }
333      endif
334    endforeach
335  endif
336endif
337
338# command to open a directory
339if os_gnu or os_freebsd
340  open_dir_cmd = find_program ('xdg-open').full_path ()
341elif os_darwin
342  open_dir_cmd = 'open'
343  find_program (open_dir_cmd)
344elif os_windows
345  open_dir_cmd = 'explorer.exe'
346endif
347
348# illegal characters to detect in PO files
349illegal_chars = [
350  ' ', # U+202F
351  ]
352illegal_char_test_args = [
353  '-c', '! "$1" -rn "$2" "$3"', '_ignored',
354  grep.full_path (),
355  ]
356
357# --- Add extra languages ---
358
359if os_darwin
360  add_languages(['objc', 'objcpp'])
361endif
362
363# --- Create configuration data ---
364#
365# Note: more configuration data might be added after
366# this section.
367
368cdata = configuration_data ()
369cdata.set_quoted ('PROGRAM_NAME', prog_name)
370cdata.set_quoted (
371  'PROGRAM_NAME_LOWERCASE', prog_name_lowercase)
372if have_custom_name
373  cdata.set ('HAVE_CUSTOM_NAME', 1)
374endif
375if have_custom_logo_and_splash
376  cdata.set ('HAVE_CUSTOM_LOGO_AND_SPLASH', 1)
377endif
378cdata.set_quoted (
379  'COPYRIGHT_NAME', copyright_name)
380cdata.set_quoted (
381  'COPYRIGHT_YEARS', copyright_years)
382cdata.set_quoted (
383  'HOST_MACHINE_SYSTEM', host_machine.system ())
384cdata.set_quoted (
385  'PACKAGE_VERSION', '@VCS_TAG@')
386cdata.set_quoted (
387  'COMPILER',
388  meson.get_compiler('c').get_id())
389cdata.set_quoted ('PREFIX', prefix)
390cdata.set_quoted (
391  'COMPILER_VERSION',
392  meson.get_compiler('c').version())
393cdata.set_quoted ('CONFIGURE_DATADIR', datadir)
394cdata.set_quoted (
395  'CONFIGURE_SOURCEVIEW_STYLES_DIR',
396  sourceviewstylesdir)
397cdata.set_quoted (
398  'CONFIGURE_THEMES_DIR', themesdir)
399cdata.set_quoted (
400  'CONFIGURE_THEMES_CSS_DIR', themes_css_dir)
401cdata.set_quoted (
402  'LIBDIR_NAME', get_option ('libdir'))
403if get_option ('check_updates')
404  cdata.set ('CHECK_UPDATES', 1)
405endif
406cdata.set_quoted ('CONFIGURE_LIBDIR', libdir)
407cdata.set_quoted ('CONFIGURE_BINDIR', bindir)
408cdata.set_quoted ('LIB_SUFFIX', lib_suffix)
409cdata.set_quoted ('BIN_SUFFIX', bin_suffix)
410cdata.set_quoted ('GSCHEMAS_DIR', schemasdir)
411cdata.set_quoted (
412  'BUILD_TYPE', get_option ('buildtype'))
413cdata.set_quoted (
414  'OPTIMIZATION', get_option ('optimization'))
415if get_option ('debug')
416  cdata.set ('IS_DEBUG_BUILD', 1)
417endif
418cdata.set_quoted (
419  'INSTALLER_VERSION_STR',
420  get_option ('buildtype'))
421if get_option ('trial_ver')
422  cdata.set ('TRIAL_VER', 1)
423endif
424if get_option ('installer_ver')
425  cdata.set ('INSTALLER_VER', 1)
426endif
427if get_option ('appimage')
428  cdata.set ('APPIMAGE_BUILD', 1)
429endif
430cdata.set (
431  'MESON_SOURCE_ROOT', meson_src_root)
432cdata.set (
433  'MESON_BUILD_ROOT', meson_build_root)
434cdata.set_quoted('OPEN_DIR_CMD', open_dir_cmd)
435cdata.set_quoted (
436  'ISSUE_TRACKER_URL',
437  'https://sr.ht/~alextee/zrythm/trackers')
438cdata.set_quoted (
439  'NEW_ISSUE_URL',
440  'https://todo.sr.ht/~alextee/zrythm-bug')
441cdata.set_quoted (
442  'NEW_ISSUE_EMAIL',
443  '~alextee/zrythm-bug@todo.sr.ht')
444cdata.set_quoted (
445  'PRIVACY_POLICY_URL',
446  'https://www.zrythm.org/en/privacy.html')
447cdata.set_quoted (
448  'BUG_REPORT_API_ENDPOINT',
449  'https://accounts.zrythm.org/api/v1/error-reports/new')
450if (get_option ('user_manual'))
451  cdata.set_quoted ('MANUAL_PATH', docdir)
452endif
453
454if os_windows
455  cdata.set ('USE_MMCSS_THREAD_PRIORITIES', 1)
456endif
457
458# if latest version in changelog is the project's
459# version, add the changelog to the config
460chlog = fs.read ('CHANGELOG.md').split('\n## [')[1].strip ()
461if chlog.contains (meson.project_version () + '] -')
462  chlog_date = chlog.split (' - ')[1].split ('\n')[0]
463  chlog = chlog.split (chlog_date + '\n')[1]
464  cdata.set ('HAVE_CHANGELOG', 1)
465  cdata.set_quoted ('CHANGELOG_DATE', chlog_date)
466  cdata.set_quoted ('CHANGELOG_TXT', '\\n'.join (chlog.split ('\n')))
467endif
468
469if os_gnu
470  have_unlimited_mem = run_command (
471    ulimit, check: true).stdout ().strip () == 'unlimited'
472  if have_unlimited_mem
473    cdata.set ('HAVE_UNLIMITED_MEM', 1)
474  endif
475endif
476
477# --- Check for size of data types ---
478
479# Require at least 32 bits for compatibility
480# between XXH32 hash and GHashTable which requires
481# unsigned int hashes
482if cc.sizeof ('unsigned int') < 4
483  error ('minimum required unsigned int size is 4')
484endif
485
486# --- Check for headers ---
487
488check_headers = [
489  'unistd.h',
490  'sys/time.h',
491  ]
492
493foreach h : check_headers
494  if cc.has_header(h)
495    cdata.set('HAVE_' + h.underscorify().to_upper(), 1)
496  endif
497endforeach
498
499# --- Check for dependencies/libraries ---
500
501# math functions might be implemented in libm
502libm = cc.find_library (
503  'm', required: false, static: all_static)
504
505check_functions = [
506  ['mlock', libm],
507  ]
508
509# prefer jack1
510jack_dep = dependency (
511  'jack', required: false, version: '<1.0',
512  static: all_static)
513if not jack_dep.found ()
514  jack_dep = dependency (
515    'jack',
516    required: get_option ('jack'),
517    static: all_static)
518endif
519have_jack = jack_dep.found () and not get_option ('jack').disabled ()
520if have_jack
521  cdata.set('HAVE_JACK', 1)
522  if jack_dep.version().version_compare('>=1.0')
523    cdata.set('HAVE_JACK2', 1)
524  endif
525  check_functions += [
526    ['jack_set_property',[jack_dep]],
527    # do not add support for this - it causes
528    # problems with jack1/jack2 mixups
529    #['jack_client_stop_thread', [jack_dep]],
530    ]
531endif
532
533glib_dep = dependency (
534  'glib-2.0', version: '>=2.64', required: false,
535  static: all_static)
536if os_freebsd
537  # force system glib on freebsd
538  glib_dep = dependency (
539    'glib-2.0', required: true)
540endif
541if glib_dep.found()
542  check_functions += [
543    # use a fallback if this does not exist (glib < 2.58)
544    ['g_canonicalize_filename',[glib_dep]],
545    ['g_get_console_charset',[glib_dep]],
546    ]
547else
548  cdata.set ('GLIB_SUBPROJECT', 1)
549  if os_freebsd
550    # note: fails finding environ during linking
551    glib_proj = subproject (
552      'glib',
553      default_options: [
554        'debug=true',
555        'optimization=3',
556        'xattr=false',
557        'iconv=external',
558        'selinux=disabled',
559        'libmount=disabled',
560        'installed_tests=false',
561        'b_lundef=false',
562        ]
563      )
564  else
565    glib_proj = subproject (
566      'glib',
567      default_options: [
568        'debug=true',
569        'optimization=3',
570        'tests=false',
571        'installed_tests=false',
572        'default_library=static',
573        ]
574      )
575  endif
576  glib_dep = glib_proj.get_variable ('libglib_dep')
577endif
578
579foreach func : check_functions
580  if cc.has_function(func[0], dependencies: func[1])
581    cdata.set('HAVE_' + func[0].underscorify().to_upper(), 1)
582  endif
583endforeach
584
585# check standard C functions
586check_c_functions = [
587  'localtime_r',
588  ]
589foreach func : check_c_functions
590  if not cc.has_function (func)
591    cdata.set('HAVE_' + func.underscorify().to_upper(), 1)
592  endif
593endforeach
594
595# Compiler flags
596test_cflags = [
597  '-Wformat=2',
598  '-Wno-missing-field-initializers',
599  '-Wno-unused-parameter',
600  '-Wno-sequence-point',
601  '-Wignored-qualifiers',
602  '-Wno-cast-function-type',
603  '-Walloca',
604  '-fno-common',
605  # dummy macro for extracting translatable strings
606  # when we can't use gettext()
607  '-D__(x)=x',
608  # use structured log
609  '-DG_LOG_USE_STRUCTURED=1',
610  '-DG_LOG_DOMAIN="' + prog_name_lowercase + '"',
611  '-DDEPRECATED_MSG(x)=__attribute__((deprecated(x)))',
612  '-DNONNULL_ARGS(...)=__attribute__((nonnull(__VA_ARGS__)))',
613  '-DACCESS(...)=' + (is_gcc ? '__attribute__((access(__VA_ARGS__)))' : ''),
614  '-DACCESS_READ_ONLY(...)=' + (is_gcc ? 'ACCESS(read_only,__VA_ARGS__)' : ''),
615  ]
616
617if is_gcc
618  test_cflags += [
619    '-frecord-gcc-switches',
620    ]
621endif
622
623# Stricter flags to be used where needed
624test_strict_cflags = []
625
626# add attribute macros
627attributes = [
628  'always_inline', 'cold', 'hot', 'pure', 'nonnull',
629  'returns_nonnull', 'stack_protect',
630  'no_stack_protector', 'warn_unused_result',
631  'const', 'malloc',
632  ]
633foreach a : attributes
634  test_cflags += '-D' + a.to_upper() + '=__attribute__((' + a + '))'
635endforeach
636
637if cc.get_id() == 'clang'
638  test_cflags += [
639    '-DREALTIME=__attribute__((annotate("realtime")))',
640    ]
641else
642  test_cflags += [
643    '-DREALTIME=',
644    ]
645endif
646
647if os_windows or get_option ('appimage')
648  test_cflags += [
649    '-DUSE_WEAK_JACK=1',
650    ]
651endif
652
653if get_option ('profiling')
654  test_cflags += [ '-pg', 'no-pie' ]
655  if get_option ('extra_optimizations')
656    error ('extra_optimizations and profiling are incompatible')
657  endif
658endif
659
660common_cflags = []
661
662if get_option ('native_build')
663  test_cflags += [
664    '-march=native',
665    '-mtune=native',
666    ]
667endif
668
669extra_optimizations_cflags = []
670if host_machine.cpu() == 'x86_64'
671  extra_optimizations_cflags += [
672    '-ffast-math',
673    '-fstrength-reduce',
674    '-DPIC',
675    '-fdata-sections',
676    '-ffunction-sections',
677    '-freciprocal-math',
678    '-fsingle-precision-constant',
679    '-msse',
680    '-msse2',
681    '-mfpmath=sse',
682    #'-fvisibility=hidden',
683    ]
684endif
685
686if not get_option ('native_build')
687  extra_optimizations_cflags += [
688    '-mtune=generic',
689    ]
690endif
691
692if get_option ('extra_debug_info') or get_option ('debug') or get_option ('buildtype').contains ('debug')
693  extra_optimizations_cflags += [
694    '-fno-omit-frame-pointer',
695    ]
696else
697  # note: this may break the backtrace
698  extra_optimizations_cflags += [
699    '-fomit-frame-pointer',
700    ]
701endif
702extra_optimizations_cflags = cc.get_supported_arguments (extra_optimizations_cflags)
703
704if get_option ('extra_optimizations')
705  test_cflags += extra_optimizations_cflags
706endif
707
708# TODO check
709# -Ofast -fgraphite-identity -floop-nest-optimize -fdevirtualize-at-ltrans -fipa-pta -fno-semantic-interposition -flto=4 -fuse-linker-plugin -pipe -falign-functions=32 -floop-nest-optimize -ftree-vectorize -floop-parallelize-all -ftree-parallelize-loops=4
710extra_extra_optimizations_cflags = [
711  '-fallow-store-data-races',
712  '-ffinite-math-only',
713  '-fno-signed-zeros',
714  '-fno-trapping-math',
715  '-ffp-contract=fast',
716  '-fmodulo-sched',
717  ]
718extra_extra_optimizations_cflags = cc.get_supported_arguments (extra_extra_optimizations_cflags)
719
720if get_option ('extra_extra_optimizations')
721  test_cflags += extra_extra_optimizations_cflags
722endif
723
724if get_option ('extra_debug_info')
725  test_cflags += '-ggdb3'
726endif
727
728common_cflags += cc.get_supported_arguments (
729  test_cflags)
730
731if os_freebsd
732  common_cflags += [
733    '-I' + includedir,
734    ]
735elif os_windows
736  common_cflags += [
737    '-mms-bitfields',
738    '-mwindows',
739    #'-mstackrealign',
740    '-Wl,-Bdynamic',
741    '-Wl,-as-needed',
742    '-D_WOE32=1',
743    ]
744endif
745
746test_strict_cflags += [
747  #'-Werror=cast-qual',
748  '-Werror=clobbered',
749  #'-Werror=conversion',
750  '-Werror=disabled-optimization',
751  '-Werror=float-equal',
752  '-Werror=logical-op',
753  '-Werror=pointer-arith',
754  '-Werror=enum-conversion',
755  '-Werror=overlength-strings',
756  '-Werror=stringop-truncation',
757  '-Werror=missing-declarations',
758  '-Werror=int-to-pointer-cast',
759  #'-Werror=double-promotion',
760  #'-Werror=redundant-decls',
761  '-Werror=shadow',
762  '-Werror=undef',
763  '-Werror=unused',
764  # TODO enable following 2 lines to catch VLAs
765  #'-Wvla',
766  #'-Werror=vla',
767  '-fstrict-aliasing',
768  '-Wstrict-aliasing=2',
769  '-Werror=strict-aliasing',
770  #'-Werror=strict-overflow',
771  '-Wstrict-overflow=2',
772  '-fstrict-overflow',
773  '-Werror=duplicated-branches',
774  '-Werror=duplicated-cond',
775  #'-Werror=null-dereference',
776  '-Werror=init-self',
777  '-Werror=jump-misses-init',
778  '-Werror=missing-prototypes',
779  '-Werror=nested-externs',
780  '-Werror=write-strings',
781  '-Werror=sign-compare',
782  '-Werror=discarded-qualifiers',
783  '-Werror=float-conversion',
784  '-Werror=implicit-function-declaration',
785  '-Werror=uninitialized',
786  '-Werror=maybe-uninitialized',
787  '-Werror=return-type',
788  '-Werror=int-conversion',
789  '-Werror=format-security',
790  '-Werror=incompatible-pointer-types',
791  '-Werror=implicit-int',
792  '-Werror=multistatement-macros',
793  '-Werror=switch',
794  '-Werror=overflow',
795  '-Werror=array-bounds',
796  '-Werror=enum-compare',
797  '-Werror=misleading-indentation',
798  '-Werror=int-in-bool-context',
799  '-Werror=type-limits',
800  '-Werror=deprecated-declarations',
801  '-Werror=format-extra-args',
802  '-Werror=format',
803  '-Werror=endif-labels',
804  '-Werror=logical-not-parentheses',
805  '-Werror=parentheses',
806  '-Werror=comment',
807  '-Werror=sizeof-pointer-div',
808  '-Werror=shift-count-overflow',
809  '-Werror=free-nonheap-object',
810  '-fanalyzer',
811  '-Werror=analyzer-possible-null-dereference',
812  '-Werror=analyzer-malloc-leak',
813  # gives false positives
814  #'-Werror=analyzer-null-dereference',
815  #'-Werror=analyzer-null-argument',
816  '-Werror=analyzer-use-after-free',
817  '-Werror=analyzer-possible-null-argument',
818  '-Werror=analyzer-double-free',
819  '-Werror=analyzer-file-leak',
820  '-Werror=nonnull',
821  '-Werror=nonnull-compare',
822  '-Werror=pointer-size',
823  '-Werror=override-init',
824  '-Werror=bool-compare',
825  '-Werror=tautological-compare',
826  '-Werror=unused-result',
827  '-Wanalyzer-too-complex',
828  '-Werror=analyzer-too-complex',
829  '-Werror=inline',
830  '-Werror=duplicate-decl-specifier',
831  ]
832
833if is_gcc
834  test_strict_cflags += [
835    '-Wextra',
836    '-Weverything',
837
838    '-Wsuggest-attribute=pure',
839    '-Wsuggest-attribute=const',
840    '-Wsuggest-attribute=noreturn',
841    '-Wsuggest-attribute=format',
842    '-Wsuggest-attribute=malloc',
843    '-Wsuggest-attribute=cold',
844
845    # only do the following on GCC because clang
846    # reports unnecessary errors
847    '-Werror=sign-conversion',
848    '-Werror=implicit-fallthrough',
849    ]
850endif
851
852strict_cflags = []
853if get_option ('strict_flags')
854  strict_cflags = cc.get_supported_arguments (
855    test_strict_cflags)
856endif
857
858# add -Wformat -Werror=format-security
859if cc.get_id() == 'gcc'
860  common_cflags += [
861    '-Wformat',
862    '-Werror=format-security',
863    ]
864endif
865
866test_ldflags = []
867
868if get_option ('profiling')
869  test_ldflags += [ '-pg', 'no-pie' ]
870endif
871
872common_ldflags = cc.get_supported_link_arguments (
873  test_ldflags)
874
875if os_freebsd
876  common_ldflags += [
877    '-L' + libdir,
878    '-lexecinfo',
879    ]
880endif
881
882if os_windows
883  common_ldflags += [
884    '-fno-stack-protector',
885    '-lws2_32',
886    '-static-libgcc',
887    '-static-libstdc++',
888    ]
889endif
890
891# set config defines
892if not os_darwin
893  x11_dep = dependency (
894    'x11', required: false, static: all_static)
895  if (x11_dep.found ())
896    cdata.set('HAVE_X11', 1)
897  endif
898endif
899alsa_dep = dependency (
900  'alsa', required: false, static: all_static)
901have_alsa = alsa_dep.found ()
902if (have_alsa)
903  cdata.set('HAVE_ALSA', 1)
904endif
905pulseaudio_dep = dependency (
906  'libpulse', required: false, static: all_static)
907have_pulseaudio = pulseaudio_dep.found ()
908if (have_pulseaudio)
909  cdata.set('HAVE_PULSEAUDIO', 1)
910endif
911libsoundio_dep = cc.find_library (
912  'soundio', required: false, static: all_static)
913have_libsoundio = libsoundio_dep.found ()
914if (have_libsoundio)
915  cdata.set('HAVE_LIBSOUNDIO', 1)
916endif
917cyaml_dep = dependency(
918  'libcyaml', version: '>=1.2.0',
919  static: all_static,
920  fallback: ['libcyaml', 'zrythm_cyaml_dep'])
921audec_dep = dependency(
922  'audec', version: '>=0.3.2',
923  fallback: ['libaudec', 'libaudec_dep'],
924  required: true, static: all_static)
925
926cairo_dep = dependency (
927  'cairo', fallback: ['cairo', 'libcairo_dep'],
928  default_options: [
929    'zlib=enabled', 'tests=disabled'])
930
931gdk_pixbuf_dep = dependency (
932  'gdk-pixbuf-2.0',
933  fallback: ['gdk-pixbuf', 'gdkpixbuf_dep'])
934gtk_dep = dependency (
935  'gtk+-3.0', version: '>=3.22',
936  fallback: ['gtk3', 'libgtk_dep'],
937  static: all_static)
938min_version = '>=1.0.25'
939if get_option ('opus')
940  cdata.set('HAVE_OPUS', 1)
941  min_version = '>=1.0.29'
942endif
943sndfile_dep = dependency (
944  'sndfile', version: min_version, required: true)
945if not sndfile_dep.found ()
946  sndfile_subproject = cmake.subproject (
947    'sndfile', options: cmake_opts)
948  sndfile_dep = sndfile_subproject.dependency (
949    'sndfile')
950endif
951samplerate_dep = dependency (
952  'samplerate', version: '>=0.1.8', required: true)
953if not samplerate_dep.found ()
954  samplerate_subproject = cmake.subproject (
955    'samplerate', options: cmake_opts)
956  samplerate_dep = samplerate_subproject.dependency (
957    'samplerate')
958endif
959lv2_dep = dependency (
960  'lv2', version: '>=1.16.0',
961  fallback: ['lv2', 'lv2_dep'],
962  static: all_static)
963if lv2_dep.version().version_compare('>=1.18.0')
964  cdata.set('HAVE_LV2_1_18', 1)
965endif
966serd_dep = dependency (
967  'serd-0', version: '>=0.30.0',
968  fallback: ['serd', 'serd_dep'],
969  static: all_static)
970sord_dep = dependency (
971  'sord-0', version: '>=0.14.0',
972  fallback: ['sord', 'sord_dep'],
973  static: all_static)
974sratom_dep = dependency (
975  'sratom-0', version: '>=0.4.0',
976  fallback: ['sratom', 'sratom_dep'],
977  static: all_static)
978lilv_dep = dependency (
979  'lilv-0', version: '>=0.24.6',
980  fallback: ['lilv', 'lilv_dep'],
981  static: all_static)
982
983# fftw
984fftw3_deps = [
985  dependency (
986    'fftw3', version: '>=3.3.5', static: all_static),
987  dependency (
988    'fftw3_threads', required: false,
989    static: all_static),
990  dependency (
991    'fftw3f_threads', required: false,
992    static: all_static),
993  ]
994if os_darwin or os_freebsd
995  fftw3_deps += [
996    cc.find_library (
997      'fftw3_threads', required: true,
998      static: all_static,
999      dirs: [ '/usr/lib', '/usr/local/lib' ]),
1000    cc.find_library (
1001      'fftw3f_threads', required: true,
1002      static: all_static,
1003      dirs: [ '/usr/lib', '/usr/local/lib' ])
1004    ]
1005else
1006  fftw3_deps += [
1007    cc.find_library (
1008      'fftw3_threads', required: false,
1009      static: all_static),
1010    cc.find_library (
1011      'fftw3f_threads', required: false,
1012      static: all_static)
1013    ]
1014endif
1015if os_windows
1016  # msys2 provides a separate fftw3f entry in
1017  # pkg-config
1018  fftw3_deps += dependency (
1019    'fftw3f', static: all_static)
1020endif
1021fftw3_funcs = [
1022  'fftw_make_planner_thread_safe',
1023  'fftwf_make_planner_thread_safe',
1024  ]
1025foreach func : fftw3_funcs
1026  if not cc.has_function (func, dependencies: fftw3_deps)
1027    warning (
1028      func + ' missing. ' +
1029      'If linking fails, on some systems you ' +
1030      'may have to point zrythm to the ' +
1031      'library that provides it directly, eg., ' +
1032      'LDFLAGS="$LDFLAGS ' +
1033      '/usr/lib/libfftw3_threads.so ' +
1034      '/usr/lib/libfftw3f_threads.so')
1035  endif
1036endforeach
1037
1038chromaprint_dep = dependency (
1039  'libchromaprint', required: false,
1040  static: all_static)
1041if (chromaprint_dep.found ())
1042  cdata.set('HAVE_CHROMAPRINT', 1)
1043endif
1044
1045gtksource_dep = dependency (
1046  'gtksourceview-4', required: false)
1047if gtksource_dep.found()
1048  cdata.set('HAVE_GTK_SOURCE_VIEW_4', 1)
1049else
1050  gtksource_dep = dependency (
1051    'gtksourceview-3.0')
1052  cdata.set('HAVE_GTK_SOURCE_VIEW_3', 1)
1053endif
1054
1055libcgraph_dep = dependency (
1056  'libcgraph',
1057  required: get_option ('graphviz'),
1058  static: all_static)
1059libgvc_dep = dependency (
1060  'libgvc',
1061  required: get_option ('graphviz'),
1062  static: all_static)
1063have_graphviz = libcgraph_dep.found () and libgvc_dep.found ()
1064if have_graphviz
1065  cdata.set('HAVE_CGRAPH', 1)
1066endif
1067
1068guile_dep = dependency (
1069  'guile-3.0', required: false,
1070  static: all_static)
1071if not guile_dep.found ()
1072  guile_dep = dependency (
1073    'guile-2.2',
1074    required: get_option ('guile'),
1075    static: all_static)
1076endif
1077have_guile = guile_dep.found () and not get_option ('guile').disabled ()
1078if have_guile
1079  cdata.set('HAVE_GUILE', 1)
1080endif
1081
1082carla_host_plugin_dep = dependency (
1083  'carla-host-plugin', version: '>=2.2.91',
1084  required: get_option ('carla'),
1085  static: all_static)
1086have_carla = carla_host_plugin_dep.found ()
1087if have_carla
1088  carla_bins_dir = get_option ('carla_binaries_dir')
1089  if carla_bins_dir == ''
1090    carla_bins_dir = carla_host_plugin_dep.get_variable (pkgconfig: 'libdir')
1091  endif
1092  install_data (
1093    find_program (
1094      carla_bins_dir / 'carla-discovery-native.exe',
1095      carla_bins_dir /
1096        'carla-discovery-native').full_path(),
1097    install_dir: zrythm_libdir / 'carla')
1098  cdata.set('HAVE_CARLA', 1)
1099
1100  # install discovery & bridge for 32-bit vst's on
1101  # windows
1102  if os_windows
1103    carla_bins_dir_32bit = get_option ('carla_binaries_dir_32bit')
1104    install_data (
1105      find_program (
1106        carla_bins_dir_32bit /
1107          'carla-discovery-win32.exe').full_path(),
1108      install_dir: zrythm_libdir / 'carla')
1109    install_data (
1110      find_program (
1111        carla_bins_dir_32bit /
1112          'carla-bridge-win32.exe').full_path(),
1113      install_dir: zrythm_libdir / 'carla')
1114  endif
1115
1116  # install gnu/linux bridges
1117  bridge_types = [
1118    'native', 'lv2-gtk2', 'lv2-gtk3', 'lv2-qt4',
1119    'lv2-qt5', 'lv2-x11' ]
1120  foreach bridge_type : bridge_types
1121    carla_bridge = find_program (
1122        carla_bins_dir / 'carla-bridge-' + bridge_type,
1123        required: false)
1124    if carla_bridge.found() and (os_gnu or os_freebsd)
1125      cdata.set('HAVE_CARLA_BRIDGE_' + bridge_type.underscorify().to_upper(), 1)
1126      install_data (
1127        carla_bridge.full_path(),
1128        install_dir: zrythm_libdir / 'carla')
1129    endif
1130  endforeach
1131endif
1132
1133portaudio_dep = dependency (
1134  # disable until it works
1135  'portaudio-2.0-dont-use-yet',
1136  required: get_option ('portaudio'),
1137  static: all_static)
1138if portaudio_dep.found ()
1139  cdata.set('HAVE_PORT_AUDIO', 1)
1140endif
1141
1142rtmidi_dep = dependency (
1143  'rtmidi', version: '>= 4.0.0',
1144  required: get_option ('rtmidi'),
1145  static: all_static)
1146if not rtmidi_dep.found () and not get_option ('rtmidi').disabled ()
1147  rtmidi_proj = subproject('rtmidi')
1148  rtmidi_dep = rtmidi_proj.get_variable(
1149    'zrythm_rtmidi_dep')
1150endif
1151if rtmidi_dep.found ()
1152  cdata.set('HAVE_RTMIDI', 1)
1153endif
1154
1155rtaudio_dep = dependency (
1156  'rtaudio', required: get_option ('rtaudio'),
1157  version: '>=5.1.0',
1158  static: all_static)
1159if not rtaudio_dep.found() and not get_option ('rtaudio').disabled ()
1160  rtaudio_proj = subproject('rtaudio')
1161  rtaudio_dep = rtaudio_proj.get_variable(
1162    'zrythm_rtaudio_dep')
1163endif
1164if rtaudio_dep.found ()
1165  cdata.set('HAVE_RTAUDIO', 1)
1166endif
1167
1168sdl_dep = dependency (
1169  'sdl2', required: get_option ('sdl'),
1170  static: all_static)
1171if sdl_dep.found ()
1172  cdata.set('HAVE_SDL', 1)
1173endif
1174
1175zstd_dep = dependency (
1176  'libzstd', required: false,
1177  static: all_static)
1178if not zstd_dep.found ()
1179  zstd_dep = cc.find_library (
1180    'zstd', static: all_static)
1181endif
1182
1183reproc_dep = dependency (
1184  'reproc', version: '>=14.1.0', required: false,
1185  static: all_static)
1186if not reproc_dep.found ()
1187  reproc_subproject = cmake.subproject (
1188    'reproc', options: cmake_opts)
1189  reproc_dep = reproc_subproject.dependency (
1190    'reproc')
1191endif
1192
1193lsp_dsp_dep = dependency (
1194  'lsp-dsp-lib', version: '>=0.5.5',
1195  static: all_static or get_option ('static_lsp_dsp'),
1196  required: get_option ('lsp_dsp'))
1197have_lsp_dsp = lsp_dsp_dep.found () and not get_option ('lsp_dsp').disabled ()
1198if have_lsp_dsp
1199  cdata.set('HAVE_LSP_DSP', 1)
1200endif
1201
1202valgrind_dep = dependency (
1203  'valgrind', required: get_option ('valgrind'))
1204have_valgrind = not get_option ('valgrind').disabled () and valgrind_dep.found ()
1205if have_valgrind
1206  cdata.set ('HAVE_VALGRIND', 1)
1207endif
1208
1209libbacktrace_dep = cc.find_library (
1210  'backtrace', required: false)
1211if not libbacktrace_dep.found ()
1212  libbacktrace_proj = subproject ('libbacktrace')
1213  libbacktrace_dep = libbacktrace_proj.get_variable ('libbacktrace_dep')
1214endif
1215cdata.set ('HAVE_LIBBACKTRACE', 1)
1216
1217xxhash_dep = dependency (
1218  'libxxhash', required: false)
1219if not xxhash_dep.found ()
1220  xxhash_dep = cc.find_library ('xxhash')
1221endif
1222
1223vamp_static = get_option ('vamp_static')
1224vamp_dep = dependency ('vamp', static: vamp_static)
1225vamp_host_sdk_dep = dependency (
1226  'vamp-hostsdk', static: vamp_static)
1227vamp_deps = [ vamp_dep, vamp_host_sdk_dep ]
1228
1229# TODO add Cantarell font as dependency
1230
1231zrythm_deps = [
1232  glib_dep,
1233  cairo_dep,
1234  gtk_dep,
1235  gdk_pixbuf_dep,
1236  sndfile_dep,
1237  samplerate_dep,
1238  alsa_dep,
1239  pulseaudio_dep,
1240  libsoundio_dep,
1241  cyaml_dep,
1242  audec_dep,
1243  libcgraph_dep,
1244  libgvc_dep,
1245  guile_dep,
1246  carla_host_plugin_dep,
1247  portaudio_dep,
1248  rtaudio_dep,
1249  rtmidi_dep,
1250  sdl_dep,
1251  zstd_dep,
1252  reproc_dep,
1253  dependency ('threads'),
1254  lv2_dep,
1255  serd_dep,
1256  sord_dep,
1257  sratom_dep,
1258  lilv_dep,
1259  dependency ('rubberband'),
1260  dependency ('libpcre'),
1261  dependency ('libpcre2-8'),
1262  dependency ('epoxy'),
1263  cc.find_library ('dl', static: all_static),
1264  chromaprint_dep,
1265  fftw3_deps,
1266  gtksource_dep,
1267  lsp_dsp_dep,
1268  valgrind_dep,
1269  libbacktrace_dep,
1270  xxhash_dep,
1271  vamp_deps,
1272  dependency ('libcurl'),
1273  dependency ('json-glib-1.0'),
1274
1275  libm,
1276]
1277
1278if all_static
1279  zrythm_deps += [
1280    # provided by bzip2
1281    cc.find_library (
1282      'bz2', static: all_static),
1283    # provided by lzip
1284    cc.find_library (
1285      'lzma', static: all_static),
1286    ]
1287endif
1288
1289if os_windows
1290  # TODO disable dbghelp and enable drmingw when
1291  # meson issue is fixed
1292  zrythm_deps += cc.find_library ('dbghelp')
1293  #drmingw_subproject = cmake.subproject (
1294  #  'drmingw', options: cmake_opts)
1295  #drmingw_dep = drmingw_subproject.dependency (
1296  #  'drmingw')
1297  #zrythm_deps += drmingw_dep
1298  zrythm_deps += jack_dep.partial_dependency (
1299    link_args: false, links: false)
1300else
1301  zrythm_deps += jack_dep
1302endif
1303
1304if os_gnu
1305  zrythm_deps += cc.find_library (
1306    'rt', static: all_static)
1307endif
1308
1309if (os_darwin)
1310  zrythm_deps += dependency (
1311    'appleframeworks',
1312    modules: [
1313      'foundation',
1314      'cocoa',
1315      'appkit',
1316      ])
1317else
1318  zrythm_deps += x11_dep
1319endif
1320
1321# copy doc files to build dir
1322root_doc_files = [
1323  'HACKING.md',
1324  'AUTHORS',
1325  'TRANSLATORS',
1326  'THANKS',
1327  'INSTALL.md',
1328  ]
1329foreach f : root_doc_files
1330  configure_file (
1331    copy: true,
1332    input: f,
1333    output: '@PLAINNAME@')
1334endforeach
1335
1336# create config.h
1337tmp_h = configure_file (
1338  output: 'tmp.h',
1339  configuration: cdata,
1340  )
1341if get_option ('fallback_version') == ''
1342  version_fallback = meson.project_version ()
1343else
1344  version_fallback = get_option ('fallback_version')
1345endif
1346config_h_vcs = vcs_tag (
1347  input: tmp_h,
1348  output: 'zrythm-config.h',
1349  fallback: version_fallback,
1350  )
1351config_h_dep = declare_dependency (
1352  sources: config_h_vcs,
1353  )
1354zrythm_deps += config_h_dep
1355
1356test_cflags_c_only = [
1357  '-Wno-bad-function-cast',
1358  '-Wno-old-style-declaration',
1359  '-Werror=absolute-value',
1360  '-Werror=parentheses-equality',
1361  ]
1362
1363common_cflags_c_only = cc.get_supported_arguments (
1364  test_cflags_c_only)
1365
1366add_project_arguments (
1367  common_cflags_c_only,
1368  language: [ 'c' ]
1369  )
1370add_project_arguments (
1371  common_cflags,
1372  language: [ 'c', 'cpp' ],
1373  )
1374add_project_link_arguments (
1375  common_ldflags,
1376  language: [ 'c', 'cpp' ],
1377  )
1378
1379ext_srcs = []
1380
1381subdir ('scripts')
1382subdir ('po')
1383subdir ('ext')
1384subdir ('resources')
1385subdir ('data')
1386subdir ('inc')
1387subdir ('src')
1388subdir ('tests')
1389subdir ('doc')
1390subdir ('tools')
1391
1392meson.add_install_script (
1393  'scripts/meson-post-install.sh')
1394
1395meson.add_dist_script (
1396  'scripts/meson_dist.sh')
1397
1398summary ({
1399  'Program name': get_option ('program_name'),
1400  'Debug': get_option ('debug'),
1401  'Optimization': get_option ('optimization'),
1402  'Link-Time Optimization': get_option ('b_lto'),
1403  'Profiling': get_option ('profiling'),
1404  'Strict flags': get_option ('strict_flags'),
1405  'Static deps': get_option ('static_deps'),
1406  'Extra optimizations': get_option ('extra_optimizations'),
1407  'Extra extra optimizations': get_option ('extra_extra_optimizations'),
1408  'Native build': get_option ('native_build'),
1409  'Build/install manpage': get_option ('manpage'),
1410  'Build/install completions': get_option ('completions'),
1411  'Build/install user manual': get_option ('user_manual'),
1412  'Install DSEG font': get_option ('dseg_font'),
1413  'Custom logo and splash': get_option ('custom_logo_and_splash'),
1414  'Trial version': get_option ('trial_ver'),
1415  'Installer version': get_option ('installer_ver'),
1416  'Check for updates': get_option ('check_updates'),
1417  'AppImage build': get_option ('appimage'),
1418  }, section: 'General')
1419
1420summary ({
1421  'ALSA': have_alsa,
1422  'Carla': have_carla,
1423  'GraphViz': have_graphviz,
1424  'Guile': have_guile,
1425  'JACK': have_jack,
1426  'SoundIO': have_libsoundio,
1427  'LSP DSP': have_lsp_dsp,
1428  'PortAudio': portaudio_dep.found (),
1429  'PulseAudio': have_pulseaudio,
1430  'RtAudio': rtaudio_dep.found (),
1431  'RtMidi': rtmidi_dep.found (),
1432  'SDL': sdl_dep.found (),
1433  }, section: 'Features')
1434
1435if have_carla
1436  # TODO
1437  summary ({
1438    }, section: 'Carla bridges')
1439endif
1440
1441tests_summary = {
1442  'Build tests': get_option('tests'),
1443  'GUI tests': get_option('gui_tests'),
1444  'Coverage reports': get_option('b_coverage'),
1445  'Valgrind': have_valgrind,
1446  }
1447foreach name, info : ext_lv2_plugins
1448  tests_summary += {
1449    info[0]: ext_lv2_plugin_bundles.get(name, 'N/A')
1450    }
1451endforeach
1452foreach name, filename : ext_vst_plugins
1453  tests_summary += {
1454    filename: ext_vst_plugin_paths.get(name, 'N/A')
1455    }
1456endforeach
1457summary (tests_summary, section: 'Tests')
1458
1459summary ({
1460  'prefix': prefix,
1461  'includedir': includedir,
1462  'libdir': libdir,
1463  'datadir': datadir,
1464  'sysconfdir': sysconfdir,
1465  }, section: 'Directories')
1466