meson.build 17 KB
Newer Older
1
project('gstreamer-full', 'c',
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
2
  version : '1.21.0.1',
3
  meson_version : '>= 0.60.0',
4
5
6
7
8
  default_options : ['buildtype=debugoptimized',
                     # Needed due to https://github.com/mesonbuild/meson/issues/1889,
                     # but this can cause problems in the future. Remove it
                     # when it's no longer necessary.
                     'cpp_std=c++14'])
Thibault Saunier's avatar
Thibault Saunier committed
9

10
apiversion = '1.0'
Thibault Saunier's avatar
Thibault Saunier committed
11
gst_version = '>= @0@'.format(meson.project_version())
Thibault Saunier's avatar
Thibault Saunier committed
12

13
build_system = build_machine.system()
14
cc = meson.get_compiler('c')
15

16
fs = import('fs')
17
gnome = import('gnome')
18
pkgconfig = import('pkgconfig')
19
python3 = import('python').find_installation()
Sebastian Fricke's avatar
Sebastian Fricke committed
20
# Ensure that we're not being run from inside the development environment
21
22
23
# because that will confuse meson, and it might find the already-built
# gstreamer. It's fine if people run `ninja` as long as it doesn't run
# reconfigure because ninja doesn't care about the env.
Sebastian Fricke's avatar
Sebastian Fricke committed
24
ensure_not_devenv = '''
25
26
27
import os
assert('GST_ENV' not in os.environ)
'''
Sebastian Fricke's avatar
Sebastian Fricke committed
28
cmdres = run_command(python3, '-c', ensure_not_devenv, check: false)
29
if cmdres.returncode() != 0
30
  error('Do not run `ninja reconfigure` or `meson` for gst-build inside the development environment, you will run into problems')
31
32
endif

33
# Install gst-indent pre-commit hook
34
run_command(python3, '-c', 'import shutil; shutil.copy("scripts/git-hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")', check: false)
35

36
37
38
39
40
41
42
43
# Ensure that the user does not have Strawberry Perl in PATH, since it ships
# with a pkg-config.bat and broken pkgconfig files for libffi and zlib. Will
# cause a build error, such as in
# https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/41
ensure_no_strawberry_perl = '''
import os
assert(r'Strawberry\perl\bin' not in os.environ['PATH'])
'''
44
if build_system == 'windows' and meson.version().version_compare('<0.60.0')
45
  cmdres = run_command(python3, '-c', ensure_no_strawberry_perl, check: false)
46
  if cmdres.returncode() != 0
47
    error('You have Strawberry Perl in PATH which is known to cause build issues with Meson < 0.60.0. Please remove it from PATH, uninstall it, or upgrade Meson.')
48
49
50
  endif
endif

51
documented_projects = ''
52
53
# Make it possible to use msys2 built zlib which fails
# when not using the mingw toolchain as it uses unistd.h
54
if not meson.is_subproject() and cc.get_id() == 'msvc'
55
56
  uname = find_program('uname', required: false)
  if uname.found()
57
    ret = run_command(uname, '-o', check: false)
58
    if ret.returncode() == 0 and ret.stdout().to_lower() == 'msys'
59
      ret = run_command(uname, '-r', check: false)
60
61
62
63
64
65
      # The kernel version returned by uname is actually the msys version
      if ret.returncode() == 0 and ret.stdout().startswith('2')
        # If a system zlib is found, disable UNIX features in zlib.h and zconf.h
        if cc.find_library('z').found()
          add_global_arguments('-DZ_SOLO', language: 'c')
        endif
66
67
68
      endif
    endif
  endif
69
endif
70

71
72
73
74
# Ensure that MSVC interprets all source code as UTF-8. Only do this when we're
# not a subproject, because subprojects are not allowed to call
# add_global_arguments().
if not meson.is_subproject() and cc.get_id() == 'msvc'
75
76
77
78
79
  add_global_arguments(
      cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
      language: ['c', 'cpp'])
endif

80
81
82
83
84
85
86
building_full = get_option('default_library') == 'static'
tools_option = 'tools=auto'
if building_full and not get_option('tools').disabled()
  # Do not build subprojects tools when we build them against gst-full
  tools_option = 'tools=disabled'
