vs: Set all compiler/linker options correctly

These need to be set via XML tags and not passed directly as
AdditionalOptions. Otherwise the project will end up with inconsistent
compiler options and the build will fail.

Since Meson internals assume that these will be set via a command-line
invocation, we need to detect the presence of various flags in
buildtype_args and buildtype_link_args and set the correct options in
the vcxproj file.

Note that this means different configurations (debug/release/etc) cannot
be enumerated in the vcxproj/sln files and chosen by the user at build
time because arbitrary build characteristics can depend on that. The
only way to support that is by doing a full parse and conversion of
Meson build files (for all build options) to vcxproj files.
pull/417/head
Nirbheek Chauhan 9 years ago
parent 2f8eaa6ed4
commit 23d29ffb14
  1. 108
      mesonbuild/backend/vs2010backend.py

@ -28,6 +28,27 @@ import xml.dom.minidom
from ..mesonlib import MesonException from ..mesonlib import MesonException
from ..environment import Environment from ..environment import Environment
def split_o_flags_args(args):
"""
Splits any /O args and returns them. Does not take care of flags overriding
previous ones. Skips non-O flag arguments.
['/Ox', '/Ob1'] returns ['/Ox', '/Ob1']
['/Oxj', '/MP'] returns ['/Ox', '/Oj']
"""
o_flags = []
for arg in args:
if not arg.startswith('/O'):
continue
flags = list(arg[2:])
# Assume that this one can't be clumped with the others since it takes
# an argument itself
if 'b' in flags:
o_flags.append(arg)
else:
o_flags += ['/O' + f for f in flags]
return o_flags
class RegenInfo(): class RegenInfo():
def __init__(self, source_dir, build_dir, depfiles): def __init__(self, source_dir, build_dir, depfiles):
self.source_dir = source_dir self.source_dir = source_dir
@ -459,7 +480,8 @@ class Vs2010Backend(backends.Backend):
proj_to_src_root = os.path.join(down, self.build_to_src) proj_to_src_root = os.path.join(down, self.build_to_src)
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir) proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
(sources, headers, objects, languages) = self.split_sources(target.sources) (sources, headers, objects, languages) = self.split_sources(target.sources)
buildtype = self.buildtype buildtype_args = compiler.get_buildtype_args(self.buildtype)
buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype)
project_name = target.name project_name = target.name
target_name = target.name target_name = target.name
root = ET.Element('Project', {'DefaultTargets' : "Build", root = ET.Element('Project', {'DefaultTargets' : "Build",
@ -469,9 +491,10 @@ class Vs2010Backend(backends.Backend):
prjconf = ET.SubElement(confitems, 'ProjectConfiguration', prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
{'Include' : self.buildtype + '|' + self.platform}) {'Include' : self.buildtype + '|' + self.platform})
p = ET.SubElement(prjconf, 'Configuration') p = ET.SubElement(prjconf, 'Configuration')
p.text= buildtype p.text= self.buildtype
pl = ET.SubElement(prjconf, 'Platform') pl = ET.SubElement(prjconf, 'Platform')
pl.text = self.platform pl.text = self.platform
# Globals
globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
guidelem.text = guid guidelem.text = guid
@ -484,13 +507,68 @@ class Vs2010Backend(backends.Backend):
pname= ET.SubElement(globalgroup, 'ProjectName') pname= ET.SubElement(globalgroup, 'ProjectName')
pname.text = project_name pname.text = project_name
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props') ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
# Start configuration
type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
ET.SubElement(type_config, 'ConfigurationType').text = conftype ET.SubElement(type_config, 'ConfigurationType').text = conftype
ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
if self.platform_toolset: if self.platform_toolset:
ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset
# FIXME: Meson's LTO support needs to be integrated here
ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false' ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false'
ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' # Let VS auto-set the RTC level
ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'Default'
o_flags = split_o_flags_args(buildtype_args)
if '/Oi' in o_flags:
ET.SubElement(type_config, 'IntrinsicFunctions').text = 'true'
if '/Ob1' in o_flags:
ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'OnlyExplicitInline'
elif '/Ob2' in o_flags:
ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'AnySuitable'
# Size-preserving flags
if '/Os' in o_flags:
ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Size'
else:
ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Speed'
# Incremental linking increases code size
if '/INCREMENTAL:NO' in buildtype_link_args:
ET.SubElement(type_config, 'LinkIncremental').text = 'false'
# CRT type; debug or release
if '/MDd' in buildtype_args:
ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL'
else:
ET.SubElement(type_config, 'UseDebugLibraries').text = 'false'
ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDLL'
# Debug format
if '/ZI' in buildtype_args:
ET.SubElement(type_config, 'DebugInformationFormat').text = 'EditAndContinue'
elif '/Zi' in buildtype_args:
ET.SubElement(type_config, 'DebugInformationFormat').text = 'ProgramDatabase'
elif '/Z7' in buildtype_args:
ET.SubElement(type_config, 'DebugInformationFormat').text = 'OldStyle'
# Generate Debug info
if '/DEBUG' in buildtype_link_args:
ET.SubElement(type_config, 'GenerateDebugInformation').text = 'true'
# Runtime checks
if '/RTC1' in buildtype_args:
ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'EnableFastChecks'
elif '/RTCu' in buildtype_args:
ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'UninitializedLocalUsageCheck'
elif '/RTCs' in buildtype_args:
ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'StackFrameRuntimeCheck'
# Optimization flags
if '/Ox' in o_flags:
ET.SubElement(type_config, 'Optimization').text = 'Full'
elif '/O2' in o_flags:
ET.SubElement(type_config, 'Optimization').text = 'MaxSpeed'
elif '/O1' in o_flags:
ET.SubElement(type_config, 'Optimization').text = 'MinSpace'
elif '/Od' in o_flags:
ET.SubElement(type_config, 'Optimization').text = 'Disabled'
# Warning level
warning_level = self.environment.coredata.get_builtin_option('warning_level')
ET.SubElement(type_config, 'WarningLevel').text = 'Level' + warning_level
# End configuration
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
generated_files, custom_target_output_files, generated_files_include_dirs = self.generate_custom_generator_commands(target, root) generated_files, custom_target_output_files, generated_files_include_dirs = self.generate_custom_generator_commands(target, root)
(gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files) (gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files)
@ -498,6 +576,7 @@ class Vs2010Backend(backends.Backend):
gen_src += custom_src gen_src += custom_src
gen_hdrs += custom_hdrs gen_hdrs += custom_hdrs
gen_langs += custom_langs gen_langs += custom_langs
# Project information
direlem = ET.SubElement(root, 'PropertyGroup') direlem = ET.SubElement(root, 'PropertyGroup')
fver = ET.SubElement(direlem, '_ProjectFileVersion') fver = ET.SubElement(direlem, '_ProjectFileVersion')
fver.text = self.project_file_version fver.text = self.project_file_version
@ -505,8 +584,6 @@ class Vs2010Backend(backends.Backend):
outdir.text = '.\\' outdir.text = '.\\'
intdir = ET.SubElement(direlem, 'IntDir') intdir = ET.SubElement(direlem, 'IntDir')
intdir.text = target.get_id() + '\\' intdir.text = target.get_id() + '\\'
inclinc = ET.SubElement(direlem, 'LinkIncremental')
inclinc.text = 'true'
tfilename = os.path.splitext(target.get_filename()) tfilename = os.path.splitext(target.get_filename())
ET.SubElement(direlem, 'TargetName').text = tfilename[0] ET.SubElement(direlem, 'TargetName').text = tfilename[0]
ET.SubElement(direlem, 'TargetExt').text = tfilename[1] ET.SubElement(direlem, 'TargetExt').text = tfilename[1]
@ -514,8 +591,6 @@ class Vs2010Backend(backends.Backend):
# Build information # Build information
compiles = ET.SubElement(root, 'ItemDefinitionGroup') compiles = ET.SubElement(root, 'ItemDefinitionGroup')
clconf = ET.SubElement(compiles, 'ClCompile') clconf = ET.SubElement(compiles, 'ClCompile')
opt = ET.SubElement(clconf, 'Optimization')
opt.text = 'disabled'
inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)), inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)),
proj_to_src_dir] + generated_files_include_dirs proj_to_src_dir] + generated_files_include_dirs
@ -529,13 +604,12 @@ class Vs2010Backend(backends.Backend):
for l, args in target.extra_args.items(): for l, args in target.extra_args.items():
if l in extra_args: if l in extra_args:
extra_args[l] += compiler.unix_compile_flags_to_native(args) extra_args[l] += compiler.unix_compile_flags_to_native(args)
general_args = compiler.get_buildtype_args(self.buildtype).copy()
# FIXME all the internal flags of VS (optimization etc) are represented # 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 # 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 # 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 # properly. This is a crapton of work for no real gain, so just dump them
# here. # here.
general_args += compiler.get_option_compile_args(self.environment.coredata.compiler_options) general_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options)
for d in target.get_external_deps(): for d in target.get_external_deps():
# Cflags required by external deps might have UNIX-specific flags, # Cflags required by external deps might have UNIX-specific flags,
# so filter them out if needed # so filter them out if needed
@ -577,8 +651,6 @@ class Vs2010Backend(backends.Backend):
preproc = ET.SubElement(clconf, 'PreprocessorDefinitions') preproc = ET.SubElement(clconf, 'PreprocessorDefinitions')
rebuild = ET.SubElement(clconf, 'MinimalRebuild') rebuild = ET.SubElement(clconf, 'MinimalRebuild')
rebuild.text = 'true' rebuild.text = 'true'
rtlib = ET.SubElement(clconf, 'RuntimeLibrary')
rtlib.text = 'MultiThreadedDebugDLL'
funclink = ET.SubElement(clconf, 'FunctionLevelLinking') funclink = ET.SubElement(clconf, 'FunctionLevelLinking')
funclink.text = 'true' funclink.text = 'true'
pch_node = ET.SubElement(clconf, 'PrecompiledHeader') pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
@ -601,15 +673,14 @@ class Vs2010Backend(backends.Backend):
pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile') pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile')
pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2] pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2]
warnings = ET.SubElement(clconf, 'WarningLevel')
warnings.text = 'Level3'
debinfo = ET.SubElement(clconf, 'DebugInformationFormat')
debinfo.text = 'EditAndContinue'
resourcecompile = ET.SubElement(compiles, 'ResourceCompile') resourcecompile = ET.SubElement(compiles, 'ResourceCompile')
ET.SubElement(resourcecompile, 'PreprocessorDefinitions') ET.SubElement(resourcecompile, 'PreprocessorDefinitions')
link = ET.SubElement(compiles, 'Link') link = ET.SubElement(compiles, 'Link')
# Put all language args here, too. # Put all language args here, too.
extra_link_args = compiler.get_option_link_args(self.environment.coredata.compiler_options) extra_link_args = compiler.get_option_link_args(self.environment.coredata.compiler_options)
# FIXME: Can these buildtype linker args be added as tags in the
# vcxproj file (similar to buildtype compiler args) instead of in
# AdditionalOptions?
extra_link_args += compiler.get_buildtype_linker_args(self.buildtype) extra_link_args += compiler.get_buildtype_linker_args(self.buildtype)
for l in self.environment.coredata.external_link_args.values(): for l in self.environment.coredata.external_link_args.values():
extra_link_args += l extra_link_args += l
@ -651,14 +722,13 @@ class Vs2010Backend(backends.Backend):
ofile.text = '$(OutDir)%s' % target.get_filename() ofile.text = '$(OutDir)%s' % target.get_filename()
subsys = ET.SubElement(link, 'SubSystem') subsys = ET.SubElement(link, 'SubSystem')
subsys.text = subsystem subsys.text = subsystem
gendeb = ET.SubElement(link, 'GenerateDebugInformation')
gendeb.text = 'true'
if isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedLibrary):
# DLLs built with MSVC always have an import library except when # DLLs built with MSVC always have an import library except when
# they're data-only DLLs, but we don't support those yet. # they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename() ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
pdb = ET.SubElement(link, 'ProgramDataBaseFileName') if '/ZI' in buildtype_args or '/Zi' in buildtype_args:
pdb.text = '$(OutDir}%s.pdb' % target_name pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
pdb.text = '$(OutDir}%s.pdb' % target_name
if isinstance(target, build.Executable): if isinstance(target, build.Executable):
ET.SubElement(link, 'EntryPointSymbol').text = entrypoint ET.SubElement(link, 'EntryPointSymbol').text = entrypoint
targetmachine = ET.SubElement(link, 'TargetMachine') targetmachine = ET.SubElement(link, 'TargetMachine')

Loading…
Cancel
Save