From fad78510c7cc57e59177632ddcb0be5372f3c00e Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sat, 31 Mar 2018 22:44:09 -0400 Subject: [PATCH] Add has_link_argument() and friends Closes: #3335. --- docs/markdown/Reference-manual.md | 20 +++++++-- docs/markdown/snippets/has-link-argument.md | 9 ++++ mesonbuild/compilers/c.py | 3 ++ mesonbuild/compilers/compilers.py | 5 +++ mesonbuild/interpreter.py | 43 +++++++++++++++++++ .../common/189 has link arg/meson.build | 42 ++++++++++++++++++ 6 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 docs/markdown/snippets/has-link-argument.md create mode 100644 test cases/common/189 has link arg/meson.build diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 5109b25134e1..6574f511cef3 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1472,6 +1472,10 @@ the following methods: strings, returns the first argument that passes the `has_argument` test above or an empty array if none pass. +- `first_supported_link_argument(list_of_strings)` *(added 0.46.0)*, given a + list of strings, returns the first argument that passes the + `has_link_argument` test above or an empty array if none pass. + - `get_define(definename)` returns the given preprocessor symbol's value as a string or empty string if it is not defined. @@ -1482,11 +1486,17 @@ the following methods: an array containing only the arguments supported by the compiler, as if `has_argument` were called on them individually. +- `get_supported_link_arguments(list_of_string)` *(added 0.46.0)* returns + an array containing only the arguments supported by the linker, + as if `has_link_argument` were called on them individually. + - `has_argument(argument_name)` returns true if the compiler accepts the specified command line argument, that is, can compile code - without erroring out or printing a warning about an unknown flag, - you can specify external dependencies to use with `dependencies` - keyword argument. + without erroring out or printing a warning about an unknown flag. + +- `has_link_argument(argument_name)` *(added 0.46.0)* returns true if the linker + accepts the specified command line argument, that is, can compile and link + code without erroring out or printing a warning about an unknown flag. - `has_function(funcname)` returns true if the given function is provided by the standard library or a library passed in with the @@ -1521,6 +1531,10 @@ the following methods: `has_argument` but takes multiple arguments and uses them all in a single compiler invocation, available since 0.37.0. +- `has_multi_link_arguments(arg1, arg2, arg3, ...)` *(added 0.46.0)* is the same + as `has_link_argument` but takes multiple arguments and uses them all in a + single compiler invocation. + - `has_type(typename)` returns true if the specified token is a type, you can specify external dependencies to use with `dependencies` keyword argument. diff --git a/docs/markdown/snippets/has-link-argument.md b/docs/markdown/snippets/has-link-argument.md new file mode 100644 index 000000000000..7beda63608a9 --- /dev/null +++ b/docs/markdown/snippets/has-link-argument.md @@ -0,0 +1,9 @@ +## has_link_argument() and friends + +A new set of methods has been added on compiler objects to test if the linker +supports given arguments. + +- `has_link_argument()` +- `has_multi_link_arguments()` +- `get_supported_link_arguments()` +- `first_supported_link_argument()` diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 56b46b4fb227..b69c16ecd36a 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -816,6 +816,9 @@ def has_multi_arguments(self, args, env): '''.format(arg)) return self.compiles('int i;\n', env, extra_args=args) + def has_multi_link_arguments(self, args, env): + code = 'int main(int argc, char **argv) { return 0; }' + return self.links(code, env, extra_args=args) class ClangCCompiler(ClangCompiler, CCompiler): def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None, **kwargs): diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 1cfdf0450954..443f3e3887c6 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -718,6 +718,11 @@ def has_multi_arguments(self, args, env): 'Language {} does not support has_multi_arguments.'.format( self.get_display_language())) + def has_multi_link_arguments(self, args, env): + raise EnvironmentException( + 'Language {} does not support has_multi_link_arguments.'.format( + self.get_display_language())) + def get_cross_extra_flags(self, environment, link): extra_flags = [] if self.is_cross and environment: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 75dae183da41..5dba948c66e9 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -716,6 +716,10 @@ def __init__(self, compiler, env): 'has_multi_arguments': self.has_multi_arguments_method, 'get_supported_arguments': self.get_supported_arguments_method, 'first_supported_argument': self.first_supported_argument_method, + 'has_link_argument': self.has_link_argument_method, + 'has_multi_link_arguments': self.has_multi_link_arguments_method, + 'get_supported_link_arguments': self.get_supported_link_arguments_method, + 'first_supported_link_argument': self.first_supported_link_argument_method, 'unittest_args': self.unittest_args_method, 'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method, }) @@ -1193,6 +1197,45 @@ def first_supported_argument_method(self, args, kwargs): mlog.log('First supported argument:', mlog.red('None')) return [] + @permittedMethodKwargs({}) + def has_link_argument_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + if len(args) != 1: + raise InterpreterException('has_link_argument takes exactly one argument.') + return self.has_multi_link_arguments_method(args, kwargs) + + @permittedMethodKwargs({}) + def has_multi_link_arguments_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + result = self.compiler.has_multi_link_arguments(args, self.environment) + if result: + h = mlog.green('YES') + else: + h = mlog.red('NO') + mlog.log( + 'Compiler for {} supports link arguments {}:'.format( + self.compiler.get_display_language(), ' '.join(args)), + h) + return result + + @permittedMethodKwargs({}) + def get_supported_link_arguments_method(self, args, kwargs): + args = mesonlib.stringlistify(args) + supported_args = [] + for arg in args: + if self.has_link_argument_method(arg, kwargs): + supported_args.append(arg) + return supported_args + + @permittedMethodKwargs({}) + def first_supported_link_argument_method(self, args, kwargs): + for i in mesonlib.stringlistify(args): + if self.has_link_argument_method(i, kwargs): + mlog.log('First supported link argument:', mlog.bold(i)) + return [i] + mlog.log('First supported link argument:', mlog.red('None')) + return [] + ModuleState = namedtuple('ModuleState', [ 'build_to_src', 'subproject', 'subdir', 'current_lineno', 'environment', 'project_name', 'project_version', 'backend', 'compilers', 'targets', diff --git a/test cases/common/189 has link arg/meson.build b/test cases/common/189 has link arg/meson.build new file mode 100644 index 000000000000..5f3bb6409a45 --- /dev/null +++ b/test cases/common/189 has link arg/meson.build @@ -0,0 +1,42 @@ +project('has link arg', 'c', 'cpp') + +cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') + +# FIXME: I have no idea how linker args works on other compilers +if cc.get_id() != 'gcc' and cc.get_id() != 'clang' + subdir_done() +endif + +is_arg = '-Wl,-Bsymbolic' +useless = '-Wl,-Lfoo' +isnt_arg = '-Wl,-iambroken' + + +assert(cc.has_link_argument(is_arg), 'Arg that should have worked does not work.') +assert(not cc.has_link_argument(isnt_arg), 'Arg that should be broken is not.') + +assert(cpp.has_link_argument(is_arg), 'Arg that should have worked does not work.') +assert(not cpp.has_link_argument(isnt_arg), 'Arg that should be broken is not.') + +assert(cc.get_supported_link_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.') +assert(cpp.get_supported_link_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.') + +# Have useless at the end to ensure that the search goes from front to back. +l1 = cc.first_supported_link_argument([isnt_arg, is_arg, isnt_arg, useless]) +l2 = cc.first_supported_link_argument(isnt_arg, isnt_arg, isnt_arg) + +assert(l1.length() == 1, 'First supported returned wrong result.') +assert(l1.get(0) == is_arg, 'First supported returned wrong argument.') +assert(l2.length() == 0, 'First supported did not return empty array.') + +l1 = cpp.first_supported_link_argument([isnt_arg, is_arg, isnt_arg, useless]) +l2 = cpp.first_supported_link_argument(isnt_arg, isnt_arg, isnt_arg) + +assert(l1.length() == 1, 'First supported returned wrong result.') +assert(l1.get(0) == is_arg, 'First supported returned wrong argument.') +assert(l2.length() == 0, 'First supported did not return empty array.') + +assert(not cc.has_multi_link_arguments([isnt_arg, is_arg]), 'Arg that should be broken is not.') +assert(cc.has_multi_link_arguments(is_arg), 'Arg that should have worked does not work.') +assert(cc.has_multi_link_arguments([useless, is_arg]), 'Arg that should have worked does not work.')