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.40.0',
25  license : 'MIT',
26  meson_version : '>= 0.50.0',
27  default_options : ['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  ]),
41  language : ['c']
42)
43
44# GCC and Clang both ignore -Wno options that they don't recognize, so test for
45# -W<opt>, then add -Wno-<opt> if it's ignored
46foreach opt : ['unused-local-typedefs']
47  if cc.has_argument('-W' + opt)
48    add_project_arguments(['-Wno-' + opt], language : ['c'])
49  endif
50endforeach
51
52use_loongson_mmi = get_option('loongson-mmi')
53have_loongson_mmi = false
54loongson_mmi_flags = ['-mloongson-mmi']
55if not use_loongson_mmi.disabled()
56  if host_machine.cpu_family() == 'mips64' and cc.compiles('''
57      #ifndef __mips_loongson_vector_rev
58      #error "Loongson Multimedia Instructions are only available on Loongson"
59      #endif
60      #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
61      #error "Need GCC >= 4.4 for Loongson MMI compilation"
62      #endif
63      #include "pixman/loongson-mmintrin.h"
64      int main () {
65        union {
66          __m64 v;
67          char c[8];
68        } a = { .c = {1, 2, 3, 4, 5, 6, 7, 8} };
69        int b = 4;
70        __m64 c = _mm_srli_pi16 (a.v, b);
71        return 0;
72      }''',
73      args : loongson_mmi_flags,
74      include_directories : include_directories('.'),
75      name : 'Loongson MMI Intrinsic Support')
76    have_loongson_mmi = true
77  endif
78endif
79
80if have_loongson_mmi
81  config.set10('USE_LOONGSON_MMI', true)
82elif use_loongson_mmi.enabled()
83  error('Loongson MMI Support unavailable, but required')
84endif
85
86use_mmx = get_option('mmx')
87have_mmx = false
88mmx_flags = []
89
90if cc.get_id() == 'msvc'
91  mmx_flags = ['/w14710', '/w14714', '/wd4244']
92elif cc.get_id() == 'sun'
93  mmx_flags = ['-xarch=sse']
94else
95  mmx_flags = ['-mmmx', '-Winline']
96endif
97if not use_mmx.disabled()
98  if host_machine.cpu_family() == 'x86_64' or cc.get_id() == 'msvc'
99    have_mmx = true
100  elif host_machine.cpu_family() == 'x86' and cc.compiles('''
101      #include <mmintrin.h>
102      #include <stdint.h>
103
104      /* Check support for block expressions */
105      #define _mm_shuffle_pi16(A, N)                    \
106        ({                                              \
107        __m64 ret;                                      \
108                                                        \
109        /* Some versions of clang will choke on K */    \
110        asm ("pshufw %2, %1, %0\n\t"                    \
111             : "=y" (ret)                               \
112             : "y" (A), "K" ((const int8_t)N)           \
113        );                                              \
114                                                        \
115        ret;                                            \
116        })
117
118      int main () {
119          __m64 v = _mm_cvtsi32_si64 (1);
120          __m64 w;
121
122          w = _mm_shuffle_pi16(v, 5);
123
124          /* Some versions of clang will choke on this */
125          asm ("pmulhuw %1, %0\n\t"
126               : "+y" (w)
127               : "y" (v)
128          );
129
130          return _mm_cvtsi64_si32 (v);
131      }''',
132      args : mmx_flags,
133      name : 'MMX Intrinsic Support')
134    have_mmx = true
135  endif
136endif
137
138if have_mmx
139  # Inline assembly do not work on X64 MSVC, so we use
140  # compatibility intrinsics there
141  if cc.get_id() != 'msvc' or host_machine.cpu_family() != 'x86_64'
142    config.set10('USE_X86_MMX', true)
143  endif
144elif use_mmx.enabled()
145  error('MMX Support unavailable, but required')
146endif
147
148use_sse2 = get_option('sse2')
149have_sse2 = false
150sse2_flags = []
151if cc.get_id() == 'sun'
152  sse2_flags = ['-xarch=sse2']
153elif cc.get_id() != 'msvc'
154  sse2_flags = ['-msse2', '-Winline']
155endif
156if not use_sse2.disabled()
157  if host_machine.cpu_family() == 'x86'
158    if cc.compiles('''
159        #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
160        #   if !defined(__amd64__) && !defined(__x86_64__)
161        #      error "Need GCC >= 4.2 for SSE2 intrinsics on x86"
162        #   endif
163        #endif
164        #include <mmintrin.h>
165        #include <xmmintrin.h>
166        #include <emmintrin.h>
167        int param;
168        int main () {
169          __m128i a = _mm_set1_epi32 (param), b = _mm_set1_epi32 (param + 1), c;
170          c = _mm_xor_si128 (a, b);
171          return _mm_cvtsi128_si32(c);
172        }''',
173        args : sse2_flags,
174        name : 'SSE2 Intrinsic Support')
175      have_sse2 = true
176    endif
177  elif host_machine.cpu_family() == 'x86_64'
178    have_sse2 = true
179  endif
180endif
181
182if have_sse2
183  config.set10('USE_SSE2', true)
184elif use_sse2.enabled()
185  error('sse2 Support unavailable, but required')
186endif
187
188use_ssse3 = get_option('ssse3')
189have_ssse3 = false
190ssse3_flags = []
191if cc.get_id() != 'msvc'
192  ssse3_flags = ['-mssse3', '-Winline']
193endif
194
195# x64 pre-2010 MSVC compilers crashes when building the ssse3 code
196if not use_ssse3.disabled() and not (cc.get_id() == 'msvc' and cc.version().version_compare('<16') and host_machine.cpu_family() == 'x86_64')
197  if host_machine.cpu_family().startswith('x86')
198    if cc.compiles('''
199        #include <mmintrin.h>
200        #include <xmmintrin.h>
201        #include <emmintrin.h>
202        int param;
203        int main () {
204          __m128i a = _mm_set1_epi32 (param), b = _mm_set1_epi32 (param + 1), c;
205          c = _mm_xor_si128 (a, b);
206          return _mm_cvtsi128_si32(c);
207        }''',
208        args : ssse3_flags,
209        name : 'SSSE3 Intrinsic Support')
210      have_ssse3 = true
211    endif
212  endif
213endif
214
215if have_ssse3
216  config.set10('USE_SSSE3', true)
217elif use_ssse3.enabled()
218  error('ssse3 Support unavailable, but required')
219endif
220
221use_vmx = get_option('vmx')
222have_vmx = false
223vmx_flags = ['-maltivec', '-mabi=altivec']
224if not use_vmx.disabled()
225  if host_machine.cpu_family().startswith('ppc')
226    if cc.compiles('''
227        #include <altivec.h>
228        int main () {
229            vector unsigned int v = vec_splat_u32 (1);
230            v = vec_sub (v, v);
231            return 0;
232        }''',
233        args : vmx_flags,
234        name : 'VMX/Altivec Intrinsic Support')
235      have_vmx = true
236    endif
237  endif
238endif
239
240if have_vmx
241  config.set10('USE_VMX', true)
242elif use_vmx.enabled()
243  error('vmx Support unavailable, but required')
244endif
245
246use_armv6_simd = get_option('arm-simd')
247have_armv6_simd = false
248if not use_armv6_simd.disabled()
249  if host_machine.cpu_family() == 'arm'
250    if cc.compiles(files('arm-simd-test.S'), name : 'ARMv6 SIMD Intrinsic Support')
251      have_armv6_simd = true
252    endif
253  endif
254endif
255
256if have_armv6_simd
257  config.set10('USE_ARM_SIMD', true)
258elif use_armv6_simd.enabled()
259  error('ARMv6 SIMD Support unavailable, but required')
260endif
261
262use_neon = get_option('neon')
263have_neon = false
264if not use_neon.disabled()
265  if host_machine.cpu_family() == 'arm'
266    if cc.compiles(files('neon-test.S'), name : 'NEON Intrinsic Support')
267      have_neon = true
268    endif
269  endif
270endif
271
272if have_neon
273  config.set10('USE_ARM_NEON', true)
274elif use_neon.enabled()
275  error('NEON Support unavailable, but required')
276endif
277
278use_iwmmxt = get_option('iwmmxt')
279have_iwmmxt = false
280iwmmxt_flags = ['-flax-vector-conversions', '-Winline']
281if not use_iwmmxt.disabled()
282  if get_option('iwmmxt2')
283    iwmmxt_flags += '-march=iwmmxt2'
284  else
285    iwmmxt_flags += '-march=iwmmxt'
286  endif
287
288  if host_machine.cpu_family() == 'arm'
289    if cc.compiles('''
290        #ifndef __IWMMXT__
291        #error "IWMMXT not enabled (with -march=iwmmxt)"
292        #endif
293        #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
294        #error "Need GCC >= 4.8 for IWMMXT intrinsics"
295        #endif
296        #include <mmintrin.h>
297        int main () {
298          union {
299            __m64 v;
300            char c[8];
301          } a = { .c = {1, 2, 3, 4, 5, 6, 7, 8} };
302          int b = 4;
303          __m64 c = _mm_srli_si64 (a.v, b);
304        }
305        ''',
306        args : iwmmxt_flags,
307        name : 'IWMMXT Intrinsic Support')
308      have_iwmmxt = true
309    endif
310  endif
311endif
312
313if have_iwmmxt
314  config.set10('USE_ARM_IWMMXT', true)
315elif use_iwmmxt.enabled()
316  error('IWMMXT Support unavailable, but required')
317endif
318
319use_mips_dspr2 = get_option('mips-dspr2')
320have_mips_dspr2 = false
321mips_dspr2_flags = ['-mdspr2']
322if not use_mips_dspr2.disabled()
323  if host_machine.cpu_family() == 'mips32'
324    if cc.compiles('''
325        #if !(defined(__mips__) &&  __mips_isa_rev >= 2)
326        #error MIPS DSPr2 is currently only available on MIPS32r2 platforms.
327        #endif
328        int
329        main ()
330        {
331            int c = 0, a = 0, b = 0;
332            __asm__ __volatile__ (
333                "precr.qb.ph %[c], %[a], %[b]          \n\t"
334                : [c] "=r" (c)
335                : [a] "r" (a), [b] "r" (b)
336            );
337            return c;
338        }''',
339        args : mipds_dspr2_flags,
340        name : 'DSPr2 Intrinsic Support')
341      have_mips_dspr2 = true
342    endif
343  endif
344endif
345
346if have_mips_dspr2
347  config.set10('USE_MIPS_DSPR2', true)
348elif use_mips_dspr2.enabled()
349  error('MIPS DSPr2 Support unavailable, but required')
350endif
351
352use_gnu_asm = get_option('gnu-inline-asm')
353if not use_gnu_asm.disabled()
354  if cc.compiles('''
355      int main () {
356        /* Most modern architectures have a NOP instruction, so this is a fairly generic test. */
357        asm volatile ( "\tnop\n" : : : "cc", "memory" );
358        return 0;
359      }
360      ''',
361      name : 'GNU Inline ASM support.')
362    config.set10('USE_GCC_INLINE_ASM', true)
363  elif use_gnu_asm.enabled()
364    error('GNU inline assembly support missing but required.')
365  endif
366endif
367
368if get_option('timers')
369  config.set('PIXMAN_TIMERS', 1)
370endif
371if get_option('gnuplot')
372  config.set('PIXMAN_GNUPLOT', 1)
373endif
374
375if cc.get_id() != 'msvc'
376  dep_openmp = dependency('openmp', required : get_option('openmp'))
377  if dep_openmp.found()
378    config.set10('USE_OPENMP', true)
379  elif meson.version().version_compare('<0.51.0')
380  # In versions of meson before 0.51 the openmp dependency can still
381  # inject arguments in the the auto case when it is not found, the
382  # detection does work correctly in that case however, so we just
383  # replace dep_openmp with null_dep to work around this.
384    dep_openmp = null_dep
385  endif
386else
387  # the MSVC implementation of openmp is not compliant enough for our
388  # uses here, so we disable it here.
389  # Please see: https://stackoverflow.com/questions/12560243/using-threadprivate-directive-in-visual-studio
390  dep_openmp = null_dep
391endif
392
393dep_gtk = dependency('gtk+-2.0', version : '>= 2.16', required : get_option('gtk'))
394dep_glib = dependency('glib-2.0', required : get_option('gtk'))
395dep_pixman = dependency('pixman-1', required : get_option('gtk'),
396                        version : '>= ' + meson.project_version())
397
398dep_png = null_dep
399if not get_option('libpng').disabled()
400  dep_png = dependency('libpng', required : false)
401
402  # We need to look for the right library to link to for libpng,
403  # when looking for libpng manually
404  foreach png_ver : [ '16', '15', '14', '13', '12', '10' ]
405    if not dep_png.found()
406      dep_png = cc.find_library('libpng@0@'.format(png_ver), has_headers : ['png.h'], required : false)
407    endif
408  endforeach
409
410  if get_option('libpng').enabled() and not dep_png.found()
411    error('libpng support requested but libpng library not found')
412  endif
413endif
414
415if dep_png.found()
416  config.set('HAVE_LIBPNG', 1)
417endif
418dep_m = cc.find_library('m', required : false)
419dep_threads = dependency('threads')
420
421# MSVC-style compilers do not come with pthreads, so we must link
422# to it explicitly, currently pthreads-win32 is supported
423pthreads_found = false
424
425if dep_threads.found() and cc.has_header('pthread.h')
426  if cc.get_argument_syntax() == 'msvc'
427    pthread_lib = null_dep
428    foreach pthread_type : ['VC3', 'VSE3', 'VCE3', 'VC2', 'VSE2', 'VCE2']
429      if not pthread_lib.found()
430        pthread_lib = cc.find_library('pthread@0@'.format(pthread_type), required : false)
431      endif
432    endforeach
433    if pthread_lib.found()
434      pthreads_found = true
435      dep_threads = pthread_lib
436    endif
437  else
438    pthreads_found = true
439  endif
440endif
441
442if pthreads_found
443  config.set('HAVE_PTHREADS', 1)
444endif
445
446funcs = ['sigaction', 'alarm', 'mprotect', 'getpagesize', 'mmap', 'getisax', 'gettimeofday']
447# mingw claimes to have posix_memalign, but it doesn't
448if host_machine.system() != 'windows'
449  funcs += 'posix_memalign'
450endif
451
452foreach f : funcs
453  if cc.has_function(f)
454    config.set('HAVE_@0@'.format(f.to_upper()), 1)
455  endif
456endforeach
457
458# This is only used in one test, that defines _GNU_SOURCE
459if cc.has_function('feenableexcept',
460                   prefix : '#define _GNU_SOURCE\n#include <fenv.h>',
461                   dependencies : dep_m)
462  config.set('HAVE_FEENABLEEXCEPT', 1)
463endif
464
465if cc.has_header_symbol('fenv.h', 'FE_DIVBYZERO')
466  config.set('HAVE_FEDIVBYZERO', 1)
467endif
468
469foreach h : ['sys/mman.h', 'fenv.h', 'unistd.h']
470  if cc.check_header(h)
471    config.set('HAVE_@0@'.format(h.underscorify().to_upper()), 1)
472  endif
473endforeach
474
475# gcc on Windows only warns that __declspec(thread) isn't supported,
476# passing -Werror=attributes makes it fail.
477if (host_machine.system() == 'windows' and
478    cc.compiles('int __declspec(thread) foo;',
479                args : cc.get_supported_arguments(['-Werror=attributes']),
480                name : 'TLS via __declspec(thread)'))
481  config.set('TLS', '__declspec(thread)')
482elif cc.compiles('int __thread foo;', name : 'TLS via __thread')
483  config.set('TLS', '__thread')
484endif
485
486if cc.links('''
487    static int x = 1;
488    static void __attribute__((constructor)) constructor_function () { x = 0; }
489    int main (void) { return x; }
490    ''',
491    name : '__attribute__((constructor))')
492  config.set('TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR', 1)
493endif
494
495if cc.links(
496    ' __float128 a = 1.0Q, b = 2.0Q; int main (void) { return a + b; }',
497    name : 'Has float128 support')
498  config.set('HAVE_FLOAT128', 1)
499endif
500
501if cc.has_function('clz')
502  config.set('HAVE_BUILTIN_CLZ', 1)
503endif
504
505if cc.links('''
506    unsigned int __attribute__ ((vector_size(16))) e, a, b;
507    int main (void) { e = a - ((b << 27) + (b >> (32 - 27))) + 1; return e[0]; }
508    ''',
509    name : 'Support for GCC vector extensions')
510  config.set('HAVE_GCC_VECTOR_EXTENSIONS', 1)
511endif
512
513if host_machine.endian() == 'big'
514  config.set('WORDS_BIGENDIAN', 1)
515endif
516
517config.set('SIZEOF_LONG', cc.sizeof('long'))
518
519# Required to make pixman-private.h
520config.set('PACKAGE', 'foo')
521
522version_conf = configuration_data()
523split = meson.project_version().split('.')
524version_conf.set('PIXMAN_VERSION_MAJOR', split[0])
525version_conf.set('PIXMAN_VERSION_MINOR', split[1])
526version_conf.set('PIXMAN_VERSION_MICRO', split[2])
527
528add_project_arguments('-DHAVE_CONFIG_H', language : ['c'])
529
530subdir('pixman')
531subdir('test')
532subdir('demos')
533
534pkg = import('pkgconfig')
535pkg.generate(
536  name : 'Pixman',
537  filebase : 'pixman-1',
538  description : 'The pixman library (version 1)',
539  libraries : libpixman,
540  subdirs: 'pixman-1',
541  version : meson.project_version(),
542)
543