1 # Copyright © 2018-2022, VideoLAN and dav1d authors
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
7 # 1. Redistributions of source code must retain the above copyright notice, this
8 # list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright notice,
11 # this list of conditions and the following disclaimer in the documentation
12 # and/or other materials provided with the distribution.
14 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 project('dav1d', ['c'],
27 default_options: ['c_std=c99',
30 'b_ndebug=if-release'],
31 meson_version: '>= 0.49.0')
33 dav1d_soname_version = '7.0.0'
34 dav1d_api_version_array = dav1d_soname_version.split('.')
35 dav1d_api_version_major = dav1d_api_version_array[0]
36 dav1d_api_version_minor = dav1d_api_version_array[1]
37 dav1d_api_version_revision = dav1d_api_version_array[2]
39 dav1d_src_root = meson.current_source_dir()
40 cc = meson.get_compiler('c')
42 # Configuratin data for config.h
43 cdata = configuration_data()
45 # Configuration data for config.asm
46 cdata_asm = configuration_data()
49 dav1d_inc_dirs = include_directories(['.', 'include/dav1d', 'include'])
58 dav1d_bitdepths = get_option('bitdepths')
59 foreach bitdepth : ['8', '16']
60 cdata.set10('CONFIG_@0@BPC'.format(bitdepth), dav1d_bitdepths.contains(bitdepth))
64 is_asm_enabled = (get_option('enable_asm') == true and
65 (host_machine.cpu_family() == 'aarch64' or
66 host_machine.cpu_family().startswith('arm') or
67 host_machine.cpu() == 'ppc64le' or
68 host_machine.cpu_family().startswith('riscv') or
69 host_machine.cpu_family().startswith('loongarch') or
70 host_machine.cpu_family() == 'x86' or
71 (host_machine.cpu_family() == 'x86_64' and cc.get_define('__ILP32__').strip() == '')))
72 cdata.set10('HAVE_ASM', is_asm_enabled)
74 if is_asm_enabled and get_option('b_sanitize') == 'memory'
75 error('asm causes false positive with memory sanitizer. Use \'-Denable_asm=false\'.')
78 cdata.set10('TRIM_DSP_FUNCTIONS', get_option('trim_dsp') == 'true' or
79 (get_option('trim_dsp') == 'if-release' and get_option('buildtype') == 'release'))
82 cdata.set10('CONFIG_LOG', get_option('logging'))
85 # OS/Compiler checks and defines
88 # Arguments in test_args will be used even on feature tests
91 optional_arguments = []
92 optional_link_arguments = []
94 if host_machine.system() in ['linux', 'gnu', 'emscripten']
95 test_args += '-D_GNU_SOURCE'
96 add_project_arguments('-D_GNU_SOURCE', language: 'c')
99 if host_machine.system() == 'windows'
100 cdata.set('_WIN32_WINNT', '0x0601')
101 cdata.set('UNICODE', 1) # Define to 1 for Unicode (Wide Chars) APIs
102 cdata.set('_UNICODE', 1) # Define to 1 for Unicode (Wide Chars) APIs
103 cdata.set('__USE_MINGW_ANSI_STDIO', 1) # Define to force use of MinGW printf
104 cdata.set('_CRT_DECLARE_NONSTDC_NAMES', 1) # Define to get off_t from sys/types.h on MSVC
105 if cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args)
106 cdata.set('_FILE_OFFSET_BITS', 64) # Not set by default by Meson on Windows
108 cdata.set('fseeko', '_fseeki64')
109 cdata.set('ftello', '_ftelli64')
112 if host_machine.cpu_family() == 'x86_64'
113 if cc.get_argument_syntax() != 'msvc'
114 optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--high-entropy-va'
116 elif host_machine.cpu_family() == 'x86' or host_machine.cpu_family() == 'arm'
117 if cc.get_argument_syntax() == 'msvc'
118 optional_link_arguments += '/largeaddressaware'
120 optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--large-address-aware'
124 # On Windows, we use a compatibility layer to emulate pthread
125 thread_dependency = []
126 thread_compat_dep = declare_dependency(sources : files('src/win32/thread.c'))
130 rc_version_array = meson.project_version().split('.')
131 winmod = import('windows')
132 rc_data = configuration_data()
133 rc_data.set('PROJECT_VERSION_MAJOR', rc_version_array[0])
134 rc_data.set('PROJECT_VERSION_MINOR', rc_version_array[1])
135 rc_data.set('PROJECT_VERSION_REVISION', rc_version_array[2])
136 rc_data.set('API_VERSION_MAJOR', dav1d_api_version_major)
137 rc_data.set('API_VERSION_MINOR', dav1d_api_version_minor)
138 rc_data.set('API_VERSION_REVISION', dav1d_api_version_revision)
139 rc_data.set('COPYRIGHT_YEARS', '2018-2024')
141 thread_dependency = dependency('threads')
142 thread_compat_dep = []
145 if cc.has_function('clock_gettime', prefix : '#include <time.h>', args : test_args)
146 cdata.set('HAVE_CLOCK_GETTIME', 1)
147 elif host_machine.system() not in ['darwin', 'ios', 'tvos']
148 rt_dependency = cc.find_library('rt', required: false)
149 if not cc.has_function('clock_gettime', prefix : '#include <time.h>', args : test_args, dependencies : rt_dependency)
150 error('clock_gettime not found')
152 cdata.set('HAVE_CLOCK_GETTIME', 1)
155 if cc.has_function('posix_memalign', prefix : '#include <stdlib.h>', args : test_args)
156 cdata.set('HAVE_POSIX_MEMALIGN', 1)
160 # check for fseeko on android. It is not always available if _FILE_OFFSET_BITS is defined to 64
162 if host_machine.system() == 'android'
163 if not cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args)
164 if cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args + ['-U_FILE_OFFSET_BITS'])
165 warning('Files larger than 2 gigabytes might not be supported in the dav1d CLI tool.')
166 add_project_arguments('-U_FILE_OFFSET_BITS', language: 'c')
167 elif get_option('enable_tools')
168 error('dav1d CLI tool needs fseeko()')
175 libdl_dependency = []
176 if host_machine.system() == 'linux'
177 libdl_dependency = cc.find_library('dl', required : false)
178 if cc.has_function('dlsym', prefix : '#include <dlfcn.h>', args : test_args, dependencies : libdl_dependency)
179 cdata.set('HAVE_DLSYM', 1)
183 libm_dependency = cc.find_library('m', required: false)
188 stdatomic_dependencies = []
189 if not cc.check_header('stdatomic.h')
190 if cc.get_id() == 'msvc'
191 # we have a custom replacement for MSVC
192 stdatomic_dependencies += declare_dependency(
193 include_directories : include_directories('include/compat/msvc'),
195 elif cc.compiles('''int main() { int v = 0; return __atomic_fetch_add(&v, 1, __ATOMIC_SEQ_CST); }''',
196 name : 'GCC-style atomics', args : test_args)
197 stdatomic_dependencies += declare_dependency(
198 include_directories : include_directories('include/compat/gcc'),
201 error('Atomics not supported')
205 if host_machine.cpu_family().startswith('wasm')
206 # enable atomics + bulk-memory features
207 stdatomic_dependencies += thread_dependency.partial_dependency(compile_args: true)
210 if cc.check_header('unistd.h')
211 cdata.set('HAVE_UNISTD_H', 1)
214 if cc.check_header('io.h')
215 cdata.set('HAVE_IO_H', 1)
218 if cc.check_header('pthread_np.h')
219 cdata.set('HAVE_PTHREAD_NP_H', 1)
220 test_args += '-DHAVE_PTHREAD_NP_H'
226 if not cc.has_function('getopt_long', prefix : '#include <getopt.h>', args : test_args)
227 getopt_dependency = declare_dependency(
228 sources: files('tools/compat/getopt.c'),
229 include_directories : include_directories('include/compat'),
232 getopt_dependency = []
235 if (host_machine.cpu_family() == 'aarch64' or
236 host_machine.cpu_family().startswith('arm') or
237 host_machine.cpu_family().startswith('loongarch') or
238 host_machine.cpu() == 'ppc64le' or
239 host_machine.cpu_family().startswith('riscv'))
240 if cc.has_function('getauxval', prefix : '#include <sys/auxv.h>', args : test_args)
241 cdata.set('HAVE_GETAUXVAL', 1)
243 if cc.has_function('elf_aux_info', prefix : '#include <sys/auxv.h>', args : test_args)
244 cdata.set('HAVE_ELF_AUX_INFO', 1)
248 pthread_np_prefix = '''
250 #ifdef HAVE_PTHREAD_NP_H
251 #include <pthread_np.h>
254 if cc.has_function('pthread_getaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency)
255 cdata.set('HAVE_PTHREAD_GETAFFINITY_NP', 1)
257 if cc.has_function('pthread_setaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency)
258 cdata.set('HAVE_PTHREAD_SETAFFINITY_NP', 1)
261 if cc.compiles('int x = _Generic(0, default: 0);', name: '_Generic', args: test_args)
262 cdata.set('HAVE_C11_GENERIC', 1)
265 # Compiler flag tests
267 if cc.has_argument('-fvisibility=hidden')
268 add_project_arguments('-fvisibility=hidden', language: 'c')
270 warning('Compiler does not support -fvisibility=hidden, all symbols will be public!')
273 # Compiler flags that should be set
274 # But when the compiler does not supports them
275 # it is not an error and silently tolerated
276 if cc.get_argument_syntax() != 'msvc'
277 optional_arguments += [
280 '-Wno-maybe-uninitialized',
281 '-Wno-missing-field-initializers',
282 '-Wno-unused-parameter',
283 '-Wstrict-prototypes',
284 '-Werror=missing-prototypes',
285 '-Wshorten-64-to-32',
287 if host_machine.cpu_family() == 'x86'
288 optional_arguments += [
294 optional_arguments += [
295 '-wd4028', # parameter different from declaration
296 '-wd4090', # broken with arrays of pointers
297 '-wd4996' # use of POSIX functions
301 if (get_option('buildtype') != 'debug' and get_option('buildtype') != 'plain')
302 optional_arguments += '-fomit-frame-pointer'
303 optional_arguments += '-ffast-math'
306 if (host_machine.system() in ['darwin', 'ios', 'tvos'] and cc.get_id() == 'clang' and
307 cc.version().startswith('11'))
308 # Workaround for Xcode 11 -fstack-check bug, see #301
309 optional_arguments += '-fno-stack-check'
312 add_project_arguments(cc.get_supported_arguments(optional_arguments), language : 'c')
313 add_project_link_arguments(cc.get_supported_link_arguments(optional_link_arguments), language : 'c')
315 # libFuzzer related things
316 fuzzing_engine = get_option('fuzzing_engine')
317 if fuzzing_engine == 'libfuzzer'
318 if not cc.has_argument('-fsanitize=fuzzer')
319 error('fuzzing_engine libfuzzer requires "-fsanitize=fuzzer"')
321 fuzzer_args = ['-fsanitize=fuzzer-no-link', '-fsanitize=fuzzer']
322 add_project_arguments(cc.first_supported_argument(fuzzer_args), language : 'c')
325 cdata.set10('ENDIANNESS_BIG', host_machine.endian() == 'big')
327 if host_machine.cpu_family().startswith('x86')
328 if get_option('stack_alignment') > 0
329 stack_alignment = get_option('stack_alignment')
330 elif host_machine.cpu_family() == 'x86_64' or host_machine.system() in ['linux', 'darwin', 'ios', 'tvos']
335 cdata_asm.set('STACK_ALIGNMENT', stack_alignment)
338 cdata.set10('ARCH_AARCH64', host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64')
339 cdata.set10('ARCH_ARM', host_machine.cpu_family().startswith('arm') and host_machine.cpu() != 'arm64')
340 if (is_asm_enabled and
341 (host_machine.cpu_family() == 'aarch64' or
342 host_machine.cpu_family().startswith('arm')))
344 as_func_code = '''__asm__ (
349 have_as_func = cc.compiles(as_func_code)
350 cdata.set10('HAVE_AS_FUNC', have_as_func)
352 # fedora package build infrastructure uses a gcc specs file to enable
353 # '-fPIE' by default. The chosen way only adds '-fPIE' to the C compiler
354 # with integrated preprocessor. It is not added to the standalone
355 # preprocessor or the preprocessing stage of '.S' files. So we have to
356 # compile code to check if we have to define PIC for the arm asm to
357 # avoid absolute relocations when building for example checkasm.
360 #error "PIC already defined"
361 #elif !(defined(__PIC__) || defined(__pic__))
365 if cc.compiles(check_pic_code)
366 cdata.set('PIC', '3')
370 cdata.set10('ARCH_X86', host_machine.cpu_family().startswith('x86'))
371 cdata.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
372 cdata.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
374 if host_machine.cpu_family().startswith('x86')
375 cdata_asm.set('private_prefix', 'dav1d')
376 cdata_asm.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
377 cdata_asm.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
378 cdata_asm.set10('PIC', true)
380 # Convert SSE asm into (128-bit) AVX when compiler flags are set to use AVX instructions
381 cdata_asm.set10('FORCE_VEX_ENCODING', cc.get_define('__AVX__').strip() != '')
384 cdata.set10('ARCH_PPC64LE', host_machine.cpu() == 'ppc64le')
386 cdata.set10('ARCH_RISCV', host_machine.cpu_family().startswith('riscv'))
387 cdata.set10('ARCH_RV32', host_machine.cpu_family() == 'riscv32')
388 cdata.set10('ARCH_RV64', host_machine.cpu_family() == 'riscv64')
390 cdata.set10('ARCH_LOONGARCH', host_machine.cpu_family().startswith('loongarch'))
391 cdata.set10('ARCH_LOONGARCH32', host_machine.cpu_family() == 'loongarch32')
392 cdata.set10('ARCH_LOONGARCH64', host_machine.cpu_family() == 'loongarch64')
394 # meson's cc.symbols_have_underscore_prefix() is unfortunately unrelieably
395 # when additional flags like '-fprofile-instr-generate' are passed via CFLAGS
396 # see following meson issue https://github.com/mesonbuild/meson/issues/5482
397 if (host_machine.system() in ['darwin', 'ios', 'tvos'] or
398 (host_machine.system() == 'windows' and host_machine.cpu_family() == 'x86'))
399 cdata.set10('PREFIX', true)
400 cdata_asm.set10('PREFIX', true)
406 if is_asm_enabled and host_machine.cpu_family().startswith('x86')
408 # NASM compiler support
410 nasm = find_program('nasm')
414 nasm_r = run_command(nasm, '-v', check: true)
416 out = nasm_r.stdout().strip().split()
417 if out[1].to_lower() == 'version'
418 if out[2].version_compare('<2.14')
419 error('nasm 2.14 or later is required, found nasm @0@'.format(out[2]))
422 error('unexpected nasm version string: @0@'.format(nasm_r.stdout()))
426 # Generate config.asm
427 config_asm_target = configure_file(output: 'config.asm', output_format: 'nasm', configuration: cdata_asm)
429 if host_machine.system() == 'windows'
431 elif host_machine.system() in ['darwin', 'ios', 'tvos']
432 nasm_format = 'macho'
436 if host_machine.cpu_family() == 'x86_64'
442 nasm_gen = generator(nasm,
443 output: '@BASENAME@.obj',
444 depfile: '@BASENAME@.obj.ndep',
447 '-I', '@0@/src/'.format(dav1d_src_root),
448 '-I', '@0@/'.format(meson.current_build_dir()),
449 '-MQ', '@OUTPUT@', '-MF', '@DEPFILE@',
457 if (is_asm_enabled and
458 (host_machine.cpu_family() == 'aarch64' or
459 host_machine.cpu_family().startswith('arm')) and
460 cc.get_argument_syntax() == 'msvc' and
461 (cc.get_id() != 'clang-cl' or meson.version().version_compare('<0.58.0')))
462 gaspp = find_program('gas-preprocessor.pl')
464 gaspp_gen = generator(gaspp,
465 output: '@BASENAME@.obj',
467 '-as-type', 'armasm',
468 '-arch', host_machine.cpu_family(),
470 host_machine.cpu_family() == 'aarch64' ? 'armasm64' : 'armasm',
472 '-I@0@'.format(dav1d_src_root),
473 '-I@0@/'.format(meson.current_build_dir()),
481 config_h_target = configure_file(output: 'config.h', configuration: cdata)
486 # Include subdir meson.build files
487 # The order is important!