endif

87
88
# Ordered list of subprojects (dict has no ordering guarantees)
subprojects = [
89
  ['gstreamer', {'build-hotdoc': true, 'subproject_options': [tools_option]}],
90
91
  ['gst-plugins-base', {'option': get_option('base'), 'build-hotdoc': true}],
  ['gst-plugins-good', {'option': get_option('good'), 'build-hotdoc': true}],
92
  ['libnice', { 'option': get_option('libnice'), 'match_gst_version': false}],
93
94
95
96
  ['gst-plugins-bad', { 'option': get_option('bad'), 'build-hotdoc': true}],
  ['gst-plugins-ugly', { 'option': get_option('ugly'), 'build-hotdoc': true}],
  ['gst-libav', { 'option': get_option('libav'), 'build-hotdoc': true}],
  ['gst-rtsp-server', { 'option': get_option('rtsp_server'), 'build-hotdoc': true}],
97
  ['gst-devtools', { 'option': get_option('devtools'), 'build-hotdoc': true, 'subproject_options': [tools_option]}],
98
  ['gst-integration-testsuites', { 'option': get_option('devtools') }],
99
  ['gst-editing-services', { 'option': get_option('ges'), 'build-hotdoc': true, 'subproject_options': [tools_option]}],
100
101
  ['gstreamer-vaapi', { 'option': get_option('vaapi'), 'build-hotdoc': true}],
  ['gst-omx', { 'option': get_option('omx'), 'build-hotdoc': true}],
102
  ['gstreamer-sharp', { 'option': get_option('sharp') }],
103
  ['pygobject', { 'option': get_option('python'), 'match_gst_version': false, 'sysdep': 'pygobject-3.0', 'sysdep_version': '>= 3.8' }],
104
  ['gst-python', { 'option': get_option('python')}],
105
  ['gst-examples', { 'option': get_option('gst-examples'), 'match_gst_versions': false}],
106
  ['gst-plugins-rs', { 'option': get_option('rs'), 'match_gst_version': false}],
107
]
108

109
110
111
112
symlink = '''
import os

os.symlink(os.path.join('@1@', 'subprojects', '@0@'),
113
  os.path.join('@1@', '@0@'))
114
'''
115

116
if build_system == 'windows'
117
  subproject('win-flex-bison-binaries')
118
  subproject('win-nasm')
119
120
elif build_system == 'darwin'
  subproject('macos-bison-binary')
121
122
endif

123
orc_subproject = subproject('orc', required: get_option('orc'))
124

125
126
127
128
129
130
131
132
foreach custom_subproj: get_option('custom_subprojects').split(',')
    if custom_subproj != ''
        message ('Adding custom subproject ' + custom_subproj)
        subprojects += [[custom_subproj, {'match_gst_version': false}]]
    endif
endforeach


133
subprojects_names = []
134
plugins_doc_caches = []
135
orc_update_targets = []
136
all_plugins = []
137
all_tools = {}
138
139
# Using a list and not a dict to keep the ordering to build the chain of `gir`
# dependencies
140
all_libraries = []
141
142
143
foreach sp : subprojects
  project_name = sp[0]
  build_infos = sp[1]
144
  is_required = build_infos.get('option', true)
145
146
  sysdep = build_infos.get('sysdep', '')
  sysdep_version = build_infos.get('sysdep_version', '')
147
  match_gst_version = build_infos.get('match_gst_version', true)
148
  default_options =  build_infos.get('subproject_options', [])
149
150

  if match_gst_version
151
    subproj = subproject(project_name, version: gst_version, required: is_required, default_options: default_options)
152
  elif sysdep != ''
153
      sysdep_dep = dependency(sysdep, version: sysdep_version, required: false, default_options: default_options)
154
      if not sysdep_dep.found()
155
        subproj = subproject(project_name, required: is_required, default_options: default_options)
156
      endif
157
  else
158
    subproj = subproject(project_name, required: is_required, default_options: default_options)
159
160
  endif

161
  if subproj.found()
162
    plugins = subproj.get_variable('plugins', [])
