summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/compile-checks.configure
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--build/moz.configure/compile-checks.configure445
1 files changed, 445 insertions, 0 deletions
diff --git a/build/moz.configure/compile-checks.configure b/build/moz.configure/compile-checks.configure
new file mode 100644
index 0000000000..a639a012f1
--- /dev/null
+++ b/build/moz.configure/compile-checks.configure
@@ -0,0 +1,445 @@
+# -*- Mode: python; c-basic-offset: 4; 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/.
+
+
+# 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.
+# - `language` is the language selection, so that the appropriate compiler is
+# used.
+# - `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.
+@template
+def try_compile(
+ includes=None,
+ body="",
+ language="C++",
+ flags=None,
+ check_msg=None,
+ when=None,
+ onerror=lambda: None,
+):
+ compiler = {
+ "C": c_compiler,
+ "C++": cxx_compiler,
+ }[language]
+
+ return compiler.try_compile(
+ includes, body, flags, check_msg, when=when, onerror=onerror
+ )
+
+
+# Generates a test program and attempts to link it. In case of failure, the
+# resulting check will return None. If the link succeeds, it will return
+# True
+# - `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.
+# - `language` is the language selection, so that the appropriate compiler is
+# used.
+# - `flags` are the flags to be passed to the compiler.
+# - `check_msg` is the message to be printed to accompany compiling the test
+# program.
+@template
+def try_link(
+ includes=None,
+ body="",
+ language="C++",
+ flags=None,
+ check_msg=None,
+ when=None,
+ onerror=lambda: None,
+):
+ compiler = {
+ "C": c_compiler,
+ "C++": cxx_compiler,
+ }[language]
+
+ return compiler.try_link(
+ linker_ldflags,
+ includes,
+ body,
+ flags,
+ check_msg,
+ when=when,
+ onerror=onerror,
+ )
+
+
+# Checks for the presence of the given header on the target system by compiling
+# a test program including that header. The return value of the template is a
+# check function returning True if the header is present, and None if it is not.
+# The value of this check function is also used to set a variable (with set_define)
+# corresponding to the checked header. For instance, HAVE_MALLOC_H will be set in
+# defines if check_header if called with 'malloc.h' as input and malloc.h is
+# present on the target.
+# - `header` is the header, as a file name, to check for.
+# - `language` is the language selection, so that the appropriate compiler is
+# used.
+# - `flags` are the flags to be passed to the compiler, in addition to `-c`.
+# - `includes` are additional includes, as file names, to appear before the
+# header checked for.
+# - `when` is a depends function that if present will make performing the check
+# conditional on the value of that function.
+@template
+def check_header(
+ header, language="C++", flags=None, includes=None, when=None, onerror=lambda: None
+):
+ if when is None:
+ when = always
+
+ if includes:
+ includes = includes[:]
+ else:
+ includes = []
+ includes.append(header)
+
+ have_header = try_compile(
+ includes=includes,
+ language=language,
+ flags=flags,
+ check_msg="for %s" % header,
+ when=when,
+ onerror=onerror,
+ )
+ header_var = "HAVE_%s" % (
+ header.upper().replace("-", "_").replace("/", "_").replace(".", "_")
+ )
+ set_define(header_var, have_header)
+ return have_header
+
+
+# A convenience wrapper for check_header for checking multiple headers.
+# returns an array of the resulting checks in order corresponding to the
+# provided headers.
+# - `headers` are the headers to be checked.
+# - `kwargs` are keyword arguments passed verbatim to check_header.
+
+
+@template
+def check_headers(*headers, **kwargs):
+ checks = []
+ for header in headers:
+ checks.append(check_header(header, **kwargs))
+ return checks
+
+
+@depends(linker_ldflags, target.kernel)
+def check_symbol_flags(linker_ldflags, kernel):
+ if kernel == "WINNT":
+ # The build doesn't use the compiler to link things as of writing,
+ # but some compilation checks do. When using clang-cl, the only
+ # linker we really support is lld.link, but clang-cl defaults to
+ # link.exe (even when cross-compiling). So we force the use of
+ # lld.link for the linkage checks.
+ return ["-fuse-ld=lld"]
+ return linker_ldflags
+
+
+# Checks for the presence of the given symbol on the target system by compiling
+# a test program. The return value of the template is a check function
+# returning True if the symbol can be found, and None if it is not.
+@template
+def check_symbol(symbol, language="C", flags=None, when=None, onerror=lambda: None):
+ if when is None:
+ when = always
+
+ compiler, extern_c = {
+ "C": (c_compiler, ""),
+ "C++": (cxx_compiler, 'extern "C" '),
+ }[language]
+
+ # Stolen from autoconf 2.13 ; might be irrelevant now, but it doesn't hurt to
+ # keep using a char return type.
+ comment = [
+ "/* Override any gcc2 internal prototype to avoid an error. */",
+ "/* We use char because int might match the return type of a gcc2",
+ " builtin and then its argument prototype would still apply. */",
+ ]
+
+ if flags:
+
+ @depends(check_symbol_flags, dependable(flags))
+ def flags(base_flags, extra_flags):
+ if base_flags and extra_flags:
+ return base_flags + list(extra_flags)
+ if extra_flags:
+ return extra_flags
+ return base_flags
+
+ else:
+ flags = check_symbol_flags
+
+ return compiler.try_run(
+ header=comment + ["%schar %s();" % (extern_c, symbol)],
+ body="%s();" % symbol,
+ flags=flags,
+ check_msg="for %s" % symbol,
+ when=when,
+ onerror=onerror,
+ )
+
+
+# Determine whether to add a given flag to the given lists of flags for C or
+# C++ compilation.
+# - `flag` is the flag to test
+# - `flags_collection` is a @depends function for a namespace of lists of
+# C/C++ compiler flags to add to.
+# - `test_flags` is a list of flags to pass to the compiler instead of merely
+# passing `flag`. This is especially useful for checking warning flags. If
+# this list is empty, `flag` will be passed on its own.
+# - `compiler` (optional) is the compiler to test against (c_compiler or
+# cxx_compiler, from toolchain.configure). When omitted, both compilers
+# are tested; the list of flags added to is dependent on the compiler tested.
+# - `when` (optional) is a @depends function or option name conditioning
+# when the warning flag is wanted.
+# - `check`, when not set, skips checking whether the flag is supported and
+# adds it to the list of flags unconditionally.
+# - `mode`, can be "compile", "link" or "assemble"
+@template
+def check_and_add_flags(
+ flag,
+ flags_collection,
+ test_flags=(),
+ compiler=None,
+ when=None,
+ check=True,
+ mode="compile",
+):
+ assert mode in ("compile", "link", "assemble")
+
+ if compiler is not None:
+ compilers = (compiler,)
+ elif mode in ("link", "assemble"):
+ compilers = (c_compiler,)
+ else:
+ compilers = (c_compiler, cxx_compiler)
+
+ if when is None:
+ when = always
+
+ results = []
+
+ if test_flags:
+ flags = test_flags
+ else:
+ flags = [flag]
+
+ for c in compilers:
+ assert c in {c_compiler, cxx_compiler, host_c_compiler, host_cxx_compiler}
+ if mode == "compile":
+ lang, list_of_flags = {
+ c_compiler: ("C", flags_collection.cflags),
+ cxx_compiler: ("C++", flags_collection.cxxflags),
+ host_c_compiler: ("host C", flags_collection.host_cflags),
+ host_cxx_compiler: ("host C++", flags_collection.host_cxxflags),
+ }[c]
+ elif mode == "assemble":
+ lang, list_of_flags = {
+ c_compiler: ("C", flags_collection.asflags),
+ host_c_compiler: ("host C", flags_collection.host_asflags),
+ }[c]
+ elif mode == "link":
+ lang, list_of_flags = {
+ c_compiler: ("C", flags_collection.ldflags),
+ cxx_compiler: ("C++", flags_collection.ldflags),
+ host_c_compiler: ("host C", flags_collection.host_ldflags),
+ host_cxx_compiler: ("host C++", flags_collection.host_ldflags),
+ }[c]
+
+ result = when
+
+ if check:
+
+ @depends(c, dependable(flags))
+ def flags(c, flags):
+ # Don't error out just because clang complains about other things.
+ if c.type in ("clang", "clang-cl"):
+ flags += ["-Wno-error=unused-command-line-argument"]
+
+ return flags
+
+ if mode == "link":
+
+ def runner(*args, **kwargs):
+ if c in (c_compiler, cxx_compiler):
+ return c.try_link(linker_ldflags, *args, **kwargs)
+ else:
+ return c.try_link(host_linker_ldflags, *args, **kwargs)
+
+ tool = "linker"
+ else:
+ runner = c.try_compile
+ tool = "compiler"
+
+ result = runner(
+ flags=flags,
+ when=result,
+ check_msg="whether the %s %s supports %s" % (lang, tool, flag),
+ )
+
+ @depends(result, list_of_flags)
+ def maybe_add_flag(result, list_of_flags):
+ if result:
+ list_of_flags.append(flag)
+
+ results.append(result)
+
+ return tuple(results)
+
+
+@dependable
+def warnings_flags():
+ return namespace(cflags=[], cxxflags=[], host_cflags=[], host_cxxflags=[])
+
+
+# Tests whether GCC or clang support the given warning flag, and if it is,
+# add it to the list of warning flags for the build.
+# - `warning` is the warning flag (e.g. -Wfoo)
+# - `compiler` (optional) is the compiler to test against (c_compiler or
+# cxx_compiler, from toolchain.configure). When omitted, both compilers
+# are tested.
+# - `when` (optional) is a @depends function or option name conditioning
+# when the warning flag is wanted.
+# - `check`, when not set, skips checking whether the flag is supported and
+# adds it to the list of warning flags unconditionally. This is only meant
+# for add_warning().
+@template
+def check_and_add_warning(warning, compiler=None, when=None, check=True):
+ # GCC and clang will fail if given an unknown warning option like
+ # -Wfoobar. But later versions won't fail if given an unknown negated
+ # warning option like -Wno-foobar. So when we are checking for support
+ # of a negated warning option, we actually test the positive form, but
+ # add the negated form to the flags variable.
+ if warning.startswith("-Wno-") and not warning.startswith("-Wno-error="):
+ flags = ["-Werror", "-W" + warning[5:]]
+ elif warning.startswith("-Werror="):
+ flags = [warning]
+ else:
+ flags = ["-Werror", warning]
+
+ return check_and_add_flags(
+ warning, warnings_flags, flags, compiler=compiler, when=when, check=check
+ )
+
+
+# Add the given warning to the list of warning flags for the build.
+# - `warning` is the warning flag (e.g. -Wfoo)
+# - `compiler` (optional) is the compiler to add the flag for (c_compiler or
+# cxx_compiler, from toolchain.configure). When omitted, the warning flag
+# is added for both compilers.
+# - `when` (optional) is a @depends function or option name conditioning
+# when the warning flag is wanted.
+
+
+@template
+def add_warning(warning, compiler=None, when=None):
+ check_and_add_warning(warning, compiler, when, check=False)
+
+
+# Like the warning checks above, but for general compilation flags.
+@dependable
+def compilation_flags():
+ return namespace(cflags=[], cxxflags=[], host_cflags=[], host_cxxflags=[])
+
+
+# Tests whether GCC or clang support the given compilation flag; if the flag
+# is supported, add it to the list of compilation flags for the build.
+# - `flag` is the flag to test
+# - `compiler` (optional) is the compiler to test against (c_compiler or
+# cxx_compiler, from toolchain.configure). When omitted, both compilers
+# are tested.
+# - `when` (optional) is a @depends function or option name conditioning
+# when the warning flag is wanted.
+# - `check`, when not set, skips checking whether the flag is supported and
+# adds it to the list of flags unconditionally. This is only meant for
+# add_flag().
+@template
+def check_and_add_flag(flag, compiler=None, when=None, check=True):
+ flags = ["-Werror", flag]
+
+ return check_and_add_flags(
+ flag, compilation_flags, flags, compiler=compiler, when=when, check=check
+ )
+
+
+# Add the given flag to the list of flags for the build.
+# - `flag` is the flag (e.g. -fno-sized-deallocation)
+# - `compiler` (optional) is the compiler to add the flag for (c_compiler or
+# cxx_compiler, from toolchain.configure). When omitted, the flag is added
+# for both compilers.
+# - `when` (optional) is a @depends function or option name conditioning
+# when the flag is wanted.
+@template
+def add_flag(warning, compiler=None, when=None):
+ check_and_add_flag(warning, compiler, when, check=False)
+
+
+# Like the compilation checks above, but for asm flags.
+@dependable
+def asm_flags():
+ return namespace(asflags=[], host_asflags=[])
+
+
+# Tests the given assembler flag is supported; if the flag
+# is supported, add it to the list of compilation flags for the build.
+# - `flag` is the flag to test
+# - `when` (optional) is a @depends function or option name conditioning
+# when the warning flag is wanted.
+# - `check`, when not set, skips checking whether the flag is supported and
+# adds it to the list of flags unconditionally. This is only meant for
+# add_flag().
+@template
+def check_and_add_asm_flag(flag, when=None, check=True):
+ return check_and_add_flags(
+ flag,
+ asm_flags,
+ [flag],
+ when=when,
+ check=check,
+ mode="assemble",
+ )
+
+
+# Like the compilation checks above, but for linker flags.
+@dependable
+def linker_flags():
+ return namespace(ldflags=[], host_ldflags=[])
+
+
+# Tests the given linker flag is supported; if the flag
+# is supported, add it to the list of compilation flags for the build.
+# - `flag` is the flag to test
+# - `when` (optional) is a @depends function or option name conditioning
+# when the warning flag is wanted.
+# - `check`, when not set, skips checking whether the flag is supported and
+# adds it to the list of flags unconditionally. This is only meant for
+# add_flag().
+@template
+def check_and_add_linker_flag(flag, compiler=None, when=None, check=True):
+ return check_and_add_flags(
+ flag,
+ linker_flags,
+ [flag],
+ when=when,
+ check=check,
+ mode="link",
+ )
+
+
+# Add the given flag to the list of linker flags for the build.
+# - `flag` is the flag (e.g. -fno-sized-deallocation)
+# - `when` (optional) is a @depends function or option name conditioning
+# when the flag is wanted.
+@template
+def add_linker_flag(flag, compiler=None, when=None):
+ check_and_add_linker_flag(flag, compiler, when, check=False)