diff options
Diffstat (limited to 'build/moz.configure/compilers-util.configure')
-rw-r--r-- | build/moz.configure/compilers-util.configure | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/build/moz.configure/compilers-util.configure b/build/moz.configure/compilers-util.configure new file mode 100644 index 0000000000..598de3dc80 --- /dev/null +++ b/build/moz.configure/compilers-util.configure @@ -0,0 +1,204 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@template +@imports("textwrap") +@imports(_from="mozbuild.configure", _import="SandboxDependsFunction") +def compiler_class(compiler, host_or_target): + is_target = host_or_target is target + + class Compiler(SandboxDependsFunction): + def _try_compile_or_link( + self, + includes, + body, + flags, + ldflags, + check_msg, + when, + onerror, + ): + if ldflags is None: + + @depends(dependable(flags)) + def flags(flags): + flags = list(flags or []) + flags.append("-c") + return flags + + else: + + @depends(compiler, dependable(ldflags), dependable(flags), when=when) + def flags(compiler, ldflags, flags): + if compiler.type == "clang-cl": + configure_error( + "checking linker flags for clang-cl is not supported yet" + ) + + flags = list(flags or []) + flags.extend(ldflags) + return flags + + @depends(dependable(includes)) + def header(includes): + includes = includes or [] + return ["#include <%s>" % f for f in includes] + + return self.try_run( + header=header, + body=body, + flags=flags, + check_msg=check_msg, + when=when, + onerror=onerror, + ) + + # Generates a test program and attempts to compile it. In case of + # failure, the resulting check will return None. If the test program + # succeeds, it will return the output of the test program. + # - `includes` are the includes (as file names) that will appear at the + # top of the generated test program. + # - `body` is the code that will appear in the main function of the + # generated test program. `return 0;` is appended to the function + # body automatically. + # - `flags` are the flags to be passed to the compiler, in addition to + # `-c`. + # - `check_msg` is the message to be printed to accompany compiling the + # test program. + def try_compile( + self, + includes=None, + body="", + flags=None, + check_msg=None, + when=None, + onerror=lambda: None, + ): + return self._try_compile_or_link( + includes=includes, + body=body, + flags=flags, + ldflags=None, + check_msg=check_msg, + when=when, + onerror=onerror, + ) + + # Same steps as try_compile but doesn't add "-c" + def try_link( + self, + ldflags, + includes=None, + body="", + flags=None, + check_msg=None, + when=None, + onerror=lambda: None, + ): + return self._try_compile_or_link( + includes=includes, + body=body, + flags=flags, + ldflags=ldflags, + check_msg=check_msg, + when=when, + onerror=onerror, + ) + + # Generates a test program and run the compiler against it. In case of + # failure, the resulting check will return None. + # - `header` is code that will appear at the top of the generated test + # program. + # - `body` is the code that will appear in the main function of the + # generated test program. `return 0;` is appended to the function + # body automatically. + # - `flags` are the flags to be passed to the compiler. + # - `check_msg` is the message to be printed to accompany compiling the + # test program. + # - `onerror` is a function called when the check fails. + def try_run( + self, + header=None, + body="", + flags=None, + check_msg=None, + when=None, + onerror=lambda: None, + ): + source = textwrap.dedent( + """\ + int + main(void) + { + %s + ; + return 0; + } + """ + % body + ) + + if check_msg: + + def checking_fn(fn): + return checking(check_msg)(fn) + + else: + + def checking_fn(fn): + return fn + + # We accept onerror being a @depends function that returns a callable. + # So, create a similar @depends function when it's not already one. + if not isinstance(onerror, SandboxDependsFunction): + onerror = dependable(lambda: onerror) + + @depends( + self, + dependable(flags), + extra_toolchain_flags, + dependable(header), + onerror, + configure_cache, + when=when, + ) + @checking_fn + def func( + compiler, + flags, + extra_flags, + header, + onerror, + configure_cache, + ): + flags = list(flags or []) + if is_target: + flags += extra_flags or [] + header = header or "" + if isinstance(header, (list, tuple)): + header = "\n".join(header) + if header: + header += "\n" + + if ( + try_invoke_compiler( + configure_cache, + [compiler.compiler] + compiler.flags, + compiler.language, + header + source, + flags, + onerror=onerror, + wrapper=compiler.wrapper, + ) + is not None + ): + return True + + return func + + compiler.__class__ = Compiler + return compiler |