163
    all_plugins += plugins
164
    all_libraries += subproj.get_variable('libraries', [])
165
166
167
    if not get_option('tools').disabled()
      all_tools += subproj.get_variable('gst_tools', {})
    endif
168

169
170
    orc_update_targets += subproj.get_variable('orc_update_targets', [])

171
    subprojects_names += [project_name]
172

173
    if not meson.is_cross_build() and build_infos.get('build-hotdoc', false)
174
      if plugins.length() > 0
175
        plugins_doc_caches += [subproj.get_variable('plugins_doc_dep', [])]
176
177
178
179
180
181
      endif
      if documented_projects != ''
        documented_projects += ','
      endif
      documented_projects  += project_name
    endif
182
  endif
Thibault Saunier's avatar
Thibault Saunier committed
183
184
endforeach

185
186
187
188
189
190
191
# Check if we need to also build glib-networking for TLS modules
glib_dep = dependency('glib-2.0')
if glib_dep.type_name() == 'internal'
  subproject('glib-networking', required : get_option('tls'),
             default_options: ['gnutls=auto', 'openssl=auto'])
endif

192
193
194
195
196
197
198
plugins_doc_dep = custom_target('plugins-doc-cache',
  command: [python3, '-c', 'print("Built all doc caches")'],
  input: plugins_doc_caches,
  output: 'plugins_doc_caches',
  capture: true,
)

199
200
201
202
203
if meson.is_cross_build() or build_machine.system() == 'windows'
    if get_option('doc').enabled()
        error('Documentation enabled but building the doc while cross building or building on windows is not supported yet.')
    endif

204
    documented_projects = ''
205
    message('Documentation not built as building the documentation while cross building or building on windows is not supported yet.')
206
207
else
  hotdoc_p = find_program('hotdoc', required : get_option('doc'))
208
209
  if not hotdoc_p.found()
    documented_projects = ''
210
211
212
    message('Not building documentation as hotdoc was not found')
  endif
endif
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
write_file_contents = '''
import os
import sys

assert len(sys.argv) >= 3
fname = sys.argv[1]
contents = sys.argv[2]

with open(fname, 'w') as f:
    f.write(contents)
'''

configure_file(
  output : 'GstDocumentedSubprojects',
  command : [python3,
             '-c', write_file_contents,
             '@OUTPUT@',
             documented_projects]
)

if documented_projects != ''
235
  subproject('gst-docs', required: get_option('doc').enabled())
236
237
238
  message('Gst docs subprojects: ' + documented_projects)
endif

239
all_plugins_paths = []
240
all_plugins_dirs = []
241
242
foreach plugin: all_plugins
  all_plugins_paths += plugin.full_path()
243
  all_plugins_dirs += fs.parent(plugin.full_path())
244
endforeach
245
246
247
# Work around meson bug: https://github.com/mesonbuild/meson/pull/6770
pathsep = host_machine.system() == 'windows' ? ';' : ':'
all_plugins_paths = pathsep.join(all_plugins_paths)
248

249
devenv = environment()
250
devenv.prepend('GST_PLUGIN_PATH', all_plugins_dirs)
251
252
253
254
255
256
257
devenv.set('CURRENT_GST', meson.current_source_dir())
devenv.set('GST_VERSION', meson.project_version())
devenv.set('GST_ENV', 'gst-' + meson.project_version())
devenv.set('GST_REGISTRY', meson.current_build_dir() / 'registry.dat')
devenv.set('GST_PLUGIN_SYSTEM_PATH', '')
meson.add_devenv(devenv)

258
259
260
261
262
263
264
generate_plugins_paths = find_program('scripts/generate_plugins_path.py')
configure_file(
  output : 'GstPluginsPath.json',
  command : [generate_plugins_paths,
             '@OUTPUT@',
             all_plugins_paths]
)
265

266
267
268
269
270
271
272
273
274
275
if building_full
  cdata = configuration_data()
  cdata.set_quoted('GST_API_VERSION', apiversion)
  cdata.set_quoted('GETTEXT_PACKAGE', 'gstreamer-full-1.0')
  cdata.set_quoted('PACKAGE_VERSION', gst_version)
  cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('package-origin'))
  configure_file(output : 'config.h', configuration : cdata)
  configinc = include_directories('.')
  gst_c_args = ['-DHAVE_CONFIG_H']

