compile-checks.configure 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this
  4. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  5. # Generates a test program and attempts to compile it. In case of failure, the
  6. # resulting check will return None. If the test program succeeds, it will return
  7. # the output of the test program.
  8. # - `includes` are the includes (as file names) that will appear at the top of
  9. # the generated test program.
  10. # - `body` is the code that will appear in the main function of the generated
  11. # test program. `return 0;` is appended to the function body automatically.
  12. # - `language` is the language selection, so that the appropriate compiler is
  13. # used.
  14. # - `flags` are the flags to be passed to the compiler, in addition to `-c`.
  15. # - `check_msg` is the message to be printed to accompany compiling the test
  16. # program.
  17. @template
  18. def try_compile(includes=None, body='', language='C++', flags=None, check_msg=None,
  19. when=None):
  20. compiler = {
  21. 'C': c_compiler,
  22. 'C++': cxx_compiler,
  23. }[language]
  24. return compiler.try_compile(includes, body, flags, check_msg, when=when)
  25. # Checks for the presence of the given header on the target system by compiling
  26. # a test program including that header. The return value of the template is a
  27. # check function returning True if the header is present, and None if it is not.
  28. # The value of this check function is also used to set a variable (with set_define)
  29. # corresponding to the checked header. For instance, HAVE_MALLOC_H will be set in
  30. # defines if check_header if called with 'malloc.h' as input and malloc.h is
  31. # present on the target.
  32. # - `header` is the header, as a file name, to check for.
  33. # - `language` is the language selection, so that the appropriate compiler is
  34. # used.
  35. # - `flags` are the flags to be passed to the compiler, in addition to `-c`.
  36. # - `includes` are additional includes, as file names, to appear before the
  37. # header checked for.
  38. # - `when` is a depends function that if present will make performing the check
  39. # conditional on the value of that function.
  40. @template
  41. def check_header(header, language='C++', flags=None, includes=None, when=None):
  42. when = when or always
  43. if includes:
  44. includes = includes[:]
  45. else:
  46. includes = []
  47. includes.append(header)
  48. have_header = try_compile(includes=includes, language=language, flags=flags,
  49. check_msg='for %s' % header, when=when)
  50. header_var = 'HAVE_%s' % (header.upper()
  51. .replace('-', '_')
  52. .replace('/', '_')
  53. .replace('.', '_'))
  54. set_define(header_var, have_header)
  55. return have_header
  56. # A convenience wrapper for check_header for checking multiple headers.
  57. # returns an array of the resulting checks in order corresponding to the
  58. # provided headers.
  59. # - `headers` are the headers to be checked.
  60. # - `kwargs` are keyword arguments passed verbatim to check_header.
  61. @template
  62. def check_headers(*headers, **kwargs):
  63. checks = []
  64. for header in headers:
  65. checks.append(check_header(header, **kwargs))
  66. return checks
  67. @depends(c_compiler)
  68. def warnings_cflags(c_compiler):
  69. return []
  70. @depends(cxx_compiler)
  71. def warnings_cxxflags(cxx_compiler):
  72. return []
  73. # Tests whether GCC or clang support the given warning flag, and if it is,
  74. # add it to the list of warning flags for the build.
  75. # - `warning` is the warning flag (e.g. -Wfoo)
  76. # - `compiler` (optional) is the compiler to test against (c_compiler or
  77. # cxx_compiler, from toolchain.configure). When omitted, both compilers
  78. # are tested.
  79. # - `when` (optional) is a @depends function or option name conditioning
  80. # when the warning flag is wanted.
  81. # - `check`, when not set, skips checking whether the flag is supported and
  82. # adds it to the list of warning flags unconditionally. This is only meant
  83. # for add_gcc_warning().
  84. @template
  85. def check_and_add_gcc_warning(warning, compiler=None, when=None, check=True):
  86. if compiler:
  87. compilers = (compiler,)
  88. else:
  89. compilers = (c_compiler, cxx_compiler)
  90. when = when or always
  91. for c in compilers:
  92. assert c in (c_compiler, cxx_compiler)
  93. lang, warnings_flags = {
  94. c_compiler: ('C', warnings_cflags),
  95. cxx_compiler: ('C++', warnings_cxxflags),
  96. }[c]
  97. # GCC and clang will fail if given an unknown warning option like
  98. # -Wfoobar. But later versions won't fail if given an unknown negated
  99. # warning option like -Wno-foobar. So when we are checking for support
  100. # of a negated warning option, we actually test the positive form, but
  101. # add the negated form to the flags variable.
  102. if (warning.startswith('-Wno-') and
  103. not warning.startswith('-Wno-error=')):
  104. flags = ['-Werror', '-W' + warning[5:]]
  105. elif warning.startswith('-Werror='):
  106. flags = [warning]
  107. else:
  108. flags = ['-Werror', warning]
  109. @depends(c, when)
  110. def result(c, when):
  111. if when and c.type in ('clang', 'gcc'):
  112. return True
  113. if check:
  114. result = c.try_compile(
  115. flags=flags, when=result,
  116. check_msg='whether the %s compiler supports %s' % (lang,
  117. warning))
  118. @depends(result, warnings_flags)
  119. def maybe_add_flag(result, warnings_flags):
  120. if result:
  121. warnings_flags.append(warning)
  122. # Add the given warning to the list of warning flags for the build.
  123. # - `warning` is the warning flag (e.g. -Wfoo)
  124. # - `compiler` (optional) is the compiler to add the flag for (c_compiler or
  125. # cxx_compiler, from toolchain.configure). When omitted, the warning flag
  126. # is added for both compilers.
  127. # - `when` (optional) is a @depends function or option name conditioning
  128. # when the warning flag is wanted.
  129. @template
  130. def add_gcc_warning(warning, compiler=None, when=None):
  131. check_and_add_gcc_warning(warning, compiler, when, check=False)