• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1project('v4l-utils', 'c', 'cpp',
2    version: '1.28.1',
3    meson_version : '>= 0.57',
4    default_options : [
5        'buildtype=debugoptimized',
6        'warning_level=1',
7        'c_std=gnu99',
8        'cpp_std=gnu++11',
9    ],
10    license : 'LGPL 2.1+')
11
12# meson >= 0.56 can use instead meson.project_source_root()
13source_root = meson.current_source_dir()
14
15cc = meson.get_compiler('c')
16cpp = meson.get_compiler('cpp')
17have_m32 = cc.has_link_argument('-m32')
18have_visibility = cc.has_argument('-fvisibility=hidden') and \
19                  cc.has_function_attribute('visibility:default')
20
21sys_root = meson.get_external_property('sys_root', '/')
22
23fs = import('fs')
24i18n = import('i18n')
25pkg = import('pkgconfig')
26qt6 = import('qt6')
27qt5 = import('qt5')
28
29as_version = meson.project_version()
30ver_arr = as_version.split('.')
31as_major_version = ver_arr[0]
32as_minor_version = ver_arr[1]
33as_patch_version = ver_arr[2]
34
35conf = configuration_data()
36conf.set_quoted('PACKAGE', meson.project_name())
37conf.set_quoted('PACKAGE_VERSION', as_version)
38conf.set_quoted('V4L_UTILS_VERSION', as_version)
39conf.set('MAN_PACKAGE_VERSION', as_version)
40conf.set('MAJOR', as_major_version)
41conf.set('MINOR', as_minor_version)
42conf.set('PATCH', as_patch_version)
43
44common_arguments = [
45    '-Wpointer-arith',
46    '-D_GNU_SOURCE',
47    '-DPROMOTED_MODE_T=int',
48    '-DENABLE_NLS',
49    '-include', meson.current_build_dir() / 'config.h',
50]
51
52v4l2_wrapper_args = [
53    # As the library needs to provide both 32-bit and 64-bit versions
54    # of file operations, disable transparent large file support (fixes
55    # 'Error: symbol `open64/mmap64' is already defined' compile failure
56    # otherwise)
57    '-U_FILE_OFFSET_BITS',
58    '-D_FILE_OFFSET_BITS=32',
59    '-D_LARGEFILE64_SOURCE',
60]
61
62v4l2_utils_incdir_arr = [
63    'lib' / 'include',
64]
65
66if host_machine.system() == 'linux'
67    v4l2_utils_incdir_arr += 'include'
68elif host_machine.system() == 'freebsd'
69    v4l2_utils_incdir_arr += 'contrib/freebsd/include'
70endif
71
72# These platforms default to __[us]64 as long. Add this define to get long long
73# as is done elsewhere.
74if host_machine.cpu_family() in ['alpha', 'mips64', 'ppc64']
75  add_project_arguments('-D__SANE_USERSPACE_TYPES__', language: ['c', 'cpp'])
76endif
77
78v4l2_utils_incdir = include_directories(v4l2_utils_incdir_arr)
79
80prog_bash = find_program('bash')
81prog_clang = find_program('clang', required : get_option('bpf'))
82prog_doxygen = find_program('doxygen', required : get_option('doxygen-doc'))
83prog_grep = find_program('grep')
84prog_perl = find_program('perl')
85
86dep_alsa = dependency('alsa', required : false)
87if dep_alsa.found()
88    conf.set('HAVE_ALSA', 1)
89endif
90
91dep_gl = dependency('gl', required : get_option('qvidcap').enabled())
92dep_glu = dependency('glu', required : false)
93
94dep_jsonc = dependency('json-c', required : get_option('v4l2-tracer'), version : '>=0.15')
95
96dep_libdl = cc.find_library('dl')
97dep_libelf = cc.find_library('elf', required : get_option('bpf'))
98dep_libm = cc.find_library('m')
99dep_librt = cc.find_library('rt')
100dep_qt6 = dependency('qt6', modules: ['Core', 'Gui', 'Widgets', 'Core5Compat'], required: false)
101if dep_qt6.found()
102  dep_qt_opengl = dependency('qt6', modules: ['OpenGL', 'OpenGLWidgets'],
103                             required : get_option('qvidcap').enabled())
104  dep_qt = dep_qt6
105  dep_qt_version = 'Qt6'
106  dep_qt_options = ['cpp_std=gnu++17']
107  dep_qt_args = ['-std=gnu++17']
108else
109  dep_qt = dependency('qt5', modules: ['Core', 'Gui', 'Widgets'],
110                      required : get_option('qvidcap').enabled() or get_option('qv4l2').enabled())
111  if dep_qt.found()
112    dep_qt_version = 'Qt5'
113  else
114    dep_qt_version = ''
115  endif
116  dep_qt_opengl = dependency('qt5', modules: ['OpenGL'],
117                             required : get_option('qvidcap').enabled())
118  dep_qt_options = []
119  dep_qt_args = []
120endif
121
122dep_libbpf = dependency('libbpf', required : get_option('bpf'), version : '>=0.7')
123
124dep_sdl = dependency('SDL2', required: false)
125if not dep_sdl.found()
126    dep_sdl = cc.find_library('SDL2', has_headers: 'SDL2/SDL.h', required: false)
127endif
128
129dep_sdl_image = dependency('SDL2_image', required: false)
130if not dep_sdl_image.found()
131    dep_sdl_image = cc.find_library('SDL2_image', has_headers: 'SDL2/SDL_image.h', required: false)
132endif
133
134dep_threads = dependency('threads')
135dep_x11 = dependency('x11', required : false)
136dep_xmlrpc = dependency('xmlrpc', required : false)
137
138have_fork = cc.has_function('fork', prefix: '#include <unistd.h>')
139have_i2c_dev = cc.has_header('linux/i2c-dev.h')
140
141if have_visibility
142    conf.set('HAVE_VISIBILITY', 1)
143endif
144
145if cc.has_function('klogctl')
146    conf.set('HAVE_KLOGCTL', 1)
147endif
148
149if cc.has_function('secure_getenv')
150    conf.set('HAVE_SECURE_GETENV', 1)
151endif
152
153if cc.has_function('__secure_getenv')
154    conf.set('HAVE___SECURE_GETENV', 1)
155endif
156
157if cc.has_header('sys/klog.h')
158    conf.set('HAVE_SYS_KLOG_H', 1)
159endif
160
161if cc.has_header_symbol('execinfo.h', 'backtrace')
162    conf.set('HAVE_BACKTRACE', 1)
163endif
164
165if cc.has_function('argp_parse')
166    dep_argp = dependency('', required : false)
167else
168    dep_argp = cc.find_library('argp')
169endif
170
171if cc.has_function('strerrorname_np')
172    conf.set('HAVE_STRERRORNAME_NP', 1)
173endif
174
175conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('datadir') / 'locale')
176
177# Meson 0.60 handles the iconv dependency natively. For older versions, fall
178# back to manual checks for the iconv_open function in libc, or finding an
179# external library otherwise.
180if meson.version().version_compare('>= 0.60')
181    dep_iconv = dependency('iconv', required : false)
182    found_iconv = dep_iconv.found()
183else
184    if cc.has_function('iconv_open')
185        dep_iconv = []
186        found_iconv = true
187    else
188        dep_iconv = [cc.find_library('iconv', required : false)]
189        found_iconv = dep_iconv.found()
190    endif
191endif
192
193if found_iconv
194    conf.set('HAVE_ICONV', 1)
195    iconv_const_test = '''#include <iconv.h>
196size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
197'''
198    if cc.compiles(iconv_const_test, dependencies : dep_iconv)
199        conf.set('ICONV_CONST', '')
200    else
201        conf.set('ICONV_CONST', 'const')
202    endif
203endif
204
205have_gconv = cc.has_header('gconv.h', required : get_option('gconv'))
206
207# Detect system gconv directory
208gconvsysdir = get_option('gconvsysdir')
209
210# Generic check: works with most distributions
211gconv_dirs_generic = [
212    'lib64',
213    'usr/lib64',
214    'lib',
215    'usr/lib',
216    'usr/local/lib64',
217    'usr/local/lib',
218]
219
220if gconvsysdir == ''
221    foreach dir : gconv_dirs_generic
222        dir = sys_root / dir / 'gconv'
223        if fs.is_dir(dir)
224            gconvsysdir = dir
225            break
226        endif
227    endforeach
228endif
229
230# Debian/Ubuntu-specific check: should be aligned with the debian package
231gconv_dirs_debian = [
232    'aarch64-linux-gnu',
233    'alphaev67-linux-gnu',
234    'arm-linux-gnueabi',
235    'arm-linux-gnueabihf',
236    'i686-kfreebsd-gnu',
237    'i686-linux-gnu',
238    'mips-linux-gnu',
239    'mips64-linux-gnuabi64',
240    'mips64-linux-gnuabin32',
241    'mips64el-linux-gnuabi64',
242    'mips64el-linux-gnuabin32',
243    'mipsel-linux-gnu',
244    'mipsisa32r6-linux-gnu',
245    'mipsisa32r6el-linux-gnu',
246    'mipsisa64r6-linux-gnuabi64',
247    'mipsisa64r6-linux-gnuabin32',
248    'mipsisa64r6el-linux-gnuabi64',
249    'mipsisa64r6el-linux-gnuabin32',
250    'powerpc-linux-gnu',
251    'powerpc64-linux-gnu',
252    's390-linux-gnu',
253    'sparc64-linux-gnu',
254    'sparcv9-linux-gnu',
255    'x86_64-linux-gnu',
256    'x86_64-linux-gnux32',
257]
258
259if gconvsysdir == ''
260    foreach dir : gconv_dirs_debian
261        dir = sys_root / 'usr' / 'lib' / dir / 'gconv'
262        if fs.is_dir(dir)
263            gconvsysdir = dir
264            break
265        endif
266    endforeach
267endif
268
269if gconvsysdir == ''
270    dep_jis = cc.find_library('JIS', required : get_option('gconv'))
271    dep_jisx0213 = cc.find_library('JISX0213', required : get_option('gconv'))
272else
273    dep_jis = cc.find_library('JIS', required : get_option('gconv'), dirs : gconvsysdir)
274    dep_jisx0213 = cc.find_library('JISX0213', required : get_option('gconv'), dirs : gconvsysdir)
275endif
276
277dep_jpeg = dependency('libjpeg', required : get_option('jpeg'))
278if dep_jpeg.found()
279    dep_jpeg_priv_libs = '-ljpeg'
280endif
281
282dep_systemd = dependency('systemd', required : false)
283systemd_systemdir = get_option('systemdsystemunitdir')
284if systemd_systemdir == ''
285    if dep_systemd.found()
286        systemd_systemdir = dep_systemd.get_variable(pkgconfig : 'systemdsystemunitdir')
287    endif
288endif
289if systemd_systemdir == ''
290    systemd_systemdir = '/lib/systemd/system'
291endif
292# Since systemd v239, udevd is not allowed to execute BPF systems calls;
293# add an override to allow bpf(2) in that case. On earlier versions, the
294# override will restrict udevd to bpf syscall only and will stop the system
295# from booting. This is also true on current debian versions.
296have_udevdsyscallfilter = run_command(prog_grep, '-s', 'SystemCallFilter',
297                                      systemd_systemdir / 'systemd-udevd.service',
298                                      check : false).returncode() == 0
299
300dep_libudev = dependency('libudev', required : get_option('libdvbv5'))
301if dep_libudev.found()
302    conf.set('HAVE_LIBUDEV', 1)
303endif
304
305udevdir = get_option('udevdir')
306if udevdir == ''
307    dep_udev = dependency('udev', required : false)
308    if dep_udev.found()
309        udevdir = dep_udev.get_variable(pkgconfig : 'udevdir')
310    endif
311endif
312if udevdir == ''
313    udevdir = '/lib/udev'
314endif
315
316docdir = get_option('docdir')
317if docdir == ''
318    docdir = get_option('datadir') / 'doc' / '@0@'.format(meson.project_name())
319endif
320
321qt_opengl_test = '''
322#define GL_GLEXT_PROTOTYPES
323#define QT_NO_OPENGL_ES_2
324
325#include <QtCore>
326#if QT_VERSION < 0x060000
327#include <QGLWidget>
328#include <QGLShader>
329#include <QGLShaderProgram>
330#include <QGLFunctions>
331#else
332#include <QOpenGLWidget>
333#include <QOpenGLFunctions>
334#include <QOpenGLShaderProgram>
335#endif
336
337#ifndef GL_UNSIGNED_INT_8_8_8_8
338#error Missing OpenGL Extensions
339#endif
340'''
341have_qt_opengl = cpp.compiles(qt_opengl_test,
342                               dependencies : [dep_gl, dep_qt, dep_qt_opengl],
343                               args : ['-fPIC'] + dep_qt_args)
344if have_qt_opengl
345    conf.set('HAVE_QTGL', 1)
346endif
347
348ioctl_posix_test = '''
349#include <sys/ioctl.h>
350int ioctl (int, int, ...);
351'''
352if cc.compiles(ioctl_posix_test)
353    conf.set('HAVE_POSIX_IOCTL', 1)
354endif
355
356c_arguments = []
357cpp_arguments = []
358
359c_arguments += common_arguments
360cpp_arguments += common_arguments
361
362add_project_arguments(c_arguments, language : 'c')
363add_project_arguments(cpp_arguments, language : 'cpp')
364add_project_link_arguments(cpp_arguments, language : 'cpp')
365
366git_sha = ''
367git_commit_cnt = ''
368git_commit_date = ''
369
370if fs.is_dir('.git')
371    prog_git = find_program('git')
372    git_sha = run_command(prog_git, '-C', source_root, 'rev-parse', '--short=12', 'HEAD',
373                          check : true).stdout().strip()
374    git_commit_cnt = '-' + run_command(prog_git, '-C', source_root, 'rev-list', '--count', 'HEAD',
375                                 check : true).stdout().strip()
376    git_commit_date = run_command(prog_git, '-C', source_root, 'show', '--quiet',
377                                  '--date=format-local:%F %T', '--format=%cd',
378                                  env : ['TZ=UTC'], check : true).stdout().strip()
379endif
380
381conf.set('GIT_SHA', git_sha)
382conf.set('GIT_COMMIT_CNT', git_commit_cnt)
383conf.set('GIT_COMMIT_DATE', git_commit_date)
384
385man_pages = []
386
387i18n_gettext_arguments = ['--directory=' + source_root,
388                          '--keyword=_', '--keyword=N_', '--keyword=P_:1,2']
389subdir('libdvbv5-po')
390subdir('v4l-utils-po')
391
392subdir('lib')
393
394if get_option('v4l-utils')
395    subdir('utils')
396    subdir('contrib')
397else
398    ir_bpf_enabled = false
399endif
400
401subdir('doc')
402
403configure_file(output : 'config.h', configuration : conf)
404
405foreach m : man_pages
406    configure_file(input : join_paths(m[0], '@0@.@1@.in'.format(m[1], m[2])),
407                   output : '@0@.@1@'.format(m[1], m[2]),
408                   install_dir : join_paths(get_option('mandir'), 'man@0@'.format(m[2])),
409                   configuration : conf)
410endforeach
411
412configure_file(input : 'v4l-utils.spec.in', output : 'v4l-utils.spec',
413               configuration : conf)
414
415summary({
416            'ALSA' : dep_alsa.found(),
417            'GL' : dep_gl.found(),
418            'GLU' : dep_glu.found(),
419            'JSON-C' : dep_jsonc.found(),
420            'Qt5/Qt6' : [
421                dep_qt.found(),
422                dep_qt_version + (have_qt_opengl ? ' with QtGL' : ' without QtGL'),
423            ],
424            'SDL' : dep_sdl.found(),
425            'X11' : dep_x11.found(),
426            'gconv' : have_gconv,
427            'iconv' : found_iconv,
428            'libjpeg' : dep_jpeg.found(),
429            'libudev' : dep_libudev.found(),
430            'threads' : dep_threads.found(),
431        }, bool_yn : true, section : 'Dependencies')
432
433summary({
434            'udevdir' : udevdir,
435        }, section : 'Directories')
436
437summary({
438            'libdvbv5' : is_variable('libdvbv5'),
439            'v4l-plugins' : get_option('v4l-plugins'),
440            'v4l-wrappers' : get_option('v4l-wrappers'),
441        }, bool_yn : true, section : 'Libraries')
442
443summary({
444            'BPF IR decoders' : ir_bpf_enabled,
445            'qv4l2' : is_variable('qv4l2'),
446            'qvidcap' : is_variable('qvidcap'),
447            'v4l-utils' : get_option('v4l-utils'),
448            'v4l2-compliance' : [
449                is_variable('v4l2_compliance'),
450                get_option('v4l2-compliance-libv4l') ? 'with libv4l' : 'without libv4l',
451            ],
452            'v4l2-compliance-32' : is_variable('v4l2_compliance_32'),
453            'v4l2-ctl' : [
454                is_variable('v4l2_ctl'),
455                get_option('v4l2-ctl-libv4l') ? 'with libv4l' : 'without libv4l',
456            ],
457            'v4l2-ctl-32' : is_variable('v4l2_ctl_32'),
458            'v4l2-tracer' : is_variable('v4l2_tracer'),
459        }, bool_yn : true, section : 'Applications')
460