276
  # Generate a .c file which declare and register all built plugins
277
278
279
280
281
282
283
284
285
286
  plugins_names = []
  foreach plugin: all_plugins
    plugins_names += plugin.full_path()
  endforeach
  all_plugin_names = ';'.join(plugins_names)

  static_plugins = get_option('gst-full-plugins')
  if static_plugins == '*'
    static_plugins = all_plugin_names
  endif
287
288
289
290
  generate_init_static_plugins = find_program('scripts/generate_init_static_plugins.py')
  init_static_plugins_c = configure_file(
    output: 'gstinitstaticplugins.c',
    command : [generate_init_static_plugins,
291
292
293
294
295
296
297
               '-o ' + '@OUTPUT@',
               '-p ' + static_plugins,
               '-e ' + get_option('gst-full-elements'),
               '-t ' + get_option('gst-full-typefind-functions'),
               '-d ' + get_option('gst-full-device-providers'),
               '-T ' + get_option('gst-full-dynamic-types')
               ]
298
299
  )

300
301
  gstfull_link_args = cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions'])

302
303
  # Get a list of libraries that needs to be exposed in the ABI.
  exposed_libs = []
304
  exposed_deps = []
305
  exposed_girs = []
306
  incdir_deps = []
307
308
309
310
311
312
313
314
315
  wanted_libs = ['gstreamer-1.0'] + get_option('gst-full-libraries')
  all_libs = '*' in wanted_libs

  foreach pkgname_library : all_libraries
    pkg_name = pkgname_library[0]
    lib_def = pkgname_library[1]

    if pkg_name in wanted_libs or all_libs
      if lib_def.has_key('lib')
316
        exposed_deps += dependency(pkg_name)
317
318
319
320
321
322
323
324
        incdir_deps += dependency(pkg_name).partial_dependency(includes: true, sources: true)
        exposed_libs += [lib_def['lib']]
      endif

      if lib_def.has_key('gir')
        exposed_girs += lib_def['gir']
      endif
    endif
325
326
327
328
329
  endforeach

  # glib and gobject are part of our public API. If we are using glib from the
  # system then our pkg-config file must require it. If we built it as
  # subproject then we need to link_whole it.
330
331
332
  glib_deps = []
  glib_dep = dependency('glib-2.0')
  gobject_dep = dependency('gobject-2.0')
333
  if gobject_dep.type_name() == 'internal'
334
335
336
337
338
339
340
    glib_subproject = subproject('glib')
    exposed_libs += glib_subproject.get_variable('libglib')
    exposed_libs += glib_subproject.get_variable('libgobject')
    incdir_deps += [
      glib_dep.partial_dependency(includes: true),
      gobject_dep.partial_dependency(includes: true),
    ]
341
  else
342
    glib_deps = [glib_dep, gobject_dep]
343
344
  endif

345
346
347
348
349
350
  link_deps = []
  if get_option('gst-full-version-script') != ''
    symbol_map = meson.current_source_dir() / get_option('gst-full-version-script')
    link_arg = '-Wl,--version-script=' + symbol_map
    if cc.has_link_argument(link_arg)
      gstfull_link_args += link_arg
351
352
353
      link_deps += symbol_map
    elif cc.get_id() == 'msvc'
      warning('FIXME: Provide a def file to publish the public symbols')
354
    else
355
      warning('FIXME: Linker does not support the supplied version script (' + symbol_map + '), please disable the "gst-full-version-script" option')
356
357
358
    endif
  endif

359
360
361
362
  # Build both shared and static library
  gstfull = both_libraries('gstreamer-full-1.0',
    init_static_plugins_c,
    link_with : all_plugins,
363
    link_args: gstfull_link_args,
364
    link_whole : exposed_libs,
365
    dependencies : incdir_deps + glib_deps,
366
    link_depends : link_deps,
367
368
    install : true,
  )
