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