meson.build revision a4e54154
1project('fontconfig', 'c',
2  version: '2.14.0',
3  meson_version : '>= 0.56.0',
4  default_options: [ 'buildtype=debugoptimized'],
5)
6
7fc_version = meson.project_version()
8version_arr = fc_version.split('.')
9fc_version_major = version_arr[0].to_int()
10fc_version_minor = version_arr[1].to_int()
11fc_version_micro = version_arr[2].to_int()
12
13# Try and maintain compatibility with the previous libtool versioning
14# (this is a bit of a hack, but it should work fine for our case where
15# API is added, in which case LT_AGE and LIBT_CURRENT are both increased)
16soversion = fc_version_major - 1
17curversion = fc_version_minor - 1
18libversion = '@0@.@1@.0'.format(soversion, curversion)
19defversion = '@0@.@1@'.format(curversion, fc_version_micro)
20osxversion = curversion + 1
21
22freetype_req = '>= 21.0.15'
23freetype_req_cmake = '>= 2.8.1'
24
25cc = meson.get_compiler('c')
26
27
28freetype_dep = dependency('freetype2', method: 'pkg-config', version: freetype_req, required: false)
29
30# Give another shot using CMake
31if not freetype_dep.found()
32  freetype_dep = dependency('freetype', method: 'cmake', version: freetype_req_cmake,
33    fallback: ['freetype2', 'freetype_dep'])
34endif
35
36expat_dep = dependency('expat',
37  fallback: ['expat', 'expat_dep'])
38
39i18n = import('i18n')
40pkgmod = import('pkgconfig')
41python3 = import('python').find_installation()
42
43check_headers = [
44  ['dirent.h'],
45  ['fcntl.h'],
46  ['stdlib.h'],
47  ['string.h'],
48  ['unistd.h'],
49  ['sys/statvfs.h'],
50  ['sys/vfs.h'],
51  ['sys/statfs.h'],
52  ['sys/param.h'],
53  ['sys/mount.h'],
54]
55
56check_funcs = [
57  ['link'],
58  ['mkstemp'],
59  ['mkostemp'],
60  ['_mktemp_s'],
61  ['mkdtemp'],
62  ['getopt'],
63  ['getopt_long'],
64  ['getprogname'],
65  ['getexecname'],
66  ['rand'],
67  ['random'],
68  ['lrand48'],
69  ['random_r'],
70  ['rand_r'],
71  ['readlink'],
72  ['fstatvfs'],
73  ['fstatfs'],
74  ['lstat'],
75  ['mmap'],
76  ['vprintf'],
77]
78
79check_freetype_funcs = [
80  ['FT_Get_BDF_Property', {'dependencies': freetype_dep}],
81  ['FT_Get_PS_Font_Info', {'dependencies': freetype_dep}],
82  ['FT_Has_PS_Glyph_Names', {'dependencies': freetype_dep}],
83  ['FT_Get_X11_Font_Format', {'dependencies': freetype_dep}],
84  ['FT_Done_MM_Var', {'dependencies': freetype_dep}],
85]
86
87check_header_symbols = [
88  ['posix_fadvise', 'fcntl.h']
89]
90
91check_struct_members = [
92  ['struct statvfs', 'f_basetype', ['sys/statvfs.h']],
93  ['struct statvfs', 'f_fstypename', ['sys/statvfs.']],
94  ['struct statfs', 'f_flags', []],
95  ['struct statfs', 'f_fstypename', []],
96  ['struct dirent', 'd_type', ['sys/types.h', 'dirent.h']],
97]
98
99check_sizeofs = [
100  ['void *', {'conf-name': 'SIZEOF_VOID_P'}],
101]
102
103check_alignofs = [
104  ['void *', {'conf-name': 'ALIGNOF_VOID_P'}],
105  ['double'],
106]
107
108add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
109
110c_args = []
111
112conf = configuration_data()
113deps = [freetype_dep, expat_dep]
114incbase = include_directories('.')
115
116# We cannot try compiling against an internal dependency
117if freetype_dep.type_name() == 'internal'
118  foreach func: check_freetype_funcs
119    name = func[0]
120    conf.set('HAVE_@0@'.format(name.to_upper()), 1)
121  endforeach
122else
123  check_funcs += check_freetype_funcs
124endif
125
126foreach check : check_headers
127  name = check[0]
128
129  if cc.has_header(name)
130    conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1)
131  endif
132endforeach
133
134foreach check : check_funcs
135  name = check[0]
136  opts = check.length() > 1 ? check[1] : {}
137  extra_deps = opts.get('dependencies', [])
138
139  if cc.has_function(name, dependencies: extra_deps)
140    conf.set('HAVE_@0@'.format(name.to_upper()), 1)
141  endif
142endforeach
143
144foreach check : check_header_symbols
145  name = check[0]
146  header = check[1]
147
148  if cc.has_header_symbol(header, name)
149    conf.set('HAVE_@0@'.format(name.to_upper()), 1)
150  endif
151endforeach
152
153foreach check : check_struct_members
154  struct_name = check[0]
155  member_name = check[1]
156  headers = check[2]
157
158  prefix = ''
159
160  foreach header : headers
161    prefix += '#include <@0@>\n'.format(header)
162  endforeach
163
164  if cc.has_member(struct_name, member_name, prefix: prefix)
165    conf.set('HAVE_@0@_@1@'.format(struct_name, member_name).to_upper().underscorify(), 1)
166  endif
167endforeach
168
169foreach check : check_sizeofs
170  type = check[0]
171  opts = check.length() > 1 ? check[1] : {}
172
173  conf_name = opts.get('conf-name', 'SIZEOF_@0@'.format(type.to_upper()))
174
175  conf.set(conf_name, cc.sizeof(type))
176endforeach
177
178foreach check : check_alignofs
179  type = check[0]
180  opts = check.length() > 1 ? check[1] : {}
181
182  conf_name = opts.get('conf-name', 'ALIGNOF_@0@'.format(type.to_upper()))
183
184  conf.set(conf_name, cc.alignment(type))
185endforeach
186
187if cc.compiles(files('meson-cc-tests/flexible-array-member-test.c'))
188  conf.set('FLEXIBLE_ARRAY_MEMBER', true)
189else
190  conf.set('FLEXIBLE_ARRAY_MEMBER', 1)
191endif
192
193if cc.links(files('meson-cc-tests/stdatomic-primitives-test.c'), name: 'stdatomic.h atomics')
194  conf.set('HAVE_STDATOMIC_PRIMITIVES', 1)
195endif
196
197if cc.links(files('meson-cc-tests/intel-atomic-primitives-test.c'), name: 'Intel atomics')
198  conf.set('HAVE_INTEL_ATOMIC_PRIMITIVES', 1)
199endif
200
201if cc.links(files('meson-cc-tests/solaris-atomic-operations.c'), name: 'Solaris atomic ops')
202  conf.set('HAVE_SOLARIS_ATOMIC_OPS', 1)
203endif
204
205
206prefix = get_option('prefix')
207
208fonts_conf = configuration_data()
209
210if host_machine.system() == 'windows'
211  fc_fonts_path = ['WINDOWSFONTDIR', 'WINDOWSUSERFONTDIR']
212  fc_cachedir = 'LOCAL_APPDATA_FONTCONFIG_CACHE'
213else
214  if host_machine.system() == 'darwin'
215    fc_fonts_path = ['/System/Library/Fonts', '/Library/Fonts', '~/Library/Fonts', '/System/Library/Assets/com_apple_MobileAsset_Font3', '/System/Library/Assets/com_apple_MobileAsset_Font4']
216  else
217    fc_fonts_path = ['/usr/share/fonts', '/usr/local/share/fonts']
218  endif
219  fc_cachedir = join_paths(prefix, get_option('localstatedir'), 'cache', meson.project_name())
220  thread_dep = dependency('threads')
221  conf.set('HAVE_PTHREAD', 1)
222  deps += [thread_dep]
223endif
224xml_path = ''
225escaped_xml_path = ''
226foreach p : fc_fonts_path
227  s = '\t<dir>' + p + '</dir>\n'
228  xml_path += s
229  # No substitution method for string
230  s = '\\t<dir>' + p + '</dir>\\n'
231  escaped_xml_path += s
232endforeach
233conf.set_quoted('FC_DEFAULT_FONTS', escaped_xml_path)
234fonts_conf.set('FC_DEFAULT_FONTS', xml_path)
235
236fc_templatedir = join_paths(prefix, get_option('datadir'), 'fontconfig/conf.avail')
237fc_baseconfigdir = join_paths(prefix, get_option('sysconfdir'), 'fonts')
238fc_configdir = join_paths(fc_baseconfigdir, 'conf.d')
239fc_xmldir = join_paths(prefix, get_option('datadir'), 'xml/fontconfig')
240
241
242conf.set_quoted('CONFIGDIR', fc_configdir)
243conf.set_quoted('FC_CACHEDIR', fc_cachedir)
244conf.set_quoted('FC_TEMPLATEDIR', fc_templatedir)
245conf.set_quoted('FONTCONFIG_PATH', fc_baseconfigdir)
246conf.set_quoted('FC_FONTPATH', '')
247
248fonts_conf.set('FC_FONTPATH', '')
249fonts_conf.set('FC_CACHEDIR', fc_cachedir)
250fonts_conf.set('CONFIGDIR', fc_configdir)
251# strip off fc_baseconfigdir prefix if that is the prefix
252if fc_configdir.startswith(fc_baseconfigdir + '/')
253  fonts_conf.set('CONFIGDIR', fc_configdir.split(fc_baseconfigdir + '/')[1])
254endif
255
256# It will automatically fallback to subproject if not found on system
257gperf = find_program('gperf')
258
259sh = find_program('sh', required : false)
260
261if not sh.found() # host_machine.system() == 'windows' or not sh.found()
262  # TODO: This is not always correct
263  if cc.get_id() == 'msvc'
264    gperf_len_type = 'size_t'
265  else
266    gperf_len_type = 'unsigned'
267  endif
268else
269  gperf_test_format = '''
270  #include <string.h>
271  const char * in_word_set(const char *, @0@);
272  @1@
273  '''
274  gperf_snippet_format = 'echo foo,bar | @0@ -L ANSI-C'
275  gperf_snippet = run_command(sh, '-c', gperf_snippet_format.format(gperf.path()))
276  gperf_test = gperf_test_format.format('size_t', gperf_snippet.stdout())
277
278  if cc.compiles(gperf_test)
279    gperf_len_type = 'size_t'
280  else
281    gperf_test = gperf_test_format.format('unsigned', gperf_snippet.stdout())
282    if cc.compiles(gperf_test)
283      gperf_len_type = 'unsigned'
284    else
285      error('unable to determine gperf len type')
286    endif
287  endif
288endif
289
290message('gperf len type is @0@'.format(gperf_len_type))
291
292conf.set('FC_GPERF_SIZE_T', gperf_len_type,
293  description : 'The type of gperf "len" parameter')
294
295conf.set('_GNU_SOURCE', true)
296
297conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())
298
299incsrc = include_directories('src')
300
301# We assume stdint.h is available
302foreach t : ['uint64_t', 'int32_t', 'uintptr_t', 'intptr_t']
303  if not cc.has_type(t, prefix: '#include <stdint.h>')
304    error('Sanity check failed: type @0@ not provided via stdint.h'.format(t))
305  endif
306endforeach
307
308fcstdint_h = configure_file(
309  input: 'src/fcstdint.h.in',
310  output: 'fcstdint.h',
311  copy: true)
312
313makealias = files('src/makealias.py')[0]
314
315alias_headers = custom_target('alias_headers',
316  output: ['fcalias.h', 'fcaliastail.h'],
317  input: ['fontconfig/fontconfig.h', 'src/fcdeprecate.h', 'fontconfig/fcprivate.h'],
318  command: [python3, makealias, join_paths(meson.current_source_dir(), 'src'), '@OUTPUT@', '@INPUT@'],
319)
320
321ft_alias_headers = custom_target('ft_alias_headers',
322  output: ['fcftalias.h', 'fcftaliastail.h'],
323  input: ['fontconfig/fcfreetype.h'],
324  command: [python3, makealias, join_paths(meson.current_source_dir(), 'src'), '@OUTPUT@', '@INPUT@']
325)
326
327tools_man_pages = []
328
329# Do not reorder
330subdir('fc-case')
331subdir('fc-lang')
332subdir('src')
333
334if not get_option('tools').disabled()
335  subdir('fc-cache')
336  subdir('fc-cat')
337  subdir('fc-conflist')
338  subdir('fc-list')
339  subdir('fc-match')
340  subdir('fc-pattern')
341  subdir('fc-query')
342  subdir('fc-scan')
343  subdir('fc-validate')
344endif
345
346if not get_option('tests').disabled()
347  subdir('test')
348endif
349
350subdir('conf.d')
351subdir('its')
352
353# xgettext is optional (on Windows for instance)
354if find_program('xgettext', required : get_option('nls')).found()
355  subdir('po')
356  subdir('po-conf')
357endif
358
359if not get_option('doc').disabled()
360  subdir('doc')
361endif
362
363configure_file(output: 'config.h', configuration: conf)
364
365configure_file(output: 'fonts.conf',
366  input: 'fonts.conf.in',
367  configuration: fonts_conf,
368  install_dir: fc_baseconfigdir,
369  install: true)
370
371install_data('fonts.dtd',
372  install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'xml/fontconfig')
373)
374
375fc_headers = [
376  'fontconfig/fontconfig.h',
377  'fontconfig/fcfreetype.h',
378  'fontconfig/fcprivate.h',
379]
380
381install_headers(fc_headers, subdir: meson.project_name())
382
383# Summary
384doc_targets = get_variable('doc_targets', [])
385
386summary({
387       'Documentation': (doc_targets.length() > 0 ? doc_targets : false),
388       'NLS': not get_option('nls').disabled(),
389       'Tests': not get_option('tests').disabled(),
390       'Tools': not get_option('tools').disabled(),
391       }, section: 'General', bool_yn: true, list_sep: ', ')
392