meson.build 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. project('harfbuzz', 'c', 'cpp',
  2. meson_version: '>= 0.55.0',
  3. version: '5.3.1',
  4. default_options: [
  5. 'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway
  6. 'cpp_std=c++11',
  7. 'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
  8. ],
  9. )
  10. hb_version_arr = meson.project_version().split('.')
  11. hb_version_major = hb_version_arr[0].to_int()
  12. hb_version_minor = hb_version_arr[1].to_int()
  13. hb_version_micro = hb_version_arr[2].to_int()
  14. # libtool versioning
  15. hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro
  16. hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int)
  17. pkgmod = import('pkgconfig')
  18. cpp = meson.get_compiler('cpp')
  19. null_dep = dependency('', required: false)
  20. if cpp.get_argument_syntax() == 'msvc'
  21. # Ignore several spurious warnings for things HarfBuzz does very commonly.
  22. # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
  23. # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
  24. # NOTE: Only add warnings here if you are sure they're spurious
  25. msvc_args = [
  26. '/wd4018', # implicit signed/unsigned conversion
  27. '/wd4146', # unary minus on unsigned (beware INT_MIN)
  28. '/wd4244', # lossy type conversion (e.g. double -> int)
  29. '/wd4305', # truncating type conversion (e.g. double -> float)
  30. cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
  31. ]
  32. add_project_arguments(msvc_args, language: ['c', 'cpp'])
  33. # Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW
  34. # noseh_link_args = ['/SAFESEH:NO']
  35. # disable exception handling
  36. add_project_arguments(['/EHs-', '/EHc-'], language: 'cpp')
  37. endif
  38. add_project_link_arguments(cpp.get_supported_link_arguments([
  39. '-Bsymbolic-functions'
  40. ]), language: 'c')
  41. add_project_arguments(cpp.get_supported_arguments([
  42. '-fno-exceptions',
  43. '-fno-rtti',
  44. '-fno-threadsafe-statics',
  45. '-fvisibility-inlines-hidden',
  46. ]), language: 'cpp')
  47. if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') != 1
  48. if cpp.has_argument('-mstructure-size-boundary=8')
  49. add_project_arguments('-mstructure-size-boundary=8', language: 'cpp')
  50. endif
  51. endif
  52. if host_machine.system() == 'windows'
  53. add_project_arguments(cpp.get_supported_arguments([
  54. '-Wa,-mbig-obj'
  55. ]), language : 'cpp')
  56. endif
  57. check_headers = [
  58. ['unistd.h'],
  59. ['sys/mman.h'],
  60. ['stdbool.h'],
  61. ['xlocale.h'],
  62. ]
  63. check_funcs = [
  64. ['atexit'],
  65. ['mprotect'],
  66. ['sysconf'],
  67. ['getpagesize'],
  68. ['mmap'],
  69. ['isatty'],
  70. ['uselocale'],
  71. ['newlocale'],
  72. ]
  73. m_dep = cpp.find_library('m', required: false)
  74. # Try pkgconfig name
  75. freetype_dep = dependency('freetype2', required: false)
  76. if not freetype_dep.found()
  77. # Try cmake name
  78. freetype_dep = dependency('freetype', required: false)
  79. endif
  80. if not freetype_dep.found()
  81. # Subproject fallback, `allow_fallback: true` means the fallback will be
  82. # tried even if the freetype option is set to `auto`.
  83. freetype_dep = dependency('freetype2',
  84. required: get_option('freetype'),
  85. default_options: ['harfbuzz=disabled'],
  86. allow_fallback: true)
  87. endif
  88. glib_dep = dependency('glib-2.0', required: get_option('glib'))
  89. gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
  90. graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
  91. graphite_dep = dependency('graphite2', required: get_option('graphite'))
  92. # Try pkgconfig name
  93. icu_dep = dependency('icu-uc', required: false)
  94. if not icu_dep.found()
  95. # Try cmake name
  96. icu_dep = dependency('ICU',
  97. required: false,
  98. components: 'uc',
  99. method: 'cmake')
  100. endif
  101. if not icu_dep.found()
  102. # Subproject fallback if icu option is enabled
  103. icu_dep = dependency('icu-uc', required: get_option('icu'))
  104. endif
  105. if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
  106. icu_defs = icu_dep.get_variable(pkgconfig: 'DEFS', default_value: '').split()
  107. if icu_defs.length() > 0
  108. add_project_arguments(icu_defs, language: ['c', 'cpp'])
  109. endif
  110. endif
  111. cairo_dep = null_dep
  112. cairo_ft_dep = null_dep
  113. if not get_option('cairo').disabled()
  114. cairo_dep = dependency('cairo', required: false)
  115. cairo_ft_dep = dependency('cairo-ft', required: false)
  116. if (not cairo_dep.found() and
  117. cpp.get_argument_syntax() == 'msvc' and
  118. cpp.has_header('cairo.h'))
  119. cairo_dep = cpp.find_library('cairo', required: false)
  120. if cairo_dep.found() and cpp.has_function('cairo_ft_font_face_create_for_ft_face',
  121. prefix: '#include <cairo-ft.h>',
  122. dependencies: cairo_dep)
  123. cairo_ft_dep = cairo_dep
  124. endif
  125. endif
  126. if not cairo_dep.found()
  127. # Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback
  128. # dependency cycle here because we have configured freetype2 above with
  129. # harfbuzz support disabled, so when cairo will lookup freetype2 dependency
  130. # it will be forced to use that one.
  131. cairo_dep = dependency('cairo', required: get_option('cairo'))
  132. cairo_ft_dep = dependency('cairo-ft', required: get_option('cairo'))
  133. endif
  134. endif
  135. chafa_dep = dependency('chafa', version: '>= 1.6.0', required: get_option('chafa'))
  136. conf = configuration_data()
  137. incconfig = include_directories('.')
  138. add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
  139. warn_cflags = [
  140. '-Wno-non-virtual-dtor',
  141. ]
  142. cpp_args = cpp.get_supported_arguments(warn_cflags)
  143. if glib_dep.found()
  144. conf.set('HAVE_GLIB', 1)
  145. endif
  146. if gobject_dep.found()
  147. conf.set('HAVE_GOBJECT', 1)
  148. endif
  149. if cairo_dep.found()
  150. conf.set('HAVE_CAIRO', 1)
  151. if cairo_dep.type_name() == 'internal'
  152. conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1)
  153. else
  154. check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]]
  155. endif
  156. endif
  157. if cairo_ft_dep.found()
  158. conf.set('HAVE_CAIRO_FT', 1)
  159. endif
  160. if chafa_dep.found()
  161. conf.set('HAVE_CHAFA', 1)
  162. endif
  163. if graphite2_dep.found() or graphite_dep.found()
  164. conf.set('HAVE_GRAPHITE2', 1)
  165. endif
  166. if icu_dep.found()
  167. conf.set('HAVE_ICU', 1)
  168. endif
  169. if get_option('icu_builtin')
  170. conf.set('HAVE_ICU_BUILTIN', 1)
  171. endif
  172. if get_option('experimental_api')
  173. conf.set('HB_EXPERIMENTAL_API', 1)
  174. endif
  175. if freetype_dep.found()
  176. conf.set('HAVE_FREETYPE', 1)
  177. check_freetype_funcs = [
  178. ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
  179. ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
  180. ['FT_Done_MM_Var', {'deps': freetype_dep}],
  181. ['FT_Get_Transform', {'deps': freetype_dep}],
  182. ]
  183. if freetype_dep.type_name() == 'internal'
  184. foreach func: check_freetype_funcs
  185. name = func[0]
  186. conf.set('HAVE_@0@'.format(name.to_upper()), 1)
  187. endforeach
  188. else
  189. check_funcs += check_freetype_funcs
  190. endif
  191. endif
  192. gdi_uniscribe_deps = []
  193. # GDI (Uniscribe) (Windows)
  194. if host_machine.system() == 'windows' and not get_option('gdi').disabled()
  195. if (get_option('directwrite').enabled() and
  196. not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
  197. error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
  198. endif
  199. gdi_deps_found = true
  200. foreach usplib : ['usp10', 'gdi32', 'rpcrt4']
  201. dep = cpp.find_library(usplib, required: get_option('gdi'))
  202. gdi_deps_found = gdi_deps_found and dep.found()
  203. gdi_uniscribe_deps += dep
  204. endforeach
  205. if gdi_deps_found
  206. conf.set('HAVE_UNISCRIBE', 1)
  207. conf.set('HAVE_GDI', 1)
  208. endif
  209. endif
  210. # DirectWrite (Windows)
  211. if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
  212. if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
  213. error('DirectWrite was enabled explicitly, but required header is missing.')
  214. endif
  215. conf.set('HAVE_DIRECTWRITE', 1)
  216. endif
  217. # CoreText (macOS)
  218. coretext_deps = []
  219. if host_machine.system() == 'darwin' and not get_option('coretext').disabled()
  220. app_services_dep = dependency('appleframeworks', modules: ['ApplicationServices'], required: false)
  221. if cpp.has_type('CTFontRef', prefix: '#include <ApplicationServices/ApplicationServices.h>', dependencies: app_services_dep)
  222. coretext_deps += [app_services_dep]
  223. conf.set('HAVE_CORETEXT', 1)
  224. # On iOS CoreText and CoreGraphics are stand-alone frameworks
  225. # Check for a different symbol to avoid getting cached result
  226. else
  227. coretext_dep = dependency('appleframeworks', modules: ['CoreText'], required: false)
  228. coregraphics_dep = dependency('appleframeworks', modules: ['CoreGraphics'], required: false)
  229. corefoundation_dep = dependency('appleframeworks', modules: ['CoreFoundation'], required: false)
  230. if cpp.has_type('CTRunRef', prefix: '#include <CoreText/CoreText.h>', dependencies: [coretext_dep, coregraphics_dep, corefoundation_dep])
  231. coretext_deps += [coretext_dep, coregraphics_dep, corefoundation_dep]
  232. conf.set('HAVE_CORETEXT', 1)
  233. elif get_option('coretext').enabled()
  234. error('CoreText was enabled explicitly, but required headers or frameworks are missing.')
  235. endif
  236. endif
  237. endif
  238. # threads
  239. thread_dep = null_dep
  240. if host_machine.system() != 'windows'
  241. thread_dep = dependency('threads', required: false)
  242. if thread_dep.found()
  243. conf.set('HAVE_PTHREAD', 1)
  244. endif
  245. endif
  246. conf.set_quoted('PACKAGE_NAME', 'HarfBuzz')
  247. conf.set_quoted('PACKAGE_VERSION', meson.project_version())
  248. foreach check : check_headers
  249. name = check[0]
  250. if cpp.has_header(name)
  251. conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1)
  252. endif
  253. endforeach
  254. harfbuzz_extra_deps = []
  255. foreach check : check_funcs
  256. name = check[0]
  257. opts = check.get(1, {})
  258. link_withs = opts.get('link_with', [])
  259. check_deps = opts.get('deps', [])
  260. extra_deps = []
  261. found = true
  262. # First try without linking
  263. found = cpp.has_function(name, dependencies: check_deps)
  264. if not found and link_withs.length() > 0
  265. found = true
  266. foreach link_with : link_withs
  267. dep = cpp.find_library(link_with, required: false)
  268. if dep.found()
  269. extra_deps += dep
  270. else
  271. found = false
  272. endif
  273. endforeach
  274. if found
  275. found = cpp.has_function(name, dependencies: check_deps + extra_deps)
  276. endif
  277. endif
  278. if found
  279. harfbuzz_extra_deps += extra_deps
  280. conf.set('HAVE_@0@'.format(name.to_upper()), 1)
  281. endif
  282. endforeach
  283. subdir('src')
  284. subdir('util')
  285. if not get_option('tests').disabled()
  286. subdir('test')
  287. endif
  288. if not get_option('benchmark').disabled()
  289. subdir('perf')
  290. endif
  291. if not get_option('docs').disabled()
  292. subdir('docs')
  293. endif
  294. configure_file(output: 'config.h', configuration: conf)
  295. build_summary = {
  296. 'Directories':
  297. {'prefix': get_option('prefix'),
  298. 'bindir': get_option('bindir'),
  299. 'libdir': get_option('libdir'),
  300. 'includedir': get_option('includedir'),
  301. 'datadir': get_option('datadir'),
  302. },
  303. 'Unicode callbacks (you want at least one)':
  304. {'Builtin': true,
  305. 'Glib': conf.get('HAVE_GLIB', 0) == 1,
  306. 'ICU': conf.get('HAVE_ICU', 0) == 1,
  307. },
  308. 'Font callbacks (the more the merrier)':
  309. {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
  310. },
  311. 'Dependencies used for command-line utilities':
  312. {'Cairo': conf.get('HAVE_CAIRO', 0) == 1,
  313. 'Chafa': conf.get('HAVE_CHAFA', 0) == 1,
  314. },
  315. 'Additional shapers':
  316. {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1,
  317. },
  318. 'Platform shapers (not normally needed)':
  319. {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1,
  320. 'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1,
  321. 'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1),
  322. },
  323. 'Other features':
  324. {'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1,
  325. 'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1,
  326. 'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1,
  327. 'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1,
  328. },
  329. 'Testing':
  330. {'Tests': get_option('tests').enabled(),
  331. 'Benchmark': get_option('benchmark').enabled(),
  332. },
  333. }
  334. foreach section_title, section : build_summary
  335. summary(section, bool_yn: true, section: section_title)
  336. endforeach