diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0c0f876c..ae034a8a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -255,7 +255,7 @@ meson shared: meson static: extends: .meson 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 - ./ci/generate-static-test.py test-static-link-all - cd test-static-link-all @@ -284,7 +284,7 @@ documentation: -Dsharp=disabled -Dgst-examples=disabled -Drs=enabled - -Dgst-plugins-rs:sodium=system + -Dgst-plugins-rs:sodium-source=system -Dgst-docs:fatal_warnings=true -Dorc=disabled script: @@ -339,7 +339,7 @@ documentation: # -Dsharp=disabled # -Dgst-examples=disabled # -Drs=enabled -# -Dgst-plugins-rs:sodium=system +# -Dgst-plugins-rs:sodium-source=system # script: # - P=$(pwd) # - cd .. diff --git a/cargo_wrapper.py b/cargo_wrapper.py index 60885e16..a538f8cd 100644 --- a/cargo_wrapper.py +++ b/cargo_wrapper.py @@ -16,12 +16,13 @@ PARSER.add_argument('build_dir', type=P) PARSER.add_argument('src_dir', type=P) PARSER.add_argument('root_dir', type=P) PARSER.add_argument('target', choices=['release', 'debug']) -PARSER.add_argument('include') PARSER.add_argument('prefix', type=P) PARSER.add_argument('libdir', type=P) PARSER.add_argument('--version', default=None) 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('--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(['--prefix', opts.prefix, '--libdir', opts.prefix / opts.libdir]) - for p in opts.include.split(','): + for p in opts.packages: cargo_cmd.extend(['-p', p]) else: cargo_cmd.extend(['--bin', opts.bin.name]) @@ -119,18 +120,14 @@ if __name__ == "__main__": if opts.command == 'build': target_dir = cargo_target_dir / '**' / opts.target if opts.bin: - if opts.exts[0]: - ext = f'.{opts.exts[0]}' - else: - ext = '' - exe = glob.glob(str(target_dir / opts.bin) + ext, recursive=True)[0] + exe = glob.glob(str(target_dir / opts.bin) + opts.exe_suffix, recursive=True)[0] shutil.copy2(exe, opts.build_dir) depfile_content = generate_depfile_for(P(exe)) else: # Copy so files to build dir depfile_content = "" - for ext in opts.exts: - for f in glob.glob(str(target_dir / f'*.{ext}'), recursive=True): + for suffix in opts.lib_suffixes: + for f in glob.glob(str(target_dir / f'*.{suffix}'), recursive=True): libfile = P(f) depfile_content += generate_depfile_for(libfile) diff --git a/docs/meson.build b/docs/meson.build index 1d79a90a..69d5cbf7 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -9,7 +9,7 @@ if meson.is_cross_build() subdir_done() endif -if static_build +if default_library == 'static' if get_option('doc').enabled() error('Documentation enabled but not supported when building statically.') endif diff --git a/meson.build b/meson.build index e700d2ee..b7312e75 100644 --- a/meson.build +++ b/meson.build @@ -28,9 +28,9 @@ if not cargo_c.found() endif system = build_machine.system() -ext_exe = '' +exe_suffix = '' if system == 'windows' - ext_exe = 'exe' + exe_suffix = '.exe' ext_dynamic = 'dll' ext_static = 'lib' elif system == 'darwin' @@ -41,97 +41,131 @@ else ext_static = 'a' endif -# workspace name -> lib name # kept in the same order as the `members` list in Cargo.toml plugins = { - 'gst-plugin-audiofx': 'libgstrsaudiofx', - 'gst-plugin-claxon': 'libgstclaxon', - # csound has an external dependency, see below - 'gst-plugin-lewton': 'libgstlewton', - 'gst-plugin-spotify': 'libgstspotify', + 'audiofx': { + 'library': 'libgstrsaudiofx', + }, + 'claxon': {'library': 'libgstclaxon'}, + # csound has a non-trivial external dependency, see below + 'lewton': {'library': 'libgstlewton'}, + 'spotify': {'library': 'libgstspotify'}, - 'gst-plugin-file': 'libgstrsfile', - # sodium has an external dependency, see below - 'gst-plugin-threadshare': 'libgstthreadshare', + 'file': {'library': 'libgstrsfile'}, + # sodium can have an external dependency, see below + 'threadshare': { + 'library': 'libgstthreadshare', + }, - 'gst-plugin-mp4': 'libgstmp4', - 'gst-plugin-fmp4': 'libgstfmp4', + 'mp4': {'library': 'libgstmp4'}, + 'fmp4': { + 'library': 'libgstfmp4', + }, - 'gst-plugin-aws': 'libgstaws', - 'gst-plugin-hlssink3': 'libgsthlssink3', - 'gst-plugin-ndi': 'libgstndi', - 'gst-plugin-raptorq': 'libgstraptorq', - 'gst-plugin-reqwest': 'libgstreqwest', - 'gst-plugin-rtp': 'libgstrsrtp', - 'gst-plugin-webrtchttp': 'libgstwebrtchttp', - 'gst-plugin-webrtc': 'libgstrswebrtc', + 'aws': { + 'library': 'libgstaws', + 'extra-deps': {'openssl': '>=1.1'}, + }, + 'hlssink3': {'library': 'libgsthlssink3'}, + 'ndi': {'library': 'libgstndi'}, + 'onvif': { + 'library': 'libgstrsonvif', + 'extra-deps': {'pangocairo': ''}, + }, + 'raptorq': {'library': 'libgstraptorq'}, + 'reqwest': {'library': 'libgstreqwest'}, + 'rtp': {'library': 'libgstrsrtp'}, + 'webrtchttp': {'library': 'libgstwebrtchttp'}, + 'webrtc': { + 'library': 'libgstrswebrtc', + }, - 'gst-plugin-textahead': 'libgsttextahead', - 'gst-plugin-json': 'libgstjson', - 'gst-plugin-regex': 'libgstregex', - 'gst-plugin-textwrap': 'libgsttextwrap', + 'textahead': {'library': 'libgsttextahead'}, + 'json': {'library': 'libgstjson'}, + 'regex': {'library': 'libgstregex'}, + 'textwrap': {'library': 'libgsttextwrap'}, - 'gst-plugin-fallbackswitch': 'libgstfallbackswitch', - 'gst-plugin-livesync': 'libgstlivesync', - 'gst-plugin-togglerecord': 'libgsttogglerecord', - 'gst-plugin-tracers': 'libgstrstracers', - 'gst-plugin-uriplaylistbin': 'libgsturiplaylistbin', + 'fallbackswitch': { + 'library': 'libgstfallbackswitch', + }, + 'livesync': { + 'library': 'libgstlivesync', + }, + 'togglerecord': { + 'library': 'libgsttogglerecord', + }, + 'tracers': {'library': 'libgstrstracers'}, + 'uriplaylistbin': { + 'library': 'libgsturiplaylistbin', + }, - 'gst-plugin-cdg': 'libgstcdg', - # closedcaption has an external dependency, see below - # dav1d has an external dependency, see below - 'gst-plugin-ffv1': 'libgstffv1', - 'gst-plugin-flavors': 'libgstrsflv', - 'gst-plugin-gif': 'libgstgif', - # gtk4 has an external dependency, see below - 'gst-plugin-hsv': 'libgsthsv', - 'gst-plugin-png': 'libgstrspng', - 'gst-plugin-rav1e': 'libgstrav1e', - # videofx has an external dependency, see below + 'cdg': {'library': 'libgstcdg'}, + 'closedcaption': { + 'library': 'libgstrsclosedcaption', + 'extra-deps': { + 'pango': '', + 'pangocairo': '', + 'cairo-gobject': '', + } + }, + 'dav1d': { + '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: # 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 if host_system not in ['windows', 'darwin'] # FIXME: libwebp-sys2 will build its bundled version on msvc and apple platforms # https://github.com/qnighy/libwebp-sys2-rs/issues/4 - plugins += {'gst-plugin-webp': 'libgstrswebp'} + plugins += {'webp': { + 'library': 'libgstrswebp', + 'extra-deps': {'libwebpdemux': ''}, + }} endif extra_env = {} -if dependency('cairo-gobject', required : get_option('videofx')).found() - plugins += {'gst-plugin-videofx': 'libgstrsvideofx',} -endif - -if dependency('pangocairo', required : get_option('closedcaption')).found() - plugins += {'gst-plugin-closedcaption' : 'libgstrsclosedcaption',} -endif - -if dependency('pangocairo', required : get_option('onvif')).found() - plugins += {'gst-plugin-onvif': 'libgstrsonvif',} -endif - -if dependency('dav1d', version : '>= 1.0.0', required : get_option('dav1d')).found() - plugins += {'gst-plugin-dav1d' : 'libgstdav1d'} -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'} +sodium_opt = get_option('sodium') +if sodium_opt.allowed() + sodium_plugin = {'sodium': { + 'library': 'libgstsodium', + }} + if get_option('sodium-source') == 'system' + sodium_dep = dependency('libsodium', required: sodium_opt.enabled()) + extra_env += {'SODIUM_USE_PKG_CONFIG': '1'} + if sodium_dep.found() + plugins += sodium_plugin + endif + else + plugins += sodium_plugin + endif endif cc = meson.get_compiler('c') csound_option = get_option('csound') -# try first to find csound using pkg-config -csound_dep = dependency('', required: false) -if not csound_dep.found() and not csound_option.disabled() +if csound_option.allowed() # 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) @@ -139,48 +173,70 @@ if not csound_dep.found() and not csound_option.disabled() csound_libdir = res.stdout().strip() csound_dep = cc.find_library('csound64', dirs: csound_libdir, required: false) if csound_dep.found() + plugins += {'csound': { + 'library': 'libgstcsound', + }} 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 -if csound_dep.found() - plugins += {'gst-plugin-csound' : 'libgstcsound'} -elif csound_option.enabled() - error('csound option is enabled, but csound64 library could not be found and CSOUND_LIB_DIR was not set') -else - message('csound not found, disabling its plugin') -endif - -if dependency('gtk4', version: '>= 4.6.0', required : get_option('gtk4')).found() - plugins += {'gst-plugin-gtk4' : 'libgstgtk4',} +# Process plugins list + +default_library = get_option('default_library') + +library_suffixes = [] +if default_library in ['shared', 'both'] + library_suffixes += [ext_dynamic] +endif +if default_library in ['static', 'both'] + library_suffixes += [ext_static] endif +# cargo packages (plugins) to build +packages = [] +# Add the plugin library files as 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 # before gstreamer-rs when building with gst-build. # Custom targets can't depend on dependency() objects so we have to depend # on the library variable from the subproject instead. -gst_req = '>= 1.18.0' +gst_req = '>= 1.20.0' depends = [] deps = [ @@ -197,9 +253,6 @@ deps = [ ['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 dep = dependency(d[0], version : gst_req, fallback : [d[1], d[2]]) @@ -252,11 +305,11 @@ rs_plugins = custom_target('gst-plugins-rs', meson.current_source_dir(), meson.global_build_root(), target, - include, get_option('prefix'), get_option('libdir'), + '--packages', packages, '--depfile', '@DEPFILE@', - '--exts', extensions, + '--lib-suffixes', library_suffixes, ] + disable_doc) plugins = rs_plugins.to_list() @@ -269,6 +322,17 @@ foreach plugin : plugins # skip the 'lib' prefix and extension from plugin path 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 plugin_deps = [] p = run_command('dependencies.py', meson.current_source_dir(), plugin_name, @@ -276,9 +340,9 @@ foreach plugin : plugins check: true) foreach dep_name : p.stdout().strip().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 - extras = {'version': dep_name_version.get(1)} + extras = {'version': dep_name_version.get(1).strip()} else extras = {} endif @@ -298,7 +362,7 @@ foreach plugin : plugins ) 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)) else gst_plugins += dep @@ -326,28 +390,28 @@ custom_target('gst-plugins-rs-pc-files', depends: rs_plugins, command: [python, '-c', '""']) - -custom_target('gst-webrtc-signalling-server', - build_by_default: true, - output: 'gst-webrtc-signalling-server', - console: true, - install: true, - install_dir: get_option('bindir'), - depfile: 'gst-webrtc-signalling-server.dep', - env: extra_env, - command: [cargo_wrapper, - 'build', - meson.current_build_dir(), - meson.current_source_dir(), - meson.global_build_root(), - target, - '', - get_option('prefix'), - get_option('libdir'), - '--depfile', '@DEPFILE@', - '--exts', ext_exe, - '--bin', 'gst-webrtc-signalling-server' - ]) +if get_option('webrtc').allowed() + custom_target('gst-webrtc-signalling-server', + build_by_default: true, + output: 'gst-webrtc-signalling-server', + console: true, + install: true, + install_dir: get_option('bindir'), + depfile: 'gst-webrtc-signalling-server.dep', + env: extra_env, + command: [cargo_wrapper, + 'build', + meson.current_build_dir(), + meson.current_source_dir(), + meson.global_build_root(), + target, + get_option('prefix'), + get_option('libdir'), + '--depfile', '@DEPFILE@', + '--bin', 'gst-webrtc-signalling-server', + '--exe-suffix', exe_suffix, + ]) +endif test('tests', cargo_wrapper, @@ -357,9 +421,9 @@ test('tests', meson.current_source_dir(), meson.global_build_root(), target, - include, get_option('prefix'), - get_option('libdir')], + get_option('libdir'), + '--packages', packages], timeout: 600) summary({ diff --git a/meson_options.txt b/meson_options.txt index b20fd937..a2d62a61 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,13 +1,62 @@ -option('videofx', type : 'feature', value : 'auto', description : 'Build videofx plugin') -option('closedcaption', type : 'feature', value : 'auto', description : 'Build closedcaption plugin') -option('onvif', type : 'feature', value : 'auto', description : 'Build onvif plugin') -option('dav1d', type : 'feature', value : 'auto', description : 'Build dav1d plugin') -option('sodium', type : 'combo', - choices : ['system', 'built-in', 'disabled'], value : 'built-in', - description : 'Weither to use libsodium from the system or the built-in version from the sodiumoxide crate') -option('csound', type : 'feature', value : 'auto', description : 'Build csound plugin') -option('gtk4', type : 'feature', value : 'auto', description : 'Build GTK4 plugin') +# Same order as members in Cargo.toml + +# audio +option('audiofx', type: 'feature', value: 'auto', description: 'Build audiofx plugin') +option('claxon', type: 'feature', value: 'auto', description: 'Build claxon plugin') +option('csound', type: 'feature', value: 'auto', description: 'Build csound plugin') +option('lewton', type: 'feature', value: 'auto', description: 'Build lewton plugin') +option('spotify', type: 'feature', value: 'auto', description: 'Build spotify 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 -option('doc', type : 'feature', value : 'auto', yield: true, - description: 'Enable documentation.') +option('doc', type: 'feature', value: 'auto', yield: true, + description: 'Enable documentation')