1project('babl', 'c',
2  license: 'LGPL3+',
3  version: '0.1.88',
4  meson_version: '>=0.54.0',
5  default_options: [
6    'buildtype=debugoptimized'
7  ],
8  # https://gitlab.gnome.org/GNOME/babl/issues/
9)
10
11# Making releases on the stable branch:
12#   BABL_MICRO_VERSION += 1;
13#   BABL_INTERFACE_AGE += 1;
14#   BABL_BINARY_AGE += 1;
15# if any functions have been added,
16#    set BABL_INTERFACE_AGE to 0.
17# if backwards compatibility has been broken,
18#    set BABL_BINARY_AGE _and_ BABL_INTERFACE_AGE to 0.
19
20conf = configuration_data()
21
22pkgconfig = import('pkgconfig')
23gnome     = import('gnome')
24python    = import('python').find_installation()
25
26cc        = meson.get_compiler('c')
27prefix    = get_option('prefix')
28buildtype = get_option('buildtype')
29
30babl_prefix = get_option('prefix')
31babl_libdir = join_paths(babl_prefix, get_option('libdir'))
32
33project_build_root = meson.current_build_dir()
34project_source_root = meson.current_source_dir()
35
36################################################################################
37# Projects infos
38
39version = meson.project_version()
40array_version = version.split('.')
41major_version = array_version[0].to_int()
42minor_version = array_version[1].to_int()
43micro_version = array_version[2].to_int()
44interface_age = 1
45
46binary_age = 100 * minor_version + micro_version
47
48lt_current = binary_age - interface_age
49
50api_version = '@0@.@1@'.format(major_version, minor_version)
51lib_version = '@0@:@1@:@2@'.format(lt_current, interface_age, lt_current)
52so_version  = '@0@.@1@.@2@'.format(0, lt_current, interface_age)
53lib_name    = meson.project_name() + '-' + api_version
54
55stability_version_number = (major_version != 0 ? minor_version : micro_version)
56stable = (stability_version_number % 2 == 0)
57
58conf.set10('BABL_UNSTABLE', not stable, Description:
59  'Define to 1 if this is an unstable version of BABL.')
60
61conf.set       ('BABL_MAJOR_VERSION',    '@0@'.format(major_version))
62conf.set       ('BABL_MINOR_VERSION',    '@0@'.format(minor_version))
63conf.set       ('BABL_MICRO_VERSION',    '@0@'.format(micro_version))
64conf.set_quoted('BABL_INTERFACE_AGE',    '@0@'.format(interface_age))
65conf.set_quoted('BABL_BINARY_AGE',       '@0@'.format(binary_age))
66conf.set_quoted('BABL_VERSION',          '@0@'.format(version))
67conf.set_quoted('BABL_REAL_VERSION',     '@0@'.format(version))
68conf.set_quoted('BABL_API_VERSION',      '@0@'.format(api_version))
69conf.set_quoted('BABL_RELEASE',          '@0@'.format(api_version))
70conf.set_quoted('BABL_LIBRARY_VERSION',  '@0@'.format(lib_version))
71conf.set_quoted('BABL_CURRENT_MINUS_AGE','@0@'.format(0))
72conf.set_quoted('BABL_LIBRARY',          '@0@'.format(lib_name))
73
74################################################################################
75# Host system environment
76
77platform_android = false
78platform_osx = false
79platform_win32 = false
80
81host_cpu_family = host_machine.cpu_family()
82if   host_cpu_family == 'x86'
83  have_x86 = true
84  conf.set10('ARCH_X86',    true)
85elif host_cpu_family == 'x86_64'
86  have_x86 = true
87  conf.set10('ARCH_X86',    true)
88  conf.set10('ARCH_X86_64', true)
89elif host_cpu_family == 'ppc'
90  have_ppc = true
91  conf.set10('ARCH_PPC',    true)
92elif host_cpu_family == 'ppc64'
93  have_ppc = true
94  conf.set10('ARCH_PPC',    true)
95  conf.set10('ARCH_PPC64',  true)
96endif
97
98host_os = host_machine.system()
99message('Host os: ' + host_os)
100
101platform_win32 = (host_os.startswith('mingw') or
102                  host_os.startswith('cygwin') or
103                  host_os.startswith('windows'))
104
105platform_osx = host_os.startswith('darwin')
106if platform_osx
107  if cc.get_id() != 'clang'
108    error('You should use Clang/Clang++ on OSX.')
109  endif
110endif
111
112platform_android = host_os.contains('android')
113
114path_sep = ( platform_win32 ? ';'     : ':' )
115dirs_sep = ( platform_win32 ? '\\\\'  : '/' )
116if platform_win32
117  lib_ext = '.dll'
118elif platform_osx
119  lib_ext = '.dylib'
120else
121  lib_ext = '.so'
122endif
123
124conf.set('BABL_PATH_SEPARATOR', '\'' + path_sep + '\'', description:
125  'separator between paths in BABL_PATH')
126conf.set_quoted('BABL_DIR_SEPARATOR',  dirs_sep, description:
127  'separator between directories in BABL_PATH')
128conf.set_quoted('SHREXT', lib_ext, description:
129  'File extension for shared libraries')
130
131# assume *nix if not android/osx/win32
132platform_unix = not (
133  platform_android or
134  platform_osx or
135  platform_win32
136)
137
138# Build system environment
139build_os = build_machine.system()
140message('Build os: ' + build_os)
141
142build_platform_win32 = (build_os.startswith('mingw') or
143                        build_os.startswith('cygwin') or
144                        build_os.startswith('windows'))
145
146# Only try to run compiled programs if native compile or cross-compile
147# and have exe wrapper. If we don't need a wrapper (e.g. 32 bit build in
148# 64-bit environment) then set proprty has_exe_wrapper=true in cross
149# file
150can_run_host_binaries = meson.has_exe_wrapper()
151
152
153################################################################################
154# Compiler arguments
155
156common_c_flags = []
157
158if buildtype == 'debugoptimized' or buildtype == 'release'
159  common_c_flags += cc.get_supported_arguments(['-Ofast'])
160endif
161common_c_flags += cc.get_supported_arguments(
162  ['-fno-unsafe-math-optimizations']
163)
164
165extra_warnings_list = [
166  '-Wdeclaration-after-statement',
167  '-Winit-self',
168  '-Wmissing-declarations',
169  '-Wmissing-prototypes',
170  '-Wold-style-definition',
171  '-Wpointer-arith',
172]
173common_c_flags += cc.get_supported_arguments(extra_warnings_list)
174
175add_project_arguments(common_c_flags, language: 'c')
176
177# Linker arguments
178if platform_win32 and cc.has_link_argument('-Wl,--no-undefined')
179  no_undefined = '-Wl,--no-undefined'
180else
181  no_undefined = []
182endif
183
184
185################################################################################
186# Check for compiler CPU extensions
187
188# intialize these to nothing, so meson doesn't complain on non-x86
189
190have_mmx    = false
191have_sse    = false
192have_sse2   = false
193have_sse4_1 = false
194have_avx2   = false
195have_f16c   = false
196
197sse2_cflags   = []
198f16c_cflags   = []
199sse4_1_cflags = []
200avx2_cflags   = []
201
202# mmx assembly
203if get_option('enable-mmx') and cc.has_argument('-mmmx')
204  if cc.compiles('asm ("movq 0, %mm0");')
205    message('mmx assembly available')
206    add_project_arguments('-mmmx', language: 'c')
207    conf.set('USE_MMX', 1, description:
208      'Define to 1 if MMX assembly is available.')
209    have_mmx = true
210
211    # sse assembly
212    if get_option('enable-sse') and cc.has_argument('-msse')
213      if cc.compiles('asm ("movntps %xmm0, 0");')
214        add_project_arguments('-msse', language: 'c')
215        message('sse assembly available')
216        conf.set('USE_SSE', 1, description:
217          'Define to 1 if SSE assembly is available.')
218        have_sse = true
219        sse_args = ['-mfpmath=sse']
220        if platform_win32
221          sse_args += '-mstackrealign'
222        endif
223
224        foreach sse_arg : sse_args
225          if cc.has_argument(sse_arg)
226            add_project_arguments(sse_arg, language: 'c')
227          endif
228        endforeach
229
230        # sse2 assembly
231        if get_option('enable-sse2') and cc.has_argument('-msse2')
232          if cc.compiles('asm ("punpckhwd %xmm0,%xmm1");')
233            message('sse2 assembly available')
234            sse2_cflags = '-msse2'
235            conf.set('USE_SSE2', 1, description:
236              'Define to 1 if sse2 assembly is available.')
237            have_sse2 = true
238
239            # sse4.1 assembly
240            if get_option('enable-sse4_1') and cc.has_argument('-msse4.1')
241              if cc.compiles('asm ("pmovzxbd %xmm0,%xmm1");')
242                message('sse4.1 assembly available')
243                sse4_1_cflags = '-msse4.1'
244                conf.set('USE_SSE4_1', 1, description:
245                  'Define to 1 if sse4.1 assembly is available.')
246                have_sse4_1 = true
247              endif
248
249              # avx2 assembly
250              if get_option('enable-avx2') and cc.has_argument('-mavx2')
251                if cc.compiles('asm ("vpgatherdd %ymm0,(%eax,%ymm1,4),%ymm2");')
252                  message('avx2 assembly available')
253                  avx2_cflags = '-mavx2'
254                  conf.set('USE_AVX2', 1, description:
255                    'Define to 1 if avx2 assembly is available.')
256                  have_avx2 = true
257                endif
258              endif
259            endif
260          endif
261        endif
262      endif
263      if get_option('enable-f16c') and cc.has_argument('-mf16c')
264        if cc.compiles(
265          'asm ("#include <immintrin.h>],' +
266          '[__m128 val = _mm_cvtph_ps ((__m128i)_mm_setzero_ps());' +
267          ' __m128i val2 = _mm_insert_epi64((__m128i)_mm_setzero_ps(),0,0);");'
268          )
269          message('Can compile half-floating point code (f16c)')
270          f16c_cflags = '-mf16c'
271          conf.set('USE_F16C', 1, description:
272            'Define to 1 if f16c intrinsics are available.')
273          have_f16c = true
274        endif
275      endif
276    endif
277  endif
278endif
279
280################################################################################
281# Check environment
282
283# Check headers
284check_headers = [
285  ['HAVE_STDATOMIC_H', 'stdatomic.h']
286]
287# Don't check for dynamic load on windows
288if not platform_win32
289  check_headers += [
290    ['HAVE_DLFCN_H', 'dlfcn.h'],
291    ['HAVE_DL_H', 'dl.h'],
292  ]
293endif
294foreach header: check_headers
295  if cc.has_header(header[1])
296    conf.set(header[0], 1, description:
297      'Define to 1 if the <@0@> header is available'.format(header[1]))
298  endif
299endforeach
300
301
302# Check functions
303# general
304check_functions = [
305  ['HAVE_GETTIMEOFDAY', 'gettimeofday', '<sys/time.h>'],
306  ['HAVE_RINT',         'rint'        , '<math.h>'],
307  ['HAVE_SRANDOM',      'srandom'     , '<stdlib.h>'],
308]
309foreach func: check_functions
310  if cc.has_function(func[1], prefix: '#include ' + func[2])
311    conf.set(func[0], 1, description:
312      'Define to 1 if the @0@() function is available'.format(func[1]))
313  endif
314endforeach
315
316
317# Check for uncommon features
318
319# babl_fish_reference(), create_name() would like this
320if cc.compiles('int main() { static __thread char buf[1024]; }')
321  conf.set('HAVE_TLS', 1, description:
322    'Define to 1 if compiler supports __thread')
323endif
324
325
326################################################################################
327# Dependencies
328
329math = cc.find_library('m',   required: false)
330thread = dependency('threads',  required: false)
331if platform_android
332  log  = cc.find_library('log', required: false)
333else
334  log = []
335endif
336if platform_win32
337  dl = []
338else
339  dl = cc.find_library('dl',  required: false)
340endif
341
342
343# gobject introspection
344g_ir = dependency('gobject-introspection-1.0', version: '>=1.32.0',
345  required: false)
346
347# lcms
348if get_option('with-lcms')
349  lcms = dependency('lcms2', version: '>=2.8', required: true)
350  if lcms.found()
351    conf.set('HAVE_LCMS', 1, description:
352      'Define to 1 if liblcms2 is available')
353  endif
354else
355  lcms = declare_dependency()
356endif
357
358# vapigen
359vapigen   = dependency('vapigen', version:'>=0.20.0', required: false)
360
361
362################################################################################
363# Build utilities
364
365# build from git repo
366git_bin = find_program('git', required: false, native: true)
367
368# docs
369env_bin = find_program('env', required: false, native: true)
370rsvg_convert_bin = find_program('rsvg-convert', required: false,
371  native: true)
372w3m_bin = find_program('w3m', required: false, native: true)
373
374
375################################################################################
376# Build flags
377
378# Docs - don't build by default in cross-build environments
379#        can't build if no env binary
380build_docs = true
381if get_option('with-docs') != 'false' and not env_bin.found()
382  build_docs = false
383  warning('env is required to build documentation')
384elif get_option('with-docs') == 'auto'
385  if meson.is_cross_build()
386    build_docs = false
387    message(
388      'configure with -Ddocs=true to cross-build documentation'
389    )
390  endif
391elif get_option('with-docs') == 'false'
392  build_docs = false
393endif
394
395# Introspection - don't build  by default on cross-build environments
396if get_option('enable-gir') == 'auto'
397  build_gir = meson.is_cross_build() ? false : true
398else
399  build_gir = get_option('enable-gir') == 'true' ? true : false
400endif
401if not g_ir.found()
402  build_gir = false
403endif
404
405# Vapi - only build if building introspection
406if build_gir and get_option('enable-vapi') and vapigen.found()
407  build_vapi = true
408else
409  build_vapi = false
410endif
411
412################################################################################
413# Configuration files
414
415# This should not be made visible in babl_dep due to possible name clash
416# when built as a sub-project.
417rootInclude = include_directories('.')
418
419# config.h
420configure_file(
421  output: 'config.h',
422  configuration: conf
423)
424
425# If git is available, always check if git-version.h should be
426# updated. If git is not available, don't do anything if git-version.h
427# already exists because then we are probably working with a tarball
428# in which case the git-version.h we ship is correct.
429if git_bin.found() and run_command(
430    git_bin,
431    'rev-parse',
432    '--is-inside-work-tree',
433).returncode() == 0
434  git_version_h = vcs_tag(
435    input : 'git-version.h.in',
436    output: 'git-version.h',
437    replace_string: '@BABL_GIT_VERSION@',
438    command: [ git_bin.path(), 'describe', '--always' ],
439  )
440
441  if not meson.is_subproject()
442    meson.add_dist_script(
443      [ 'ninja', 'git-version.h', ],
444    )
445    meson.add_dist_script(
446      [ 'sh', '-c', ' '.join(
447      [ 'cp', git_version_h.full_path(), '${MESON_DIST_ROOT}' ]
448      )]
449    )
450  endif
451else
452  git_version_h = files('git-version.h')
453endif
454
455################################################################################
456# Global variables
457
458xml_insert_file = files('tools' / 'xml-insert.py')
459authors_file = files('AUTHORS')
460news_file = files('NEWS')
461todo_file = files('TODO')
462export_symbols_file = files('export-symbols')
463gen_babl_map_file = files('gen_babl_map.py')
464
465################################################################################
466# Subdirs
467
468subdir('babl')
469subdir('extensions')
470subdir('tests')
471subdir('tools')
472if build_docs
473  subdir('docs')
474endif
475
476# Create README file from web page
477if w3m_bin.found() and build_docs
478  custom_target('README',
479    input: index_html,
480    output: 'README',
481    command: [
482      w3m_bin,
483      '-cols', '72',
484      '-dump',
485      '@INPUT@',
486    ],
487    capture: true,
488    build_by_default: true
489  )
490endif
491
492
493# pkg-config file
494pkgconfig.generate(
495  babl,
496  filebase: 'babl',
497  name: 'babl',
498  description: 'Pixel encoding and color space conversion engine.',
499  version: meson.project_version(),
500  subdirs: lib_name,
501  uninstalled_variables: [
502    'babl_path=@0@'.format(babl_extensions_build_dir),
503    'babl_libdir=@0@'.format(babl_library_build_dir),
504  ],
505)
506
507# dependency for wrap builds
508babl_dep = declare_dependency(
509  include_directories: bablInclude,
510  link_with : babl,
511  sources: [
512    babl_version_h,
513    is_variable('babl_gir') ? babl_gir : []
514  ],
515  variables: {
516    'babl_path'   : babl_extensions_build_dir,
517    'babl_libdir' : babl_library_build_dir,
518  },
519)
520
521################################################################################
522# Build summary
523summary(
524  {
525    'prefix': babl_prefix,
526    'libdir': get_option('libdir'),
527  }, section: 'Directories'
528)
529summary(
530  {
531    'BABL docs'      : build_docs,
532    'Introspection'  : build_gir,
533    'VALA support'   : build_vapi,
534  }, section: 'Optional features'
535)
536summary(
537  {
538    'mmx'            : have_mmx,
539    'sse'            : have_sse,
540    'sse2'           : have_sse2,
541    'sse4_1'         : have_sse4_1,
542    'avx2'           : have_avx2,
543    'f16c (half fp)' : have_f16c,
544  }, section: 'Processor extensions'
545)
546summary(
547  {
548    'lcms' : get_option('with-lcms'),
549  }, section: 'Optional dependencies'
550)
551