From 49418cfe8ab1f42fa28ca9f408f60050bf56c5dc Mon Sep 17 00:00:00 2001 From: Nicolas Schneider Date: Sat, 12 Mar 2016 02:02:36 +0100 Subject: [PATCH] vs2010: support multiple precompiled headers (one per language) This creates the PrecompiledHeader properties for every source file in the project if multiple languages are present. Otherwise, the global pch settings are used. The pch to use is determined by checking the suffix of the source file. --- mesonbuild/backend/vs2010backend.py | 62 +++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 7a427f06a..217bb6990 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -14,6 +14,8 @@ import os, sys import pickle + +from mesonbuild import compilers from . import backends from .. import build from .. import dependencies @@ -312,6 +314,24 @@ class Vs2010Backend(backends.Backend): tree = ET.ElementTree(root) tree.write(ofname, encoding='utf-8', xml_declaration=True) + def add_pch(self, inc_cl, proj_to_src_dir, pch_sources, source_file): + if len(pch_sources) <= 1: + # We only need per file precompiled headers if we have more than 1 language. + return + if source_file.split('.')[-1] in compilers.c_suffixes: + lang = 'c' + elif source_file.split('.')[-1] in compilers.cpp_suffixes: + lang = 'cpp' + else: + return + header = os.path.join(proj_to_src_dir, pch_sources[lang][0]) + pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') + pch_file.text = header + pch_include = ET.SubElement(inc_cl, 'ForcedIncludeFiles') + pch_include.text = header + ';%(ForcedIncludeFiles)' + pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') + pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang + def gen_vcxproj(self, target, ofname, guid, compiler): mlog.debug('Generating vcxproj %s.' % target.name) entrypoint = 'WinMainCRTStartup' @@ -427,19 +447,25 @@ class Vs2010Backend(backends.Backend): funclink = ET.SubElement(clconf, 'FunctionLevelLinking') funclink.text = 'true' pch_node = ET.SubElement(clconf, 'PrecompiledHeader') - pch_sources = [] + pch_sources = {} for lang in ['c', 'cpp']: pch = target.get_pch(lang) if len(pch) == 0: continue - if len(pch_sources) > 0: - raise MesonException('VS2010 backend does not support multiple precompiled header files.') pch_node.text = 'Use' + pch_sources[lang] = [pch[0], pch[1], 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. + pch_source = list(pch_sources.values())[0] + header = os.path.join(proj_to_src_dir, pch_source[0]) pch_file = ET.SubElement(clconf, 'PrecompiledHeaderFile') - pch_file.text = pch[0] + pch_file.text = header pch_include = ET.SubElement(clconf, 'ForcedIncludeFiles') - pch_include.text = pch[0] + ';%(ForcedIncludeFiles)' - pch_sources.append(pch[1]) + pch_include.text = header + ';%(ForcedIncludeFiles)' + pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile') + pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2] + warnings = ET.SubElement(clconf, 'WarningLevel') warnings.text = 'Level3' debinfo = ET.SubElement(clconf, 'DebugInformationFormat') @@ -504,15 +530,25 @@ class Vs2010Backend(backends.Backend): inc_src = ET.SubElement(root, 'ItemGroup') for s in sources: relpath = s.rel_to_builddir(proj_to_src_root) - ET.SubElement(inc_src, 'CLCompile', Include=relpath) - for s in pch_sources: - relpath = os.path.join(proj_to_src_dir, s) - comp_pch = ET.SubElement(inc_src, 'CLCompile', Include=relpath) - pch = ET.SubElement(comp_pch, 'PrecompiledHeader') - pch.text = 'Create' + inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) for s in gen_src: relpath = self.relpath(s, target.subdir) - ET.SubElement(inc_src, 'CLCompile', Include=relpath) + inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) + for lang in pch_sources: + header, impl, suffix = pch_sources[lang] + relpath = os.path.join(proj_to_src_dir, impl) + inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + pch = ET.SubElement(inc_cl, 'PrecompiledHeader') + pch.text = 'Create' + pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') + pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % suffix + pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') + # MSBuild searches for the header relative from the implementation, so we have to use + # just the file name instead of the relative path to the file. + pch_file.text = os.path.split(header)[1] + if len(objects) > 0: # Do not add gen_objs to project file. Those are automatically used by MSBuild, because they are part of # the CustomBuildStep Outputs.