1# Copyright © 2018 Intel Corporation
2
3# Permission is hereby granted, free of charge, to any person obtaining a copy
4# of this software and associated documentation files (the "Software"), to deal
5# in the Software without restriction, including without limitation the rights
6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7# copies of the Software, and to permit persons to whom the Software is
8# furnished to do so, subject to the following conditions:
9
10# The above copyright notice and this permission notice shall be included in
11# all copies or substantial portions of the Software.
12
13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19# SOFTWARE.
20
21project(
22  'pixman',
23  ['c'],
24  version : '0.46.4',
25  license : 'MIT',
26  meson_version : '>= 1.3.0',
27  default_options : ['c_std=gnu99,c99', 'buildtype=debugoptimized'],
28)
29
30config = configuration_data()
31cc = meson.get_compiler('c')
32null_dep = dependency('', required : false)
33
34add_project_arguments(
35  cc.get_supported_arguments([
36    '-Wdeclaration-after-statement',
37    '-fno-strict-aliasing',
38    '-fvisibility=hidden',
39    '-Wundef',
40    # -ftrapping-math is the default for gcc, but -fno-trapping-math is the
41    # default for clang.  The FLOAT_IS_ZERO macro is used to guard against
42    # floating-point exceptions, however with -fno-trapping-math, the compiler
43    # can reorder floating-point operations so that they occur before the guard.
44    # Note, this function is ignored in clang < 10.0.0.
45    '-ftrapping-math'
46  ]),
47  language : ['c']
48)
49
50# GCC and Clang both ignore -Wno options that they don't recognize, so test for
51# -W<opt>, then add -Wno-<opt> if it's ignored
52foreach opt : ['unused-local-typedefs']
53  if cc.has_argument('-W' + opt)
54    add_project_arguments(['-Wno-' + opt], language : ['c'])
55  endif
56endforeach
57
58use_loongson_mmi = get_option('loongson-mmi')
59have_loongson_mmi = false
60loongson_mmi_flags = ['-mloongson-mmi']
61if not use_loongson_mmi.disabled()
62  if host_machine.cpu_family() == 'mips64' and cc.compiles('''
63      #ifndef __mips_loongson_vector_rev
64      #error "Loongson Multimedia Instructions are only available on Loongson"
65      #endif
66      #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
67      #error "Need GCC >= 4.4 for Loongson MMI compilation"
68      #endif
69      #include "pixman/loongson-mmintrin.h"
70      int main () {
71        union {
72          __m64 v;
73          char c[8];
74        } a = { .c = {1, 2, 3, 4, 5, 6, 7, 8} };
75        int b = 4;
76        __m64 c = _mm_srli_pi16 (a.v, b);
77        return 0;
78      }''',
79      args : loongson_mmi_flags,
80      include_directories : include_directories('.'),
81      name : 'Loongson MMI Intrinsic Support')
82    have_loongson_mmi = true
83  endif
84endif
85
86if have_loongson_mmi
87  config.set10('USE_LOONGSON_MMI', true)
88elif use_loongson_mmi.enabled()
89  error('Loongson MMI Support unavailable, but required')
90endif
91
92use_mmx = get_option('mmx')
93have_mmx = false
94mmx_flags = []
95
96if cc.get_id() == 'msvc'
97  mmx_flags = ['/w14710', '/w14714', '/wd4244']
98elif cc.get_id() == 'sun'
99  mmx_flags = ['-xarch=sse']
100else
101  mmx_flags = ['-mmmx', '-Winline']
102endif
103if not use_mmx.disabled()
104  if host_machine.cpu_family() == 'x86_64' or cc.get_id() == 'msvc'
105    have_mmx = true
106  elif host_machine.cpu_family() == 'x86' and cc.compiles('''
107      #include <mmintrin.h>
108      #include <stdint.h>
109
110      /* Check support for block expressions */
111      #define _mm_shuffle_pi16(A, N)                    \
112        ({                                              \
113        __m64 ret;                                      \
114                                                        \
115        /* Some versions of clang will choke on K */    \
116        asm ("pshufw %2, %1, %0\n\t"                    \
117             : "=y" (ret)                               \
118             : "y" (A), "K" ((const int8_t)N)           \
119        );                                              \
120                                                        \
121        ret;                                            \
122        })
123
124      int main () {
125          __m64 v = _mm_cvtsi32_si64 (1);
126          __m64 w;
127
128          w = _mm_shuffle_pi16(v, 5);
129
130          /* Some versions of clang will choke on this */
131          asm ("pmulhuw %1, %0\n\t"
132               : "+y" (w)
133               : "y" (v)
134          );
135
136          return _mm_cvtsi64_si32 (v);
137      }''',
138      args : mmx_flags,
139      name : 'MMX Intrinsic Support')
140    have_mmx = true
141  endif
142endif
143
144if have_mmx
145  # Inline assembly do not work on X64 MSVC, so we use
146  # compatibility intrinsics there
147  if cc.get_id() != 'msvc' or host_machine.cpu_family() != 'x86_64'
148    config.set10('USE_X86_MMX', true)
149  endif
150elif use_mmx.enabled()
151  error('MMX Support unavailable, but required')
152endif
153
154use_sse2 = get_option('sse2')
155have_sse2 = false
156sse2_flags = []
157if cc.get_id() == 'sun'
158  sse2_flags = ['-xarch=sse2']
159elif cc.get_id() != 'msvc'
160  sse2_flags = ['-msse2', '-Winline']
161endif
162if not use_sse2.disabled()
163  if host_machine.cpu_family() == 'x86'
164    if cc.compiles('''
165        #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
166        #   if !defined(__amd64__) && !defined(__x86_64__)
167        #      error "Need GCC >= 4.2 for SSE2 intrinsics on x86"
168        #   endif
169        #endif
170        #include <mmintrin.h>
171        #include <xmmintrin.h>
172        #include <emmintrin.h>
173        int param;
174        int main () {
175          __m128i a = _mm_set1_epi32 (param), b = _mm_set1_epi32 (param + 1), c;
176          c = _mm_xor_si128 (a, b);
177          return _mm_cvtsi128_si32(c);
178        }''',
179        args : sse2_flags,
180        name : 'SSE2 Intrinsic Support')
181      have_sse2 = true
182    endif
183  elif host_machine.cpu_family() == 'x86_64'
184    have_sse2 = true
185  endif
186endif
187
188if have_sse2
189  config.set10('USE_SSE2', true)
190elif use_sse2.enabled()
191  error('sse2 Support unavailable, but required')
192endif
193
194use_ssse3 = get_option('ssse3')
195have_ssse3 = false
196ssse3_flags = []
197if cc.get_id() != 'msvc'
198  ssse3_flags = ['-mssse3', '-Winline']
199endif
200
201# x64 pre-2010 MSVC compilers crashes when building the ssse3 code
202if not use_ssse3.disabled() and not (cc.get_id() == 'msvc' and cc.version().version_compare('<16') and host_machine.cpu_family() == 'x86_64')
203  if host_machine.cpu_family().startswith('x86')
204    if cc.compiles('''
205        #include <mmintrin.h>
206        #include <xmmintrin.h>
207        #include <emmintrin.h>
208        int param;
209        int main () {
210          __m128i a = _mm_set1_epi32 (param), b = _mm_set1_epi32 (param + 1), c;
211          c = _mm_xor_si128 (a, b);
212          return _mm_cvtsi128_si32(c);
213        }''',
214        args : ssse3_flags,
215        name : 'SSSE3 Intrinsic Support')
216      have_ssse3 = true
217    endif
218  endif
219endif
220
221if have_ssse3
222  config.set10('USE_SSSE3', true)
223elif use_ssse3.enabled()
224  error('ssse3 Support unavailable, but required')
225endif
226
227use_vmx = get_option('vmx')
228have_vmx = false
229vmx_flags = ['-maltivec', '-mabi=altivec']
230if not use_vmx.disabled()
231  if host_machine.cpu_family().startswith('ppc')
232    if cc.compiles('''
233        #include <altivec.h>
234        int main () {
235            vector unsigned int v = vec_splat_u32 (1);
236            v = vec_sub (v, v);
237            return 0;
238        }''',
239        args : vmx_flags,
240        name : 'VMX/Altivec Intrinsic Support')
241      have_vmx = true
242    endif
243  endif
244endif
245
246if cc.compiles('''
247    __asm__ (
248    ".func meson_test"
249    ".endfunc"
250    );''',
251    name : 'test for ASM .func directive')
252    config.set('ASM_HAVE_FUNC_DIRECTIVE', 1)    
253endif
254
255if cc.compiles('''
256    __asm__ (
257    ".syntax unified\n"
258    );''',
259    name : 'test for ASM .syntax unified directive')
260    config.set('ASM_HAVE_SYNTAX_UNIFIED', 1)
261endif
262
263if cc.links('''
264    #include <stdint.h>
265
266    __asm__ (
267        "   .global _testlabel\n"
268        "_testlabel:\n"
269    );
270
271    int testlabel();
272    int main(int argc, char* argv[]) {
273        return testlabel();
274    }''',
275    name : 'test for ASM leading underscore')
276    config.set('ASM_LEADING_UNDERSCORE', 1)    
277endif
278
279
280
281if have_vmx
282  config.set10('USE_VMX', true)
283elif use_vmx.enabled()
284  error('vmx Support unavailable, but required')
285endif
286
287use_armv6_simd = get_option('arm-simd')
288have_armv6_simd = false
289if not use_armv6_simd.disabled()
290  if host_machine.cpu_family() == 'arm'
291    if cc.compiles(files('arm-simd-test.S'), name : 'ARMv6 SIMD Intrinsic Support')
292      have_armv6_simd = true
293    endif
294  endif
295endif
296
297if have_armv6_simd
298  config.set10('USE_ARM_SIMD', true)
299elif use_armv6_simd.enabled()
300  error('ARMv6 SIMD Support unavailable, but required')
301endif
302
303use_neon = get_option('neon')
304have_neon = false
305if not use_neon.disabled()
306  if host_machine.cpu_family() == 'arm'
307    if cc.compiles(files('neon-test.S'), name : 'NEON Intrinsic Support')
308      have_neon = true
309    endif
310  endif
311endif
312
313if have_neon
314  config.set10('USE_ARM_NEON', true)
315elif use_neon.enabled()
316  error('NEON Support unavailable, but required')
317endif
318
319use_a64neon = get_option('a64-neon')
320have_a64neon = false
321if not use_a64neon.disabled()
322  if host_machine.cpu_family() == 'aarch64'
323    if cc.compiles(files('a64-neon-test.S'), name : 'NEON A64 Intrinsic Support')
324      have_a64neon = true
325    endif
326  endif
327endif
328
329if have_a64neon
330  config.set10('USE_ARM_A64_NEON', true)
331elif use_a64neon.enabled()
332  error('A64 NEON Support unavailable, but required')
333endif
334
335use_mips_dspr2 = get_option('mips-dspr2')
336have_mips_dspr2 = false
337mips_dspr2_flags = ['-mdspr2']
338if not use_mips_dspr2.disabled()
339  if host_machine.cpu_family().startswith('mips')
340    if cc.compiles('''
341        #if !(defined(__mips__) &&  __mips_isa_rev >= 2)
342        #error MIPS DSPr2 is currently only available on MIPS32r2 platforms.
343        #endif
344        int
345        main ()
346        {
347            int c = 0, a = 0, b = 0;
348            __asm__ __volatile__ (
349                "precr.qb.ph %[c], %[a], %[b]          \n\t"
350                : [c] "=r" (c)
351                : [a] "r" (a), [b] "r" (b)
352            );
353            return c;
354        }''',
355        args : mips_dspr2_flags,
356        name : 'DSPr2 Intrinsic Support')
357      have_mips_dspr2 = true
358    endif
359  endif
360endif
361
362if have_mips_dspr2
363  config.set10('USE_MIPS_DSPR2', true)
364elif use_mips_dspr2.enabled()
365  error('MIPS DSPr2 Support unavailable, but required')
366endif
367
368use_rvv = get_option('rvv')
369have_rvv = false
370rvv_flags = ['-march=rv64gcv1p0']
371if not use_rvv.disabled()
372  if host_machine.cpu_family() == 'riscv64'
373    if cc.compiles('''
374        #include <riscv_vector.h>
375        #include <asm/hwprobe.h>
376        #include <linux/version.h>
377        #include <sys/auxv.h>
378        #include <sys/syscall.h>
379        #include <unistd.h>
380
381        #if defined(__riscv_v) && __riscv_v < 1000000
382        #error "Minimum supported RVV is 1.0"
383        #endif
384        #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)
385        #error "Minimum supported kernel is 6.5.0"
386        #endif
387        int main() {
388            struct riscv_hwprobe pair = {RISCV_HWPROBE_KEY_IMA_EXT_0, 0};
389            long result = sys_riscv_hwprobe (&pair, 1, 0, 0, 0);
390            vfloat32m1_t tmp1; /* added in gcc-13 */
391            vfloat32m1x4_t tmp2; /* added in gcc-14 */
392            return 0;
393        }
394      ''',
395      args : rvv_flags,
396      name : 'RISC-V Vector Intrinsic Support')
397      have_rvv = true
398    endif
399  endif
400endif
401
402if have_rvv
403  config.set10('USE_RVV', true)
404elif use_rvv.enabled()
405  error('RISC-V Vector Support unavailable, but required')
406endif
407
408use_gnu_asm = get_option('gnu-inline-asm')
409if not use_gnu_asm.disabled()
410  if cc.compiles('''
411      int main () {
412        /* Most modern architectures have a NOP instruction, so this is a fairly generic test. */
413        asm volatile ( "\tnop\n" : : : "cc", "memory" );
414        return 0;
415      }
416      ''',
417      name : 'GNU Inline ASM support.')
418    config.set10('USE_GCC_INLINE_ASM', true)
419  elif use_gnu_asm.enabled()
420    error('GNU inline assembly support missing but required.')
421  endif
422endif
423
424if get_option('timers')
425  config.set('PIXMAN_TIMERS', 1)
426endif
427if get_option('gnuplot')
428  config.set('PIXMAN_GNUPLOT', 1)
429endif
430
431if cc.get_id() != 'msvc'
432  dep_openmp = dependency('openmp', required : get_option('openmp'))
433  if dep_openmp.found()
434    config.set10('USE_OPENMP', true)
435  endif
436else
437  # the MSVC implementation of openmp is not compliant enough for our
438  # uses here, so we disable it here.
439  # Please see: https://stackoverflow.com/questions/12560243/using-threadprivate-directive-in-visual-studio
440  dep_openmp = null_dep
441endif
442
443dep_gtk = dependency('gtk+-3.0', required : get_option('gtk').enabled() and get_option('demos').enabled())
444dep_glib = dependency('glib-2.0', required : get_option('gtk').enabled() and get_option('demos').enabled())
445
446dep_png = null_dep
447if not get_option('libpng').disabled()
448  dep_png = dependency('libpng', required : false)
449
450  # We need to look for the right library to link to for libpng,
451  # when looking for libpng manually
452  foreach png_ver : [ '16', '15', '14', '13', '12', '10' ]
453    if not dep_png.found()
454      dep_png = cc.find_library('libpng@0@'.format(png_ver), has_headers : ['png.h'], required : false)
455    endif
456  endforeach
457
458  if get_option('libpng').enabled() and not dep_png.found()
459    error('libpng support requested but libpng library not found')
460  endif
461endif
462
463if dep_png.found()
464  config.set('HAVE_LIBPNG', 1)
465endif
466dep_m = cc.find_library('m', required : false)
467dep_threads = dependency('threads')
468
469# MSVC-style compilers do not come with pthreads, so we must link
470# to it explicitly, currently pthreads-win32 is supported
471pthreads_found = false
472
473if dep_threads.found() and cc.has_header('pthread.h')
474  if cc.get_argument_syntax() == 'msvc'
475    pthread_lib = null_dep
476    foreach pthread_type : ['VC3', 'VSE3', 'VCE3', 'VC2', 'VSE2', 'VCE2']
477      if not pthread_lib.found()
478        pthread_lib = cc.find_library('pthread@0@'.format(pthread_type), required : false)
479      endif
480    endforeach
481    if pthread_lib.found()
482      pthreads_found = true
483      dep_threads = pthread_lib
484    endif
485  else
486    pthreads_found = true
487  endif
488else
489  # Avoid linking with -pthread if we don't actually have pthreads
490  dep_threads = null_dep
491endif
492
493if pthreads_found
494  config.set('HAVE_PTHREADS', 1)
495endif
496
497funcs = ['sigaction', 'alarm', 'mprotect', 'getpagesize', 'mmap', 'getisax', 'gettimeofday']
498# mingw claimes to have posix_memalign, but it doesn't
499if host_machine.system() != 'windows'
500  funcs += 'posix_memalign'
501endif
502
503foreach f : funcs
504  if cc.has_function(f)
505    config.set('HAVE_@0@'.format(f.to_upper()), 1)
506  endif
507endforeach
508
509# This is only used in one test, that defines _GNU_SOURCE
510if cc.has_function('feenableexcept',
511                   prefix : '#define _GNU_SOURCE\n#include <fenv.h>',
512                   dependencies : dep_m)
513  config.set('HAVE_FEENABLEEXCEPT', 1)
514endif
515
516if cc.has_header_symbol('fenv.h', 'FE_DIVBYZERO')
517  config.set('HAVE_FEDIVBYZERO', 1)
518endif
519
520foreach h : ['sys/mman.h', 'fenv.h', 'unistd.h']
521  if cc.check_header(h)
522    config.set('HAVE_@0@'.format(h.underscorify().to_upper()), 1)
523  endif
524endforeach
525
526use_tls = get_option('tls')
527have_tls = ''
528if not use_tls.disabled()
529  # gcc on Windows only warns that __declspec(thread) isn't supported,
530  # passing -Werror=attributes makes it fail.
531  if (host_machine.system() == 'windows' and
532      cc.compiles('int __declspec(thread) foo;',
533                  args : cc.get_supported_arguments(['-Werror=attributes']),
534                  name : 'TLS via __declspec(thread)'))
535    have_tls = '__declspec(thread)'
536  elif cc.compiles('int __thread foo;', name : 'TLS via __thread')
537    have_tls = '__thread'
538  endif
539endif
540
541if have_tls != ''
542  config.set('TLS', have_tls)
543elif use_tls.enabled()
544  error('Compiler TLS Support unavailable, but required')
545endif
546
547if cc.links('''
548    static int x = 1;
549    static void __attribute__((constructor)) constructor_function () { x = 0; }
550    int main (void) { return x; }
551    ''',
552    name : '__attribute__((constructor))')
553  config.set('TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR', 1)
554endif
555
556if cc.links('''
557    static int x = 1;
558    static void __attribute__((destructor)) destructor_function () { x = 0; }
559    int main (void) { return x; }
560    ''',
561    name : '__attribute__((destructor))')
562  config.set('TOOLCHAIN_SUPPORTS_ATTRIBUTE_DESTRUCTOR', 1)
563endif
564
565if cc.links(
566    ' __float128 a = 1.0Q, b = 2.0Q; int main (void) { return a + b; }',
567    name : 'Has float128 support')
568  config.set('HAVE_FLOAT128', 1)
569endif
570
571if cc.has_function('clz')
572  config.set('HAVE_BUILTIN_CLZ', 1)
573endif
574
575if cc.links('''
576    unsigned int __attribute__ ((vector_size(16))) e, a, b;
577    int main (void) { e = a - ((b << 27) + (b >> (32 - 27))) + 1; return e[0]; }
578    ''',
579    name : 'Support for GCC vector extensions')
580  config.set('HAVE_GCC_VECTOR_EXTENSIONS', 1)
581endif
582
583if host_machine.endian() == 'big'
584  config.set('WORDS_BIGENDIAN', 1)
585endif
586
587config.set('SIZEOF_LONG', cc.sizeof('long'))
588
589# Required to make pixman-private.h
590config.set('PACKAGE', 'foo')
591
592version_conf = configuration_data()
593split = meson.project_version().split('.')
594version_conf.set('PIXMAN_VERSION_MAJOR', split[0])
595version_conf.set('PIXMAN_VERSION_MINOR', split[1])
596version_conf.set('PIXMAN_VERSION_MICRO', split[2])
597
598add_project_arguments('-DHAVE_CONFIG_H', language : ['c'])
599
600subdir('pixman')
601
602if not get_option('tests').disabled() or not get_option('demos').disabled()
603  subdir('test/utils')
604endif
605
606if not get_option('demos').disabled()
607  subdir('demos')
608endif
609
610if not get_option('tests').disabled()
611  subdir('test')
612endif
613
614pkg = import('pkgconfig')
615pkg.generate(libpixman,
616  name : 'Pixman',
617  filebase : 'pixman-1',
618  description : 'The pixman library (version 1)',
619  subdirs: 'pixman-1',
620  version : meson.project_version(),
621)
622