From 52f23f8c34bd9f6eacd31e8dff70066ca2aeb4e1 Mon Sep 17 00:00:00 2001 From: Haakon Sporsheim Date: Thu, 9 Mar 2017 14:25:24 +0100 Subject: [PATCH 1/4] compiler: Add compute_int functionality. Fixes #435 --- mesonbuild/compilers.py | 28 +++++++++++++++ mesonbuild/interpreter.py | 15 ++++++++ test cases/common/139 compute int/config.h.in | 2 ++ test cases/common/139 compute int/foobar.h | 6 ++++ test cases/common/139 compute int/meson.build | 35 +++++++++++++++++++ test cases/common/139 compute int/prog.c.in | 16 +++++++++ 6 files changed, 102 insertions(+) create mode 100644 test cases/common/139 compute int/config.h.in create mode 100644 test cases/common/139 compute int/foobar.h create mode 100644 test cases/common/139 compute int/meson.build create mode 100644 test cases/common/139 compute int/prog.c.in diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 8c2bb9272..d1a564b39 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -1010,6 +1010,34 @@ class CCompiler(Compiler): return i raise EnvironmentException('Cross-compile check overflowed') + def cross_compute_int(self, fragment, prefix, env, extra_args=None, dependencies=None): + if extra_args is None: + extra_args = [] + fargs = {'prefix': prefix, 'fragment': fragment} + t = '''#include + {prefix} + int temparray[{size}-({fragment})];''' + return self._bisect_compiles(t, fargs, env, extra_args, dependencies) + + def compute_int(self, fragment, prefix, env, extra_args=None, dependencies=None): + if extra_args is None: + extra_args = [] + fargs = {'prefix': prefix, 'fragment': fragment} + if self.is_cross: + return self.cross_compute_int(fragment, prefix, env, extra_args, dependencies) + t = '''#include + {prefix} + int main(int argc, char **argv) {{ + printf("%ld\\n", (long)({fragment})); + return 0; + }};''' + res = self.run(t.format(**fargs), env, extra_args, dependencies) + if not res.compiled: + return -1 + if res.returncode != 0: + raise EnvironmentException('Could not run compute_int test binary.') + return int(res.stdout) + def cross_sizeof(self, element, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 07b5c4074..dca7934da 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -631,6 +631,7 @@ class CompilerHolder(InterpreterObject): self.methods.update({'compiles': self.compiles_method, 'links': self.links_method, 'get_id': self.get_id_method, + 'compute_int': self.compute_int_method, 'sizeof': self.sizeof_method, 'has_header': self.has_header_method, 'has_header_symbol': self.has_header_symbol_method, @@ -822,6 +823,20 @@ class CompilerHolder(InterpreterObject): mlog.log('Checking for type "', mlog.bold(typename), '": ', hadtxt, sep='') return had + def compute_int_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('Compute_int takes exactly one argument.') + check_stringlist(args) + fragment = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of compute_int must be a string.') + extra_args = self.determine_args(kwargs) + deps = self.determine_dependencies(kwargs) + res = self.compiler.compute_int(fragment, prefix, self.environment, extra_args, deps) + mlog.log('Computing int of "%s": %d' % (fragment, res)) + return res + def sizeof_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Sizeof takes exactly one argument.') diff --git a/test cases/common/139 compute int/config.h.in b/test cases/common/139 compute int/config.h.in new file mode 100644 index 000000000..ad8d07720 --- /dev/null +++ b/test cases/common/139 compute int/config.h.in @@ -0,0 +1,2 @@ +#define INTSIZE @INTSIZE@ +#define FOOBAR_IN_CONFIG_H @FOOBAR@ diff --git a/test cases/common/139 compute int/foobar.h b/test cases/common/139 compute int/foobar.h new file mode 100644 index 000000000..fd3cb5ea6 --- /dev/null +++ b/test cases/common/139 compute int/foobar.h @@ -0,0 +1,6 @@ +#ifndef __FOOBAR_H__ +#define __FOOBAR_H__ + +#define FOOBAR_IN_FOOBAR_H 10 + +#endif /*__FOOBAR_H__*/ diff --git a/test cases/common/139 compute int/meson.build b/test cases/common/139 compute int/meson.build new file mode 100644 index 000000000..6f813c5e3 --- /dev/null +++ b/test cases/common/139 compute int/meson.build @@ -0,0 +1,35 @@ +project('compute int', 'c', 'cpp') + +inc = include_directories('.') + +# Test with C +cc = meson.get_compiler('c') + +intsize = cc.compute_int('sizeof(int)') +foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc) + +cd = configuration_data() +cd.set('INTSIZE', intsize) +cd.set('FOOBAR', foobar) +cd.set('CONFIG', 'config.h') +configure_file(input : 'config.h.in', output : 'config.h', configuration : cd) +s = configure_file(input : 'prog.c.in', output : 'prog.c', configuration : cd) + +e = executable('prog', s) +test('compute int test', e) + +# Test with C++ +cpp = meson.get_compiler('cpp') + +intsize = cpp.compute_int('sizeof(int)') +foobar = cpp.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc) + +cdpp = configuration_data() +cdpp.set('INTSIZE', intsize) +cdpp.set('FOOBAR', foobar) +cdpp.set('CONFIG', 'config.hpp') +configure_file(input : 'config.h.in', output : 'config.hpp', configuration : cdpp) +spp = configure_file(input : 'prog.c.in', output : 'prog.cc', configuration : cdpp) + +epp = executable('progpp', spp) +test('compute int test c++', epp) diff --git a/test cases/common/139 compute int/prog.c.in b/test cases/common/139 compute int/prog.c.in new file mode 100644 index 000000000..3ff14637f --- /dev/null +++ b/test cases/common/139 compute int/prog.c.in @@ -0,0 +1,16 @@ +#include "@CONFIG@" +#include +#include +#include "foobar.h" + +int main(int argc, char **argv) { + if(INTSIZE != sizeof(int)) { + fprintf(stderr, "Mismatch: computed int size %d, actual size %d.\n", INTSIZE, (int)sizeof(int)); + return 1; + } + if(FOOBAR_IN_CONFIG_H != FOOBAR_IN_FOOBAR_H) { + fprintf(stderr, "Mismatch: computed int %d, should be %d.\n", FOOBAR_IN_CONFIG_H, FOOBAR_IN_FOOBAR_H); + return 1; + } + return 0; +} From 1e2c914b3c508e1749890be85867e1f51336ece1 Mon Sep 17 00:00:00 2001 From: Haakon Sporsheim Date: Fri, 10 Mar 2017 11:40:48 +0100 Subject: [PATCH 2/4] compiler: Fix compute_int and sizeof for cross compilation. sizeof now uses compute_int which again binary searches for correct value. --- mesonbuild/compilers.py | 60 ++++++++++--------- mesonbuild/interpreter.py | 15 ++++- test cases/common/139 compute int/meson.build | 2 +- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index d1a564b39..403dda153 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -998,37 +998,43 @@ class CCompiler(Compiler): mlog.debug(se) return RunResult(True, pe.returncode, so, se) - def _bisect_compiles(self, t, fargs, env, extra_args, dependencies): - # FIXME: Does not actually do bisection right now - for i in range(1, 1024): - fargs['size'] = i - if self.compiles(t.format(**fargs), env, extra_args, dependencies): - if self.id == 'msvc': - # MSVC refuses to construct an array of zero size, so - # the test only succeeds when i is sizeof(element) + 1 - return i - 1 - return i - raise EnvironmentException('Cross-compile check overflowed') - - def cross_compute_int(self, fragment, prefix, env, extra_args=None, dependencies=None): - if extra_args is None: - extra_args = [] - fargs = {'prefix': prefix, 'fragment': fragment} + def _compile_int(self, expression, prefix, env, extra_args, dependencies): + fargs = {'prefix': prefix, 'expression': expression} t = '''#include {prefix} - int temparray[{size}-({fragment})];''' - return self._bisect_compiles(t, fargs, env, extra_args, dependencies) + int main() {{ static int a[1-2*!({expression})]; a[0]=0; return 0; }}''' + return self.compiles(t.format(**fargs), env, extra_args, dependencies) + + def cross_compute_int(self, expression, l, h, guess, prefix, env, extra_args, dependencies): + if isinstance(guess, int): + if self._compile_int('%s == %d' % (expression, guess), prefix, env, extra_args, dependencies): + return guess - def compute_int(self, fragment, prefix, env, extra_args=None, dependencies=None): + cur = l + while l < h: + cur = int((l + h) / 2) + if cur == l: + break + + if self._compile_int('%s >= %d' % (expression, cur), prefix, env, extra_args, dependencies): + l = cur + else: + h = cur + + if self._compile_int('%s == %d' % (expression, cur), prefix, env, extra_args, dependencies): + return cur + raise EnvironmentException('Cross-compile check overflowed') + + def compute_int(self, expression, l, h, guess, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] - fargs = {'prefix': prefix, 'fragment': fragment} if self.is_cross: - return self.cross_compute_int(fragment, prefix, env, extra_args, dependencies) + return self.cross_compute_int(expression, l, h, guess, prefix, env, extra_args, dependencies) + fargs = {'prefix': prefix, 'expression': expression} t = '''#include {prefix} int main(int argc, char **argv) {{ - printf("%ld\\n", (long)({fragment})); + printf("%ld\\n", (long)({expression})); return 0; }};''' res = self.run(t.format(**fargs), env, extra_args, dependencies) @@ -1049,10 +1055,7 @@ class CCompiler(Compiler): }}''' if not self.compiles(t.format(**fargs), env, extra_args, dependencies): return -1 - t = '''#include - {prefix} - int temparray[{size}-sizeof({name})];''' - return self._bisect_compiles(t, fargs, env, extra_args, dependencies) + return self.cross_compute_int('sizeof(%s)' % element, 1, 128, None, prefix, env, extra_args, dependencies) def sizeof(self, element, prefix, env, extra_args=None, dependencies=None): if extra_args is None: @@ -1087,9 +1090,8 @@ class CCompiler(Compiler): struct tmp {{ char c; {type} target; - }}; - int testarray[{size}-offsetof(struct tmp, target)];''' - return self._bisect_compiles(t, fargs, env, extra_args, dependencies) + }};''' + return self.cross_compute_int('offsetof(struct tmp, target)', 1, 1024, None, t.format(**fargs), env, extra_args, dependencies) def alignment(self, typename, env, extra_args=None, dependencies=None): if extra_args is None: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index dca7934da..bd818bb71 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -827,14 +827,23 @@ class CompilerHolder(InterpreterObject): if len(args) != 1: raise InterpreterException('Compute_int takes exactly one argument.') check_stringlist(args) - fragment = args[0] + expression = args[0] prefix = kwargs.get('prefix', '') + l = kwargs.get('low', -1024) + h = kwargs.get('high', 1024) + guess = kwargs.get('guess', None) if not isinstance(prefix, str): raise InterpreterException('Prefix argument of compute_int must be a string.') + if not isinstance(l, int): + raise InterpreterException('Low argument of compute_int must be an int.') + if not isinstance(h, int): + raise InterpreterException('High argument of compute_int must be an int.') + if guess is not None and not isinstance(guess, int): + raise InterpreterException('Guess argument of compute_int must be an int.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) - res = self.compiler.compute_int(fragment, prefix, self.environment, extra_args, deps) - mlog.log('Computing int of "%s": %d' % (fragment, res)) + res = self.compiler.compute_int(expression, l, h, guess, prefix, self.environment, extra_args, deps) + mlog.log('Computing int of "%s": %d' % (expression, res)) return res def sizeof_method(self, args, kwargs): diff --git a/test cases/common/139 compute int/meson.build b/test cases/common/139 compute int/meson.build index 6f813c5e3..43553fe72 100644 --- a/test cases/common/139 compute int/meson.build +++ b/test cases/common/139 compute int/meson.build @@ -5,7 +5,7 @@ inc = include_directories('.') # Test with C cc = meson.get_compiler('c') -intsize = cc.compute_int('sizeof(int)') +intsize = cc.compute_int('sizeof(int)', low : 1, high : 16, guess : 4) foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc) cd = configuration_data() From c9fe3a3ad4f58e2a263f8fc30c21bc009c109480 Mon Sep 17 00:00:00 2001 From: Haakon Sporsheim Date: Fri, 10 Mar 2017 11:55:05 +0100 Subject: [PATCH 3/4] compiler: Ensure prefix and dependencies are used for alignment. This is now similar to how prefix and dependencies are used in all the other similar checks performed by the compiler. --- mesonbuild/compilers.py | 13 ++++++++----- mesonbuild/interpreter.py | 6 +++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 403dda153..65a611f03 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -1076,31 +1076,34 @@ class CCompiler(Compiler): raise EnvironmentException('Could not run sizeof test binary.') return int(res.stdout) - def cross_alignment(self, typename, env, extra_args=None, dependencies=None): + def cross_alignment(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] - fargs = {'type': typename} + fargs = {'prefix': prefix, 'type': typename} t = '''#include + {prefix} int main(int argc, char **argv) {{ {type} something; }}''' if not self.compiles(t.format(**fargs), env, extra_args, dependencies): return -1 t = '''#include + {prefix} struct tmp {{ char c; {type} target; }};''' return self.cross_compute_int('offsetof(struct tmp, target)', 1, 1024, None, t.format(**fargs), env, extra_args, dependencies) - def alignment(self, typename, env, extra_args=None, dependencies=None): + def alignment(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] if self.is_cross: - return self.cross_alignment(typename, env, extra_args, dependencies) - fargs = {'type': typename} + return self.cross_alignment(typename, prefix, env, extra_args, dependencies) + fargs = {'prefix': prefix, 'type': typename} t = '''#include #include + {prefix} struct tmp {{ char c; {type} target; diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index bd818bb71..9e8b13642 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -700,8 +700,12 @@ class CompilerHolder(InterpreterObject): raise InterpreterException('Alignment method takes exactly one positional argument.') check_stringlist(args) typename = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of sizeof must be a string.') extra_args = mesonlib.stringlistify(kwargs.get('args', [])) - result = self.compiler.alignment(typename, self.environment, extra_args) + deps = self.determine_dependencies(kwargs) + result = self.compiler.alignment(typename, prefix, self.environment, extra_args, deps) mlog.log('Checking for alignment of "', mlog.bold(typename), '": ', result, sep='') return result From 2f11e2e4630a7770eddbce7efdd7ce9b63de5ba1 Mon Sep 17 00:00:00 2001 From: Haakon Sporsheim Date: Fri, 10 Mar 2017 11:56:45 +0100 Subject: [PATCH 4/4] compiler: Rename element argument of sizeof to typename. --- mesonbuild/compilers.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 65a611f03..1fb9c5ab6 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -1044,29 +1044,29 @@ class CCompiler(Compiler): raise EnvironmentException('Could not run compute_int test binary.') return int(res.stdout) - def cross_sizeof(self, element, prefix, env, extra_args=None, dependencies=None): + def cross_sizeof(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] - fargs = {'prefix': prefix, 'name': element} + fargs = {'prefix': prefix, 'type': typename} t = '''#include {prefix} int main(int argc, char **argv) {{ - {name} something; + {type} something; }}''' if not self.compiles(t.format(**fargs), env, extra_args, dependencies): return -1 - return self.cross_compute_int('sizeof(%s)' % element, 1, 128, None, prefix, env, extra_args, dependencies) + return self.cross_compute_int('sizeof(%s)' % typename, 1, 128, None, prefix, env, extra_args, dependencies) - def sizeof(self, element, prefix, env, extra_args=None, dependencies=None): + def sizeof(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] - fargs = {'prefix': prefix, 'name': element} + fargs = {'prefix': prefix, 'type': typename} if self.is_cross: - return self.cross_sizeof(element, prefix, env, extra_args, dependencies) + return self.cross_sizeof(typename, prefix, env, extra_args, dependencies) t = '''#include {prefix} int main(int argc, char **argv) {{ - printf("%ld\\n", (long)(sizeof({name}))); + printf("%ld\\n", (long)(sizeof({type}))); return 0; }};''' res = self.run(t.format(**fargs), env, extra_args, dependencies)