aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2016-11-04 23:17:24 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-11-10 00:40:16 +0530
commit00dc929b62e8ca0c4c9dcc02ad813f2ec55e85e8 (patch)
tree85ff1de87d8ba3f743a0d5aba3c80e0573832987
parent52eab4b00674b160ba1bdaec8ceeb1114143063d (diff)
downloadmeson-00dc929b62e8ca0c4c9dcc02ad813f2ec55e85e8.zip
meson-00dc929b62e8ca0c4c9dcc02ad813f2ec55e85e8.tar.gz
meson-00dc929b62e8ca0c4c9dcc02ad813f2ec55e85e8.tar.bz2
vs: Properly split per-compiler args into per-file options
Previously we were just dumping all defines and include directories into the target-wide list of defines and include directories. Now we have separate per-target and per-file (actually per-language) arguments, defines, and include directories.
-rw-r--r--mesonbuild/backend/vs2010backend.py160
1 files changed, 96 insertions, 64 deletions
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index f1d949a..c66233e 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -284,20 +284,13 @@ class Vs2010Backend(backends.Backend):
def generate_projects(self):
projlist = []
- comp = None
- for l, c in self.environment.coredata.compilers.items():
- if l == 'c' or l == 'cpp':
- comp = c
- break
- if comp is None:
- raise RuntimeError('C and C++ compilers missing.')
for name, target in self.build.targets.items():
outdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
fname = name + '.vcxproj'
relname = os.path.join(target.subdir, fname)
projfile = os.path.join(outdir, fname)
uuid = self.environment.coredata.target_guids[name]
- self.gen_vcxproj(target, projfile, uuid, comp)
+ self.gen_vcxproj(target, projfile, uuid)
projlist.append((name, relname, uuid))
return projlist
@@ -430,12 +423,26 @@ class Vs2010Backend(backends.Backend):
pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile')
pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang
- def add_additional_options(self, source_file, parent_node, extra_args, has_additional_options_set):
- if has_additional_options_set:
+ def add_additional_options(self, lang, parent_node, file_args):
+ if len(file_args[lang]) == 0:
# We only need per file options if they were not set per project.
return
- lang = Vs2010Backend.lang_from_source_file(source_file)
- ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(extra_args[lang]) + ' %(AdditionalOptions)'
+ args = file_args[lang] + ['%(AdditionalOptions)']
+ ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(args)
+
+ def add_preprocessor_defines(self, lang, parent_node, file_defines):
+ if len(file_defines[lang]) == 0:
+ # We only need per file options if they were not set per project.
+ return
+ defines = file_defines[lang] + ['%(PreprocessorDefinitions)']
+ ET.SubElement(parent_node, "PreprocessorDefinitions").text = ';'.join(defines)
+
+ def add_include_dirs(self, lang, parent_node, file_inc_dirs):
+ if len(file_inc_dirs[lang]) == 0:
+ # We only need per file options if they were not set per project.
+ return
+ dirs = file_inc_dirs[lang] + ['%(AdditionalIncludeDirectories)']
+ ET.SubElement(parent_node, "AdditionalIncludeDirectories").text = ';'.join(dirs)
@staticmethod
def has_objects(objects, additional_objects, generated_objects):
@@ -505,7 +512,19 @@ class Vs2010Backend(backends.Backend):
other.append(arg)
return (lpaths, libs, other)
- def gen_vcxproj(self, target, ofname, guid, compiler):
+ def _get_cl_compiler(self, target):
+ for lang, c in target.compilers.items():
+ if lang in ('c', 'cpp'):
+ return c
+ # No source files, only objects, but we still need a compiler, so
+ # return a found compiler
+ if len(target.objects) > 0:
+ for lang, c in self.environment.coredata.compilers.items():
+ if lang in ('c', 'cpp'):
+ return c
+ raise MesonException('Could not find a C or C++ compiler. MSVC can only build C/C++ projects.')
+
+ def gen_vcxproj(self, target, ofname, guid):
mlog.debug('Generating vcxproj %s.' % target.name)
entrypoint = 'WinMainCRTStartup'
subsystem = 'Windows'
@@ -532,6 +551,7 @@ class Vs2010Backend(backends.Backend):
# Prefix to use to access the source tree's subdir from the vcxproj dir
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
(sources, headers, objects, languages) = self.split_sources(target.sources)
+ compiler = self._get_cl_compiler(target)
buildtype_args = compiler.get_buildtype_args(self.buildtype)
buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype)
project_name = target.name
@@ -643,83 +663,86 @@ class Vs2010Backend(backends.Backend):
# Build information
compiles = ET.SubElement(root, 'ItemDefinitionGroup')
clconf = ET.SubElement(compiles, 'ClCompile')
- inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)),
- proj_to_src_dir] + generated_files_include_dirs
-
- extra_args = {'c': [], 'cpp': []}
+ # Arguments, include dirs, defines for all files in the current target
+ target_args = []
+ target_defines = []
+ target_inc_dirs = ['.', self.relpath(self.get_target_private_dir(target),
+ self.get_target_dir(target)),
+ proj_to_src_dir] + generated_files_include_dirs
+ # Arguments, include dirs, defines passed to individual files in
+ # a target; perhaps because the args are language-specific
+ file_args = dict((lang, []) for lang in target.compilers)
+ file_defines = dict((lang, []) for lang in target.compilers)
+ file_inc_dirs = dict((lang, []) for lang in target.compilers)
for l, args in self.environment.coredata.external_args.items():
- if l in extra_args:
- extra_args[l] += args
+ if l in file_args:
+ file_args[l] += args
for l, args in self.build.global_args.items():
- if l in extra_args:
- extra_args[l] += args
+ if l in file_args:
+ file_args[l] += args
for l, args in target.extra_args.items():
- if l in extra_args:
- extra_args[l] += compiler.unix_compile_flags_to_native(args)
- # FIXME all the internal flags of VS (optimization etc) are represented
- # by their own XML elements. In theory we should split all flags to those
- # that have an XML element and those that don't and serialise them
- # properly. This is a crapton of work for no real gain, so just dump them
- # here.
- general_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options)
+ if l in file_args:
+ file_args[l] += compiler.unix_compile_flags_to_native(args)
+ for l, comp in target.compilers.items():
+ if l in file_args:
+ file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options)
for d in target.get_external_deps():
# Cflags required by external deps might have UNIX-specific flags,
# so filter them out if needed
d_compile_args = compiler.unix_compile_flags_to_native(d.get_compile_args())
for arg in d_compile_args:
- if arg.startswith('-I') or arg.startswith('/I'):
+ if arg.startswith(('-D', '/D')):
+ define = arg[2:]
+ # De-dup
+ if define not in target_defines:
+ target_defines.append(define)
+ elif arg.startswith(('-I', '/I')):
inc_dir = arg[2:]
# De-dup
- if inc_dir not in inc_dirs:
- inc_dirs.append(inc_dir)
+ if inc_dir not in target_inc_dirs:
+ target_inc_dirs.append(inc_dir)
else:
- general_args.append(arg)
+ # De-dup
+ if arg not in target_args:
+ target_args.append(arg)
- defines = []
# Split preprocessor defines and include directories out of the list of
# all extra arguments. The rest go into %(AdditionalOptions).
- for l, args in extra_args.items():
- extra_args[l] = []
+ for l, args in file_args.items():
+ file_args[l] = []
for arg in args:
- if arg.startswith('-D') or arg.startswith('/D'):
+ if arg.startswith(('-D', '/D')):
define = self.escape_preprocessor_define(arg[2:])
# De-dup
- if define not in defines:
- defines.append(define)
- elif arg.startswith('-I') or arg.startswith('/I'):
+ if define not in file_defines[l]:
+ file_defines[l].append(define)
+ elif arg.startswith(('-I', '/I')):
inc_dir = arg[2:]
# De-dup
- if inc_dir not in inc_dirs:
- inc_dirs.append(inc_dir)
+ if inc_dir not in file_inc_dirs[l]:
+ file_inc_dirs[l].append(inc_dir)
else:
- extra_args[l].append(self.escape_additional_option(arg))
+ file_args[l].append(self.escape_additional_option(arg))
languages += gen_langs
- has_language_specific_args = any(l != extra_args['c'] for l in extra_args.values())
- additional_options_set = False
- if not has_language_specific_args or len(languages) == 1:
- if len(languages) == 0:
- extra_args = []
- else:
- extra_args = extra_args[languages[0]]
- extra_args = general_args + extra_args
- if len(extra_args) > 0:
- extra_args.append('%(AdditionalOptions)')
- ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(extra_args)
- additional_options_set = True
+ if len(target_args) > 0:
+ target_args.append('%(AdditionalOptions)')
+ ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args)
+ additional_options_set = True
for d in target.include_dirs:
for i in d.incdirs:
curdir = os.path.join(d.curdir, i)
- inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
- inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir
+ target_inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
+ target_inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir
for i in d.get_extra_build_dirs():
curdir = os.path.join(d.curdir, i)
- inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
+ target_inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
- inc_dirs.append('%(AdditionalIncludeDirectories)')
- ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(inc_dirs)
- ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(defines)
+ target_inc_dirs.append('%(AdditionalIncludeDirectories)')
+ ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(target_inc_dirs)
+ target_defines.append('%(PreprocessorDefinitions)')
+ ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines)
rebuild = ET.SubElement(clconf, 'MinimalRebuild')
rebuild.text = 'true'
funclink = ET.SubElement(clconf, 'FunctionLevelLinking')
@@ -834,19 +857,26 @@ class Vs2010Backend(backends.Backend):
for s in sources:
relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath)
+ lang = Vs2010Backend.lang_from_source_file(s)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
- self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
+ 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)
basename = os.path.basename(s.fname)
if basename in self.sources_conflicts[target.get_id()]:
ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s)
for s in gen_src:
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=s)
+ lang = Vs2010Backend.lang_from_source_file(s)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
- self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
+ 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)
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)
+ lang = Vs2010Backend.lang_from_source_file(s)
pch = ET.SubElement(inc_cl, 'PrecompiledHeader')
pch.text = 'Create'
pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile')
@@ -855,7 +885,9 @@ class Vs2010Backend(backends.Backend):
# 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]
- self.add_additional_options(impl, inc_cl, extra_args, additional_options_set)
+ 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)
if self.has_objects(objects, additional_objects, gen_objs):
inc_objs = ET.SubElement(root, 'ItemGroup')