meson: Add options for all plugins

Required a slight rework of the build file, and how options are passed
to cargo_wrapper.py

Necessitated a bump of the required gstreamer version to 1.20, which
should be fine for the meson build since its primary function is to be
built as part of the gstreamer monorepo build to get a dev env.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1028>
This commit is contained in:
Nirbheek Chauhan 2022-12-27 23:55:16 +05:30
parent 851c82df85
commit a3d405f670
5 changed files with 262 additions and 152 deletions

View file

@ -255,7 +255,7 @@ meson shared:
meson static: meson static:
extends: .meson extends: .meson
script: script:
- meson build --default-library=static --prefix=$(pwd)/install -Dsodium=built-in - meson build --default-library=static --prefix=$(pwd)/install -Dsodium-source=built-in
- ninja -C build install - ninja -C build install
- ./ci/generate-static-test.py test-static-link-all - ./ci/generate-static-test.py test-static-link-all
- cd test-static-link-all - cd test-static-link-all
@ -284,7 +284,7 @@ documentation:
-Dsharp=disabled -Dsharp=disabled
-Dgst-examples=disabled -Dgst-examples=disabled
-Drs=enabled -Drs=enabled
-Dgst-plugins-rs:sodium=system -Dgst-plugins-rs:sodium-source=system
-Dgst-docs:fatal_warnings=true -Dgst-docs:fatal_warnings=true
-Dorc=disabled -Dorc=disabled
script: script:
@ -339,7 +339,7 @@ documentation:
# -Dsharp=disabled # -Dsharp=disabled
# -Dgst-examples=disabled # -Dgst-examples=disabled
# -Drs=enabled # -Drs=enabled
# -Dgst-plugins-rs:sodium=system # -Dgst-plugins-rs:sodium-source=system
# script: # script:
# - P=$(pwd) # - P=$(pwd)
# - cd .. # - cd ..

View file

@ -16,12 +16,13 @@ PARSER.add_argument('build_dir', type=P)
PARSER.add_argument('src_dir', type=P) PARSER.add_argument('src_dir', type=P)
PARSER.add_argument('root_dir', type=P) PARSER.add_argument('root_dir', type=P)
PARSER.add_argument('target', choices=['release', 'debug']) PARSER.add_argument('target', choices=['release', 'debug'])
PARSER.add_argument('include')
PARSER.add_argument('prefix', type=P) PARSER.add_argument('prefix', type=P)
PARSER.add_argument('libdir', type=P) PARSER.add_argument('libdir', type=P)
PARSER.add_argument('--version', default=None) PARSER.add_argument('--version', default=None)
PARSER.add_argument('--bin', default=None, type=P) PARSER.add_argument('--bin', default=None, type=P)
PARSER.add_argument('--exts', nargs="+", default=[]) PARSER.add_argument('--packages', nargs="+", default=[])
PARSER.add_argument('--lib-suffixes', nargs="+", default=[])
PARSER.add_argument('--exe-suffix')
PARSER.add_argument('--depfile') PARSER.add_argument('--depfile')
PARSER.add_argument('--disable-doc', action="store_true", default=False) PARSER.add_argument('--disable-doc', action="store_true", default=False)
@ -102,7 +103,7 @@ if __name__ == "__main__":
cargo_cmd.extend(['--manifest-path', opts.src_dir / 'Cargo.toml']) cargo_cmd.extend(['--manifest-path', opts.src_dir / 'Cargo.toml'])
cargo_cmd.extend(['--prefix', opts.prefix, '--libdir', cargo_cmd.extend(['--prefix', opts.prefix, '--libdir',
opts.prefix / opts.libdir]) opts.prefix / opts.libdir])
for p in opts.include.split(','): for p in opts.packages:
cargo_cmd.extend(['-p', p]) cargo_cmd.extend(['-p', p])
else: else:
cargo_cmd.extend(['--bin', opts.bin.name]) cargo_cmd.extend(['--bin', opts.bin.name])
@ -119,18 +120,14 @@ if __name__ == "__main__":
if opts.command == 'build': if opts.command == 'build':
target_dir = cargo_target_dir / '**' / opts.target target_dir = cargo_target_dir / '**' / opts.target
if opts.bin: if opts.bin:
if opts.exts[0]: exe = glob.glob(str(target_dir / opts.bin) + opts.exe_suffix, recursive=True)[0]
ext = f'.{opts.exts[0]}'
else:
ext = ''
exe = glob.glob(str(target_dir / opts.bin) + ext, recursive=True)[0]
shutil.copy2(exe, opts.build_dir) shutil.copy2(exe, opts.build_dir)
depfile_content = generate_depfile_for(P(exe)) depfile_content = generate_depfile_for(P(exe))
else: else:
# Copy so files to build dir # Copy so files to build dir
depfile_content = "" depfile_content = ""
for ext in opts.exts: for suffix in opts.lib_suffixes:
for f in glob.glob(str(target_dir / f'*.{ext}'), recursive=True): for f in glob.glob(str(target_dir / f'*.{suffix}'), recursive=True):
libfile = P(f) libfile = P(f)
depfile_content += generate_depfile_for(libfile) depfile_content += generate_depfile_for(libfile)

