Repository: mesonbuild/meson

Issue:
cc.has_header assumes header can be included by itself
Not all headers can be included directly; sometimes they require a specific define, and especially on Windows a lot of headers (such as `GL/wglext.h`) require including `windows.h`. We should allow specifying a prefix to verify the usability of a header. This might also be useful for people who want to detect the correct prefixes necessary to make a header usable.


Discussion:

Resolving patch:
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -638,13 +638,11 @@ def sanity_check(self, work_dir, environment):
         code = 'int main(int argc, char **argv) { int class=0; return class; }\n'
         return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code)
 
-    def has_header(self, hname, env, extra_args=None, dependencies=None):
+    def has_header(self, hname, prefix, env, extra_args=None, dependencies=None):
         if extra_args is None:
             extra_args = []
-        templ = '''#include<%s>
-int someSymbolHereJustForFun;
-'''
-        return self.compiles(templ % hname, env, extra_args, dependencies)
+        code = '{}\n#include<{}>\nint someUselessSymbol;'.format(prefix, hname)
+        return self.compiles(code, env, extra_args, dependencies)
 
     def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None):
         if extra_args is None:
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -896,15 +896,18 @@ def has_header_method(self, args, kwargs):
         if len(args) != 1:
             raise InterpreterException('has_header method takes exactly one argument.')
         check_stringlist(args)
-        string = args[0]
+        hname = args[0]
+        prefix = kwargs.get('prefix', '')
+        if not isinstance(prefix, str):
+            raise InterpreterException('Prefix argument of has_header must be a string.')
         extra_args = self.determine_args(kwargs)
         deps = self.determine_dependencies(kwargs, allowed_dep_types=(dependencies.Dependency,))
-        haz = self.compiler.has_header(string, self.environment, extra_args, deps)
+        haz = self.compiler.has_header(hname, prefix, self.environment, extra_args, deps)
         if haz:
             h = mlog.green('YES')
         else:
             h = mlog.red('NO')
-        mlog.log('Has header "%s":' % string, h)
+        mlog.log('Has header "%s":' % hname, h)
         return haz
 
     def has_header_symbol_method(self, args, kwargs):
@@ -915,7 +918,7 @@ def has_header_symbol_method(self, args, kwargs):
         symbol = args[1]
         prefix = kwargs.get('prefix', '')
         if not isinstance(prefix, str):
-            raise InterpreterException('Prefix argument of has_function must be a string.')
+            raise InterpreterException('Prefix argument of has_header_symbol must be a string.')
         extra_args = self.determine_args(kwargs)
         deps = self.determine_dependencies(kwargs, allowed_dep_types=(dependencies.Dependency,))
         haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment, extra_args, deps)


Test patch:
diff --git a/test cases/common/37 has header/meson.build b/test cases/common/37 has header/meson.build
--- a/test cases/common/37 has header/meson.build	
+++ b/test cases/common/37 has header/meson.build	
@@ -1,10 +1,28 @@
 project('has header', 'c', 'cpp')
 
 foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')]
-  if comp.has_header('stdio.h') == false
+  if not comp.has_header('stdio.h')
     error('Stdio missing.')
   endif
 
+  # stdio.h doesn't actually need stdlib.h, but I don't know any headers on
+  # UNIX/Linux that need other headers defined beforehand
+  if not comp.has_header('stdio.h', prefix : '#include <stdlib.h>')
+    error('Stdio missing.')
+  endif
+
+  # XInput.h needs windows.h included beforehand. We only do this check on MSVC
+  # because MinGW often defines its own wrappers that pre-include windows.h
+  if comp.get_id() == 'msvc'
+    if not comp.has_header('XInput.h', prefix : '#include <windows.h>')
+      error('XInput.h is missing on Windows')
+    endif
+    if comp.has_header('XInput.h')
+      error('XInput.h needs windows.h')
+    endif
+  endif
+
+
   if comp.has_header('ouagadougou.h')
     error('Found non-existant header.')
   endif