diff options
21 files changed, 84 insertions, 54 deletions
diff --git a/docs/markdown/Precompiled-headers.md b/docs/markdown/Precompiled-headers.md index 3f7d4b4..8dfb438 100644 --- a/docs/markdown/Precompiled-headers.md +++ b/docs/markdown/Precompiled-headers.md @@ -75,8 +75,11 @@ executable('multilang', sources : srclist, Using precompiled headers with MSVC -- +Since Meson version 0.50.0, precompiled headers with MSVC work just like +with GCC. Meson will automatically create the matching pch implementation +file for you. -MSVC is a bit trickier, because in addition to the header file, it +Before version 0.50.0, in addition to the header file, Meson also requires a corresponding source file. If your header is called `foo_pch.h`, the corresponding source file is usually called `foo_pch.cpp` and it resides in the same `pch` subdirectory as the diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 14b189b..5062767 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -515,6 +515,23 @@ class Backend: args += compiler.get_pch_use_args(pchpath, p[0]) return includeargs + args + def create_msvc_pch_implementation(self, target, lang, pch_header): + # We have to include the language in the file name, otherwise + # pch.c and pch.cpp will both end up as pch.obj in VS backends. + impl_name = 'meson_pch-%s.%s' % (lang, lang) + pch_rel_to_build = os.path.join(self.get_target_private_dir(target), impl_name) + # Make sure to prepend the build dir, since the working directory is + # not defined. Otherwise, we might create the file in the wrong path. + pch_file = os.path.join(self.build_dir, pch_rel_to_build) + os.makedirs(os.path.dirname(pch_file), exist_ok=True) + + content = '#include "%s"' % os.path.basename(pch_header) + pch_file_tmp = pch_file + '.tmp' + with open(pch_file_tmp, 'w') as f: + f.write(content) + mesonlib.replace_if_different(pch_file, pch_file_tmp) + return pch_rel_to_build + @staticmethod def escape_extra_args(compiler, args): # No extra escaping/quoting needed when not running on Windows diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 5958af8..1e0bb8b 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2252,22 +2252,28 @@ rule FORTRAN_DEP_HACK%s return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets] def generate_msvc_pch_command(self, target, compiler, pch): - if len(pch) != 2: - raise MesonException('MSVC requires one header and one source to produce precompiled headers.') header = pch[0] - source = pch[1] pchname = compiler.get_pch_name(header) dst = os.path.join(self.get_target_private_dir(target), pchname) commands = [] commands += self.generate_basic_compiler_args(target, compiler) + + if len(pch) == 1: + # Auto generate PCH. + source = self.create_msvc_pch_implementation(target, compiler.get_language(), pch[0]) + pch_header_dir = os.path.dirname(os.path.join(self.build_to_src, target.get_source_subdir(), header)) + commands += compiler.get_include_args(pch_header_dir, False) + else: + source = os.path.join(self.build_to_src, target.get_source_subdir(), pch[1]) + just_name = os.path.basename(header) (objname, pch_args) = compiler.gen_pch_args(just_name, source, dst) commands += pch_args commands += self._generate_single_compile(target, compiler) commands += self.get_compile_debugfile_args(compiler, target, objname) dep = dst + '.' + compiler.get_depfile_suffix() - return commands, dep, dst, [objname] + return commands, dep, dst, [objname], source def generate_gcc_pch_command(self, target, compiler, pch): commands = self._generate_single_compile(target, compiler) @@ -2296,8 +2302,7 @@ rule FORTRAN_DEP_HACK%s raise InvalidArguments(msg) compiler = target.compilers[lang] if isinstance(compiler, VisualStudioCCompiler): - src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[-1]) - (commands, dep, dst, objs) = self.generate_msvc_pch_command(target, compiler, pch) + (commands, dep, dst, objs, src) = self.generate_msvc_pch_command(target, compiler, pch) extradep = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0]) elif compiler.id == 'intel': # Intel generates on target generation diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 2a50dd2..dd99125 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import copy import os import pickle import xml.dom.minidom @@ -1035,13 +1036,18 @@ class Vs2010Backend(backends.Backend): 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] + if len(pch) == 1: + # Auto generate PCH. + src = os.path.join(down, self.create_msvc_pch_implementation(target, lang, pch[0])) + pch_header_dir = os.path.dirname(os.path.join(proj_to_src_dir, pch[0])) + else: + src = os.path.join(proj_to_src_dir, pch[1]) + pch_header_dir = None + pch_sources[lang] = [pch[0], src, lang, pch_header_dir] 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] + pch_sources[lang] = [pch[0], None, lang, None] 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. @@ -1205,14 +1211,19 @@ class Vs2010Backend(backends.Backend): self.add_preprocessor_defines(lang, inc_cl, file_defines) self.add_include_dirs(lang, inc_cl, file_inc_dirs) for lang in pch_sources: - header, impl, suffix = pch_sources[lang] + impl = pch_sources[lang][1] if impl: - relpath = os.path.join(proj_to_src_dir, impl) - inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=impl) self.create_pch(pch_sources, lang, inc_cl) self.add_additional_options(lang, inc_cl, file_args) self.add_preprocessor_defines(lang, inc_cl, file_defines) - self.add_include_dirs(lang, inc_cl, file_inc_dirs) + pch_header_dir = pch_sources[lang][3] + if pch_header_dir: + inc_dirs = copy.deepcopy(file_inc_dirs) + inc_dirs[lang] = [pch_header_dir] + inc_dirs[lang] + else: + inc_dirs = file_inc_dirs + self.add_include_dirs(lang, inc_cl, inc_dirs) if self.has_objects(objects, additional_objects, gen_objs): inc_objs = ET.SubElement(root, 'ItemGroup') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 2187d3e..9a1d158 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1096,6 +1096,8 @@ You probably should put it in link_with instead.''') if (os.path.dirname(pchlist[0]) != os.path.dirname(pchlist[1])): raise InvalidArguments('PCH files must be stored in the same folder.') + + mlog.warning('PCH source files are deprecated, only a single header file should be used.') elif len(pchlist) > 2: raise InvalidArguments('PCH definition may have a maximum of 2 files.') for f in pchlist: diff --git a/test cases/common/13 pch/c/meson.build b/test cases/common/13 pch/c/meson.build index cb8349d..fe4ac68 100644 --- a/test cases/common/13 pch/c/meson.build +++ b/test cases/common/13 pch/c/meson.build @@ -5,4 +5,4 @@ if cc_id == 'lcc' endif exe = executable('prog', 'prog.c', -c_pch : ['pch/prog_pch.c', 'pch/prog.h']) +c_pch : 'pch/prog.h') diff --git a/test cases/common/13 pch/c/pch/prog_pch.c b/test cases/common/13 pch/c/pch/prog_pch.c deleted file mode 100644 index 4960505..0000000 --- a/test cases/common/13 pch/c/pch/prog_pch.c +++ /dev/null @@ -1,5 +0,0 @@ -#if !defined(_MSC_VER) -#error "This file is only for use with MSVC." -#endif - -#include "prog.h" diff --git a/test cases/common/13 pch/cpp/meson.build b/test cases/common/13 pch/cpp/meson.build index 802c3e1..b01cd58 100644 --- a/test cases/common/13 pch/cpp/meson.build +++ b/test cases/common/13 pch/cpp/meson.build @@ -1 +1 @@ -exe = executable('prog', 'prog.cc', cpp_pch : ['pch/prog.hh', 'pch/prog_pch.cc']) +exe = executable('prog', 'prog.cc', cpp_pch : 'pch/prog.hh') diff --git a/test cases/common/13 pch/cpp/pch/prog_pch.cc b/test cases/common/13 pch/cpp/pch/prog_pch.cc deleted file mode 100644 index aff1225..0000000 --- a/test cases/common/13 pch/cpp/pch/prog_pch.cc +++ /dev/null @@ -1,5 +0,0 @@ -#if !defined(_MSC_VER) -#error "This file is only for use with MSVC." -#endif - -#include "prog.hh" diff --git a/test cases/common/13 pch/generated/meson.build b/test cases/common/13 pch/generated/meson.build index 372a00e..1ef771b 100644 --- a/test cases/common/13 pch/generated/meson.build +++ b/test cases/common/13 pch/generated/meson.build @@ -13,4 +13,4 @@ generated_generator = generator(find_program('gen_generator.py'), arguments: ['@INPUT@', '@OUTPUT@']) exe = executable('prog', 'prog.c', generated_customTarget, generated_generator.process('generated_generator.in'), - c_pch: ['pch/prog_pch.c', 'pch/prog.h']) + c_pch: 'pch/prog.h') diff --git a/test cases/common/13 pch/generated/pch/prog_pch.c b/test cases/common/13 pch/generated/pch/prog_pch.c deleted file mode 100644 index 4960505..0000000 --- a/test cases/common/13 pch/generated/pch/prog_pch.c +++ /dev/null @@ -1,5 +0,0 @@ -#if !defined(_MSC_VER) -#error "This file is only for use with MSVC." -#endif - -#include "prog.h" diff --git a/test cases/common/13 pch/meson.build b/test cases/common/13 pch/meson.build index 43129c9..4438c9e 100644 --- a/test cases/common/13 pch/meson.build +++ b/test cases/common/13 pch/meson.build @@ -3,6 +3,7 @@ project('pch test', 'c', 'cpp') subdir('c') subdir('cpp') subdir('generated') +subdir('userDefined') subdir('withIncludeDirectories') if meson.backend() == 'xcode' diff --git a/test cases/common/13 pch/mixed/meson.build b/test cases/common/13 pch/mixed/meson.build index f0c3eca..cbb7bac 100644 --- a/test cases/common/13 pch/mixed/meson.build +++ b/test cases/common/13 pch/mixed/meson.build @@ -1,17 +1,6 @@ exe = executable( 'prog', files('main.cc', 'func.c'), - c_pch : ['pch/func.h', 'pch/func_pch.c'], - cpp_pch : ['pch/main_pch.cc', 'pch/main.h'], + c_pch : ['pch/func.h'], + cpp_pch : ['pch/main.h'], ) - -# test pch when only a header is given (not supported by msvc) -cc = meson.get_compiler('c') -if not ['msvc', 'clang-cl'].contains(cc.get_id()) - exe2 = executable( - 'prog2', - files('main.cc', 'func.c'), - c_pch : 'pch/func.h', - cpp_pch : 'pch/main.h', - ) -endif diff --git a/test cases/common/13 pch/mixed/pch/func_pch.c b/test cases/common/13 pch/mixed/pch/func_pch.c deleted file mode 100644 index 5566739..0000000 --- a/test cases/common/13 pch/mixed/pch/func_pch.c +++ /dev/null @@ -1 +0,0 @@ -#include"func.h" diff --git a/test cases/common/13 pch/mixed/pch/main_pch.cc b/test cases/common/13 pch/mixed/pch/main_pch.cc deleted file mode 100644 index acd3f57..0000000 --- a/test cases/common/13 pch/mixed/pch/main_pch.cc +++ /dev/null @@ -1 +0,0 @@ -#include"main.h" diff --git a/test cases/common/13 pch/userDefined/meson.build b/test cases/common/13 pch/userDefined/meson.build new file mode 100644 index 0000000..9b60572 --- /dev/null +++ b/test cases/common/13 pch/userDefined/meson.build @@ -0,0 +1,10 @@ +cc = meson.get_compiler('c') +cc_id = cc.get_id() + +# User supplied PCH implementation should override the auto +# generated one. PCH implementations are only supported for +# msvc and generally should not be used at all. Support for +# them is only kept for backwards compatibility. +if cc_id == 'msvc' + exe = executable('prog', 'prog.c', c_pch : ['pch/pch.h', 'pch/pch.c']) +endif diff --git a/test cases/common/13 pch/userDefined/pch/pch.c b/test cases/common/13 pch/userDefined/pch/pch.c new file mode 100644 index 0000000..c107b1a --- /dev/null +++ b/test cases/common/13 pch/userDefined/pch/pch.c @@ -0,0 +1,5 @@ +#include "pch.h" + +int foo() { + return 0; +} diff --git a/test cases/common/13 pch/userDefined/pch/pch.h b/test cases/common/13 pch/userDefined/pch/pch.h new file mode 100644 index 0000000..5d5f8f0 --- /dev/null +++ b/test cases/common/13 pch/userDefined/pch/pch.h @@ -0,0 +1 @@ +int foo(); diff --git a/test cases/common/13 pch/userDefined/prog.c b/test cases/common/13 pch/userDefined/prog.c new file mode 100644 index 0000000..eb068d9 --- /dev/null +++ b/test cases/common/13 pch/userDefined/prog.c @@ -0,0 +1,8 @@ +// No includes here, they need to come from the PCH + +int main(int argc, char **argv) { + // Method is implemented in pch.c. + // This makes sure that we can properly handle user defined + // pch implementation files and not only auto-generated ones. + return foo(); +} diff --git a/test cases/common/13 pch/withIncludeDirectories/meson.build b/test cases/common/13 pch/withIncludeDirectories/meson.build index 2ab2cd8..68e544b 100644 --- a/test cases/common/13 pch/withIncludeDirectories/meson.build +++ b/test cases/common/13 pch/withIncludeDirectories/meson.build @@ -6,4 +6,4 @@ endif exe = executable('prog', 'prog.c', include_directories: 'include', - c_pch : ['pch/prog_pch.c', 'pch/prog.h']) + c_pch : 'pch/prog.h') diff --git a/test cases/common/13 pch/withIncludeDirectories/pch/prog_pch.c b/test cases/common/13 pch/withIncludeDirectories/pch/prog_pch.c deleted file mode 100644 index 4960505..0000000 --- a/test cases/common/13 pch/withIncludeDirectories/pch/prog_pch.c +++ /dev/null @@ -1,5 +0,0 @@ -#if !defined(_MSC_VER) -#error "This file is only for use with MSVC." -#endif - -#include "prog.h" |