369
370

  gst_full_dep = declare_dependency(link_with: gstfull.get_shared_lib(),
371
    dependencies : incdir_deps + glib_deps,
372
373
    include_directories: include_directories('.')
  )
374

375
376
377
378
  gst_full_libs_private = cc.get_supported_link_arguments(['-Wl,--undefined=gst_init_static_plugins'])
  if gst_full_libs_private == []
    warning('The compiler does not support `-Wl,--undefined` linker flag. The method `gst_init_static_plugins` might be dropped during the link stage of an application using libgstreamer-full-1.0.a, preventing plugins registration.')
  endif
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

  if not get_option('introspection').disabled()
    built_girs = {}
    foreach gir: exposed_girs
      includes = []
      foreach include: gir.get('includes', [])
        includes += [built_girs.get(include, include)]
      endforeach

      gir += {
        'includes': includes,
        'extra_args': gir.get('extra_args', []) + ['--add-include-path=' + meson.current_build_dir()],
        'install': true,
      }
      built_girs += {gir.get('namespace') + '-' + gir.get('nsversion'): gnome.generate_gir(gstfull, kwargs: gir)[0]}
    endforeach
  endif

397
  pkgconfig.generate(gstfull,
398
    requires: glib_deps,
399
    libraries_private: gst_full_libs_private,
400
    subdirs : 'gstreamer-1.0')
401
  meson.override_dependency('gstreamer-full-1.0', gst_full_dep)
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

  if not get_option('tools').disabled()
    foreach tool, data: all_tools
      exe_name = '@0@-@1@'.format(tool, apiversion)
      extra_args = data.get('extra_c_args', [])
      sources = data.get('files')
      deps = []
      foreach d : data.get('deps', [])
        if d not in exposed_deps
          deps += d
        endif
      endforeach

      executable(exe_name,
        sources,
        install: true,
        include_directories : [configinc],
        dependencies : [gst_full_dep] + deps,
        c_args: extra_args + gst_c_args + ['-DG_LOG_DOMAIN="@0@"'.format(exe_name)],
      )

      if data.has_key('man_page')
        install_man(data.get('man_page'))
      endif

    endforeach
  endif
429
430
endif

431
message('Building subprojects: ' + ', '.join(subprojects_names))
432

433
setenv = find_program('gst-env.py')
434

435
436
devenv_cmd = [setenv, '--builddir=@0@'.format(meson.global_build_root()),
              '--srcdir=@0@'.format(meson.global_source_root())]
437

438
subdir('tests')
439
440
subdir('ci/fuzzing')

441
if meson.can_run_host_binaries() and build_machine.system() == 'linux' and host_machine.system() == 'windows'
442
443
444
445
446
447
448
449
450
  # FIXME: Ideally we could get the wrapper directly from meson
  devenv_cmd += ['--wine', host_machine.cpu_family() == 'x86_64' ? 'wine64' : 'wine32']
  sysroot = meson.get_cross_property('sys_root')
  if sysroot != ''
    # Logic from meson
    devenv_cmd += ['--winepath', 'Z:' + join_paths(sysroot, 'bin')]
  endif
endif

451
run_target('devenv', command : devenv_cmd)
452

453
if orc_subproject.found() and orc_update_targets.length() > 0
454
455
  alias_target('update-orc-dist', orc_update_targets)
endif
456

457
458
459
dotnet_format = find_program('dotnet-format', required: false)
if dotnet_format.found()
    run_target('csharp_format_check',
460
        command: [join_paths(meson.current_source_dir(), 'scripts', 'format-csharp'),
461
462
463
464
            '--check'
        ],
    )
    run_target('csharp_format_apply',
465
        command: [join_paths(meson.current_source_dir(), 'scripts', 'format-csharp'),
466
467
468
469
        ],
    )
endif

470
summary({
471
  'gstreamer-full library': building_full,
472
}, section: 'Build options', bool_yn: true, list_sep: '  ')
473
474
475
476
477
478
479
480
481

gst_tools = []
foreach tool, data: all_tools
  gst_tools += tool
endforeach

summary({
    'Tools': gst_tools,
}, section: 'Build options', list_sep: ', ')