a highly automated and intuitive digital audio workstation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1519 lines
39 KiB

# SPDX-FileCopyrightText: © 2019-2022 Alexandros Theodotou <alex@zrythm.org>
# SPDX-License-Identifier: LicenseRef-ZrythmLicense
project (
'zrythm', ['c', 'cpp'],
version: files ('VERSION'),
license: 'AGPL-3-or-later',
meson_version: '>= 0.57.0',
default_options: [
# 1: -Wall
# 2: -Wall -Wextra
# 3: -Wall -Wextra -Wpedantic
'warning_level=2',
'buildtype=debugoptimized',
'c_std=gnu11',
'b_lto=true',
'b_lto_threads=2',
],
)
# --- Import/configure required modules ---
gnome = import ('gnome')
fs = import ('fs')
cmake = import ('cmake')
cmake_opts = cmake.subproject_options ()
cmake_opts.add_cmake_defines ({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'})
# --- Check for programs ---
find_program ('sed')
find_program ('gettext')
msgattrib = find_program ('msgattrib')
msguniq = find_program ('msguniq')
msggrep = find_program ('msggrep')
msgfmt = find_program ('msgfmt', required: false)
bash = find_program ('bash')
grep = find_program ('grep')
dot_bin = find_program ('dot', required: false)
rubberband = find_program (
'rubberband', required: false)
cppcheck = find_program (
'cppcheck', required: false)
clang_tidy = find_program (
'clang-tidy', required: false)
jq = find_program ('jq', required: false)
sphinx_build = find_program (
['sphinx-build', 'sphinx-build-3'],
required: get_option ('user_manual'))
sphinx_intl = find_program (
'sphinx-intl',
required: get_option ('user_manual'))
sass = find_program (
'sass', required: get_option ('user_manual'))
help2man = find_program (
['help2man'],
required: get_option ('manpage'))
find_program (
'flex', required: get_option ('completions'))
stoat = find_program (
['stoat'], required: false)
python3 = find_program (
['python3', 'python'])
guile = find_program (
['guile2.2', 'guile'])
guild = find_program (
['guild2.2', 'guild'], required: false)
guile_snarf = find_program (
['guile-snarf2.2', 'guile-snarf'], required: false)
pandoc = find_program (
['pandoc'], required: false)
texi2html = find_program (
['texi2html'], required: false)
ulimit = find_program (
'tools/check_have_unlimited_memlock.sh')
lv2ls_bin = find_program ('lv2ls', required: false)
lv2info_bin = find_program (
'lv2info', required: false)
get_lv2_bundle_uri_bin = find_program (
'tools/get_lv2_bundle_uri.sh')
get_vst_path_bin = find_program (
'tools/get_vst_path.sh')
manpage_completions_run_sh = find_program (
'ext/sh-manpage-completions/run.sh')
xmllint = find_program ('xmllint')
iwyu_tool = find_program (
'iwyu_tool', 'iwyu-tool', required: false)
faust2lv2 = find_program (
'faust2lv2', required: false)
# --- Set common variables ---
cc = meson.get_compiler ('c')
is_gcc = cc.get_id() == 'gcc'
is_clang = cc.get_id() == 'clang'
meson_src_root = meson.current_source_dir ()
meson_build_root = meson.current_build_dir ()
prog_name = get_option ('program_name')
prog_name_lowercase = prog_name.to_lower()
copyright_name = 'The ' + prog_name + ' contributors'
copyright_years = '2018-2022'
prefix = get_option ('prefix')
bindir = prefix / get_option ('bindir')
libdir = prefix / get_option ('libdir')
libexecdir = prefix / get_option ('libexecdir')
includedir = prefix / get_option ('includedir')
datadir = prefix / get_option ('datadir')
sysconfdir = get_option ('sysconfdir')
mandir = datadir / 'man' / 'man1'
schemasdir = datadir / 'glib-2.0/schemas'
fontsdir = datadir / 'fonts' / prog_name_lowercase
zrythm_libdir = prefix / get_option ('libdir') / 'zrythm'
zrythmdatadir = datadir / prog_name_lowercase
themesdir = zrythmdatadir / 'themes'
themes_css_dir = themesdir / 'css'
samplesdir = zrythmdatadir / 'samples'
scriptsdir = zrythmdatadir / 'scripts'
docdir = datadir / 'doc' / prog_name_lowercase
sourceviewstylesdir = zrythmdatadir / 'sourceview-styles'
resources_dir = meson_src_root / 'resources'
data_dir = meson_src_root / 'data'
flatpak_build = get_option ('for_flathub') or get_option ('flatpak')
# Used for building manpages, manual, etc., using
# foreach.
language_mappings = {
'af_ZA': 'Afrikaans',
'ar': َلْعَرَبِيَّةُ',
'ca': 'Català',
#'cs': 'Czech',
#'da': 'Dansk',
'de': 'Deutsch',
'el': 'Ελληνικά',
'en': 'English',
'en_GB': 'English UK',
'es': 'Español',
#'et': 'Eeti',
'fa': 'فارسی',
#'fi': 'Suomi',
'fr': 'Français',
#'gd': 'Gaelic',
'gl': 'Galego',
'he': ִבְרִית',
'hi': 'हि',
'hu': 'magyar nyelv',
'id': 'bahasa Indonesia',
'it': 'Italiano',
'ja': '日本語',
'ko': '한국어',
'nb_NO': 'Bokmål',
'nl': 'Nederlands',
'pl': 'Polski',
'pt': 'Português',
'pt_BR': 'Português BR',
'ru': 'Русский',
'sv': 'Svenska',
'th': 'ภาษาไทย',
'tr': 'Türkiye',
'uk': 'Українська',
'vi': 'Tiếng Việt',
'zh_CN': '简体中文',
'zh_TW': '繁體中文',
}
locales = language_mappings
locales_str = ' '.join (locales.keys())
# get host system and library suffix
os_darwin = false
os_gnu = false
os_freebsd = false
os_windows = false
bin_suffix = ''
lib_suffix = '.so'
if host_machine.system() == 'darwin'
os_darwin = true
lib_suffix = '.dylib'
elif host_machine.system() == 'linux'
os_gnu = true
elif host_machine.system() == 'freebsd'
os_freebsd = true
elif host_machine.system() == 'windows'
os_windows = true
bin_suffix = '.exe'
lib_suffix = '.dll'
else
error ('unknown host system ' + host_machine.system ())
endif
# add global arguments
if os_windows
# if not building an msys2 package, this might
# also need -Wl,-allow-multiple-definition
# see https://stackoverflow.com/questions/11267877/mingw-multiple-definition-of-unwind-resume
add_global_link_arguments (
'-lssp',
language: [ 'c', 'cpp' ])
endif
have_custom_name = prog_name != 'Zrythm'
have_custom_logo_and_splash = get_option ('custom_logo_and_splash')
# include dirs
root_inc = include_directories ('.')
inc_inc = include_directories ('inc')
ext_inc = include_directories ('ext')
midilib_inc = include_directories ('ext/midilib')
whereami_inc = include_directories ('ext/whereami')
zix_inc = include_directories ('ext/zix')
weakjack_inc = include_directories ('ext/weakjack')
suil_inc = include_directories ('inc/plugins/lv2')
all_inc = [
root_inc,
inc_inc,
ext_inc,
midilib_inc,
whereami_inc,
zix_inc,
weakjack_inc,
suil_inc,
]
all_static = get_option ('static_deps')
# plugins for testing
ext_lv2_plugins = {
'ams_lfo': [
'AMS LFO',
'http://github.com/blablack/ams-lv2/lfo'],
'calf_monosynth': [
'Calf Monosynth',
'http://calf.sourceforge.net/plugins/Monosynth'],
'helm': [
'Helm', 'http://tytel.org/helm'],
'sherlock_atom_inspector': [
'Sherlock Atom Inspector',
'http://open-music-kontrollers.ch/lv2/sherlock#atom_inspector'],
'lsp_compressor_mono': [
'LSP Compressor Mono',
'http://lsp-plug.in/plugins/lv2/compressor_mono'],
'lsp_compressor': [
'LSP Compressor',
'http://lsp-plug.in/plugins/lv2/compressor_stereo'],
'lsp_sidechain_compressor': [
'LSP Sidechain Compressor',
'http://lsp-plug.in/plugins/lv2/sc_compressor_stereo'],
'lsp_multisampler_24_do': [
'LSP MultiSampler x24 Direct Out',
'http://lsp-plug.in/plugins/lv2/multisampler_x24_do'],
'carla_rack': [
'Carla Rack',
'http://kxstudio.sf.net/carla/plugins/carlarack'],
'no_delay_line': [
'No Delay Line',
'http://gareus.org/oss/lv2/nodelay'],
'mda_ambience': [
'mda Ambience',
'http://drobilla.net/plugins/mda/Ambience'],
'midi_cc_map': [
'MIDI CC Map',
'http://gareus.org/oss/lv2/midifilter#mapcc'],
'noize_maker': [
'NoizeMak3r',
'http://kunz.corrupt.ch/products/tal-noisemaker'],
'tal_filter': [
'TAL Filter',
'urn:juce:TalFilter'],
'geonkick': [
'Geonkick',
'http://geontime.com/geonkick/single'],
'chipwave': [
'ChipWave',
'https://github.com/linuxmao-org/shiru-plugins/chipwave'],
'calf_compressor': [
'Calf Compressor',
'http://calf.sourceforge.net/plugins/Compressor'],
'mverb': [
'MVerb',
'http://distrho.sf.net/plugins/MVerb'],
'sfizz': [
'Sfizz',
'http://sfztools.github.io/sfizz'],
'drops': [
'Drops',
'http://github.com/clearly-broken-software/drops'],
'test_signal': [
'Test Signal',
'http://gareus.org/oss/lv2/testsignal'],
}
have_ext_lv2_plugins = {}
ext_lv2_plugin_bundles = {}
ext_vst_plugins = {
'noizemaker': 'TAL-NoiseMaker.so',
}
have_ext_vst_plugins = {}
ext_vst_plugin_paths = {}
if get_option ('tests')
# get lv2 bundle paths
if lv2ls_bin.found () and lv2info_bin.found ()
lv2ls_res = run_command (
lv2ls_bin, check: true).stdout ()
foreach name, info : ext_lv2_plugins
uri = info[1]
have_ext_lv2 = lv2ls_res.contains (uri)
have_ext_lv2_plugins += {
name: have_ext_lv2
}
if have_ext_lv2
ext_lv2_plugin_bundles += {
name: run_command (
get_lv2_bundle_uri_bin, lv2info_bin,
uri, check: true).stdout ().strip ()
}
endif
endforeach
endif
# get vst plugin paths
if get_vst_path_bin.found ()
foreach name, filename : ext_vst_plugins
have_ext_vst = run_command (
get_vst_path_bin,
filename).returncode () == 0
have_ext_vst_plugins += {
name: have_ext_vst
}
if have_ext_vst
ext_vst_plugin_paths += {
name: run_command (
get_vst_path_bin, filename,
check: true).stdout ().strip ()
}
endif
endforeach
endif
endif
3 years ago
# command to open a directory
if os_gnu or os_freebsd
open_dir_cmd = find_program ('xdg-open').full_path ()
3 years ago
elif os_darwin
open_dir_cmd = 'open'
find_program (open_dir_cmd)
3 years ago
elif os_windows
open_dir_cmd = 'explorer.exe'
3 years ago
endif
# illegal characters to detect in PO files
illegal_chars = [
'', # U+202F
]
illegal_char_test_args = [
'-c', '! "$1" -rn "$2" "$3"', '_ignored',
grep.full_path (),
]
# GTK/GLIB versions
gtk_req = '4.6.0'
glib_req = '2.66.0'
# --- Add extra languages ---
if os_darwin
add_languages(['objc', 'objcpp'])
endif
# --- Create configuration data ---
#
# Note: more configuration data might be added after
# this section.
cdata = configuration_data ()
cdata.set_quoted ('PROGRAM_NAME', prog_name)
cdata.set_quoted (
'PROGRAM_NAME_LOWERCASE', prog_name_lowercase)
if have_custom_name
cdata.set ('HAVE_CUSTOM_NAME', 1)
endif
if have_custom_logo_and_splash
cdata.set ('HAVE_CUSTOM_LOGO_AND_SPLASH', 1)
endif
cdata.set_quoted (
'COPYRIGHT_NAME', copyright_name)
cdata.set_quoted (
'COPYRIGHT_YEARS', copyright_years)
cdata.set_quoted (
'HOST_MACHINE_SYSTEM', host_machine.system ())
cdata.set_quoted (
'PACKAGE_VERSION', '@VCS_TAG@')
cdata.set_quoted (
'COMPILER',
meson.get_compiler('c').get_id())
cdata.set_quoted ('PREFIX', prefix)
cdata.set_quoted (
'COMPILER_VERSION',
meson.get_compiler('c').version())
cdata.set_quoted ('CONFIGURE_DATADIR', datadir)
cdata.set_quoted (
'CONFIGURE_SOURCEVIEW_STYLES_DIR',
sourceviewstylesdir)
cdata.set_quoted (
'CONFIGURE_THEMES_DIR', themesdir)
cdata.set_quoted (
'CONFIGURE_THEMES_CSS_DIR', themes_css_dir)
cdata.set_quoted (
'LIBDIR_NAME', get_option ('libdir'))
if get_option ('check_updates')
cdata.set ('CHECK_UPDATES', 1)
endif
cdata.set_quoted ('CONFIGURE_LIBDIR', libdir)
cdata.set_quoted (
'CONFIGURE_ZRYTHM_LIBDIR', zrythm_libdir)
cdata.set_quoted ('CONFIGURE_BINDIR', bindir)
cdata.set_quoted ('LIB_SUFFIX', lib_suffix)
cdata.set_quoted ('BIN_SUFFIX', bin_suffix)
cdata.set_quoted ('GSCHEMAS_DIR', schemasdir)
if flatpak_build
cdata.set ('FLATPAK_BUILD', 1)
endif
if get_option ('for_flathub')
cdata.set ('FOR_FLATHUB', 1)
endif
if get_option ('dseg_font')
cdata.set ('HAVE_BUNDLED_DSEG', 1)
endif
cdata.set_quoted (
'BUILD_TYPE', get_option ('buildtype'))
cdata.set_quoted (
'OPTIMIZATION', get_option ('optimization'))
if get_option ('debug')
cdata.set ('IS_DEBUG_BUILD', 1)
endif
cdata.set_quoted (
'INSTALLER_VERSION_STR',
get_option ('buildtype'))
if get_option ('trial_ver')
cdata.set ('TRIAL_VER', 1)
endif
if get_option ('installer_ver')
cdata.set ('INSTALLER_VER', 1)
endif
if get_option ('appimage')
cdata.set ('APPIMAGE_BUILD', 1)
endif
cdata.set (
'MESON_SOURCE_ROOT', meson_src_root)
cdata.set (
'MESON_BUILD_ROOT', meson_build_root)
cdata.set_quoted('OPEN_DIR_CMD', open_dir_cmd)
cdata.set_quoted (
'ISSUE_TRACKER_URL',
'https://sr.ht/~alextee/zrythm/trackers')
cdata.set_quoted (
'NEW_ISSUE_URL',
'https://todo.sr.ht/~alextee/zrythm-bug')
cdata.set_quoted (
'NEW_ISSUE_EMAIL',
'~alextee/zrythm-bug@todo.sr.ht')
cdata.set_quoted (
'PRIVACY_POLICY_URL',
'https://www.zrythm.org/en/privacy.html')
cdata.set_quoted (
'DONATION_URL',
'https://www.zrythm.org/en/community.html#donate')
cdata.set_quoted (
'PURCHASE_URL',
'https://www.zrythm.org/en/download.html')
cdata.set_quoted (
'USER_MANUAL_URL',
'https://manual.zrythm.org/en/index.html')
cdata.set_quoted (
'LICENSE_URL',
'https://git.sr.ht/~alextee/zrythm/tree/master/item/COPYING')
cdata.set_quoted (
'BUG_REPORT_API_ENDPOINT',
'https://accounts.zrythm.org/api/v1/error-reports/new')
if get_option ('user_manual')
cdata.set_quoted ('MANUAL_PATH', docdir)
endif
if get_option ('carla_use_cv32_patchbay_variant')
cdata.set ('CARLA_HAVE_CV32_PATCHBAY_VARIANT', 1)
endif
if os_windows
cdata.set ('USE_MMCSS_THREAD_PRIORITIES', 1)
endif
# if latest version in changelog is the project's
# version, add the changelog to the config
chlog_full = fs.read ('CHANGELOG.md')
chlog_list = chlog_full.split('\n## [')
chlog = chlog_list[1].strip ()
if chlog.contains (meson.project_version () + '] -')
chlog_date = chlog.split (' - ')[1].split ('\n')[0]
chlog = chlog.split (chlog_date + '\n')[1]
cdata.set ('HAVE_CHANGELOG', 1)
cdata.set_quoted ('CHANGELOG_DATE', chlog_date)
cdata.set_quoted ('CHANGELOG_TXT', '\\n'.join (chlog.split ('\n')))
endif
if os_gnu
have_unlimited_mem = run_command (
ulimit, check: true).stdout ().strip () == 'unlimited'
if have_unlimited_mem
cdata.set ('HAVE_UNLIMITED_MEM', 1)
endif
endif
# --- Check for size of data types ---
# Require at least 32 bits for compatibility
# between XXH32 hash and GHashTable which requires
# unsigned int hashes
if cc.sizeof ('unsigned int') < 4
error ('minimum required unsigned int size is 4')
endif
# --- Check for headers ---
check_headers = [
'unistd.h',
'sys/time.h',
]
foreach h : check_headers
if cc.has_header(h)
cdata.set('HAVE_' + h.underscorify().to_upper(), 1)
endif
endforeach
# --- Check for dependencies/libraries ---
# math functions might be implemented in libm
libm = cc.find_library (
'm', required: false, static: all_static)
check_functions = [
['mlock', libm],
]
# prefer jack1
jack_dep = dependency (
'jack', required: false, version: '<1.0',
static: all_static)
if not jack_dep.found ()
jack_dep = dependency (
'jack',
required: get_option ('jack'),
static: all_static)
endif
have_jack = jack_dep.found () and not get_option ('jack').disabled ()
if have_jack
cdata.set('HAVE_JACK', 1)
if jack_dep.version().version_compare('>=1.0')
cdata.set('HAVE_JACK2', 1)
endif
check_functions += [
['jack_set_property',[jack_dep]],
# do not add support for this - it causes
# problems with jack1/jack2 mixups
#['jack_client_stop_thread', [jack_dep]],
]
endif
glib_version_arr = glib_req.split('.')
glib_major_version = glib_version_arr[0]
glib_minor_version = glib_version_arr[1]
gtk_version_arr = gtk_req.split('.')
gtk_major_version = gtk_version_arr[0]
gtk_minor_version = gtk_version_arr[1]
add_project_arguments([
'-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_@0@_@1@'.format(glib_major_version, glib_minor_version),
'-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_@0@_@1@'.format(glib_major_version, glib_minor_version),
'-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_@0@_@1@'.format(gtk_major_version, gtk_minor_version),
'-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_@0@_@1@'.format(gtk_major_version, gtk_minor_version),
],
language: 'c')
foreach func : check_functions
if cc.has_function(func[0], dependencies: func[1])
cdata.set('HAVE_' + func[0].underscorify().to_upper(), 1)
endif
endforeach
# check standard C functions
check_c_functions = [
'localtime_r',
]
foreach func : check_c_functions
if not cc.has_function (func)
cdata.set('HAVE_' + func.underscorify().to_upper(), 1)
endif
endforeach
# Compiler flags
test_cflags = [
'-Wformat=2',
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-Wno-sequence-point',
'-Wignored-qualifiers',
'-Wno-cast-function-type',
3 years ago
'-Walloca',
'-fno-common',
'-DLV2_UI__Gtk4UI="https://lv2plug.in/ns/extensions/ui#Gtk4UI"',
'-DGDK_DISABLE_DEPRECATED',
'-DGTK_DISABLE_DEPRECATED',
# dummy macro for extracting translatable strings
# when we can't use gettext()
'-D__(x)=x',
# use structured log
'-DG_LOG_USE_STRUCTURED=1',
'-DG_LOG_DOMAIN="' + prog_name_lowercase + '"',
'-DREALTIME=' + (is_clang ? '__attribute__((annotate("realtime")))' : ''),
'-DDEPRECATED_MSG(x)=__attribute__((deprecated(x)))',
'-DOPTIMIZE(x)=' + (is_gcc ? '__attribute__((optimize(#x)))' : ''),
'-DOPTIMIZE_O0=OPTIMIZE(00)',
'-DOPTIMIZE_O1=OPTIMIZE(01)',
'-DOPTIMIZE_O2=OPTIMIZE(02)',
'-DOPTIMIZE_O3=OPTIMIZE(03)',
'-DNONNULL_ARGS(...)=__attribute__((nonnull(__VA_ARGS__)))',
'-DACCESS(...)=' + (is_gcc ? '__attribute__((access(__VA_ARGS__)))' : ''),
'-DACCESS_READ_ONLY(...)=' + (is_gcc ? 'ACCESS(read_only,__VA_ARGS__)' : ''),
]
# not supported on windows
if is_gcc and not os_windows
test_cflags += [
'-frecord-gcc-switches',
]
endif
# Stricter flags to be used where needed
test_strict_cflags = []
# add attribute macros
attributes = [
'always_inline', 'cold', 'hot', 'pure', 'nonnull',
'returns_nonnull', 'stack_protect',
'no_stack_protector', 'warn_unused_result',
'const', 'malloc',
]
foreach a : attributes
test_cflags += '-D' + a.to_upper() + '=__attribute__((' + a + '))'
endforeach
if os_windows or get_option ('appimage')
test_cflags += [
'-DUSE_WEAK_JACK=1',
]
endif
if get_option ('profiling')
test_cflags += [ '-pg', 'no-pie' ]
if get_option ('extra_optimizations')
error ('extra_optimizations and profiling are incompatible')
endif
endif
common_cflags = []
extra_optimizations_cflags = []
if get_option ('native_build')
test_cflags += [
'-march=native',
'-mtune=native',
]
else
extra_optimizations_cflags += [
'-mtune=generic',
]
endif
if host_machine.cpu() == 'x86_64'
extra_optimizations_cflags += [
'-ffast-math',
'-fstrength-reduce',
'-DPIC',
'-fdata-sections',
'-ffunction-sections',
'-freciprocal-math',
'-fsingle-precision-constant',
'-msse',
'-msse2',
'-mfpmath=sse',
#'-fvisibility=hidden',
'-fno-math-errno',
]
endif
if get_option ('extra_debug_info') or get_option ('debug') or get_option ('buildtype').contains ('debug')
extra_optimizations_cflags += [
'-fno-omit-frame-pointer',
]
else
# note: this may break the backtrace
extra_optimizations_cflags += [
'-fomit-frame-pointer',
]
endif