diff --git a/.gitignore b/.gitignore index ce3195baac..ce3183f3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,10 @@ libtool flint.pc autom4te.cache/ config.m4 +config.m4.in src/flint-mparam.h .gdb_history vgcore.* +meson +meson.build +meson.options diff --git a/_meson_build/Makefile b/_meson_build/Makefile new file mode 100644 index 0000000000..88907fd785 --- /dev/null +++ b/_meson_build/Makefile @@ -0,0 +1,31 @@ +BUILDDIR = build.meson + +all: setup + meson compile -C $(BUILDDIR) + +setup: $(BUILDDIR)/.build-dir-created + +$(BUILDDIR)/.build-dir-created: + meson setup $(BUILDDIR) + touch $(BUILDDIR)/.build-dir-created + +clean: + rm -rf $(BUILDDIR) + +install: setup + meson install -C $(BUILDDIR) + +uninstall: + cd $(BUILDDIR) && ninja uninstall + +test: setup + meson configure $(BUILDDIR) -Dtests=enabled + meson test -C $(BUILDDIR) --timeout-multiplier 10 + +coverage: setup + # Coverage tool e.g. gcovr needs to be installed *before* meson configure: + # pip install gcovr + meson configure $(BUILDDIR) -Dtests=enabled -Db_coverage=true + meson test -C $(BUILDDIR) --timeout-multiplier 10 + cd $(BUILDDIR) && ninja coverage-html + # open $(BUILDDIR)/meson-logs/coveragereport/index.html diff --git a/_meson_build/bad_test.c b/_meson_build/bad_test.c new file mode 100644 index 0000000000..3af1103e33 --- /dev/null +++ b/_meson_build/bad_test.c @@ -0,0 +1,10 @@ +/* + * This is used to fail the build tests of someone tries to run them without + * enabling them in the build first. + */ +#include <stdio.h> + +int main() { + printf("No tests run. Need to enable building tests with meson configure -Dtests=enabled\n"); + return 1; +} diff --git a/_meson_build/config.m4.in b/_meson_build/config.m4.in new file mode 100644 index 0000000000..2a36c4c373 --- /dev/null +++ b/_meson_build/config.m4.in @@ -0,0 +1,21 @@ +dnl config.m4. Generated automatically by configure. +changequote(<,>) +ifdef(<__CONFIG_M4_INCLUDED__>,,< +define(<TEXT>, <.text>) +define(<DATA>, <.data>) +define(<LABEL_SUFFIX>, <:>) +define(<GLOBL>, <.globl>) +define(<GLOBL_ATTR>, <>) +define(<GSYM_PREFIX>, <_>) +define(<RODATA>, < .section __TEXT,__const>) +define(<TYPE>, <>) +define(<SIZE>, <>) +define(<LSYM_PREFIX>, @LSYM_PREFIX@) +define(<ALIGN_LOGARITHMIC>,<yes>) +>) +changequote(`,') +ifdef(`__CONFIG_M4_INCLUDED__',,` +include(`../src/mpn_extras/asm-defs.m4') +include(`../src/mpn_extras/arm64/darwin.m4') +') +define(`__CONFIG_M4_INCLUDED__') diff --git a/_meson_build/configure b/_meson_build/configure new file mode 100755 index 0000000000..2985c95bf3 --- /dev/null +++ b/_meson_build/configure @@ -0,0 +1,217 @@ +#!/usr/bin/env python + +from os.path import join, abspath, dirname +import sys +import shutil +from subprocess import check_call +from argparse import ArgumentParser + + +def enable_disable_to_do(args, feature): + """Translate --enable-foo=no etc to foo=True/False/None""" + enable = getattr(args, 'enable_' + feature) + disable = getattr(args, 'disable_' + feature) + if enable is not None and disable is not None: + msg = 'Cannot use --enable-{} and --disable-{} together' + raise ValueError(msg.format(feature, feature)) + if enable is not None: + return enable == 'yes' + if disable is not None: + return disable == 'no' + return None + + +def run_command(cmd): + print('-' * 80) + print('$', ' '.join(cmd)) + print('-' * 80) + check_call(cmd) + + +def enabled_disabled(value): + if value is True: + return 'enabled' + elif value is False: + return 'disabled' + else: + raise ValueError('Invalid value: ' + value) + + +def true_false(value): + if value is True: + return 'true' + elif value is False: + return 'false' + else: + raise ValueError('Invalid value: ' + str(value)) + + +def add_feature_option(parser, feature): + parser.add_argument('--enable-' + feature, help='Enable ' + feature, + choices=['yes', 'no', 'auto'], nargs='?', const='yes', action='store') + parser.add_argument('--disable-' + feature, help='Disable ' + feature, + choices=['yes', 'no', 'auto'], nargs='?', const='yes', action='store') + + +def add_with_option(parser, libname, default): + parser.add_argument('--with-' + libname, help=f'Link to {libname}', + default=default, const=True, nargs='?') + + +parser = ArgumentParser(description='Configure FLINT for building with meson') + +parser.add_argument('--build-dir', default='build.meson', help='Build directory') + +parser.add_argument('--prefix', default=None, help='Installation prefix') +parser.add_argument('--bindir', default=None, help='Binary directory') +parser.add_argument('--libdir', default=None, help='Library directory') +parser.add_argument('--includedir', default=None, help='Include directory') + +parser.add_argument('--build', default=None, help='Not supported...') +parser.add_argument('--host', default=None, help='Not supported...') + +add_feature_option(parser, 'shared') +add_feature_option(parser, 'static') + +add_feature_option(parser, 'libtool-lock') +add_feature_option(parser, 'pthread') +add_feature_option(parser, 'reentrant') +add_feature_option(parser, 'thread-safe') +add_feature_option(parser, 'assert') +add_feature_option(parser, 'coverage') +add_feature_option(parser, 'debug') +add_feature_option(parser, 'dependency-tracking') +add_feature_option(parser, 'pretty-tests') + +add_feature_option(parser, 'gmp-internals') +add_feature_option(parser, 'assembly') +add_feature_option(parser, 'avx2') +add_feature_option(parser, 'avx512') + +add_with_option(parser, 'gmp', default=True) +add_with_option(parser, 'mpfr', default=True) +add_with_option(parser, 'ntl', default=False) + +parser.add_argument('--with-blas', default=None, help='Not supported...') +parser.add_argument('--with-gc', default=None, help='Not supported...') + + +def get_meson_command_from_configure_args(args): + """ + Translate e.g. + ./configure --prefix=/opt/foo --enable-assembly=no + to + meson setup build --prefix=/opt/foo -Dassembly=disabled + Raise ValueError if modifying an option is not supported. + """ + args = parser.parse_args(args) + + setup_args = [] + + if args.bindir is not None: + setup_args.append('--bindir=' + args.bindir) + if args.libdir is not None: + setup_args.append('--libdir=' + args.libdir) + else: + setup_args.append('--libdir=lib') + if args.includedir is not None: + setup_args.append('--includedir=' + args.includedir) + if args.prefix is not None: + setup_args.append('--prefix=' + args.prefix) + + do_shared = enable_disable_to_do(args, 'shared') + do_static = enable_disable_to_do(args, 'static') + + do_libtool_lock = enable_disable_to_do(args, 'libtool_lock') + do_pthread = enable_disable_to_do(args, 'pthread') + do_reentrant = enable_disable_to_do(args, 'reentrant') + do_thread_safe = enable_disable_to_do(args, 'thread_safe') + do_assert = enable_disable_to_do(args, 'assert') + do_coverage = enable_disable_to_do(args, 'coverage') + do_debug = enable_disable_to_do(args, 'debug') + do_dependency_tracking = enable_disable_to_do(args, 'dependency_tracking') + do_pretty_tests = enable_disable_to_do(args, 'pretty_tests') + + do_gmp_internals = enable_disable_to_do(args, 'gmp_internals') + do_assembly = enable_disable_to_do(args, 'assembly') + do_avx2 = enable_disable_to_do(args, 'avx2') + do_avx512 = enable_disable_to_do(args, 'avx512') + + if do_shared is None: + do_shared = True + if do_static is None: + do_static = False + + if do_shared and not do_static: + pass + elif not do_shared and do_static: + setup_args.append('--default-library=static') + elif do_shared and do_static: + setup_args.append('--default-library=both') + else: + raise ValueError('Cannot disable both shared and static libraries') + + if do_debug is True: + setup_args.append('--buildtype=debugoptimized') + + if do_libtool_lock is not None: + setup_args.append('-Dlibtool_lock=' + 'disabled') + if do_pthread is not None: + setup_args.append('-Dpthread=' + enabled_disabled(do_pthread)) + if do_reentrant is not None: + setup_args.append('-Dreentrant=' + enabled_disabled(do_reentrant)) + if do_thread_safe is not None: + setup_args.append('-Dthread_safe=' + enabled_disabled(do_thread_safe)) + if do_assert is not None: + setup_args.append('-Dassert=' + enabled_disabled(do_assert)) + if do_coverage is not None: + setup_args.append('-Db_coverage=' + true_false(do_coverage)) + if do_dependency_tracking is not None: + pass # Meson always does dependency tracking with Ninja + if do_pretty_tests is not None: + setup_args.append('-Dpretty_tests=' + enabled_disabled(do_pretty_tests)) + + if do_gmp_internals is not None: + setup_args.append('-Dgmp_internals=' + enabled_disabled(do_gmp_internals)) + + if do_assembly is not None: + setup_args.append('-Dassembly=' + enabled_disabled(do_assembly)) + + if do_avx2 is False or do_avx512 is False: + setup_args.append('-Dfft_small=' + 'disabled') + elif do_avx2 is True or do_avx512 is True: + setup_args.append('-Dfft_small=' + 'enabled') + + for lib in ['gmp', 'mpfr', 'gc', 'ntl', 'blas']: + val = getattr(args, 'with_' + lib) + if isinstance(val, str): + setup_args.append('--pkg-config-path=' + join(val, 'lib', 'pkgconfig')) + + if args.with_ntl: + setup_args.append('-Dntl=enabled') + + if args.with_blas is not None: + raise ValueError('--with-blas is not supported') + if args.with_gc is not None: + raise ValueError('--with-gc is not supported') + + cmd = ['meson', 'setup', args.build_dir] + setup_args + return cmd, args + + +def main(*args): + cmd, args = get_meson_command_from_configure_args(args) + # The default behaviour of ./configure is to basically wipe out the build. + # Everything is then rebuilt from scratch. We will do the same here to + # match the semantics of configure which does not preserve any settings + # from one run of configure to the next. When using meson directly, it is + # better not to do this because the files might not need to be rebuilt. + shutil.rmtree(args.build_dir, ignore_errors=True) + run_command(cmd) + # The Makefile uses this to check if project is configured + with open(join(args.build_dir, '.build-dir-created'), 'w') as f: + pass + + +if __name__ == '__main__': + sys.exit(main(*sys.argv[1:])) diff --git a/_meson_build/generate_meson_build.py b/_meson_build/generate_meson_build.py new file mode 100644 index 0000000000..2c77ba07ed --- /dev/null +++ b/_meson_build/generate_meson_build.py @@ -0,0 +1,408 @@ +import sys +from os import listdir, makedirs +from os.path import join, dirname, abspath, isdir +from shutil import copyfile +from argparse import ArgumentParser + +this_dir = dirname(abspath(__file__)) + +files_to_copy = [ + 'configure', + 'Makefile', + 'meson.build', + 'meson.options', + 'include/meson.build', + 'include/flint/meson.build', + 'config.m4.in', +] + +# Directories in src that are not modules or that need special handling +exclude_mod_dirs = [ + 'test', + 'profile', + 'interfaces', + 'python', + 'include', +] + +conditional_modules = [ + 'fft_small', +] + +# Modules that do not have a corresponding header file +mod_no_header = [ + 'generic_files', +] + +# Headers that do not have a corresponding module +head_no_dir = [ + 'NTL-interface', + 'acb_types', + 'acf_types', + 'arb_types', + 'arf_types', + 'crt_helpers', + 'fmpq_types', + 'fmpz_mod_types', + 'fmpz_types', + 'fq_nmod_types', + 'fq_types', + 'fq_zech_types', + 'gettimeofday', + 'limb_types', + 'longlong', + 'longlong_asm_clang', + 'longlong_asm_gcc', + 'longlong_asm_gnu', + 'longlong_div_gnu', + 'longlong_msc_arm64', + 'longlong_msc_x86', + 'machine_vectors', + 'mpf-impl', + 'mpoly_types', + 'n_poly_types', + 'nmod_types', + 'padic_types', + 'profiler', + 'templates', + 'test_helpers', +] + +headers_skip = [ + 'flint', + 'config', + 'flint-config', + 'flint-mparam', + 'gmpcompat', +] + +mod_no_tests = [ + 'ca_vec', + 'calcium', + 'fexpr_builtin', + 'fmpz_mod_vec', + 'fq_zech_mpoly', + 'fq_zech_mpoly_factor', + 'generic_files', + 'hypgeom', + # XXX: Templates... + 'fq_templates', + 'fq_embed_templates', + 'fq_poly_templates', + 'fq_poly_factor_templates', + 'fq_mat_templates', + 'fq_vec_templates', +] + +src_meson_build = '''\ +# +# This file is generated automatically. +# +# To regenerate it, run: +# python _meson_build/generate_meson_build.py +# + +modules = [ +%s +] + +modules_no_header = [ +%s +] + +modules_no_tests = [ +%s +] + +headers_no_dir = [ +%s +] + +headers_all = [] +c_files_all = [] +mod_tests = [] + +# Select the right version of fmpz.c (see configuration) +c_files_all += files('fmpz/link' / fmpz_c_in) + +foreach mod : modules + subdir(mod) + if mod not in modules_no_tests + mod_tests += [mod / 'test'] + endif +endforeach + +foreach mod : modules + headers_no_dir + if mod not in modules_no_header + headers_all += [mod + '.h'] + endif +endforeach + +# Add conditional modules + +if have_fft_small + subdir('fft_small') + mod_tests += ['fft_small/test'] + headers_all += ['fft_small.h'] +endif + +if ntl_opt.enabled() + mod_tests += ['interfaces/test'] +endif + +headers_all = files(headers_all) +''' + +src_mod_meson_build = '''\ +# +# This file is generated automatically. +# +# To regenerate it, run: +# python _meson_build/generate_meson_build.py +# + +c_files_all += files( +%s +) +''' + +test_mod_meson_build = '''\ +# This file is generated automatically. +# +# To regenerate it, run: +# python _meson_build/generate_meson_build.py +# + +test_exe = executable('main', + 'main.c', + dependencies: flint_deps, + link_with: libflint, + include_directories: [headers_built_nodir_inc, '../..'], + install: false, +) + +test('%s', test_exe) +''' + + +test_mod_NTL_meson_build = '''\ +# This file is generated automatically. +# +# To regenerate it, run: +# python _meson_build/generate_meson_build.py +# + +# NTL no found by pkgconfig +cpp = meson.get_compiler('cpp') +ntl_dep = cpp.find_library('ntl') + +test_exe = executable('main', + 't-NTL-interface.cpp', + dependencies: flint_deps + [ntl_dep], + link_with: libflint, + include_directories: [headers_built_nodir_inc, '../..'], + install: false, +) + +test('%s', test_exe) +''' + +asm_submodule_arm64 = '''\ + +asm_deps = [ + '../asm-defs.m4', +] + +if host_machine.system() == 'darwin' + asm_deps += ['darwin.m4'] +else + asm_deps += ['arm64-defs.m4'] +endif + +asm_files = [ +%s +] + +src_dir_inc = include_directories('.') +''' + +asm_submodule_x86_broadwell = '''\ + +asm_deps = [ + '../../asm-defs.m4', + '../x86_64-defs.m4', +] + +if host_machine.system() == 'darwin' + asm_deps += ['darwin.m4'] +endif + +asm_files = [ +%s +] +''' + +asm_to_s_files = '''\ + +m4_prog = find_program('m4', native: true) + +foreach asm_file: asm_files + s_filename = fs.stem(asm_file) + '.s' + s_file = custom_target(s_filename, + input: [asm_file, config_m4] + asm_deps, + output: s_filename, + command: [m4_prog, '@INPUT0@'], + capture: true, + ) + s_files += [s_file] +endforeach +''' + + +asm_modules = [ + ('mpn_extras/arm64', asm_submodule_arm64), + ('mpn_extras/x86_64/broadwell', asm_submodule_x86_broadwell), +] + + +def get_flint_modules(flint_root): + """ + Scan the src directory and return a list of all modules. + + Also check for possible mismatches between subdirs and headers. + """ + src_path = join(flint_root, 'src') + is_mod = lambda p: isdir(join(src_path, p)) and p not in exclude_mod_dirs + subdirs = [p for p in listdir(src_path) if is_mod(p)] + headers = [p[:-2] for p in listdir(src_path) if p.endswith('.h')] + + # Check for mismatches between subdirs and headers apart from the + # known exceptions (exclude_mod_dirs, mod_no_header, head_no_dir) + extra_dirs = set(subdirs) - set(headers) - set(mod_no_header) + extra_headers = set(headers) - set(subdirs) - set(head_no_dir) - set(headers_skip) + if extra_dirs or extra_headers: + print('Mismatch between subdirs and headers in src') + print('Extra headers:\n', '\n'.join(sorted(extra_headers))) + print('Extra subdirs:\n', '\n'.join(sorted(extra_dirs))) + sys.exit(1) + missing_dirs = set(mod_no_header) - set(subdirs) + missing_headers = (set(head_no_dir) - set(headers)) + if missing_dirs or missing_headers: + print('Missing subdirs:\n', '\n'.join(sorted(missing_dirs))) + print('Missing headers:\n', '\n'.join(sorted(missing_headers))) + sys.exit(1) + + return subdirs + + +parser = ArgumentParser(description='Generate Meson build files') +parser.add_argument('-q', '--quiet', action='store_true', + help='Do not print anything') +parser.add_argument('-v', '--verbose', action='store_true', + help='Show all steps') +parser.add_argument('output_dir', default='.', help='Output directory') + + +def main(args): + args = parser.parse_args(args) + + for fname in files_to_copy: + src_path = join(this_dir, fname) + dst_path = join(args.output_dir, fname) + if not args.quiet: + print('Copying %s to %s' % (src_path, dst_path)) + copy_file(src_path, dst_path) + + modules = get_flint_modules(args.output_dir) + + # We will generate the meson.build file for conditional modules but the + # main meson.build file will decide whether to include them or not. + modules_unconditional = set(modules) - set(conditional_modules) + + # src/meson.build + src_meson_build_text = src_meson_build % ( + format_lines(modules_unconditional), + format_lines(mod_no_header), + format_lines(mod_no_tests), + format_lines(head_no_dir), + ) + dst_path = join(args.output_dir, 'src', 'meson.build') + if not args.quiet: + print('Writing %s' % dst_path) + write_file(dst_path, src_meson_build_text) + + if not args.quiet: + print('Making meson.build files in all modules') + # src/mod/meson.build + for mod in modules + mod_no_header: + mod_dir = join(args.output_dir, 'src', mod) + c_files = [f for f in listdir(mod_dir) if f.endswith('.c')] + if mod == 'fmpz': + c_files = [f for f in c_files if f != 'fmpz.c'] + src_mod_meson_build_text = src_mod_meson_build % format_lines(c_files) + dst_path = join(mod_dir, 'meson.build') + if args.verbose: + print('Writing %s' % dst_path) + write_file(dst_path, src_mod_meson_build_text) + + # src/mod/test/meson.build + if mod not in mod_no_tests: + test_dir = join(mod_dir, 'test') + test_mod_meson_build_text = test_mod_meson_build % mod + dst_path = join(test_dir, 'meson.build') + if args.verbose: + print('Writing %s' % dst_path) + write_file(dst_path, test_mod_meson_build_text) + + # Build for the NTL tests + dst_path = join(args.output_dir, 'src', 'interfaces', 'test', 'meson.build') + test_mod_meson_build_text = test_mod_NTL_meson_build % 'NTL-interface' + if args.verbose: + print('Writing %s' % dst_path) + write_file(dst_path, test_mod_meson_build_text) + + # src/mpn_extras/*/meson.build + for path, asm_submodule in asm_modules: + asm_dir = join(args.output_dir, 'src', path) + asm_files = [f for f in listdir(asm_dir) if f.endswith('.asm')] + asm_submodule_text = asm_submodule % format_lines(asm_files) + asm_submodule_text += asm_to_s_files + dst_path = join(asm_dir, 'meson.build') + if args.verbose: + print('Writing %s' % dst_path) + write_file(dst_path, asm_submodule_text) + + +def format_lines(lst): + return '\n'.join(f" '{m}'," for m in sorted(lst)) + + +def write_file(dst_path, text): + makedirs(dirname(dst_path), exist_ok=True) + with open(dst_path, 'w') as fout: + fout.write(text) + + +def copy_file(src_path, dst_path): + makedirs(dirname(dst_path), exist_ok=True) + copyfile(src_path, dst_path) + + +def same_files(src_path, dst_path): + with open(src_path, 'rb') as f: + src_content = f.read() + return same_content(src_content, dst_path) + + +def same_content(src_content, dst_path): + try: + with open(dst_path, 'rb') as f: + dst_content = f.read() + except FileNotFoundError: + return False + else: + return src_content == dst_content + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/_meson_build/include/flint/meson.build b/_meson_build/include/flint/meson.build new file mode 100644 index 0000000000..9848867438 --- /dev/null +++ b/_meson_build/include/flint/meson.build @@ -0,0 +1,62 @@ +header_install_kwargs = { + 'install_dir': get_option('includedir') / 'flint', + 'install': true, +} + +flint_h = configure_file( + input: '../../src/flint.h.in', + output: 'flint.h', + configuration: { + 'FLINT_MAJOR': FLINT_MAJOR, + 'FLINT_MINOR': FLINT_MINOR, + 'FLINT_PATCH': FLINT_PATCH, + 'FLINT_VERSION_FULL': FLINT_VERSION_FULL, + }, + kwargs: header_install_kwargs, +) + +flint_config_h = configure_file( + output: 'flint-config.h', + configuration: cfg_data, + kwargs: header_install_kwargs, +) + +config_h = configure_file( + output: 'config.h', + configuration: cfg_data_internal, + kwargs: header_install_kwargs, +) + +if gmp_long_long_limb + gmpcompat_h_in = 'gmpcompat-longlong.h.in' +else + gmpcompat_h_in = 'gmpcompat.h.in' +endif + +gmpcompat_h = fs.copyfile( + '../../src' / gmpcompat_h_in, + 'gmpcompat.h', + kwargs: header_install_kwargs, +) + +flint_mparam_h_in = '../../src/mpn_extras' / flint_mparam / 'flint-mparam.h' + +flint_mparam_h = fs.copyfile( + flint_mparam_h_in, + 'flint-mparam.h', + kwargs: header_install_kwargs, +) + +# Copy all the other headers to the build directory so you can do +# gcc -Ibuild-dir/include ... +foreach h: headers_all + fs.copyfile(h, kwargs: header_install_kwargs) +endforeach + +headers_all += [ + flint_h, + flint_config_h, + config_h, + gmpcompat_h, + flint_mparam_h, +] diff --git a/_meson_build/include/meson.build b/_meson_build/include/meson.build new file mode 100644 index 0000000000..39b83d76e8 --- /dev/null +++ b/_meson_build/include/meson.build @@ -0,0 +1,4 @@ +subdir('flint') + +headers_built_inc = include_directories('.') +headers_built_nodir_inc = include_directories('flint') diff --git a/_meson_build/meson.build b/_meson_build/meson.build new file mode 100644 index 0000000000..375a229e3c --- /dev/null +++ b/_meson_build/meson.build @@ -0,0 +1,78 @@ +project('FLINT', 'c', 'cpp', + version: '3.2.0-dev', + license: 'LGPL3+', + default_options: [ + 'buildtype=release', + 'c_std=c11', + 'cpp_std=c++11', + ], +) + +FLINT_MAJOR = meson.project_version().split('.')[0] +FLINT_MINOR = meson.project_version().split('.')[1] +FLINT_PATCH = meson.project_version().split('.')[2] +FLINT_VERSION_FULL = meson.project_version() + +cc = meson.get_compiler('c') +fs = import('fs') + +m_dep = cc.find_library('m', required: false) + +gmp_dep = dependency('gmp', version: '>= 6.2.1') +mpfr_dep = dependency('mpfr', version: '>= 4.1.0') + +flint_deps = [gmp_dep, mpfr_dep, m_dep] + +add_project_arguments( + '-Werror=implicit-function-declaration', + language: 'c', +) + +subdir('config') +subdir('src') + +if have_assembly + # Generate config.m4 with assembly language configuration + config_m4 = configure_file( + input: 'config.m4.in', + output: 'config.m4', + configuration: {'LSYM_PREFIX': LSYM_PREFIX}, + ) + + s_files = [] + subdir('src' / assembly_dir) + c_files_all += s_files +endif + +# Build include directory after list of all source files is complete +subdir('include') + +libflint = library('flint', c_files_all, + dependencies: flint_deps, + include_directories: [headers_built_nodir_inc, 'src'], + install: true, + c_args: [ + '-DBUILDING_FLINT', + '-DFLINT_NOSTDIO', + '-DFLINT_NOSTDARG', + ] +) + +tests_opt = get_option('tests') +if tests_opt.enabled() + foreach mod_test : mod_tests + subdir('src' / mod_test) + endforeach +else + bad_test_exe = executable('bad_test', '_meson_build/bad_test.c') + test('Need to build tests with -Dtests=enabled', bad_test_exe) +endif + +pkg_mod = import('pkgconfig') +pkg_mod.generate( + libraries: libflint, + version : '3.1.0', + name: 'flint', + filebase: 'flint', + description: 'Fast Library for Number Theory' +) diff --git a/_meson_build/meson.options b/_meson_build/meson.options new file mode 100644 index 0000000000..dbaa7eaaaf --- /dev/null +++ b/_meson_build/meson.options @@ -0,0 +1,38 @@ +option('tests', type : 'feature', value : 'disabled', + description: 'Build the tests') +option('libtool_lock', type : 'feature', value : 'enabled', + description: 'Use libtool lock') +option('pthread', type : 'feature', value : 'enabled', + description: 'Use pthread') +option('reentrant', type : 'feature', value : 'disabled', + description: 'Build the reentrant module') +option('thread_safe', type : 'feature', value : 'enabled', + description: 'Build the threadsafe module') +option('assert', type : 'feature', value : 'disabled', + description: 'Enable assertions') +option('pretty_tests', type : 'feature', value : 'enabled', + description: 'Pretty print test output') +option('gmp_internals', type : 'feature', value : 'auto', + description: 'Use GMP internals') +option('assembly', type : 'feature', value : 'auto', + description: 'Use assembly code') +option('avx2', type : 'feature', value : 'disabled', + description: 'Use AVX2 instructions') +option('avx512', type : 'feature', value : 'disabled', + description: 'Use AVX512 instructions') +option('fft_small', type : 'feature', value : 'auto', + description: 'Build the fft_small module') +option('blas', type : 'feature', value : 'disabled', + description: 'Use BLAS') +option('gc', type : 'feature', value : 'disabled', + description: 'Use the Boehm garbage collector') +option('ntl', type : 'feature', value : 'disabled', + description: 'Use NTL (in tests)') +# Not included from original configure: +# coverage -Db_coverage=true +# debug +# dependency_tracking +# with-pic +# with-aix-soname +# with-gnu-ld +# with-sysroot diff --git a/config/meson.build b/config/meson.build new file mode 100644 index 0000000000..7a2a644ea8 --- /dev/null +++ b/config/meson.build @@ -0,0 +1,783 @@ +# ----------------------------------------------------------------------------- +# FLINT configuration +# ----------------------------------------------------------------------------- + +# Data set on cfg_data is used to generate flint-config.h +# Data set on cfg_data_internal (below) is also used to generate config.h +cfg_data = configuration_data() + +# ----------------------------------------------------------------------------- +# Project options +# ----------------------------------------------------------------------------- + +libtool_lock_opt = get_option('libtool_lock') +pthread_opt = get_option('pthread') +reentrant_opt = get_option('reentrant') +thread_safe_opt = get_option('thread_safe') +assert_opt = get_option('assert') +pretty_tests_opt = get_option('pretty_tests') +gmp_internals_opt = get_option('gmp_internals') +assembly_opt = get_option('assembly') +avx2_opt = get_option('avx2') +avx512_opt = get_option('avx512') +fft_small_opt = get_option('fft_small') +blas_opt = get_option('blas') +gc_opt = get_option('gc') +ntl_opt = get_option('ntl') +coverage_opt = get_option('b_coverage') + +# ----------------------------------------------------------------------------- +# Unsupported options +# ----------------------------------------------------------------------------- + +if avx2_opt.enabled() + error('AVX2 support is not yet implemented') +elif avx512_opt.enabled() + error('AVX512 support is not yet implemented') +elif blas_opt.enabled() + error('BLAS support is not yet implemented') +elif gc_opt.enabled() + error('Garbage collection is not yet implemented') +endif + +# ----------------------------------------------------------------------------- +# fmpz memory management +# ----------------------------------------------------------------------------- + +if gc_opt.allowed() + if thread_safe_opt.allowed() + error('Garbage collection is not thread safe') + else + fmpz_c_in = 'fmpz_gc.c' + endif +else + if reentrant_opt.enabled() + fmpz_c_in = 'fmpz_reentrant.c' + else + fmpz_c_in = 'fmpz_single.c' + endif +endif + +# ----------------------------------------------------------------------------- +# libm +# ----------------------------------------------------------------------------- + +if not cc.has_function('atan2', dependencies: m_dep) + error('libm is required') +endif + +# ----------------------------------------------------------------------------- +# GMP +# ----------------------------------------------------------------------------- + +gmp_long_long_limb = cc.compiles(''' +#include <gmp.h> +#if !defined(_LONG_LONG_LIMB) +# error mp_limb_t != unsigned long long int +#endif +''') + +# We need to check with cc.links rather than cc.has_function etc because we +# are checking if we can link symbols not in the headers. + +gmp_test_code = ''' +#include <gmp.h> + +@0@ + +int main() { + @1@ + return 0; +} +''' + +gmp_base_tests = { + 'mpz_init': ['', 'mpz_t x; __gmpz_init(x);'], + 'mpn_mul_basecase': [ + 'void __gmpn_mul_basecase(mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);', + 'mp_limb_t a[2], b[2], p[4]; __gmpn_mul_basecase(p, a, (mp_size_t) 1, b, (mp_size_t) 1);', + ], +} + +foreach name, snippets : gmp_base_tests + _code = gmp_test_code.format(snippets[0], snippets[1]) + if not cc.links(_code, dependencies: gmp_dep, name: name + ' links') + message('This code did not link with -lgmp: ', _code) + error('GMP does not have ' + name) + endif +endforeach + +if gmp_internals_opt.allowed() + + gmp_internals_required = { + 'mpn_gcd_11': ['', 'mp_limb_t res, a=0, b=0; res = __gmpn_gcd_11(a, b);'], + 'mpn_div_q': [ + 'void __gmpn_div_q(mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);', + 'mp_limb_t q[2], n[2], d[2], t[2]; __gmpn_div_q(q, t, (mp_size_t) 1, n, (mp_size_t) 1, d);' + ], + } + + foreach name, snippets : gmp_internals_required + _code = gmp_test_code.format(snippets[0], snippets[1]) + if not cc.links(_code, dependencies: gmp_dep, name: name + ' links') + message('This code did not link with -lgmp: ', _code) + # Maybe disable gmp_internals rather than error? + error('GMP does not have ' + name) + endif + endforeach + + gmp_internals_optional = { + 'mpn_add_n_sub_n': [ + 'void __gmpn_add_n_sub_n(mp_ptr, mp_ptr, mp_ptr, mp_size_t);', + 'mp_limb_t a[2], b[2], c[2], d[2]; __gmpn_add_n_sub_n(a, b, c, (mp_size_t) 1);', + ], + 'mpn_add_nc': [ + 'mp_limb_t __gmpn_add_nc(mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2], b[2]; __gmpn_add_nc(a, b, (mp_size_t) 1, (mp_limb_t) 0);', + ], + 'mpn_addlsh1_n': [ + 'mp_limb_t __gmpn_addlsh1_n(mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2], b[2]; __gmpn_addlsh1_n(a, b, (mp_size_t) 1, (mp_limb_t) 0);', + ], + 'mpn_addlsh1_n_ip1': [ + 'mp_limb_t __gmpn_addlsh1_n_ip1(mp_ptr, mp_srcptr, mp_size_t);', + 'mp_limb_t a[2], b[2]; __gmpn_addlsh1_n_ip1(a, b, (mp_size_t) 1);', + ], + 'mpn_addmul_2': [ + 'void __gmpn_addmul_2(mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2], b[2]; __gmpn_addmul_2(a, b, (mp_size_t) 1, (mp_limb_t) 0);', + ], + 'mpn_modexact_1_odd': [ + 'mp_limb_t __gmpn_modexact_1_odd(mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2]; __gmpn_modexact_1_odd(a, (mp_size_t) 1, (mp_limb_t) 0);', + ], + 'mpn_rsh1add_n': [ + 'mp_limb_t __gmpn_rsh1add_n(mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2], b[2]; __gmpn_rsh1add_n(a, b, (mp_size_t) 1, (mp_limb_t) 0);', + ], + 'mpn_rsh1sub_n': [ + 'mp_limb_t __gmpn_rsh1sub_n(mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2], b[2]; __gmpn_rsh1sub_n(a, b, (mp_size_t) 1, (mp_limb_t) 0);', + ], + 'mpn_sub_nc': [ + 'mp_limb_t __gmpn_sub_nc(mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);', + 'mp_limb_t a[2], b[2]; __gmpn_sub_nc(a, b, (mp_size_t) 1, (mp_limb_t) 0);', + ], + } + + foreach name, snippets : gmp_internals_optional + _code = gmp_test_code.format(snippets[0], snippets[1]) + if cc.links(_code, dependencies: gmp_dep, name: name + ' links') + cfg_data.set('FLINT_HAVE_NATIVE_' + name, 1, + description: 'Define if GMP has ' + name) + endif + endforeach + +endif + +# ----------------------------------------------------------------------------- +# CPU detection +# ----------------------------------------------------------------------------- + +# We check here for gcc or clang because the config.guess script probably does +# not work for other compilers. This check will also allow MinGW and cygwin on +# Windows but not MSVC. + +# The config.guess script inspects the current CPU so should not be used for a +# cross build. Maybe there should be a way to configure the exact CPU as a +# project build option. + +if not meson.is_cross_build() and cc.get_id() in ['gcc', 'clang'] + config_guess_result = run_command('./config.guess', check: true) + target_triple = config_guess_result.stdout().strip() + exact_cpu = target_triple.split('-')[0] +else + # This could be 'aarch64' or 'x86_64' + # https://mesonbuild.com/Reference-tables.html#cpu-families + exact_cpu = host_machine.cpu_family() +endif + +message('EXACT CPU:', exact_cpu) + +################################################################################ +# architecture specifics +################################################################################ + +gcc_cflags = '-O3 -pedantic -std=c11' +gcc_warnings = '-Werror=implicit-function-declaration -Wall -Wno-stringop-overread -Wno-stringop-overflow' + +# We only try to provide specifics for those systems that currently supports +# our assembly routines. If more combinations are wished for than what is +# specified, please open up an issue at +# <https://github.com/flintlib/flint/issues/> and we will consider it. +# +# For these systems we aim to provide: +# +# gcc_cflags flags for GCC-compatible compilers +# +# asm_path directory for assembly, relative to src/mpn_extras +# param_path directory for flint-mparam.h, relative to src/mpn_extras +# +# For x86_64 systems, we can also set: +# +# have_avx512 system has AVX512F and AVX512DQ (we assume this implies have_avx2) +# have_avx2 system has AVX2 and FMA + +# x86_64 CPUs that have AVX2: +X86_64_ADX_CPU_NAMES = [ + 'zen1', + 'zen2', + 'zen3', + 'zen4', + 'coreibwl', + 'broadwell', + 'skylake', + 'skylake_server', + 'cannonlake', + 'kabylake', + 'icelake', + 'icelake_server', + 'rocketlake', + 'tigerlake', + 'alderlake', + 'raptorlake', + 'knightslanding', + 'sapphirerapids', + 'cometlake', +] + +if host_machine.cpu_family() == 'aarch64' + + gcc_cflags = gcc_cflags + gcc_cflags_optlist = 'arch tune' + asm_path = 'arm64' + param_path = 'arm64' + flint_cv_have_fft_small_arm_i = 'yes' + flint_know_strong_order = 'no' + + # NOTE: Cortex values where taken from + # https://developer.arm.com/Processors/Cortex-XXX + + if exact_cpu in ['armcortexa35', 'armcortexa35neon'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=cortex-a35' + + elif exact_cpu in ['armcortexa53', 'armcortexa53neon'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=cortex-a53' + + elif exact_cpu in ['armcortexa55', 'armcortexa55neon'] + gcc_cflags_arch = '-march=armv8.2-a' + gcc_cflags_tune = '-mtune=cortex-a55' + + elif exact_cpu in ['armcortexa57', 'armcortexa57neon'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=cortex-a57' + + elif exact_cpu in ['armcortexa72', 'armcortexa72neon'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=cortex-a72' + + elif exact_cpu in ['armcortexa73', 'armcortexa73neon'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=cortex-a73' + + elif exact_cpu in ['armcortexa75', 'armcortexa75neon'] + gcc_cflags_arch = '-march=armv8.2-a' + gcc_cflags_tune = '-mtune=cortex-a75' + + elif exact_cpu in ['armcortexa76', 'armcortexa76neon'] + gcc_cflags_arch = '-march=armv8.2-a' + gcc_cflags_tune = '-mtune=cortex-a76' + + elif exact_cpu in ['armcortexa77', 'armcortexa77neon'] + gcc_cflags_arch = '-march=armv8.2-a' + gcc_cflags_tune = '-mtune=cortex-a77' + + elif exact_cpu in ['armcortexa65', 'armcortexa65neon'] + gcc_cflags_arch = '-march=armv8.2-a' + gcc_cflags_tune = '-mtune=cortex-a65' + + elif exact_cpu in ['armcortexa34', 'armcortexa34neon'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=cortex-a34' + + elif exact_cpu in ['armcortexa78', 'armcortexa78neon'] + gcc_cflags_arch = '-march=armv8.2-a' + gcc_cflags_tune = '-mtune=cortex-a78' + + elif exact_cpu in ['armexynosm1'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=exynos-m1' + + elif exact_cpu in ['armthunderx'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=thunderx' + + elif exact_cpu in ['armxgene1'] + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '-mtune=xgene1' + + elif exact_cpu.startswith('applem1') + gcc_cflags_arch = '-march=armv8.5-a' + gcc_cflags_tune = '' + + elif exact_cpu.startswith('applem2') + gcc_cflags_arch = '-march=armv8.6-a' + gcc_cflags_tune = '' + + elif exact_cpu.startswith('applem3') + gcc_cflags_arch = '-march=armv8.6-a' + gcc_cflags_tune = '' + + elif exact_cpu.startswith('aarch64') or exact_cpu.startswith('armv8') + gcc_cflags_arch = '-march=armv8-a' + gcc_cflags_tune = '' + + else + error_msg = ''' + Error in deciding flags for @0@. + Please report at <https://github.com/flintlib/flint/issues/> + ''' + error(error_msg.format(exact_cpu)) + + endif + +elif host_machine.cpu_family() == 'x86_64' and exact_cpu in X86_64_ADX_CPU_NAMES + + gcc_cflags = gcc_cflags + gcc_cflags_optlist = 'arch' + asm_path = 'x86_64/broadwell' + param_path = 'x86_64/broadwell' + + have_avx512 = 'no' + have_avx2 = 'yes' + flint_cv_have_fft_small_x86_i = 'yes' + flint_know_strong_order = 'yes' + + if exact_cpu == 'zen' + gcc_cflags_arch = '-march=znver1' + param_path = 'x86_64/zen3' + + elif exact_cpu == 'zen2' + gcc_cflags_arch = '-march=znver2' + param_path = 'x86_64/zen3' + + elif exact_cpu == 'zen3' + gcc_cflags_arch = '-march=znver3' + param_path = 'x86_64/zen3' + + elif exact_cpu == 'zen4' + gcc_cflags_arch = '-march=znver4' + param_path = 'x86_64/zen3' + have_avx512 = 'yes' + + elif exact_cpu in ['coreibwl', 'broadwell'] + gcc_cflags_arch = '-march=broadwell' + param_path = 'x86_64/skylake' + + elif exact_cpu == 'skylake' + gcc_cflags_arch = '-march=skylake' + param_path = 'x86_64/skylake' + + elif exact_cpu == 'skylake_server' + gcc_cflags_arch = '-march=skylake-avx512' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'cannonlake' + gcc_cflags_arch = '-march=cannonlake' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'kabylake' + gcc_cflags_arch = '-march=skylake' + param_path = 'x86_64/skylake' + + elif exact_cpu == 'icelake' + gcc_cflags_arch = '-march=icelake-client' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'icelake_server' + gcc_cflags_arch = '-march=icelake-server' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'rocketlake' + gcc_cflags_arch = '-march=rocketlake' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'tigerlake' + gcc_cflags_arch = '-march=tigerlake' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'alderlake' + gcc_cflags_arch = '-march=alderlake' + param_path = 'x86_64/skylake' + + elif exact_cpu == 'raptorlake' + gcc_cflags_arch = '-march=alderlake' + param_path = 'x86_64/skylake' + + elif exact_cpu == 'knightslanding' + gcc_cflags_arch = '-march=knl' + param_path = 'x86_64/skylake' + + elif exact_cpu == 'sapphirerapids' + gcc_cflags_arch = '-march=sapphirerapids' + param_path = 'x86_64/skylake' + have_avx512 = 'yes' + + elif exact_cpu == 'cometlake' + gcc_cflags_arch = '-march=kabylake' + param_path = 'x86_64/skylake' + + else + error_msg = ''' + Error in deciding flags for @0@. + Please report at <https://github.com/flintlib/flint/issues/> + ''' + error(error_msg.format(exact_cpu)) + + endif + + # Disable assembly on Windows + if host_machine.system() == 'windows' + flint_nonstd_abi = 'yes' + asm_path = '' + param_path = 'x86_64' + endif + +elif host_machine.cpu_family() == 'x86_64' + + # NOTE: We do not care if the user specifies noavx! + gcc_cflags = '$gcc_cflags' + gcc_cflags_optlist = 'arch' + asm_path = '' + param_path = 'x86_64' + + have_avx512 = 'no' + have_avx2 = 'no' + flint_know_strong_order = 'yes' + + if exact_cpu in ['coreiibr', 'ivybridge'] + gcc_cflags_arch = '-march=ivybridge' + + elif exact_cpu in ['coreihwl', 'haswell'] + gcc_cflags_arch = '-march=haswell' + + elif exact_cpu in ['piledriver', 'bd2'] + gcc_cflags_arch = '-march=bdver2' + + elif exact_cpu in ['steamroller', 'bd3'] + gcc_cflags_arch = '-march=bdver3' + + elif exact_cpu in ['excavator', 'bd4'] + gcc_cflags_arch = '-march=bdver4' + have_avx2 = 'yes' + + elif exact_cpu in ['x86_64v3'] + gcc_cflags_arch = '-march=x86-64-v3' + have_avx2 = 'yes' + + elif exact_cpu in ['x86_64v4'] + gcc_cflags_arch = '-march=x86-64-v4' + have_avx512 = 'yes' + + else + flint_know_strong_order = 'no' + + endif + + if have_avx512 == 'yes' + have_avx2 = 'yes' + endif + + if have_avx2 == 'yes' + flint_cv_have_fft_small_x86_i = 'yes' + else + flint_cv_have_fft_small_x86_i = 'no' + endif + +else + # Generic case for unrecognised CPU + asm_path = '' + param_path = 'generic' + gcc_cflags = gcc_cflags + + have_avx512 = 'no' + have_avx2 = 'no' + flint_cv_have_fft_small_x86_i = 'no' + flint_know_strong_order = 'no' + +endif + +# ----------------------------------------------------------------------------- +# mparam +# ----------------------------------------------------------------------------- + +flint_mparam = param_path + +# ----------------------------------------------------------------------------- +# fft_small +# ----------------------------------------------------------------------------- + +fft_small_opt = get_option('fft_small') + +fft_small_arm_code = ''' +#include <arm_neon.h> +#if !(defined(__GNUC__) && defined(__ARM_NEON)) +# if !(defined(_MSC_VER) && defined(_M_ARM64)) +# error +error +# endif +#endif +int main(){return 0;} +''' + +fft_small_x86_code = ''' +#if defined(__GNUC__) +# include <x86intrin.h> +#elif defined(_MSC_VER) +# include <intrin.h> +#else +# error +error +#endif + +#if !defined(__AVX2__) +# error +error +#endif +int main(){return 0;} +''' + +if host_machine.cpu_family() == 'aarch64' + fft_small_supported = ( + flint_cv_have_fft_small_arm_i == 'yes' + and cc.compiles(fft_small_arm_code, dependencies: gmp_dep) + ) +else + fft_small_supported = ( + flint_cv_have_fft_small_x86_i == 'yes' + and cc.compiles(fft_small_x86_code, dependencies: gmp_dep) + ) +endif + +# Error if fft_small enabled but not possible, otherwise disable if auto +fft_small_opt = fft_small_opt.require(fft_small_supported, + error_message: 'host CPU does not support AVX/NEON. Set fft_small to disabled or auto') + +# If fft_small was auto we enable it if possible +fft_small_opt = fft_small_opt.enable_auto_if(fft_small_supported) +have_fft_small = fft_small_opt.enabled() + +message('FFT_SMALL: ', have_fft_small ? 'enabled' : 'disabled') + +# ----------------------------------------------------------------------------- +# Assembly +# ----------------------------------------------------------------------------- + +if asm_path != '' + assembly_cpu_supported = true + assembly_dir = 'mpn_extras/' + asm_path + if host_machine.cpu_family() == 'aarch64' + FLINT_HAVE_ASSEMBLY = 'armv8' + elif host_machine.cpu_family() == 'x86_64' + FLINT_HAVE_ASSEMBLY = 'x86_64_adx' + else + error('Assembly only supported for x86_64 or aarch64') + endif +else + assembly_cpu_supported = false + FLINT_HAVE_ASSEMBLY = '' +endif + +assembly_opt = assembly_opt.require(host_machine.system() != 'windows', + error_message: 'No assembly support for Windows') + +assembly_opt = assembly_opt.require(assembly_cpu_supported, + error_message: 'No assembly support for host CPU') + +assembly_opt = assembly_opt.enable_auto_if(true) +have_assembly = assembly_opt.enabled() + +message('ASSEMBLY: ', have_assembly ? 'enabled' : 'disabled') + +# XXX: Need better detection of ASM language support +if have_assembly + LSYM_PREFIX = 'L' +endif + +# ----------------------------------------------------------------------------- +# cpu_set_t support +# ----------------------------------------------------------------------------- + +have_cpu_set_t = cc.compiles(''' +#define _GNU_SOURCE +#include <sched.h> +#include <pthread.h> + +int main() { + cpu_set_t s; + CPU_ZERO(&s); + pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &s); + return 0; +} +''') + +# ----------------------------------------------------------------------------- +# external configuration for flint_config.h +# ----------------------------------------------------------------------------- + +if host_machine.endian() == 'big' + cfg_data.set('FLINT_BIG_ENDIAN', 1, + description: 'Define if system is big endian.') +endif + +if have_assembly and FLINT_HAVE_ASSEMBLY == 'armv8' + cfg_data.set('FLINT_HAVE_ASSEMBLY_armv8', 1, + description: 'Define if Arm v8 assembly is available') +elif have_assembly and FLINT_HAVE_ASSEMBLY == 'x86_64_adx' + cfg_data.set('FLINT_HAVE_ASSEMBLY_x86_64_adx', 1, + description: 'Define if x86_64 ADX assembly is available') +endif + +if have_fft_small + cfg_data.set('FLINT_HAVE_FFT_SMALL', 1, + description: 'Define to use the fft_small module') +endif + +if flint_know_strong_order == 'yes' + cfg_data.set('FLINT_KNOW_STRONG_ORDER', 1, + description: 'Define if system is strongly ordered') +endif + +if reentrant_opt.enabled() + cfg_data.set('FLINT_REENTRANT', 1, + description: 'Define to enable reentrant.') +endif + +cfg_data.set('FLINT_UNROLL_LOOPS', 1, + description: 'Define to locally unroll some loops') + +if blas_opt.enabled() + cfg_data.set('FLINT_USES_BLAS', 1, + description: 'Define to enable BLAS.') +endif + +if have_cpu_set_t + cfg_data.set('FLINT_USES_CPUSET', 1, + description: 'Define if system has cpu_set_t') +endif + +if gc_opt.enabled() + cfg_data.set('FLINT_USES_GC', 1, + description: 'Define to enable the Boehm-Demers-Weise garbage collector.') +endif + +if pthread_opt.enabled() + cfg_data.set('FLINT_USES_PTHREAD', 1, + description: 'Define to enable the use of pthread.') +endif + +if thread_safe_opt.enabled() + cfg_data.set('FLINT_USES_TLS', 1, + description: 'Define to enable thread-local storage.') +endif + +if assert_opt.enabled() + cfg_data.set('FLINT_WANT_ASSERT', 1, + description: 'Define to enable use of asserts.') +endif + +if gmp_internals_opt.allowed() + cfg_data.set('FLINT_WANT_GMP_INTERNALS', 1, + description: 'Define to enable use of GMP internals.') +endif + +if pretty_tests_opt.enabled() + cfg_data.set('FLINT_WANT_PRETTY_TESTS', 1, + description: 'Define to enable pretty printing for tests.') +endif + +# ----------------------------------------------------------------------------- +# internal configuration for config.h +# ----------------------------------------------------------------------------- + +cfg_data_internal = cfg_data + +#cfg_data_internal.set('AC_APPLE_UNIVERSAL_BUILD', 1) + +if coverage_opt + cfg_data_internal.set('FLINT_COVERAGE', 1) +endif + +if cc.has_header_symbol('stdlib.h', 'aligned_alloc') + cfg_data_internal.set('HAVE_ALIGNED_ALLOC', 1, + description: 'Define to 1 if you have the \'aligned_alloc\' function.') +endif + +ac_headers_check = [ + 'alloca.h', + 'arm_neon.h', + 'dlfcn.h', + 'errno.h', + 'fenv.h', + 'float.h', + 'immintrin.h', # XXX: has_header is not equivalent to autotools check... + 'inttypes.h', + 'malloc.h', + 'math.h', + 'pthread_np.h', + 'stdarg.h', + 'stdint.h', + 'stdio.h', + 'stdlib.h', + 'string.h', + 'strings.h', + 'sys/param.h', + 'sys/stat.h', + 'sys/types.h', + 'unistd.h', + 'windows.h', +] + +foreach h : ac_headers_check + if cc.has_header(h) + cfg_data_internal.set('HAVE_' + h.underscorify().to_upper(), 1, + description: f'Define to 1 if you have the <@h@> header file.') + endif +endforeach + +# XXX: Do we need to check for _alligned_malloc? + +# XXX: Need better checking for LSYM_PREFIX and related assembly options +cfg_data_internal.set_quoted('LSYM_PREFIX', 'L', + description: 'Assembler local label prefix') + +cfg_data_internal.set_quoted('LT_OBJDIR', '.libs/', + description: 'Define to the sub-directory where libtool stores uninstalled libraries.') +cfg_data_internal.set_quoted('PACKAGE_BUGREPORT', + 'https://github.com/flintlib/flint/issues/', + description: 'Define to the address where bug reports for this package should be sent.') +cfg_data_internal.set_quoted('PACKAGE_NAME', 'FLINT', + description: 'Define to the full name of this package.') +cfg_data_internal.set_quoted('PACKAGE_STRING', 'FLINT ' + FLINT_VERSION_FULL, + description: 'Define to the full name and version of this package.') +cfg_data_internal.set_quoted('PACKAGE_TARNAME', 'flint', + description: 'Define to the one symbol short name of this package.') +cfg_data_internal.set_quoted('PACKAGE_URL', 'https://flintlib.org/', + description: 'Define to the home page for this package.') +cfg_data_internal.set_quoted('PACKAGE_VERSION', FLINT_VERSION_FULL, + description: 'Define to the version of this package.') + +cfg_data_internal.set('STDC_HEADERS', 1, + description: '''Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it.''') + +# XXX: set WORDS_BIGENDIAN or undef inline here? diff --git a/meson_bootstrap.py b/meson_bootstrap.py new file mode 100755 index 0000000000..e610fdc18a --- /dev/null +++ b/meson_bootstrap.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +from os.path import join, dirname, abspath +from sys import executable as python, argv +from subprocess import check_call + +this_dir = dirname(abspath(__file__)) +meson_build_dir = join(this_dir, '_meson_build') +generate_script = join(meson_build_dir, 'generate_meson_build.py') +check_call([python, generate_script, this_dir] + argv[1:])