View file

@ -9,7 +9,7 @@ if meson.is_cross_build()
subdir_done() subdir_done()
endif endif
if static_build if default_library == 'static'
if get_option('doc').enabled() if get_option('doc').enabled()
error('Documentation enabled but not supported when building statically.') error('Documentation enabled but not supported when building statically.')
endif endif

View file

@ -28,9 +28,9 @@ if not cargo_c.found()
endif endif
system = build_machine.system() system = build_machine.system()
ext_exe = '' exe_suffix = ''
if system == 'windows' if system == 'windows'
ext_exe = 'exe' exe_suffix = '.exe'
ext_dynamic = 'dll' ext_dynamic = 'dll'
ext_static = 'lib' ext_static = 'lib'
elif system == 'darwin' elif system == 'darwin'
@ -41,97 +41,131 @@ else
ext_static = 'a' ext_static = 'a'
endif endif
# workspace name -> lib name
# kept in the same order as the `members` list in Cargo.toml # kept in the same order as the `members` list in Cargo.toml
plugins = { plugins = {
'gst-plugin-audiofx': 'libgstrsaudiofx', 'audiofx': {
'gst-plugin-claxon': 'libgstclaxon', 'library': 'libgstrsaudiofx',
# csound has an external dependency, see below },
'gst-plugin-lewton': 'libgstlewton', 'claxon': {'library': 'libgstclaxon'},
'gst-plugin-spotify': 'libgstspotify', # csound has a non-trivial external dependency, see below
'lewton': {'library': 'libgstlewton'},
'spotify': {'library': 'libgstspotify'},
'gst-plugin-file': 'libgstrsfile', 'file': {'library': 'libgstrsfile'},
# sodium has an external dependency, see below # sodium can have an external dependency, see below
'gst-plugin-threadshare': 'libgstthreadshare', 'threadshare': {
'library': 'libgstthreadshare',
},
'gst-plugin-mp4': 'libgstmp4', 'mp4': {'library': 'libgstmp4'},
'gst-plugin-fmp4': 'libgstfmp4', 'fmp4': {
'library': 'libgstfmp4',
},
'gst-plugin-aws': 'libgstaws', 'aws': {
'gst-plugin-hlssink3': 'libgsthlssink3', 'library': 'libgstaws',
'gst-plugin-ndi': 'libgstndi', 'extra-deps': {'openssl': '>=1.1'},
'gst-plugin-raptorq': 'libgstraptorq', },
'gst-plugin-reqwest': 'libgstreqwest', 'hlssink3': {'library': 'libgsthlssink3'},
'gst-plugin-rtp': 'libgstrsrtp', 'ndi': {'library': 'libgstndi'},
'gst-plugin-webrtchttp': 'libgstwebrtchttp', 'onvif': {
'gst-plugin-webrtc': 'libgstrswebrtc', 'library': 'libgstrsonvif',
'extra-deps': {'pangocairo': ''},
},
'raptorq': {'library': 'libgstraptorq'},
'reqwest': {'library': 'libgstreqwest'},
'rtp': {'library': 'libgstrsrtp'},
'webrtchttp': {'library': 'libgstwebrtchttp'},
'webrtc': {
'library': 'libgstrswebrtc',
},
'gst-plugin-textahead': 'libgsttextahead', 'textahead': {'library': 'libgsttextahead'},
'gst-plugin-json': 'libgstjson', 'json': {'library': 'libgstjson'},
'gst-plugin-regex': 'libgstregex', 'regex': {'library': 'libgstregex'},
'gst-plugin-textwrap': 'libgsttextwrap', 'textwrap': {'library': 'libgsttextwrap'},
'gst-plugin-fallbackswitch': 'libgstfallbackswitch', 'fallbackswitch': {
'gst-plugin-livesync': 'libgstlivesync', 'library': 'libgstfallbackswitch',
'gst-plugin-togglerecord': 'libgsttogglerecord', },
'gst-plugin-tracers': 'libgstrstracers', 'livesync': {
'gst-plugin-uriplaylistbin': 'libgsturiplaylistbin', 'library': 'libgstlivesync',
},
'togglerecord': {
'library': 'libgsttogglerecord',
},
'tracers': {'library': 'libgstrstracers'},
'uriplaylistbin': {
'library': 'libgsturiplaylistbin',
},
'gst-plugin-cdg': 'libgstcdg', 'cdg': {'library': 'libgstcdg'},
# closedcaption has an external dependency, see below 'closedcaption': {
# dav1d has an external dependency, see below 'library': 'libgstrsclosedcaption',
'gst-plugin-ffv1': 'libgstffv1', 'extra-deps': {
'gst-plugin-flavors': 'libgstrsflv', 'pango': '',
'gst-plugin-gif': 'libgstgif', 'pangocairo': '',
# gtk4 has an external dependency, see below 'cairo-gobject': '',
'gst-plugin-hsv': 'libgsthsv', }
'gst-plugin-png': 'libgstrspng', },
'gst-plugin-rav1e': 'libgstrav1e', 'dav1d': {
# videofx has an external dependency, see below 'library': 'libgstdav1d',
'extra-deps': {'dav1d': '>=1.0'},
},
'ffv1': {'library': 'libgstffv1'},
'flavors': {'library': 'libgstrsflv'},
'gif': {
'library': 'libgstgif',
},
'gtk4': {
'library': 'libgstgtk4',
'extra-deps': {'gtk4': '>=4.6'},
},
'hsv': {'library': 'libgsthsv'},
'png': {
'library': 'libgstrspng',
},
'rav1e': {'library': 'libgstrav1e'},
'videofx': {
'library': 'libgstrsvideofx',
'extra-deps': {'cairo-gobject': ''},
},
} }
# Won't build on platforms where it bundles the sources because of: # Won't build on platforms where it bundles the sources because of:
# https://github.com/qnighy/libwebp-sys2-rs/issues/12 # https://github.com/qnighy/libwebp-sys2-rs/issues/12
# Remove this check once we update to a version that contains the fix: # the fix is:
# https://github.com/qnighy/libwebp-sys2-rs/pull/13 # https://github.com/qnighy/libwebp-sys2-rs/pull/13
if host_system not in ['windows', 'darwin'] if host_system not in ['windows', 'darwin']
# FIXME: libwebp-sys2 will build its bundled version on msvc and apple platforms # FIXME: libwebp-sys2 will build its bundled version on msvc and apple platforms
# https://github.com/qnighy/libwebp-sys2-rs/issues/4 # https://github.com/qnighy/libwebp-sys2-rs/issues/4
plugins += {'gst-plugin-webp': 'libgstrswebp'} plugins += {'webp': {
'library': 'libgstrswebp',
'extra-deps': {'libwebpdemux': ''},
}}
endif endif
extra_env = {} extra_env = {}
if dependency('cairo-gobject', required : get_option('videofx')).found() sodium_opt = get_option('sodium')
plugins += {'gst-plugin-videofx': 'libgstrsvideofx',} if sodium_opt.allowed()
endif sodium_plugin = {'sodium': {
'library': 'libgstsodium',
if dependency('pangocairo', required : get_option('closedcaption')).found() }}
plugins += {'gst-plugin-closedcaption' : 'libgstrsclosedcaption',} if get_option('sodium-source') == 'system'
endif sodium_dep = dependency('libsodium', required: sodium_opt.enabled())
extra_env += {'SODIUM_USE_PKG_CONFIG': '1'}
if dependency('pangocairo', required : get_option('onvif')).found() if sodium_dep.found()
plugins += {'gst-plugin-onvif': 'libgstrsonvif',} plugins += sodium_plugin
endif endif
else
if dependency('dav1d', version : '>= 1.0.0', required : get_option('dav1d')).found() plugins += sodium_plugin
plugins += {'gst-plugin-dav1d' : 'libgstdav1d'} endif
endif
sodium = get_option ('sodium')
if sodium == 'system'
dependency('libsodium')
plugins += {'gst-plugin-sodium': 'libgstsodium'}
extra_env += {'SODIUM_USE_PKG_CONFIG': '1'}
elif sodium == 'built-in'
plugins += {'gst-plugin-sodium': 'libgstsodium'}
endif endif
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
csound_option = get_option('csound') csound_option = get_option('csound')
# try first to find csound using pkg-config if csound_option.allowed()
csound_dep = dependency('', required: false)
if not csound_dep.found() and not csound_option.disabled()
# if csound isn't distributed with pkg-config then user needs to define CSOUND_LIB_DIR with its location # if csound isn't distributed with pkg-config then user needs to define CSOUND_LIB_DIR with its location
res = run_command(python, '-c', 'import os; print(os.environ["CSOUND_LIB_DIR"])', check: false) res = run_command(python, '-c', 'import os; print(os.environ["CSOUND_LIB_DIR"])', check: false)
@ -139,48 +173,70 @@ if not csound_dep.found() and not csound_option.disabled()
csound_libdir = res.stdout().strip() csound_libdir = res.stdout().strip()
csound_dep = cc.find_library('csound64', dirs: csound_libdir, required: false) csound_dep = cc.find_library('csound64', dirs: csound_libdir, required: false)
if csound_dep.found() if csound_dep.found()
plugins += {'csound': {
'library': 'libgstcsound',
}}
extra_env += {'CSOUND_LIB_DIR': csound_libdir} extra_env += {'CSOUND_LIB_DIR': csound_libdir}
elif csound_option.enabled()
error('csound option is enabled, but csound64 library could not be found and CSOUND_LIB_DIR was not set')
endif endif
endif endif
endif endif
if csound_dep.found() # Process plugins list
plugins += {'gst-plugin-csound' : 'libgstcsound'}
elif csound_option.enabled() default_library = get_option('default_library')
error('csound option is enabled, but csound64 library could not be found and CSOUND_LIB_DIR was not set')
else library_suffixes = []
message('csound not found, disabling its plugin') if default_library in ['shared', 'both']
endif library_suffixes += [ext_dynamic]
endif
if dependency('gtk4', version: '>= 4.6.0', required : get_option('gtk4')).found() if default_library in ['static', 'both']
plugins += {'gst-plugin-gtk4' : 'libgstgtk4',} library_suffixes += [ext_static]
endif endif
# cargo packages (plugins) to build
packages = []
# Add the plugin library files as output
output = [] output = []
# Used to not lookup the same dependency multiple times which clutters logs
deps_cache = {}
extensions = [] foreach plugin_name, details: plugins
plugin_opt = get_option(plugin_name)
if plugin_opt.allowed()
plugin_deps_found = true
foreach dep_name, dep_ver: details.get('extra-deps', {})
if dep_ver != ''
dep = dependency(dep_name, version: dep_ver, required: plugin_opt)
else
dep = dependency(dep_name, required: plugin_opt)
endif
deps_cache += {dep_name: dep}
if not dep.found()
plugin_deps_found = false
endif
endforeach
if plugin_deps_found
packages += f'gst-plugin-@plugin_name@'
lib = details.get('library')
if default_library in ['shared', 'both']
output += [lib + '.' + ext_dynamic]
endif
if default_library in ['static', 'both']
output += [lib + '.' + ext_static]
endif
endif
endif
endforeach
# Add the plugin file as output
if get_option('default_library') == 'shared' or get_option('default_library') == 'both'
extensions += [ext_dynamic]
foreach p, lib : plugins
output += [lib + '.' + ext_dynamic]
endforeach
endif
static_build = get_option('default_library') == 'static'
if static_build or get_option('default_library') == 'both'
extensions += [ext_static]
foreach p, lib : plugins
output += [lib + '.' + ext_static]
endforeach
endif
# Need to depends on all gstreamer-rs deps to ensure they are built # Need to depends on all gstreamer-rs deps to ensure they are built
# before gstreamer-rs when building with gst-build. # before gstreamer-rs when building with gst-build.
# Custom targets can't depend on dependency() objects so we have to depend # Custom targets can't depend on dependency() objects so we have to depend
# on the library variable from the subproject instead. # on the library variable from the subproject instead.
gst_req = '>= 1.18.0' gst_req = '>= 1.20.0'
depends = [] depends = []
deps = [ deps = [
@ -197,9 +253,6 @@ deps = [
['gstreamer-webrtc-1.0', 'gst-plugins-bad', 'gstwebrtc_dep', 'gstwebrtc'], ['gstreamer-webrtc-1.0', 'gst-plugins-bad', 'gstwebrtc_dep', 'gstwebrtc'],
] ]
# Used to not lookup the same dependency multiple times which clutters logs
deps_cache = {}
foreach d: deps foreach d: deps
dep = dependency(d[0], version : gst_req, dep = dependency(d[0], version : gst_req,
fallback : [d[1], d[2]]) fallback : [d[1], d[2]])
@ -252,11 +305,11 @@ rs_plugins = custom_target('gst-plugins-rs',
meson.current_source_dir(), meson.current_source_dir(),
meson.global_build_root(), meson.global_build_root(),
target, target,
include,
get_option('prefix'), get_option('prefix'),
get_option('libdir'), get_option('libdir'),
'--packages', packages,
'--depfile', '@DEPFILE@', '--depfile', '@DEPFILE@',
'--exts', extensions, '--lib-suffixes', library_suffixes,
] + disable_doc) ] + disable_doc)
plugins = rs_plugins.to_list() plugins = rs_plugins.to_list()
@ -269,6 +322,17 @@ foreach plugin : plugins
# skip the 'lib' prefix and extension from plugin path # skip the 'lib' prefix and extension from plugin path
plugin_name = fs.stem(plugin.full_path()).substring(3) plugin_name = fs.stem(plugin.full_path()).substring(3)
option_name = plugin_name.substring(3)
if option_name.startswith('rs')
option_name = option_name.substring(2)
endif
if option_name == 'flv'
option_name = 'flavors'
endif
if not get_option(option_name).allowed()
continue
endif
# Extract plugin dependencies from their Cargo.toml file # Extract plugin dependencies from their Cargo.toml file
plugin_deps = [] plugin_deps = []
p = run_command('dependencies.py', meson.current_source_dir(), plugin_name, p = run_command('dependencies.py', meson.current_source_dir(), plugin_name,
@ -276,9 +340,9 @@ foreach plugin : plugins
check: true) check: true)
foreach dep_name : p.stdout().strip().split(',') foreach dep_name : p.stdout().strip().split(',')
dep_name_version = dep_name.split('|') dep_name_version = dep_name.split('|')
dep_name = dep_name_version.get(0) dep_name = dep_name_version.get(0).strip()
if dep_name_version.length() > 1 if dep_name_version.length() > 1
extras = {'version': dep_name_version.get(1)} extras = {'version': dep_name_version.get(1).strip()}
else else
extras = {} extras = {}
endif endif
@ -298,7 +362,7 @@ foreach plugin : plugins
) )
meson.override_dependency(plugin_name, dep) meson.override_dependency(plugin_name, dep)
if static_build and plugin_name in ['gstcsound', 'gstthreadshare', 'gstgtk4'] if default_library == 'static' and plugin_name in ['gstcsound', 'gstthreadshare', 'gstgtk4']
warning('Static plugin @0@ is known to fail. It will not be included in libgstreamer-full.'.format(plugin_name)) warning('Static plugin @0@ is known to fail. It will not be included in libgstreamer-full.'.format(plugin_name))
else else
gst_plugins += dep gst_plugins += dep
@ -326,28 +390,28 @@ custom_target('gst-plugins-rs-pc-files',
depends: rs_plugins, depends: rs_plugins,
command: [python, '-c', '""']) command: [python, '-c', '""'])
if get_option('webrtc').allowed()
custom_target('gst-webrtc-signalling-server', custom_target('gst-webrtc-signalling-server',
build_by_default: true, build_by_default: true,
output: 'gst-webrtc-signalling-server', output: 'gst-webrtc-signalling-server',
console: true, console: true,
install: true, install: true,
install_dir: get_option('bindir'), install_dir: get_option('bindir'),
depfile: 'gst-webrtc-signalling-server.dep', depfile: 'gst-webrtc-signalling-server.dep',
env: extra_env, env: extra_env,
command: [cargo_wrapper, command: [cargo_wrapper,
'build', 'build',
meson.current_build_dir(), meson.current_build_dir(),
meson.current_source_dir(), meson.current_source_dir(),
meson.global_build_root(), meson.global_build_root(),
target, target,
'', get_option('prefix'),
get_option('prefix'), get_option('libdir'),
get_option('libdir'), '--depfile', '@DEPFILE@',
'--depfile', '@DEPFILE@', '--bin', 'gst-webrtc-signalling-server',
'--exts', ext_exe, '--exe-suffix', exe_suffix,
'--bin', 'gst-webrtc-signalling-server' ])
]) endif
test('tests', test('tests',
cargo_wrapper, cargo_wrapper,
@ -357,9 +421,9 @@ test('tests',
meson.current_source_dir(), meson.current_source_dir(),
meson.global_build_root(), meson.global_build_root(),
target, target,
include,
get_option('prefix'), get_option('prefix'),
get_option('libdir')], get_option('libdir'),
'--packages', packages],
timeout: 600) timeout: 600)
summary({ summary({

View file

@ -1,13 +1,62 @@
option('videofx', type : 'feature', value : 'auto', description : 'Build videofx plugin') # Same order as members in Cargo.toml
option('closedcaption', type : 'feature', value : 'auto', description : 'Build closedcaption plugin')
option('onvif', type : 'feature', value : 'auto', description : 'Build onvif plugin') # audio
option('dav1d', type : 'feature', value : 'auto', description : 'Build dav1d plugin') option('audiofx', type: 'feature', value: 'auto', description: 'Build audiofx plugin')
option('sodium', type : 'combo', option('claxon', type: 'feature', value: 'auto', description: 'Build claxon plugin')
choices : ['system', 'built-in', 'disabled'], value : 'built-in', option('csound', type: 'feature', value: 'auto', description: 'Build csound plugin')
description : 'Weither to use libsodium from the system or the built-in version from the sodiumoxide crate') option('lewton', type: 'feature', value: 'auto', description: 'Build lewton plugin')
option('csound', type : 'feature', value : 'auto', description : 'Build csound plugin') option('spotify', type: 'feature', value: 'auto', description: 'Build spotify plugin')
option('gtk4', type : 'feature', value : 'auto', description : 'Build GTK4 plugin')
# generic
option('file', type: 'feature', value: 'auto', description: 'Build file plugin')
option('sodium', type: 'feature', value: 'auto', description: 'Build sodium plugin')
option('sodium-source', type: 'combo',
choices: ['system', 'built-in'], value: 'built-in',
description: 'Whether to use libsodium from the system or the built-in version from the sodiumoxide crate')
option('threadshare', type: 'feature', value: 'auto', description: 'Build threadshare plugin')
# mux
option('flavors', type: 'feature', value: 'auto', description: 'Build flavors plugin')
option('fmp4', type: 'feature', value: 'auto', description: 'Build fmp4 plugin')
option('mp4', type: 'feature', value: 'auto', description: 'Build mp4 plugin')
# net
option('aws', type: 'feature', value: 'auto', description: 'Build aws plugin')
option('hlssink3', type: 'feature', value: 'auto', description: 'Build hlssink3 plugin')
option('ndi', type: 'feature', value: 'auto', description: 'Build ndi plugin')
option('onvif', type: 'feature', value: 'auto', description: 'Build onvif plugin')
option('raptorq', type: 'feature', value: 'auto', description: 'Build raptorq plugin')
option('reqwest', type: 'feature', value: 'auto', description: 'Build reqwest plugin')
option('rtp', type: 'feature', value: 'auto', description: 'Build rtp plugin')
option('webrtc', type: 'feature', value: 'auto', description: 'Build webrtc plugin')
option('webrtchttp', type: 'feature', value: 'auto', description: 'Build webrtchttp plugin')
# text
option('textahead', type: 'feature', value: 'auto', description: 'Build textahead plugin')
option('json', type: 'feature', value: 'auto', description: 'Build json plugin')
option('regex', type: 'feature', value: 'auto', description: 'Build regex plugin')
option('textwrap', type: 'feature', value: 'auto', description: 'Build textwrap plugin')
# utils
option('fallbackswitch', type: 'feature', value: 'auto', description: 'Build fallbackswitch plugin')
option('livesync', type: 'feature', value: 'auto', description: 'Build livesync plugin')
option('togglerecord', type: 'feature', value: 'auto', description: 'Build togglerecord plugin')
option('tracers', type: 'feature', value: 'auto', description: 'Build tracers plugin')
option('uriplaylistbin', type: 'feature', value: 'auto', description: 'Build uriplaylistbin plugin')
# video
option('cdg', type: 'feature', value: 'auto', description: 'Build cdg plugin')
option('closedcaption', type: 'feature', value: 'auto', description: 'Build closedcaption plugin')
option('dav1d', type: 'feature', value: 'auto', description: 'Build dav1d plugin')
option('ffv1', type: 'feature', value: 'auto', description: 'Build ffv1 plugin')
option('gif', type: 'feature', value: 'auto', description: 'Build gif plugin')
option('gtk4', type: 'feature', value: 'auto', description: 'Build GTK4 plugin')
option('hsv', type: 'feature', value: 'auto', description: 'Build hsv plugin')
option('png', type: 'feature', value: 'auto', description: 'Build png plugin')
option('rav1e', type: 'feature', value: 'auto', description: 'Build rav1e plugin')
option('videofx', type: 'feature', value: 'auto', description: 'Build videofx plugin')
option('webp', type: 'feature', value: 'auto', description: 'Build webp plugin')
# Common options # Common options
option('doc', type : 'feature', value : 'auto', yield: true, option('doc', type: 'feature', value: 'auto', yield: true,
description: 'Enable documentation.') description: 'Enable documentation')