From a991b009b11fb791a9217af23659b092eb45377e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 16 Feb 2018 00:09:33 +0000 Subject: [PATCH] Add support for building with the Meson build system The Meson build system is being adopted by projects such as GNOME, GTK, GStreamer, and there is support for it in Pango as well. Having support for building with Meson in fribidi would facilitate builds of GTK, Pango, etc. via Meson's subproject support. Meson also supports builds on Windows with MSVC. Cross-compilation is of course also supported, but has not been tested yet for this build. Try with: $ meson --prefix=/tmp/prefix builddir $ ninja -C builddir $ ninja -C builddir test $ ninja -C builddir install Build time comparison: - autotools: 18 seconds - meson: 4 seconds http://mesonbuild.com for more information. --- bin/meson.build | 27 ++++++++ doc/meson.build | 39 +++++++++++ gen.tab/meson.build | 79 +++++++++++++++++++++ lib/meson.build | 75 ++++++++++++++++++++ meson.build | 100 +++++++++++++++++++++++++++ meson_options.txt | 6 ++ test/meson.build | 20 ++++++ test/test-runner.py | 25 +++++++ test/unicode-conformance/meson.build | 19 +++++ 9 files changed, 390 insertions(+) create mode 100644 bin/meson.build create mode 100644 doc/meson.build create mode 100644 gen.tab/meson.build create mode 100644 lib/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 test/meson.build create mode 100755 test/test-runner.py create mode 100644 test/unicode-conformance/meson.build diff --git a/bin/meson.build b/bin/meson.build new file mode 100644 index 0000000..823ed02 --- /dev/null +++ b/bin/meson.build @@ -0,0 +1,27 @@ +fribidi = executable('fribidi', + 'fribidi-main.c', 'getopt.c', 'getopt1.c', fribidi_unicode_version_h, + c_args: ['-DHAVE_CONFIG_H'], + include_directories: incs, + link_with: libfribidi, + install: true) + +executable('fribidi-benchmark', + 'fribidi-benchmark.c', 'getopt.c', 'getopt1.c', fribidi_unicode_version_h, + c_args: ['-DHAVE_CONFIG_H'], + include_directories: incs, + link_with: libfribidi, + install: false) + +executable('fribidi-bidi-types', + 'fribidi-bidi-types.c', fribidi_unicode_version_h, + c_args: ['-DHAVE_CONFIG_H'], + include_directories: incs, + link_with: libfribidi, + install: false) + +executable('fribidi-caprtl2utf8', + 'fribidi-caprtl2utf8.c', fribidi_unicode_version_h, + c_args: ['-DHAVE_CONFIG_H'], + include_directories: incs, + link_with: libfribidi, + install: false) diff --git a/doc/meson.build b/doc/meson.build new file mode 100644 index 0000000..00bfa7c --- /dev/null +++ b/doc/meson.build @@ -0,0 +1,39 @@ +c2man = find_program('c2man', required: false) + +if not c2man.found() + error('c2man is required to build documentation. Or disable with -Ddocs=false') +endif + +# Extract list of man pages (one man page per symbol) from lib/libfribidi.def +python3 = import('python3').find_python() + +result = run_command(python3, + '-c', 'import sys; print(open(sys.argv[1], "r").read())', + files('../lib/fribidi.def')) + +if result.returncode() != 0 + error('Could not extract list of symbols from fribidi.def.') +endif + +gen_man_pages = [] + +syms = result.stdout().strip().split('\n') +foreach sym : syms + gen_man_pages += ['@0@.3'.format(sym)] +endforeach + +c2man_incs = [] +c2man_incs += ['-I' + join_paths(meson.source_root(), 'lib')] +c2man_incs += ['-I' + join_paths(meson.build_root(), 'lib')] +c2man_incs += ['-I' + join_paths(meson.source_root(), 'gen.tab')] +c2man_incs += ['-I' + join_paths(meson.build_root(), 'gen.tab')] + +custom_target('man pages', + command: [c2man, '-v', '-T', 'n', '-M', 'Programmer\'s Manual', c2man_incs, + '-D__FRIBIDI_DOC', '-DDONT_HAVE_FRIBIDI_CONFIG_H', + '-o@0@'.format(meson.current_build_dir()), + fribidi_headers], + depends: [fribidi_unicode_version_h], + output: gen_man_pages, + install_dir: join_paths(get_option('prefix'), get_option('mandir'), 'man3'), + install: true) diff --git a/gen.tab/meson.build b/gen.tab/meson.build new file mode 100644 index 0000000..6006d98 --- /dev/null +++ b/gen.tab/meson.build @@ -0,0 +1,79 @@ +# gen.tab + +native_cc = meson.get_compiler('c') + +# Don't pick up top-level config.h, as that has defines for the cross-compiler +# (if we're cross-compiling), but here we need values for the host compiler/env +# in that case. We shall pass those on the command line since it's just a few. +native_args = ['-UHAVE_CONFIG_H'] + +# This is available pretty much everywhere +native_args += ['-DHAVE_STRINGIZE'] + +native_args += ['-DDONT_HAVE_FRIBIDI_CONFIG_H'] + +if native_cc.has_header('stdlib.h') + native_args += ['-DHAVE_STDLIB_H'] +endif + +if native_cc.has_header('string.h') + native_args += ['-DHAVE_STRING_H'] +endif + +if native_cc.has_header('strings.h') + native_args += ['-DHAVE_STRINGS_H'] + + # Not entirely correct, but sufficient for us. Should move away from this + # ancient define and just include individual headers based on individual defs. + # stdlib.h and string.h are standard nowadays, but strings.h not (msvc) + native_args += ['-DSTDC_HEADERS=1'] +endif + +gen_unicode_version = executable('gen-unicode-version', + 'gen-unicode-version.c', + include_directories: incs, + c_args: native_args, + install: false) + +fribidi_unicode_version_h = custom_target('fribidi-unicode-version.h', + input: files('unidata/ReadMe.txt', 'unidata/BidiMirroring.txt'), + output: 'fribidi-unicode-version.h', + command: [gen_unicode_version, '@INPUT0@', '@INPUT1@', 'gen-unicode-version'], + capture: true, + install_dir: join_paths(get_option('includedir'), 'fribidi'), + install: true) + +COMPRESSION='2' + +tabs = [ + ['bidi-type', files('unidata/UnicodeData.txt')], + ['joining-type', files('unidata/UnicodeData.txt', 'unidata/ArabicShaping.txt')], + ['arabic-shaping', files('unidata/UnicodeData.txt')], + ['mirroring', files('unidata/BidiMirroring.txt')], + ['brackets', files('unidata/BidiBrackets.txt', 'unidata/UnicodeData.txt')], + ['brackets-type', files('unidata/BidiBrackets.txt')], +] + +generated_tab_include_files = [] + +foreach tab : tabs + gen_prog_name = 'gen-@0@-tab'.format(tab[0]) + gen_prog_src = 'gen-@0@-tab.c'.format(tab[0]) + gen_prog_out = '@0@.tab.i'.format(tab[0]) + gen_prog_inputs = tab[1] + + gen_exe = executable(gen_prog_name, + fribidi_unicode_version_h, + gen_prog_src, 'packtab.c', + include_directories: incs, + c_args: native_args, + install: false) + + tab_inc_file = custom_target(gen_prog_name, + input: gen_prog_inputs, + output: gen_prog_out, + command: [gen_exe, COMPRESSION, '@INPUT@', gen_prog_name], + capture: true) + + generated_tab_include_files += [tab_inc_file] +endforeach diff --git a/lib/meson.build b/lib/meson.build new file mode 100644 index 0000000..919542b --- /dev/null +++ b/lib/meson.build @@ -0,0 +1,75 @@ +fribidi_config = configuration_data() + +fribidi_config.set('configure_input', 'fribidi-config.h file generated by Meson') +fribidi_config.set('PACKAGE', meson.project_name()) +fribidi_config.set('PACKAGE_NAME', 'GNU FriBidi') +fribidi_config.set('PACKAGE_BUGREPORT', 'https://github.com/fribidi/fribidi/issues/new') +fribidi_config.set('FRIBIDI_VERSION', meson.project_version()) + +version_arr = meson.project_version().split('.') +fribidi_config.set('FRIBIDI_MAJOR_VERSION', version_arr[0].to_int()) +fribidi_config.set('FRIBIDI_MINOR_VERSION', version_arr[1].to_int()) +fribidi_config.set('FRIBIDI_MICRO_VERSION', version_arr[2].to_int()) + +fribidi_config.set('FRIBIDI_INTERFACE_VERSION', interface_version) + +fribidi_config.set('SIZEOF_INT', cc.sizeof('int')) + +fribidi_config_h = configure_file(input: files('fribidi-config.h.in'), + output: 'fribidi-config.h', + configuration: fribidi_config, + install_dir: join_paths(get_option('includedir'), 'fribidi')) + +fribidi_headers = files( + 'fribidi-arabic.h', + 'fribidi-begindecls.h', + 'fribidi-bidi.h', + 'fribidi-bidi-types.h', + 'fribidi-bidi-types-list.h', + 'fribidi-char-sets.h', + 'fribidi-char-sets-list.h', + 'fribidi-common.h', + 'fribidi-deprecated.h', + 'fribidi-enddecls.h', + 'fribidi-flags.h', + 'fribidi-joining.h', + 'fribidi-joining-types.h', + 'fribidi-joining-types-list.h', + 'fribidi-mirroring.h', + 'fribidi-brackets.h', + 'fribidi-shape.h', + 'fribidi-types.h', + 'fribidi-unicode.h', + 'fribidi.h', +) +install_headers(fribidi_headers, subdir: 'fribidi') + +fribidi_sources = [ + 'fribidi.c', + 'fribidi-arabic.c', + 'fribidi-bidi.c', + 'fribidi-bidi-types.c', + 'fribidi-char-sets.c', + 'fribidi-char-sets-cap-rtl.c', + 'fribidi-char-sets-cp1255.c', + 'fribidi-char-sets-cp1256.c', + 'fribidi-char-sets-iso8859-6.c', + 'fribidi-char-sets-iso8859-8.c', + 'fribidi-char-sets-utf8.c', + 'fribidi-deprecated.c', + 'fribidi-joining.c', + 'fribidi-joining-types.c', + 'fribidi-mirroring.c', + 'fribidi-brackets.c', + 'fribidi-run.c', + 'fribidi-shape.c', +] + +libfribidi = library('fribidi', + fribidi_sources, fribidi_unicode_version_h, fribidi_config_h, + generated_tab_include_files, config_h, + include_directories: incs, + c_args: ['-DHAVE_CONFIG_H'] + visibility_args, + version: libversion, + soversion: soversion, + install: true) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..d8bad49 --- /dev/null +++ b/meson.build @@ -0,0 +1,100 @@ +project('fribidi', 'c', version: '1.0.1', + meson_version : '>= 0.44') + +# New release: +# interface_age++ +# micro version++ +# +# If any functions have been added: +# interface_age = 0 +# interface_version++ +# +# If binary backwards compatibility has been broken: +# panic! + +interface_age = 0 +interface_version = 4 + +soversion = 0 +libversion = '@0@.@1@.0'.format(soversion, interface_version, interface_age) + +# C compiler. This is the cross compiler if we're cross-compiling +cc = meson.get_compiler('c') + +if cc.get_id() == 'gcc' and cc.has_argument('-ansi') + add_project_arguments('-ansi', language: 'c') +endif + +# Symbol visibility +have_visibility_hidden = cc.has_argument('-fvisibility=hidden') +if have_visibility_hidden + add_project_arguments('-fvisibility=hidden', language: 'c') +endif + +# Must explicitly make symbols public if default visibility is hidden +if have_visibility_hidden + visibility_args = ['-DFRIBIDI_ENTRY=extern __attribute__ ((visibility ("default")))'] +else + if host_machine.system() == 'windows' + visibility_args = ['-DFRIBIDI_ENTRY=__declspec(dllexport)'] + else + visibility_args = ['-DFRIBIDI_ENTRY=extern'] + endif +endif + +cdata = configuration_data() + +# Checks for library functions +foreach f : ['memmove', 'memset', 'strdup'] + cdata.set('HAVE_' + f.to_upper(), cc.has_function(f)) +endforeach + +# Checks for header files +# Some HAVE_FOO defines need to be defined to either 1 or 0, others need to +# be defined or undefined. The code base is a bit inconsistent there. +foreach h : ['stdlib.h', 'string.h', 'memory.h'] + cdata.set10('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) +endforeach +foreach h : ['strings.h', 'sys/times.h'] + cdata.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) +endforeach + +# Not entirely correct, but sufficient for us. Should move away from this +# ancient define and just include individual headers based on individual defs +if cc.has_header('strings.h') + # define to 1 or leave undefined otherwise, don't simplify + cdata.set('STDC_HEADERS', 1) +endif + +# This is available pretty much everywhere +cdata.set('HAVE_STRINGIZE', 1) + +buildtype = get_option('buildtype') +if buildtype == 'debug' or buildtype == 'debugoptimized' + cdata.set('DEBUG', 1) +endif + +no_deprecated = not get_option('deprecated') +cdata.set('FRIBIDI_NO_DEPRECATED', no_deprecated) + +# write config.h +config_h = configure_file(output: 'config.h', configuration: cdata) + +incs = include_directories('.', 'lib') + +subdir('gen.tab') +subdir('lib') +subdir('bin') +subdir('test') +if get_option('docs') + subdir('doc') +endif + +# fribidi.pc +pkg = import('pkgconfig') +pkg.generate(name: 'GNU FriBidi', + filebase: 'fribidi', + description: 'Unicode Bidirectional Algorithm Library', + libraries: libfribidi, + subdirs: 'fribidi', + version: meson.project_version()) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..8af9b9e --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,6 @@ +option('deprecated', type : 'boolean', value : true, + description: 'Build deprecated functionality') +option('docs', type : 'boolean', value : true, + description: 'Build documentation') +option('glib', type : 'boolean', value : true, + description: 'Use GLib (in unit tests)') diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000..9f7e1a7 --- /dev/null +++ b/test/meson.build @@ -0,0 +1,20 @@ +tests = [ + ['CapRTL', 'explicit'], + ['CapRTL', 'implicit'], + ['ISO8859-8', 'hebrew'], + ['UTF-8', 'persian'], + ['UTF-8', 'reordernsm'], +] + +test_runner = find_program('test-runner.py') + +foreach t : tests + charset = t[0] + suffix = t[1] + test_name = '@0@_@1@'.format(charset, suffix) + input_file = files('test_@0@.input'.format(test_name)) + reference_file = files('test_@0@.reference'.format(test_name)) + test(test_name, test_runner, args: [fribidi, charset, input_file, reference_file]) +endforeach + +subdir('unicode-conformance') diff --git a/test/test-runner.py b/test/test-runner.py new file mode 100755 index 0000000..0f9d0d9 --- /dev/null +++ b/test/test-runner.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +# Test runner that calls ../bin/fribidi --test --charset CHARSET *.input, +# captures the output and compares it to the data in the reference file given +import subprocess +import sys + +if len(sys.argv) != 5: + raise Exception('Expected 4 command-line arguments: test_exe charset test.input test.reference') + +script = sys.argv[0] +test_exe = sys.argv[1] +charset = sys.argv[2] +input_file = sys.argv[3] +reference_file = sys.argv[4] + +try: + output = subprocess.check_output([test_exe, '--test', '--charset', charset, input_file]) + ref_data = open(reference_file, "rb").read() + if output != ref_data: + print('Output:\n', output) + print('Reference file:\n', ref_data) + raise Exception('fribidi --test output for charset ' + charset + ' and input file ' + input_file + ' does not match data from reference file ' + reerence_file) +except: + raise Exception('fribidi --test failed for charset ' + charset + ' and input file ' + input_file) diff --git a/test/unicode-conformance/meson.build b/test/unicode-conformance/meson.build new file mode 100644 index 0000000..9a77ea7 --- /dev/null +++ b/test/unicode-conformance/meson.build @@ -0,0 +1,19 @@ +with_glib = get_option('glib') +if with_glib + glib_dep = dependency('glib-2.0', version: '>= 2.4', required: false) + if glib_dep.found() + tests = [ + ['BidiTest', 'test.c'], + ['BidiCharacterTest', 'test-character.c'], + ] + foreach t : tests + exe = executable(t[0], + t[1], fribidi_unicode_version_h, + c_args: ['-DHAVE_CONFIG_H'], + include_directories: incs, + dependencies: glib_dep, + link_with: libfribidi) + test(t[0], exe, args: files('@0@.txt'.format(t[0]))) + endforeach + endif +endif -- 2.40.0