xref: /aosp_15_r20/external/libopus/meson.build (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1project('opus', 'c',
2  version: run_command('meson/get-version.py', '--package-version', check: true).stdout().strip(),
3  meson_version: '>=0.54.0',
4  default_options: ['warning_level=2',
5                    'c_std=gnu99',
6                    'buildtype=debugoptimized'])
7
8libversion = run_command('meson/get-version.py', '--libtool-version', check: true).stdout().strip()
9macosversion = run_command('meson/get-version.py', '--darwin-version', check: true).stdout().strip()
10
11cc = meson.get_compiler('c')
12host_system = host_machine.system()
13host_cpu_family = host_machine.cpu_family()
14top_srcdir = meson.current_source_dir()
15top_builddir = meson.current_build_dir()
16
17opus_includes = include_directories('.', 'include', 'celt', 'silk', 'dnn')
18opus_public_includes = include_directories('include')
19
20add_project_arguments('-DOPUS_BUILD', language: 'c')
21add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
22
23if host_system == 'windows'
24  if cc.get_argument_syntax() == 'msvc'
25    add_project_arguments('-D_CRT_SECURE_NO_WARNINGS', language: 'c')
26  endif
27endif
28
29if cc.get_argument_syntax() == 'gnu'
30  add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c')
31endif
32
33# Check for extra compiler args
34additional_c_args = []
35if cc.get_argument_syntax() != 'msvc'
36  additional_c_args += [
37    '-fvisibility=hidden',
38    '-Wcast-align',
39    '-Wnested-externs',
40    '-Wshadow',
41    '-Wstrict-prototypes',
42  ]
43
44  # On Windows, -fstack-protector-strong adds a libssp-0.dll dependency and
45  # prevents static linking
46  if host_system != 'windows'
47    additional_c_args += ['-fstack-protector-strong']
48  endif
49endif
50
51foreach arg : additional_c_args
52  if cc.has_argument(arg)
53    add_project_arguments(arg, language: 'c')
54  endif
55endforeach
56
57# Windows MSVC warnings
58if cc.get_id() == 'msvc'
59  # Ignore several spurious warnings.
60  # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
61  # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
62  # NOTE: Only add warnings here if you are sure they're spurious
63  add_project_arguments('/wd4035', '/wd4715', '/wd4116', '/wd4046', '/wd4068',
64    '/wd4820', '/wd4244', '/wd4255', '/wd4668',
65    language : 'c')
66endif
67
68opus_version = meson.project_version()
69
70opus_conf = configuration_data()
71opus_conf.set('PACKAGE_BUGREPORT', '"[email protected]"')
72opus_conf.set('PACKAGE_NAME', '"opus"')
73opus_conf.set('PACKAGE_STRING', '"opus @0@"'.format(opus_version))
74opus_conf.set('PACKAGE_TARNAME', '"opus"')
75opus_conf.set('PACKAGE_URL', '""')
76opus_conf.set('PACKAGE_VERSION', '"@0@"'.format(opus_version))
77
78# FIXME: optional Ne10 dependency
79have_arm_ne10 = false
80
81libm = cc.find_library('m', required : false)
82
83opus_conf.set('HAVE_LRINTF', cc.has_function('lrintf', prefix: '#include <math.h>', dependencies: libm))
84opus_conf.set('HAVE_LRINT', cc.has_function('lrint', prefix: '#include <math.h>', dependencies: libm))
85opus_conf.set('HAVE___MALLOC_HOOK', cc.has_function('__malloc_hook', prefix: '#include <malloc.h>'))
86opus_conf.set('HAVE_STDINT_H', cc.check_header('stdint.h'))
87
88# Check for restrict keyword
89restrict_tmpl = '''
90typedef int * int_ptr;
91int foo (int_ptr @0@ ip, int * @0@ baz[]) {
92  return ip[0];
93}
94int main (int argc, char ** argv) {
95  int s[1];
96  int * @0@ t = s;
97  t[0] = 0;
98  return foo(t, (void *)0);
99}'''
100# Define restrict to the equivalent of the C99 restrict keyword, or to
101# nothing if this is not supported.  Do not define if restrict is
102# supported directly.
103if not cc.compiles(restrict_tmpl.format('restrict'), name : 'restrict keyword')
104  if cc.compiles(restrict_tmpl.format('__restrict'), name : '__restrict')
105    opus_conf.set('restrict', '__restrict')
106  elif cc.compiles(restrict_tmpl.format('__restrict__'), name : '__restrict__')
107    opus_conf.set('restrict', '__restrict')
108  elif cc.compiles(restrict_tmpl.format('_Restrict'), name : '_Restrict')
109    opus_conf.set('restrict', '_Restrict')
110  else
111    opus_conf.set('restrict', '/**/')
112  endif
113endif
114
115# Check for C99 variable-size arrays, or alloca() as fallback
116msg_use_alloca = false
117if cc.compiles('''static int x;
118                  char some_func (void) {
119                    char a[++x];
120                    a[sizeof a - 1] = 0;
121                    int N;
122                    return a[0];
123                  }''', name : 'C99 variable-size arrays')
124  opus_conf.set('VAR_ARRAYS', 1)
125  msg_use_alloca = 'NO (using C99 variable-size arrays instead)'
126elif cc.compiles('''#include <alloca.h>
127                    void some_func (void) {
128                      int foo=10;
129                      int * array = alloca(foo);
130                    }''', name : 'alloca (alloca.h)')
131  opus_conf.set('USE_ALLOCA', true)
132  opus_conf.set('HAVE_ALLOCA_H', true)
133  msg_use_alloca = true
134elif cc.compiles('''#include <malloc.h>
135                    #include <stdlib.h>
136                    void some_func (void) {
137                      int foo=10;
138                      int * array = alloca(foo);
139                    }''', name : 'alloca (std)')
140  opus_conf.set('USE_ALLOCA', true)
141  msg_use_alloca = true
142endif
143
144opts = [
145  [ 'fixed-point', 'FIXED_POINT' ],
146  [ 'fixed-point-debug', 'FIXED_DEBUG' ],
147  [ 'custom-modes', 'CUSTOM_MODES' ],
148  [ 'float-approx', 'FLOAT_APPROX' ],
149  [ 'enable-deep-plc', 'ENABLE_DEEP_PLC' ],
150  [ 'enable-dred', 'ENABLE_DRED' ],
151  [ 'enable-osce', 'ENABLE_OSCE' ],
152  [ 'assertions', 'ENABLE_ASSERTIONS' ],
153  [ 'hardening', 'ENABLE_HARDENING' ],
154  [ 'fuzzing', 'FUZZING' ],
155  [ 'check-asm', 'OPUS_CHECK_ASM' ],
156]
157
158foreach opt : opts
159  # we assume these are all boolean options
160  opt_foo = get_option(opt[0])
161  if opt_foo
162    opus_conf.set(opt[1], 1)
163  endif
164  set_variable('opt_' + opt[0].underscorify(), opt_foo)
165endforeach
166
167opt_asm = get_option('asm')
168opt_rtcd = get_option('rtcd')
169opt_intrinsics = get_option('intrinsics')
170extra_programs = get_option('extra-programs')
171opt_tests = get_option('tests')
172
173disable_float_api = not get_option('float-api')
174if disable_float_api
175  opus_conf.set('DISABLE_FLOAT_API', 1)
176endif
177
178if not get_option('enable-dnn-debug-float')
179  opus_conf.set('DISABLE_DEBUG_FLOAT', 1)
180endif
181
182# This is for the description in the pkg-config .pc file
183if opt_fixed_point
184  pc_build = 'fixed-point'
185else
186  pc_build = 'floating-point'
187endif
188if opt_custom_modes
189  pc_build = pc_build + ', custom modes'
190endif
191
192rtcd_support = []
193# With GCC, Clang, ICC, etc, we differentiate between 'may support this SIMD'
194# and 'presume we have this SIMD' by checking whether the SIMD / intrinsics can
195# be compiled by the compiler as-is (presume) or with SIMD cflags (may have).
196# With MSVC, the compiler will always build SIMD/intrinsics targeting all
197# specific instruction sets supported by that version of the compiler. No
198# special arguments are ever needed. If runtime CPU detection is not disabled,
199# we must always assume that we only 'may have' it.
200opus_can_presume_simd = true
201if cc.get_argument_syntax() == 'msvc'
202  if opt_rtcd.disabled()
203    warning('Building with an MSVC-like compiler and runtime CPU detection is disabled. Outputs may not run on all @0@ CPUs.'.format(host_cpu_family))
204  else
205    opus_can_presume_simd = false
206  endif
207endif
208
209opus_arm_external_asm = false
210
211asm_tmpl = '''
212int main (int argc, char ** argv) {
213  __asm__("@0@");
214  return 0;
215}'''
216
217asm_optimization = []
218inline_optimization = []
219if not opt_asm.disabled()
220  # Currently we only have inline asm for fixed-point
221  if host_cpu_family == 'arm' and opt_fixed_point
222    opus_conf.set('OPUS_ARM_ASM', true)
223
224    # Check if compiler supports gcc-style inline assembly
225    if cc.compiles('''#ifdef __GNUC_MINOR__
226                      #if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004
227                      #error GCC before 3.4 has critical bugs compiling inline assembly
228                      #endif
229                      #endif
230                      __asm__ (""::)''',
231                   name : 'compiler supports gcc-style inline assembly')
232
233      opus_conf.set('OPUS_ARM_INLINE_ASM', 1)
234
235      # AS_ASM_ARM_EDSP
236      if cc.compiles(asm_tmpl.format('qadd r3,r3,r3'),
237                     name : 'assembler supports EDSP instructions on ARM')
238        opus_conf.set('OPUS_ARM_INLINE_EDSP', 1)
239        inline_optimization += ['ESDP']
240      endif
241
242      # AS_ASM_ARM_MEDIA
243      if cc.compiles(asm_tmpl.format('shadd8 r3,r3,r3'),
244                     name : 'assembler supports ARMv6 media instructions on ARM')
245        opus_conf.set('OPUS_ARM_INLINE_MEDIA', 1)
246        inline_optimization += ['Media']
247      endif
248
249      # AS_ASM_ARM_NEON
250      if cc.compiles(asm_tmpl.format('vorr d0,d0,d0'),
251                     name : 'assembler supports NEON instructions on ARM')
252        opus_conf.set('OPUS_ARM_INLINE_NEON', 1)
253        inline_optimization += ['NEON']
254      endif
255    endif
256
257    # We need Perl to translate RVCT-syntax asm to gas syntax
258    perl = find_program('perl', required: get_option('asm'))
259    if perl.found()
260      opus_arm_external_asm = true
261      # opus_arm_presume_* mean we can and will use those instructions
262      # directly without doing runtime CPU detection.
263      # opus_arm_may_have_* mean we can emit those instructions, but we can
264      # only use them after runtime detection.
265      # The same rules apply for x86 assembly and intrinsics.
266
267      opus_arm_may_have_edsp = opus_conf.has('OPUS_ARM_INLINE_EDSP')
268      opus_arm_presume_edsp = opus_arm_may_have_edsp and opus_can_presume_simd
269
270      opus_arm_may_have_media = opus_conf.has('OPUS_ARM_INLINE_MEDIA')
271      opus_arm_presume_media = opus_arm_may_have_media and opus_can_presume_simd
272
273      opus_arm_may_have_neon = opus_conf.has('OPUS_ARM_INLINE_NEON')
274      opus_arm_presume_neon = opus_arm_may_have_neon and opus_can_presume_simd
275
276      if not opt_rtcd.disabled()
277        if not opus_arm_may_have_edsp
278          message('Trying to force-enable armv5e EDSP instructions...')
279          # AS_ASM_ARM_EDSP_FORCE
280          opus_arm_may_have_edsp = cc.compiles(asm_tmpl.format('.arch armv5te\n.object_arch armv4t\nqadd r3,r3,r3'),
281                                               name : 'Assembler supports EDSP instructions on ARM (forced)')
282        endif
283        if not opus_arm_may_have_media
284          message('Trying to force-enable ARMv6 media instructions...')
285          opus_arm_may_have_media = cc.compiles(asm_tmpl.format('.arch armv6\n.object_arch armv4t\nshadd8 r3,r3,r3'),
286                                                name : 'Assembler supports ARMv6 media instructions on ARM (forced)')
287        endif
288        if not opus_arm_may_have_neon
289          message('Trying to force-enable NEON instructions...')
290          opus_arm_may_have_neon = cc.compiles(asm_tmpl.format('.arch armv7-a\n.fpu neon\n.object_arch armv4t\nvorr d0,d0,d0'),
291                                               name : 'Assembler supports NEON instructions on ARM (forced)')
292        endif
293      endif
294
295      if opus_arm_may_have_edsp
296        opus_conf.set('OPUS_ARM_MAY_HAVE_EDSP', 1)
297        if opus_arm_presume_edsp
298          opus_conf.set('OPUS_ARM_PRESUME_EDSP', 1)
299          asm_optimization += ['EDSP']
300        else
301          rtcd_support += ['EDSP']
302        endif
303      endif
304      if opus_arm_may_have_media
305        opus_conf.set('OPUS_ARM_MAY_HAVE_MEDIA', 1)
306        if opus_arm_presume_media
307          opus_conf.set('OPUS_ARM_PRESUME_MEDIA', 1)
308          asm_optimization += ['Media']
309        else
310          rtcd_support += ['Media']
311        endif
312      endif
313      if opus_arm_may_have_neon
314        opus_conf.set('OPUS_ARM_MAY_HAVE_NEON', 1)
315        if opus_arm_presume_neon
316          opus_conf.set('OPUS_ARM_PRESUME_NEON', 1)
317          asm_optimization += ['NEON']
318        else
319          rtcd_support += ['NEON']
320        endif
321      endif
322      if opus_arm_may_have_dotprod
323        opus_conf.set('OPUS_ARM_MAY_HAVE_DOTPROD', 1)
324        if opus_arm_presume_dotprod
325          opus_conf.set('OPUS_ARM_PRESUME_DOTPROD', 1)
326          asm_optimization += ['DOTPROD']
327        else
328          rtcd_support += ['DOTPROD']
329        endif
330      endif
331
332      if cc.get_define('__APPLE__') != ''
333        arm2gnu_args = ['--apple']
334      else
335        arm2gnu_args = []
336      endif
337    endif # found perl
338  else # arm + enable fixed point
339    if opt_asm.enabled()
340      error('asm option is enabled, but no assembly support for ' + host_cpu_family)
341    endif
342  endif
343endif # enable asm
344
345# Check whether we require assembly and we support assembly on this arch,
346# but none were detected. Can happen because of incorrect compiler flags, such
347# as missing -mfloat-abi=softfp on ARM32 softfp architectures.
348if opt_asm.enabled() and (asm_optimization.length() + inline_optimization.length()) == 0
349  error('asm option was enabled, but no assembly support was detected')
350endif
351
352# XXX: NEON has hardfp vs softfp compiler configuration issues
353# When targeting ARM32 softfp, we sometimes need to explicitly pass
354# -mfloat-abi=softfp to enable NEON. F.ex., on Android. It should
355# be set in the cross file.
356arm_neon_intr_link_args = ['-mfpu=neon']
357arm_dotprod_intr_link_args = ['-march=armv8.2-a+dotprod']
358
359have_sse = false
360have_sse2 = false
361have_sse4_1 = false
362have_avx2 = false
363have_neon_intr = false
364have_dotprod_intr = false
365
366intrinsics_support = []
367if not opt_intrinsics.disabled()
368  if host_cpu_family in ['arm', 'aarch64']
369    # Check for ARMv7/AArch64 neon intrinsics
370    intrin_check = '''
371    #include <arm_neon.h>
372      int main (void) {
373        static float32x4_t A0, A1, SUMM;
374        SUMM = vmlaq_f32(SUMM, A0, A1);
375        return (int)vgetq_lane_f32(SUMM, 0);
376      }'''
377    intrin_name = 'ARMv7/AArch64 NEON'
378    if cc.links(intrin_check,
379                name: 'compiler supports @0@ intrinsics'.format(intrin_name))
380      opus_arm_presume_neon_intr = opus_can_presume_simd
381      opus_arm_may_have_neon_intr = true
382    else
383      opus_arm_presume_neon_intr = false
384      if cc.links(intrin_check,
385                  args: arm_neon_intr_link_args,
386                  name: 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(arm_neon_intr_link_args)))
387        opus_arm_may_have_neon_intr = true
388      else
389        opus_arm_may_have_neon_intr = false
390      endif
391    endif
392
393    if opus_arm_may_have_neon_intr
394      have_neon_intr = true
395      intrinsics_support += [intrin_name]
396      opus_conf.set('OPUS_ARM_MAY_HAVE_NEON_INTR', 1)
397      if opus_arm_presume_neon_intr
398        opus_conf.set('OPUS_ARM_PRESUME_NEON_INTR', 1)
399      else
400        rtcd_support += [intrin_name]
401        opus_neon_intr_args = arm_neon_intr_link_args
402      endif
403    else
404      message('Compiler does not support @0@ intrinsics'.format(intrin_name))
405    endif
406
407    # Check for aarch64 neon intrinsics
408    intrin_check = '''
409    #include <arm_neon.h>
410      int main (void) {
411        static int32_t IN;
412        static int16_t OUT;
413        OUT = vqmovns_s32(IN);
414      }'''
415    intrin_name = 'AArch64 NEON'
416    if cc.links(intrin_check,
417                name: 'compiler supports @0@ intrinsics'.format(intrin_name))
418      opus_arm_presume_aarch64_neon_intr = opus_can_presume_simd
419      opus_arm_may_have_aarch64_neon_intr = true
420    else
421      opus_arm_presume_aarch64_neon_intr = false
422      if cc.links(intrin_check,
423                  args: arm_neon_intr_link_args,
424                  name: 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(arm_neon_intr_link_args)))
425        opus_arm_may_have_aarch64_neon_intr = true
426      else
427        opus_arm_may_have_aarch64_neon_intr = false
428      endif
429    endif
430
431    if opus_arm_may_have_aarch64_neon_intr
432      intrinsics_support += [intrin_name]
433      opus_conf.set('OPUS_X86_MAY_HAVE_AARCH64_NEON_INTR', 1)
434      if opus_arm_presume_aarch64_neon_intr
435        opus_conf.set('OPUS_X86_PRESUME_AARCH64_NEON_INTR', 1)
436      endif
437    else
438      message('Compiler does not support @0@ intrinsics'.format(intrin_name))
439    endif
440
441    # Check for ARMv8.2 dotprod intrinsics
442    intrin_check = '''
443    #include <arm_neon.h>
444      int main (void) {
445        static int8x16_t a, b;
446        static int32x4_t SUMM;
447        SUMM = vdotq_s32(SUMM, a, b);
448        return (int)vgetq_lane_s32(SUMM, 0);
449      }'''
450    intrin_name = 'AArch64 DOTPROD'
451    if cc.links(intrin_check,
452                name: 'compiler supports @0@ intrinsics'.format(intrin_name))
453      opus_arm_presume_dotprod_intr = opus_can_presume_simd
454      opus_arm_may_have_dotprod_intr = true
455    else
456      opus_arm_presume_dotprod_intr = false
457      if cc.links(intrin_check,
458                  args: arm_dotprod_intr_link_args,
459                  name: 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(arm_dotprod_intr_link_args)))
460        opus_arm_may_have_dotprod_intr = true
461      else
462        opus_arm_may_have_dotprod_intr = false
463      endif
464    endif
465
466    if opus_arm_may_have_dotprod_intr
467      have_dotprod_intr = true
468      intrinsics_support += [intrin_name]
469      opus_conf.set('OPUS_ARM_MAY_HAVE_DOTPROD', 1)
470      if opus_arm_presume_dotprod_intr
471        opus_conf.set('OPUS_ARM_PRESUME_DOTPROD', 1)
472      else
473        rtcd_support += [intrin_name]
474        opus_dotprod_intr_args = arm_dotprod_intr_link_args
475      endif
476    else
477      message('Compiler does not support @0@ intrinsics'.format(intrin_name))
478    endif
479
480  elif host_cpu_family in ['x86', 'x86_64']
481    # XXX: allow external override/specification of the flags
482    x86_intrinsics = [
483      [ 'SSE', 'xmmintrin.h', '__m128', '_mm_setzero_ps()', ['-msse'] ],
484      [ 'SSE2', 'emmintrin.h', '__m128i', '_mm_setzero_si128()', ['-msse2'] ],
485      [ 'SSE4.1', 'smmintrin.h', '__m128i', '_mm_setzero_si128(); mtest = _mm_cmpeq_epi64(mtest, mtest)', ['-msse4.1'] ],
486      [ 'AVX2', 'immintrin.h', '__m256i', '_mm256_abs_epi32(_mm256_setzero_si256())', ['-mavx', '-mfma', '-mavx2'] ],
487    ]
488
489    foreach intrin : x86_intrinsics
490      intrin_check = '''#include <@0@>
491                        int main (int argc, char ** argv) {
492                          static @1@ mtest;
493                          mtest = @2@;
494                          return *((unsigned char *) &mtest) != 0;
495                        }'''.format(intrin[1],intrin[2],intrin[3])
496      intrin_name = intrin[0]
497      # Intrinsics arguments are not available with MSVC-like compilers
498      intrin_args = cc.get_argument_syntax() == 'msvc' ? [] : intrin[4]
499      if cc.links(intrin_check, name : 'compiler supports @0@ intrinsics'.format(intrin_name))
500        may_have_intrin = true
501        presume_intrin = opus_can_presume_simd
502      elif intrin_args.length() > 0
503        presume_intrin = false
504        if cc.links(intrin_check,
505                    args : intrin_args,
506                    name : 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(intrin_args)))
507          may_have_intrin = true
508        else
509          may_have_intrin = false
510        endif
511      endif
512      if may_have_intrin
513        intrinsics_support += [intrin_name]
514        intrin_lower_name = intrin_name.to_lower().underscorify()
515        set_variable('have_' + intrin_lower_name, true)
516        opus_conf.set('OPUS_X86_MAY_HAVE_' + intrin_name.underscorify(), 1)
517        if presume_intrin
518          opus_conf.set('OPUS_X86_PRESUME_' + intrin_name.underscorify(), 1)
519        else
520          rtcd_support += [intrin_name]
521          set_variable('opus_@0@_args'.format(intrin_lower_name), intrin_args)
522        endif
523      else
524        message('Compiler does not support @0@ intrinsics'.format(intrin_name))
525      endif
526    endforeach
527
528    if not opt_rtcd.disabled()
529      get_cpuid_by_asm = false
530      cpuid_asm_code = '''
531        #include <stdio.h>
532        int main (int argc, char ** argv) {
533                 unsigned int CPUInfo0;
534                 unsigned int CPUInfo1;
535                 unsigned int CPUInfo2;
536                 unsigned int CPUInfo3;
537                 unsigned int InfoType;
538                #if defined(__i386__) && defined(__PIC__)
539                 __asm__ __volatile__ (
540                 "xchg %%ebx, %1\n"
541                 "cpuid\n"
542                 "xchg %%ebx, %1\n":
543                 "=a" (CPUInfo0),
544                 "=r" (CPUInfo1),
545                 "=c" (CPUInfo2),
546                 "=d" (CPUInfo3) :
547                 "a" (InfoType), "c" (0)
548                );
549               #else
550                 __asm__ __volatile__ (
551                 "cpuid":
552                 "=a" (CPUInfo0),
553                 "=b" (CPUInfo1),
554                 "=c" (CPUInfo2),
555                 "=d" (CPUInfo3) :
556                 "a" (InfoType), "c" (0)
557                );
558               #endif
559          return 0;
560        }'''
561      cpuid_c_code = '''
562        #include <cpuid.h>
563        int main (int argc, char ** argv) {
564          unsigned int CPUInfo0;
565          unsigned int CPUInfo1;
566          unsigned int CPUInfo2;
567          unsigned int CPUInfo3;
568          unsigned int InfoType;
569          __get_cpuid(InfoType, &CPUInfo0, &CPUInfo1, &CPUInfo2, &CPUInfo3);
570          return 0;
571        }'''
572      cpuid_msvc_code = '''
573        #include <intrin.h>
574        int main (void) {
575          int CPUInfo, InfoType;
576          __cpuid(&CPUInfo, InfoType);
577        }'''
578      if cc.links(cpuid_asm_code, name : 'Get X86 CPU info via inline assembly')
579        opus_conf.set('CPU_INFO_BY_ASM', 1)
580      elif cc.links(cpuid_c_code, name : 'Get X86 CPU info via C method')
581        opus_conf.set('CPU_INFO_BY_C', 1)
582      elif cc.get_define('_MSC_VER') != '' and cc.links(cpuid_msvc_code)
583        message('Getting X86 CPU info via __cpuid')
584      else
585        if opt_intrinsics.enabled() and opt_rtcd.enabled()
586          error('intrinsics and rtcd options are enabled, but no Get CPU Info method detected')
587        endif
588        warning('Get CPU Info method not detected, no rtcd for intrinsics')
589      endif
590    endif # opt_rtcd
591  else
592    if opt_intrinsics.enabled()
593      error('intrinsics option enabled, but no intrinsics support for ' + host_cpu_family)
594    endif
595    warning('No intrinsics support for ' + host_cpu_family)
596  endif
597endif
598
599# Check whether we require intrinsics and we support intrinsics on this arch,
600# but none were detected. Can happen because of incorrect compiler flags, such
601# as missing -mfloat-abi=softfp on ARM32 softfp architectures.
602if opt_intrinsics.enabled() and intrinsics_support.length() == 0
603  error('intrinsics option was enabled, but none were detected')
604endif
605
606if opt_rtcd.disabled()
607  rtcd_support = 'disabled'
608else
609  if rtcd_support.length() > 0
610    opus_conf.set('OPUS_HAVE_RTCD', 1)
611  else
612    if intrinsics_support.length() == 0
613      rtcd_support = 'none'
614      if opt_rtcd.enabled()
615        error('rtcd option is enabled, but no support for intrinsics or assembly is available')
616      endif
617    else
618      rtcd_support = 'not needed'
619    endif
620  endif
621endif
622
623# extract source file lists from .mk files
624mk_files = [
625  'opus_headers.mk', 'opus_sources.mk',
626  'silk_headers.mk', 'silk_sources.mk',
627  'celt_sources.mk', 'celt_headers.mk',
628  'lpcnet_headers.mk', 'lpcnet_sources.mk',
629]
630lines = run_command('meson/read-sources-list.py', mk_files, check: true).stdout().strip().split('\n')
631sources = {}
632foreach l : lines
633  a = l.split(' = ')
634  var_name = a[0]
635  file_list = a[1].split()
636  sources += {var_name: files(file_list)}
637endforeach
638
639subdir('include')
640subdir('celt')
641subdir('silk')
642subdir('dnn')
643subdir('src')
644
645configure_file(output: 'config.h', configuration: opus_conf)
646
647if not opt_tests.disabled()
648  subdir('celt/tests')
649  subdir('silk/tests')
650  subdir('tests')
651endif
652
653# pkg-config files (not using pkg module so we can use the existing .pc.in file)
654pkgconf = configuration_data()
655
656pkgconf.set('prefix', join_paths(get_option('prefix')))
657pkgconf.set('exec_prefix', '${prefix}')
658pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir')))
659pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir')))
660pkgconf.set('VERSION', opus_version)
661pkgconf.set('PC_BUILD', pc_build)
662pkgconf.set('LIBM', libm.found() ? '-lm' : '')
663
664pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir'))
665
666configure_file(input : 'opus.pc.in',
667  output : 'opus.pc',
668  configuration : pkgconf,
669  install_dir : pkg_install_dir)
670
671# The uninstalled one has hardcoded libtool + static lib stuff, skip it for now
672#configure_file(input : 'opus-uninstalled.pc.in',
673#  output : 'opus-uninstalled.pc',
674#  configuration : pkgconf,
675#  install : false)
676
677doxygen = find_program('doxygen', required: get_option('docs'))
678if doxygen.found()
679  subdir('doc')
680endif
681
682summary(
683  {
684    'C99 var arrays': opus_conf.has('VAR_ARRAYS'),
685    'C99 lrintf': opus_conf.has('HAVE_LRINTF'),
686    'Use alloca': msg_use_alloca,
687  },
688  section: 'Compiler support',
689  bool_yn: true,
690  list_sep: ', ',
691)
692
693# Parse optimization status
694foreach status : [['inline_optimization', opt_asm],
695                  ['asm_optimization', opt_asm],
696                  ['intrinsics_support', opt_intrinsics]]
697  res = status[0]
698  opt = status[1]
699  resval = get_variable(res)
700  if opt.disabled()
701    set_variable(res, 'disabled')
702  elif resval.length() == 0
703    if host_cpu_family not in ['arm', 'aarch64', 'x86', 'x86_64']
704      set_variable(res, 'No optimizations for your platform, please send patches')
705    else
706      set_variable(res, 'none')
707    endif
708  endif
709endforeach
710
711summary(
712  {
713    'Floating point support': not opt_fixed_point,
714    'Fast float approximations': opt_float_approx,
715    'Fixed point debugging': opt_fixed_point_debug,
716    'Inline assembly optimizations': inline_optimization,
717    'External assembly optimizations': asm_optimization,
718    'Intrinsics optimizations': intrinsics_support,
719    'Run-time CPU detection': rtcd_support,
720  },
721  section: 'Optimizations',
722  bool_yn: true,
723  list_sep: ', ',
724)
725summary(
726  {
727    'Custom modes': opt_custom_modes,
728    'Assertions': opt_assertions,
729    'Hardening': opt_hardening,
730    'Fuzzing': opt_fuzzing,
731    'Check ASM': opt_check_asm,
732    'API documentation': doxygen.found(),
733    'Extra programs': not extra_programs.disabled(),
734    'Tests': not opt_tests.disabled(),
735  },
736  section: 'General configuration',
737  bool_yn: true,
738  list_sep: ', ',
739)
740