aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/backend/vs2010backend.py
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-07-13 22:18:50 +0300
committerGitHub <noreply@github.com>2016-07-13 22:18:50 +0300
commit64919b1c7463d2adceec961350f33707cae9718b (patch)
tree1be6f8d33b822ab20d443fdde18a107f3b45c5a6 /mesonbuild/backend/vs2010backend.py
parent38a896ae5154b54865db57bbd8f3ddc69a8083ba (diff)
parentf8d75883724e115083bff1befa75def42be282c5 (diff)
downloadmeson-64919b1c7463d2adceec961350f33707cae9718b.zip
meson-64919b1c7463d2adceec961350f33707cae9718b.tar.gz
meson-64919b1c7463d2adceec961350f33707cae9718b.tar.bz2
Merge pull request #417 from nirbheek/dll-paths
Fix filenames and paths used in DLL shared library generation
Diffstat (limited to 'mesonbuild/backend/vs2010backend.py')
-rw-r--r--mesonbuild/backend/vs2010backend.py229
1 files changed, 190 insertions, 39 deletions
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index d262e6b..12f224c 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -28,6 +28,27 @@ import xml.dom.minidom
from ..mesonlib import MesonException
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():
def __init__(self, source_dir, build_dir, depfiles):
self.source_dir = source_dir
@@ -76,9 +97,14 @@ class Vs2010Backend(backends.Backend):
outputs = []
custom_target_include_dirs = []
custom_target_output_files = []
+ target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
+ down = self.target_to_build_root(target)
for genlist in target.get_generated_sources():
if isinstance(genlist, build.CustomTarget):
- custom_target_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output]
+ for i in genlist.output:
+ # Path to the generated source from the current vcxproj dir via the build root
+ ipath = os.path.join(down, self.get_target_dir(genlist), i)
+ custom_target_output_files.append(ipath)
idir = self.relpath(self.get_target_dir(genlist), self.get_target_dir(target))
if idir not in custom_target_include_dirs:
custom_target_include_dirs.append(idir)
@@ -89,7 +115,6 @@ class Vs2010Backend(backends.Backend):
outfilelist = genlist.get_outfilelist()
exe_arr = self.exe_object_to_cmd_array(exe)
base_args = generator.get_arglist()
- target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
sole_output = os.path.join(target_private_dir, outfilelist[i])
@@ -123,7 +148,17 @@ class Vs2010Backend(backends.Backend):
def generate(self, interp):
self.resolve_source_conflicts()
self.interpreter = interp
- self.platform = 'Win32'
+ target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None)
+ if target_machine.endswith('64'):
+ # amd64 or x86_64
+ self.platform = 'x64'
+ elif target_machine == 'x86':
+ # x86
+ self.platform = 'Win32'
+ elif 'arm' in target_machine.lower():
+ self.platform = 'ARM'
+ else:
+ raise MesonException('Unsupported Visual Studio platform: ' + target_machine)
self.buildtype = self.environment.coredata.get_builtin_option('buildtype')
sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln')
projlist = self.generate_projects()
@@ -404,6 +439,37 @@ class Vs2010Backend(backends.Backend):
def quote_define_cmdline(cls, arg):
return re.sub(r'^([-/])D(.*?)="(.*)"$', r'\1D\2=\"\3\"', arg)
+ @staticmethod
+ def split_link_args(args):
+ """
+ Split a list of link arguments into three lists:
+ * library search paths
+ * library filenames (or paths)
+ * other link arguments
+ """
+ lpaths = []
+ libs = []
+ other = []
+ for arg in args:
+ if arg.startswith('/LIBPATH:'):
+ lpath = arg[9:]
+ # De-dup library search paths by removing older entries when
+ # a new one is found. This is necessary because unlike other
+ # search paths such as the include path, the library is
+ # searched for in the newest (right-most) search path first.
+ if lpath in lpaths:
+ lpaths.remove(lpath)
+ lpaths.append(lpath)
+ # It's ok if we miss libraries with non-standard extensions here.
+ # They will go into the general link arguments.
+ elif arg.endswith('.lib') or arg.endswith('.a'):
+ # De-dup
+ if arg not in libs:
+ libs.append(arg)
+ else:
+ other.append(arg)
+ return (lpaths, libs, other)
+
def gen_vcxproj(self, target, ofname, guid, compiler):
mlog.debug('Generating vcxproj %s.' % target.name)
entrypoint = 'WinMainCRTStartup'
@@ -424,11 +490,15 @@ class Vs2010Backend(backends.Backend):
return self.gen_run_target_vcxproj(target, ofname, guid)
else:
raise MesonException('Unknown target type for %s' % target.get_basename())
+ # Prefix to use to access the build root from the vcxproj dir
down = self.target_to_build_root(target)
+ # Prefix to use to access the source tree's root from the vcxproj dir
proj_to_src_root = os.path.join(down, self.build_to_src)
+ # 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)
- 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
target_name = target.name
root = ET.Element('Project', {'DefaultTargets' : "Build",
@@ -438,9 +508,10 @@ class Vs2010Backend(backends.Backend):
prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
{'Include' : self.buildtype + '|' + self.platform})
p = ET.SubElement(prjconf, 'Configuration')
- p.text= buildtype
+ p.text= self.buildtype
pl = ET.SubElement(prjconf, 'Platform')
pl.text = self.platform
+ # Globals
globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
guidelem.text = guid
@@ -453,13 +524,68 @@ class Vs2010Backend(backends.Backend):
pname= ET.SubElement(globalgroup, 'ProjectName')
pname.text = project_name
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
+ # Start configuration
type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
ET.SubElement(type_config, 'ConfigurationType').text = conftype
ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
if 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, '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')
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)
@@ -467,6 +593,7 @@ class Vs2010Backend(backends.Backend):
gen_src += custom_src
gen_hdrs += custom_hdrs
gen_langs += custom_langs
+ # Project information
direlem = ET.SubElement(root, 'PropertyGroup')
fver = ET.SubElement(direlem, '_ProjectFileVersion')
fver.text = self.project_file_version
@@ -474,15 +601,13 @@ class Vs2010Backend(backends.Backend):
outdir.text = '.\\'
intdir = ET.SubElement(direlem, 'IntDir')
intdir.text = target.get_id() + '\\'
- tname = ET.SubElement(direlem, 'TargetName')
- tname.text = target_name
- inclinc = ET.SubElement(direlem, 'LinkIncremental')
- inclinc.text = 'true'
+ tfilename = os.path.splitext(target.get_filename())
+ ET.SubElement(direlem, 'TargetName').text = tfilename[0]
+ ET.SubElement(direlem, 'TargetExt').text = tfilename[1]
+ # Build information
compiles = ET.SubElement(root, 'ItemDefinitionGroup')
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)),
proj_to_src_dir] + generated_files_include_dirs
@@ -496,18 +621,24 @@ class Vs2010Backend(backends.Backend):
for l, args in target.extra_args.items():
if l in extra_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
# 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)
+ general_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options)
for d in target.get_external_deps():
- try:
- general_args += d.compile_args
- except AttributeError:
- pass
+ # 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'):
+ inc_dir = arg[2:]
+ # De-dup
+ if inc_dir not in inc_dirs:
+ inc_dirs.append(inc_dir)
+ else:
+ general_args.append(arg)
for l, args in extra_args.items():
extra_args[l] = [Vs2010Backend.quote_define_cmdline(x) for x in args]
@@ -540,8 +671,6 @@ class Vs2010Backend(backends.Backend):
preproc = ET.SubElement(clconf, 'PreprocessorDefinitions')
rebuild = ET.SubElement(clconf, 'MinimalRebuild')
rebuild.text = 'true'
- rtlib = ET.SubElement(clconf, 'RuntimeLibrary')
- rtlib.text = 'MultiThreadedDebugDLL'
funclink = ET.SubElement(clconf, 'FunctionLevelLinking')
funclink.text = 'true'
pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
@@ -564,28 +693,39 @@ class Vs2010Backend(backends.Backend):
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')
- debinfo.text = 'EditAndContinue'
resourcecompile = ET.SubElement(compiles, 'ResourceCompile')
ET.SubElement(resourcecompile, 'PreprocessorDefinitions')
link = ET.SubElement(compiles, 'Link')
# Put all language args here, too.
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)
for l in self.environment.coredata.external_link_args.values():
- extra_link_args += compiler.unix_link_flags_to_native(l)
- extra_link_args += compiler.unix_link_flags_to_native(target.link_args)
+ extra_link_args += l
+ if not isinstance(target, build.StaticLibrary):
+ extra_link_args += target.link_args
+ # External deps must be last because target link libraries may depend on them.
+ for dep in target.get_external_deps():
+ extra_link_args += dep.get_link_args()
+ for d in target.get_dependencies():
+ if isinstance(d, build.StaticLibrary):
+ for dep in d.get_external_deps():
+ extra_link_args += dep.get_link_args()
+ extra_link_args = compiler.unix_link_flags_to_native(extra_link_args)
+ (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args)
if len(extra_link_args) > 0:
extra_link_args.append('%(AdditionalOptions)')
ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
+ if len(additional_libpaths) > 0:
+ additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)')
+ ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths)
- additional_links = []
+ # Add more libraries to be linked if needed
for t in target.get_dependencies():
lobj = self.build.targets[t.get_id()]
- rel_path = self.relpath(lobj.subdir, target.subdir)
- linkname = os.path.join(rel_path, lobj.get_import_filename())
+ linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
additional_links.append(linkname)
for lib in self.get_custom_target_provided_libraries(target):
additional_links.append(self.relpath(lib, self.get_target_dir(target)))
@@ -600,26 +740,37 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links)
ofile = ET.SubElement(link, 'OutputFile')
ofile.text = '$(OutDir)%s' % target.get_filename()
- addlibdir = ET.SubElement(link, 'AdditionalLibraryDirectories')
- addlibdir.text = '%(AdditionalLibraryDirectories)'
subsys = ET.SubElement(link, 'SubSystem')
subsys.text = subsystem
- gendeb = ET.SubElement(link, 'GenerateDebugInformation')
- gendeb.text = 'true'
if isinstance(target, build.SharedLibrary):
+ # DLLs built with MSVC always have an import library except when
+ # they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
- pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
- pdb.text = '$(OutDir}%s.pdb' % target_name
+ # Add module definitions file, if provided
+ if target.vs_module_defs:
+ relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src))
+ ET.SubElement(link, 'ModuleDefinitionFile').text = relpath
+ if '/ZI' in buildtype_args or '/Zi' in buildtype_args:
+ pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
+ pdb.text = '$(OutDir}%s.pdb' % target_name
if isinstance(target, build.Executable):
ET.SubElement(link, 'EntryPointSymbol').text = entrypoint
targetmachine = ET.SubElement(link, 'TargetMachine')
- targetmachine.text = 'MachineX86'
+ targetplatform = self.platform.lower()
+ if targetplatform == 'win32':
+ targetmachine.text = 'MachineX86'
+ elif targetplatform == 'x64':
+ targetmachine.text = 'MachineX64'
+ elif targetplatform == 'arm':
+ targetmachine.text = 'MachineARM'
+ else:
+ raise MesonException('Unsupported Visual Studio target machine: ' + targetmachine)
extra_files = target.extra_files
if len(headers) + len(gen_hdrs) + len(extra_files) > 0:
inc_hdrs = ET.SubElement(root, 'ItemGroup')
for h in headers:
- relpath = h.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src))
ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
for h in gen_hdrs:
ET.SubElement(inc_hdrs, 'CLInclude', Include=h)
@@ -630,7 +781,7 @@ class Vs2010Backend(backends.Backend):
if len(sources) + len(gen_src) + len(pch_sources) > 0:
inc_src = ET.SubElement(root, 'ItemGroup')
for s in sources:
- relpath = s.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
@@ -658,7 +809,7 @@ class Vs2010Backend(backends.Backend):
if self.has_objects(objects, additional_objects, gen_objs):
inc_objs = ET.SubElement(root, 'ItemGroup')
for s in objects:
- relpath = s.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
ET.SubElement(inc_objs, 'Object', Include=relpath)
for s in additional_objects:
ET.SubElement(inc_objs, 'Object', Include=s)