Repository: mesonbuild/meson

Issue:
VS backends do not use b_pch
When setting `b_pch=false`, a meson project (e.g. test case `common/13 pch`) compiles fine with VS, but fails with ninja.

This assumes the project is set up in a way that it requires PCH in order to compile (because it does not add individual includes to source files). However, the correct behavior would be for VS to also fail, since it should be possible to toggle usage of PCH just by switching the `b_pch` option. If a project is set up incorrectly, VS should not make it compile magically.


Discussion:

Resolving patch:
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -982,7 +982,6 @@ def gen_vcxproj(self, target, ofname, guid):
         target_defines.append('%(PreprocessorDefinitions)')
         ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines)
         ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true'
-        pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
         # Warning level
         warning_level = self.get_option_for_target('warning_level', target)
         ET.SubElement(clconf, 'WarningLevel').text = 'Level' + str(1 + int(warning_level))
@@ -990,19 +989,21 @@ def gen_vcxproj(self, target, ofname, guid):
             ET.SubElement(clconf, 'TreatWarningAsError').text = 'true'
         # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default
         pch_sources = {}
-        for lang in ['c', 'cpp']:
-            pch = target.get_pch(lang)
-            if not pch:
-                continue
-            pch_node.text = 'Use'
-            if compiler.id == 'msvc':
-                if len(pch) != 2:
-                    raise MesonException('MSVC requires one header and one source to produce precompiled headers.')
-                pch_sources[lang] = [pch[0], pch[1], lang]
-            else:
-                # I don't know whether its relevant but let's handle other compilers
-                # used with a vs backend
-                pch_sources[lang] = [pch[0], None, lang]
+        if self.environment.coredata.base_options.get('b_pch', False):
+            pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
+            for lang in ['c', 'cpp']:
+                pch = target.get_pch(lang)
+                if not pch:
+                    continue
+                pch_node.text = 'Use'
+                if compiler.id == 'msvc':
+                    if len(pch) != 2:
+                        raise MesonException('MSVC requires one header and one source to produce precompiled headers.')
+                    pch_sources[lang] = [pch[0], pch[1], lang]
+                else:
+                    # I don't know whether its relevant but let's handle other compilers
+                    # used with a vs backend
+                    pch_sources[lang] = [pch[0], None, lang]
         if len(pch_sources) == 1:
             # If there is only 1 language with precompiled headers, we can use it for the entire project, which
             # is cleaner than specifying it for each source file.


Test patch:
diff --git a/test cases/failing build/3 pch disabled/c/meson.build b/test cases/failing build/3 pch disabled/c/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/3 pch disabled/c/meson.build	
@@ -0,0 +1,2 @@
+exe = executable('prog', 'prog.c',
+c_pch : ['pch/prog_pch.c', 'pch/prog.h'])
diff --git a/test cases/failing build/3 pch disabled/c/pch/prog.h b/test cases/failing build/3 pch disabled/c/pch/prog.h
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/3 pch disabled/c/pch/prog.h	
@@ -0,0 +1 @@
+#include<stdio.h>
diff --git a/test cases/failing build/3 pch disabled/c/pch/prog_pch.c b/test cases/failing build/3 pch disabled/c/pch/prog_pch.c
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/3 pch disabled/c/pch/prog_pch.c	
@@ -0,0 +1,5 @@
+#if !defined(_MSC_VER)
+#error "This file is only for use with MSVC."
+#endif
+
+#include "prog.h"
diff --git a/test cases/failing build/3 pch disabled/c/prog.c b/test cases/failing build/3 pch disabled/c/prog.c
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/3 pch disabled/c/prog.c	
@@ -0,0 +1,10 @@
+// No includes here, they need to come from the PCH
+
+void func() {
+    fprintf(stdout, "This is a function that fails if stdio is not #included.\n");
+}
+
+int main(int argc, char **argv) {
+    return 0;
+}
+
diff --git a/test cases/failing build/3 pch disabled/meson.build b/test cases/failing build/3 pch disabled/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/3 pch disabled/meson.build	
@@ -0,0 +1,5 @@
+# Disable PCH usage to make sure backends respect this setting.
+# Since the .c file requires PCH usage (it does not include necessary
+# headers itself), the build should fail.
+project('pch test', 'c', default_options: ['b_pch=false'])
+subdir('c')