12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196 |
- # Copyright 2014-2016 The Meson development team
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- # http://www.apache.org/licenses/LICENSE-2.0
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import os, sys
- import pickle
- import xml.dom.minidom
- import xml.etree.ElementTree as ET
- from . import backends
- from .. import build
- from .. import dependencies
- from .. import mlog
- from .. import compilers
- from ..build import BuildTarget
- from ..compilers import CompilerArgs
- from ..mesonlib import MesonException, File, get_meson_script
- from ..environment import Environment
- def autodetect_vs_version(build):
- vs_version = os.getenv('VisualStudioVersion', None)
- vs_install_dir = os.getenv('VSINSTALLDIR', None)
- if not vs_version and not vs_install_dir:
- raise MesonException('Could not detect Visual Studio: VisualStudioVersion and VSINSTALLDIR are unset!\n'
- 'Are we inside a Visual Studio build environment? '
- 'You can also try specifying the exact backend to use.')
- # VisualStudioVersion is set since Visual Studio 12.0, but sometimes
- # vcvarsall.bat doesn't set it, so also use VSINSTALLDIR
- if vs_version == '14.0' or 'Visual Studio 14' in vs_install_dir:
- from mesonbuild.backend.vs2015backend import Vs2015Backend
- return Vs2015Backend(build)
- if vs_version == '15.0' or 'Visual Studio 17' in vs_install_dir or \
- 'Visual Studio\\2017' in vs_install_dir:
- from mesonbuild.backend.vs2017backend import Vs2017Backend
- return Vs2017Backend(build)
- if 'Visual Studio 10.0' in vs_install_dir:
- return Vs2010Backend(build)
- raise MesonException('Could not detect Visual Studio using VisualStudioVersion: {!r} or VSINSTALLDIR: {!r}!\n'
- 'Please specify the exact backend to use.'.format(vs_version, vs_install_dir))
- 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
- self.build_dir = build_dir
- self.depfiles = depfiles
- class Vs2010Backend(backends.Backend):
- def __init__(self, build):
- super().__init__(build)
- self.name = 'vs2010'
- self.project_file_version = '10.0.30319.1'
- self.sources_conflicts = {}
- self.platform_toolset = None
- self.vs_version = '2010'
- self.windows_target_platform_version = None
- def object_filename_from_source(self, target, source, is_unity=False):
- basename = os.path.basename(source.fname)
- filename_without_extension = '.'.join(basename.split('.')[:-1])
- if basename in self.sources_conflicts[target.get_id()]:
- # If there are multiple source files with the same basename, we must resolve the conflict
- # by giving each a unique object output file.
- filename_without_extension = '.'.join(source.fname.split('.')[:-1]).replace('/', '_').replace('\\', '_')
- return filename_without_extension + '.' + self.environment.get_object_suffix()
- def resolve_source_conflicts(self):
- for name, target in self.build.targets.items():
- if not isinstance(target, BuildTarget):
- continue
- conflicts = {}
- for s in target.get_sources():
- if hasattr(s, 'held_object'):
- s = s.held_object
- if not isinstance(s, File):
- continue
- basename = os.path.basename(s.fname)
- conflicting_sources = conflicts.get(basename, None)
- if conflicting_sources is None:
- conflicting_sources = []
- conflicts[basename] = conflicting_sources
- conflicting_sources.append(s)
- self.sources_conflicts[target.get_id()] = {name: src_conflicts for name, src_conflicts in conflicts.items()
- if len(src_conflicts) > 1}
- def generate_custom_generator_commands(self, target, parent_node):
- generator_output_files = []
- custom_target_include_dirs = []
- custom_target_output_files = []
- target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
- source_target_dir = self.get_target_source_dir(target)
- down = self.target_to_build_root(target)
- for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
- for i in genlist.get_outputs():
- # 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)
- else:
- generator = genlist.get_generator()
- exe = generator.get_exe()
- infilelist = genlist.get_inputs()
- outfilelist = genlist.get_outputs()
- exe_arr = self.exe_object_to_cmd_array(exe)
- base_args = generator.get_arglist()
- idgroup = ET.SubElement(parent_node, 'ItemGroup')
- for i in range(len(infilelist)):
- if len(infilelist) == len(outfilelist):
- sole_output = os.path.join(target_private_dir, outfilelist[i])
- else:
- sole_output = ''
- curfile = infilelist[i]
- infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src))
- outfiles_rel = genlist.get_outputs_for(curfile)
- outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel]
- generator_output_files += outfiles
- args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)
- for x in base_args]
- args = self.replace_outputs(args, target_private_dir, outfiles_rel)
- args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir())
- .replace("@BUILD_DIR@", target_private_dir)
- for x in args]
- args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args]
- args = [x.replace("@SOURCE_ROOT@", self.environment.get_source_dir())
- .replace("@BUILD_ROOT@", self.environment.get_build_dir())
- for x in args]
- cmd = exe_arr + self.replace_extra_args(args, genlist)
- cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename)
- ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd))
- ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
- return generator_output_files, custom_target_output_files, custom_target_include_dirs
- def generate(self, interp):
- self.resolve_source_conflicts()
- self.interpreter = interp
- 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()
- self.gen_testproj('RUN_TESTS', os.path.join(self.environment.get_build_dir(), 'RUN_TESTS.vcxproj'))
- self.gen_regenproj('REGEN', os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj'))
- self.generate_solution(sln_filename, projlist)
- self.generate_regen_info()
- Vs2010Backend.touch_regen_timestamp(self.environment.get_build_dir())
- @staticmethod
- def get_regen_stampfile(build_dir):
- return os.path.join(os.path.join(build_dir, Environment.private_dir), 'regen.stamp')
- @staticmethod
- def touch_regen_timestamp(build_dir):
- with open(Vs2010Backend.get_regen_stampfile(build_dir), 'w'):
- pass
- def generate_regen_info(self):
- deps = self.get_regen_filelist()
- regeninfo = RegenInfo(self.environment.get_source_dir(),
- self.environment.get_build_dir(),
- deps)
- filename = os.path.join(self.environment.get_scratch_dir(),
- 'regeninfo.dump')
- with open(filename, 'wb') as f:
- pickle.dump(regeninfo, f)
- def get_obj_target_deps(self, obj_list):
- result = {}
- for o in obj_list:
- if isinstance(o, build.ExtractedObjects):
- result[o.target.get_id()] = o.target
- return result.items()
- def get_target_deps(self, t, recursive=False):
- all_deps = {}
- for target in t.values():
- if isinstance(target, build.CustomTarget):
- for d in target.get_target_dependencies():
- all_deps[d.get_id()] = d
- elif isinstance(target, build.RunTarget):
- for d in [target.command] + target.args:
- if isinstance(d, (build.BuildTarget, build.CustomTarget)):
- all_deps[d.get_id()] = d
- elif isinstance(target, build.BuildTarget):
- for ldep in target.link_targets:
- all_deps[ldep.get_id()] = ldep
- for ldep in target.link_whole_targets:
- all_deps[ldep.get_id()] = ldep
- for obj_id, objdep in self.get_obj_target_deps(target.objects):
- all_deps[obj_id] = objdep
- for gendep in target.get_generated_sources():
- if isinstance(gendep, build.CustomTarget):
- all_deps[gendep.get_id()] = gendep
- else:
- gen_exe = gendep.generator.get_exe()
- if isinstance(gen_exe, build.Executable):
- all_deps[gen_exe.get_id()] = gen_exe
- else:
- raise MesonException('Unknown target type for target %s' % target)
- if not t or not recursive:
- return all_deps
- ret = self.get_target_deps(all_deps, recursive)
- ret.update(all_deps)
- return ret
- def generate_solution(self, sln_filename, projlist):
- default_projlist = self.get_build_by_default_targets()
- with open(sln_filename, 'w') as ofile:
- ofile.write('Microsoft Visual Studio Solution File, Format '
- 'Version 11.00\n')
- ofile.write('# Visual Studio ' + self.vs_version + '\n')
- prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n'
- for p in projlist:
- prj_line = prj_templ % (self.environment.coredata.guid,
- p[0], p[1], p[2])
- ofile.write(prj_line)
- target = self.build.targets[p[0]]
- t = {target.get_id(): target}
- # Get direct deps
- all_deps = self.get_target_deps(t)
- # Get recursive deps
- recursive_deps = self.get_target_deps(t, recursive=True)
- ofile.write('\tProjectSection(ProjectDependencies) = '
- 'postProject\n')
- regen_guid = self.environment.coredata.regen_guid
- ofile.write('\t\t{%s} = {%s}\n' % (regen_guid, regen_guid))
- for dep in all_deps.keys():
- guid = self.environment.coredata.target_guids[dep]
- ofile.write('\t\t{%s} = {%s}\n' % (guid, guid))
- ofile.write('EndProjectSection\n')
- ofile.write('EndProject\n')
- for dep, target in recursive_deps.items():
- if p[0] in default_projlist:
- default_projlist[dep] = target
- test_line = prj_templ % (self.environment.coredata.guid,
- 'RUN_TESTS', 'RUN_TESTS.vcxproj',
- self.environment.coredata.test_guid)
- ofile.write(test_line)
- ofile.write('EndProject\n')
- regen_line = prj_templ % (self.environment.coredata.guid,
- 'REGEN', 'REGEN.vcxproj',
- self.environment.coredata.regen_guid)
- ofile.write(regen_line)
- ofile.write('EndProject\n')
- ofile.write('Global\n')
- ofile.write('\tGlobalSection(SolutionConfigurationPlatforms) = '
- 'preSolution\n')
- ofile.write('\t\t%s|%s = %s|%s\n' %
- (self.buildtype, self.platform, self.buildtype,
- self.platform))
- ofile.write('\tEndGlobalSection\n')
- ofile.write('\tGlobalSection(ProjectConfigurationPlatforms) = '
- 'postSolution\n')
- ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' %
- (self.environment.coredata.regen_guid, self.buildtype,
- self.platform, self.buildtype, self.platform))
- ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' %
- (self.environment.coredata.regen_guid, self.buildtype,
- self.platform, self.buildtype, self.platform))
- # Create the solution configuration
- for p in projlist:
- # Add to the list of projects in this solution
- ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' %
- (p[2], self.buildtype, self.platform,
- self.buildtype, self.platform))
- if p[0] in default_projlist and \
- not isinstance(self.build.targets[p[0]], build.RunTarget):
- # Add to the list of projects to be built
- ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' %
- (p[2], self.buildtype, self.platform,
- self.buildtype, self.platform))
- ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' %
- (self.environment.coredata.test_guid, self.buildtype,
- self.platform, self.buildtype, self.platform))
- ofile.write('\tEndGlobalSection\n')
- ofile.write('\tGlobalSection(SolutionProperties) = preSolution\n')
- ofile.write('\t\tHideSolutionNode = FALSE\n')
- ofile.write('\tEndGlobalSection\n')
- ofile.write('EndGlobal\n')
- def generate_projects(self):
- projlist = []
- 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)
- projlist.append((name, relname, uuid))
- return projlist
- def split_sources(self, srclist):
- sources = []
- headers = []
- objects = []
- languages = []
- for i in srclist:
- if self.environment.is_header(i):
- headers.append(i)
- elif self.environment.is_object(i):
- objects.append(i)
- elif self.environment.is_source(i):
- sources.append(i)
- lang = self.lang_from_source_file(i)
- if lang not in languages:
- languages.append(lang)
- elif self.environment.is_library(i):
- pass
- else:
- # Everything that is not an object or source file is considered a header.
- headers.append(i)
- return sources, headers, objects, languages
- def target_to_build_root(self, target):
- if target.subdir == '':
- return ''
- directories = os.path.normpath(target.subdir).split(os.sep)
- return os.sep.join(['..'] * len(directories))
- def quote_arguments(self, arr):
- return ['"%s"' % i for i in arr]
- def create_basic_crap(self, target):
- project_name = target.name
- root = ET.Element('Project', {'DefaultTargets': "Build",
- 'ToolsVersion': '4.0',
- 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'})
- confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'})
- prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
- {'Include': self.buildtype + '|' + self.platform})
- p = ET.SubElement(prjconf, 'Configuration')
- p.text = self.buildtype
- pl = ET.SubElement(prjconf, 'Platform')
- pl.text = self.platform
- globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
- guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
- guidelem.text = '{%s}' % self.environment.coredata.test_guid
- kw = ET.SubElement(globalgroup, 'Keyword')
- kw.text = self.platform + 'Proj'
- p = ET.SubElement(globalgroup, 'Platform')
- p.text = self.platform
- pname = ET.SubElement(globalgroup, 'ProjectName')
- pname.text = project_name
- if self.windows_target_platform_version:
- ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
- type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
- ET.SubElement(type_config, 'ConfigurationType')
- ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
- ET.SubElement(type_config, 'UseOfMfc').text = 'false'
- if self.platform_toolset:
- ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
- direlem = ET.SubElement(root, 'PropertyGroup')
- fver = ET.SubElement(direlem, '_ProjectFileVersion')
- fver.text = self.project_file_version
- outdir = ET.SubElement(direlem, 'OutDir')
- outdir.text = '.\\'
- intdir = ET.SubElement(direlem, 'IntDir')
- intdir.text = target.get_id() + '\\'
- tname = ET.SubElement(direlem, 'TargetName')
- tname.text = target.name
- return root
- def gen_run_target_vcxproj(self, target, ofname, guid):
- root = self.create_basic_crap(target)
- action = ET.SubElement(root, 'ItemDefinitionGroup')
- customstep = ET.SubElement(action, 'PostBuildEvent')
- cmd_raw = [target.command] + target.args
- cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
- self.environment.get_build_dir(),
- self.environment.get_source_dir(),
- self.get_target_dir(target),
- get_meson_script(self.environment, 'mesonintrospect')]
- for i in cmd_raw:
- if isinstance(i, build.BuildTarget):
- cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i)))
- elif isinstance(i, dependencies.ExternalProgram):
- cmd += i.get_command()
- elif isinstance(i, File):
- relfname = i.rel_to_builddir(self.build_to_src)
- cmd.append(os.path.join(self.environment.get_build_dir(), relfname))
- else:
- cmd.append(i)
- cmd_templ = '''"%s" ''' * len(cmd)
- ET.SubElement(customstep, 'Command').text = cmd_templ % tuple(cmd)
- ET.SubElement(customstep, 'Message').text = 'Running custom command.'
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
- self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
- def gen_custom_target_vcxproj(self, target, ofname, guid):
- root = self.create_basic_crap(target)
- action = ET.SubElement(root, 'ItemDefinitionGroup')
- customstep = ET.SubElement(action, 'CustomBuildStep')
- # We need to always use absolute paths because our invocation is always
- # from the target dir, not the build root.
- target.absolute_paths = True
- (srcs, ofilenames, cmd) = self.eval_custom_target_command(target, True)
- depend_files = self.get_custom_target_depend_files(target, True)
- # Always use a wrapper because MSBuild eats random characters when
- # there are many arguments.
- tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
- exe_data = self.serialize_executable(target.command[0], cmd[1:],
- # All targets run from the target dir
- tdir_abs,
- capture=ofilenames[0] if target.capture else None)
- wrapper_cmd = [sys.executable, self.environment.get_build_command(),
- '--internal', 'exe', exe_data]
- ET.SubElement(customstep, 'Command').text = ' '.join(self.quote_arguments(wrapper_cmd))
- ET.SubElement(customstep, 'Outputs').text = ';'.join(ofilenames)
- ET.SubElement(customstep, 'Inputs').text = ';'.join([exe_data] + srcs + depend_files)
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
- self.generate_custom_generator_commands(target, root)
- self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
- @classmethod
- def lang_from_source_file(cls, src):
- ext = src.split('.')[-1]
- if ext in compilers.c_suffixes:
- return 'c'
- if ext in compilers.cpp_suffixes:
- return 'cpp'
- raise MesonException('Could not guess language from source file %s.' % src)
- 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
- lang = Vs2010Backend.lang_from_source_file(source_file)
- 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 add_additional_options(self, lang, parent_node, file_args):
- args = []
- for arg in file_args[lang].to_native():
- if arg == '%(AdditionalOptions)':
- args.append(arg)
- else:
- args.append(self.escape_additional_option(arg))
- ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(args)
- def add_preprocessor_defines(self, lang, parent_node, file_defines):
- defines = []
- for define in file_defines[lang]:
- if define == '%(PreprocessorDefinitions)':
- defines.append(define)
- else:
- defines.append(self.escape_preprocessor_define(define))
- ET.SubElement(parent_node, "PreprocessorDefinitions").text = ';'.join(defines)
- def add_include_dirs(self, lang, parent_node, file_inc_dirs):
- dirs = file_inc_dirs[lang]
- ET.SubElement(parent_node, "AdditionalIncludeDirectories").text = ';'.join(dirs)
- @staticmethod
- def has_objects(objects, additional_objects, generated_objects):
- # Ignore generated objects, those are automatically used by MSBuild because they are part of
- # the CustomBuild Outputs.
- return len(objects) + len(additional_objects) > 0
- @staticmethod
- def add_generated_objects(node, generated_objects):
- # Do not add generated objects to project file. Those are automatically used by MSBuild, because
- # they are part of the CustomBuild Outputs.
- return
- @staticmethod
- def escape_preprocessor_define(define):
- # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx
- table = str.maketrans({'%': '%25', '$': '%24', '@': '%40',
- "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A',
- # We need to escape backslash because it'll be un-escaped by
- # Windows during process creation when it parses the arguments
- # Basically, this converts `\` to `\\`.
- '\\': '\\\\'})
- return define.translate(table)
- @staticmethod
- def escape_additional_option(option):
- # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx
- table = str.maketrans({'%': '%25', '$': '%24', '@': '%40',
- "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A', ' ': '%20'})
- option = option.translate(table)
- # Since we're surrounding the option with ", if it ends in \ that will
- # escape the " when the process arguments are parsed and the starting
- # " will not terminate. So we escape it if that's the case. I'm not
- # kidding, this is how escaping works for process args on Windows.
- if option.endswith('\\'):
- option += '\\'
- return '"{}"'.format(option)
- @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 _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 _prettyprint_vcxproj_xml(self, tree, ofname):
- tree.write(ofname, encoding='utf-8', xml_declaration=True)
- # ElementTree can not do prettyprinting so do it manually
- doc = xml.dom.minidom.parse(ofname)
- with open(ofname, 'w') as of:
- of.write(doc.toprettyxml())
- def gen_vcxproj(self, target, ofname, guid):
- mlog.debug('Generating vcxproj %s.' % target.name)
- entrypoint = 'WinMainCRTStartup'
- subsystem = 'Windows'
- if isinstance(target, build.Executable):
- conftype = 'Application'
- if not target.gui_app:
- subsystem = 'Console'
- entrypoint = 'mainCRTStartup'
- elif isinstance(target, build.StaticLibrary):
- conftype = 'StaticLibrary'
- elif isinstance(target, build.SharedLibrary):
- conftype = 'DynamicLibrary'
- entrypoint = '_DllMainCrtStartup'
- elif isinstance(target, build.CustomTarget):
- return self.gen_custom_target_vcxproj(target, ofname, guid)
- elif isinstance(target, build.RunTarget):
- 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)
- if self.is_unity(target):
- sources = self.generate_unity_files(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
- target_name = target.name
- root = ET.Element('Project', {'DefaultTargets': "Build",
- 'ToolsVersion': '4.0',
- 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'})
- confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'})
- prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
- {'Include': self.buildtype + '|' + self.platform})
- p = ET.SubElement(prjconf, 'Configuration')
- 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 = '{%s}' % guid
- kw = ET.SubElement(globalgroup, 'Keyword')
- kw.text = self.platform + 'Proj'
- ns = ET.SubElement(globalgroup, 'RootNamespace')
- ns.text = target_name
- p = ET.SubElement(globalgroup, 'Platform')
- p.text = self.platform
- pname = ET.SubElement(globalgroup, 'ProjectName')
- pname.text = project_name
- if self.windows_target_platform_version:
- ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version
- 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'
- # 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'
- # 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)
- (custom_src, custom_hdrs, custom_objs, custom_langs) = self.split_sources(custom_target_output_files)
- 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
- outdir = ET.SubElement(direlem, 'OutDir')
- outdir.text = '.\\'
- intdir = ET.SubElement(direlem, 'IntDir')
- intdir.text = target.get_id() + '\\'
- 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')
- # Arguments, include dirs, defines for all files in the current target
- target_args = []
- target_defines = []
- target_inc_dirs = []
- # Arguments, include dirs, defines passed to individual files in
- # a target; perhaps because the args are language-specific
- #
- # file_args is also later split out into defines and include_dirs in
- # case someone passed those in there
- file_args = dict((lang, CompilerArgs(comp)) for lang, comp in target.compilers.items())
- file_defines = dict((lang, []) for lang in target.compilers)
- file_inc_dirs = dict((lang, []) for lang in target.compilers)
- # The order in which these compile args are added must match
- # generate_single_compile() and generate_basic_compiler_args()
- for l, comp in target.compilers.items():
- if l in file_args:
- file_args[l] += compilers.get_base_compile_args(self.environment.coredata.base_options, comp)
- file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options)
- # Add compile args added using add_project_arguments()
- for l, args in self.build.projects_args.get(target.subproject, {}).items():
- if l in file_args:
- file_args[l] += args
- # Add compile args added using add_global_arguments()
- # These override per-project arguments
- for l, args in self.build.global_args.items():
- if l in file_args:
- file_args[l] += args
- if not target.is_cross:
- # Compile args added from the env: CFLAGS/CXXFLAGS, etc. We want these
- # to override all the defaults, but not the per-target compile args.
- for l, args in self.environment.coredata.external_args.items():
- if l in file_args:
- file_args[l] += args
- for args in file_args.values():
- # This is where Visual Studio will insert target_args, target_defines,
- # etc, which are added later from external deps (see below).
- args += ['%(AdditionalOptions)', '%(PreprocessorDefinitions)', '%(AdditionalIncludeDirectories)']
- # Add include dirs from the `include_directories:` kwarg on the target
- # and from `include_directories:` of internal deps of the target.
- #
- # Target include dirs should override internal deps include dirs.
- # This is handled in BuildTarget.process_kwargs()
- #
- # Include dirs from internal deps should override include dirs from
- # external deps and must maintain the order in which they are
- # specified. Hence, we must reverse so that the order is preserved.
- #
- # These are per-target, but we still add them as per-file because we
- # need them to be looked in first.
- for d in reversed(target.get_include_dirs()):
- for i in d.get_incdirs():
- curdir = os.path.join(d.get_curdir(), i)
- args.append('-I' + self.relpath(curdir, target.subdir)) # build dir
- args.append('-I' + os.path.join(proj_to_src_root, curdir)) # src dir
- for i in d.get_extra_build_dirs():
- curdir = os.path.join(d.get_curdir(), i)
- args.append('-I' + self.relpath(curdir, target.subdir)) # build dir
- # Add per-target compile args, f.ex, `c_args : ['/DFOO']`. We set these
- # near the end since these are supposed to override everything else.
- for l, args in target.extra_args.items():
- if l in file_args:
- file_args[l] += args
- # The highest priority includes. In order of directory search:
- # target private dir, target build dir, generated sources include dirs,
- # target source dir
- for args in file_args.values():
- t_inc_dirs = ['.', self.relpath(self.get_target_private_dir(target),
- self.get_target_dir(target))]
- t_inc_dirs += generated_files_include_dirs + [proj_to_src_dir]
- args += ['-I' + arg for arg in t_inc_dirs]
- # Split preprocessor defines and include directories out of the list of
- # all extra arguments. The rest go into %(AdditionalOptions).
- for l, args in file_args.items():
- for arg in args[:]:
- if arg.startswith(('-D', '/D')) or arg == '%(PreprocessorDefinitions)':
- file_args[l].remove(arg)
- # Don't escape the marker
- if arg == '%(PreprocessorDefinitions)':
- define = arg
- else:
- define = arg[2:]
- # De-dup
- if define in file_defines[l]:
- file_defines[l].remove(define)
- file_defines[l].append(define)
- elif arg.startswith(('-I', '/I')) or arg == '%(AdditionalIncludeDirectories)':
- file_args[l].remove(arg)
- # Don't escape the marker
- if arg == '%(AdditionalIncludeDirectories)':
- inc_dir = arg
- else:
- inc_dir = arg[2:]
- # De-dup
- if inc_dir not in file_inc_dirs[l]:
- file_inc_dirs[l].append(inc_dir)
- # Split compile args needed to find external dependencies
- # Link args are added while generating the link command
- for d in reversed(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_args_to_native(d.get_compile_args())
- for arg in d_compile_args:
- if arg.startswith(('-D', '/D')):
- define = arg[2:]
- # De-dup
- if define in target_defines:
- target_defines.remove(define)
- target_defines.append(define)
- elif arg.startswith(('-I', '/I')):
- inc_dir = arg[2:]
- # De-dup
- if inc_dir not in target_inc_dirs:
- target_inc_dirs.append(inc_dir)
- else:
- target_args.append(arg)
- languages += gen_langs
- if len(target_args) > 0:
- target_args.append('%(AdditionalOptions)')
- ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args)
- 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)
- ET.SubElement(clconf, 'MinimalRebuild').text = 'true'
- ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true'
- pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
- # Warning level
- warning_level = self.get_option_for_target('warning_level', target)
- ET.SubElement(clconf, 'WarningLevel').text = 'Level' + str(1 + int(warning_level))
- if self.get_option_for_target('werror', target):
- ET.SubElement(clconf, 'TreatWarningAsError').text = 'true'
- # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default
- pch_sources = {}
- for lang in ['c', 'cpp']:
- pch = target.get_pch(lang)
- if not pch:
- continue
- 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 = header
- pch_include = ET.SubElement(clconf, 'ForcedIncludeFiles')
- pch_include.text = header + ';%(ForcedIncludeFiles)'
- pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile')
- pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2]
- resourcecompile = ET.SubElement(compiles, 'ResourceCompile')
- ET.SubElement(resourcecompile, 'PreprocessorDefinitions')
- # Linker options
- link = ET.SubElement(compiles, 'Link')
- extra_link_args = CompilerArgs(compiler)
- # 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)
- if not isinstance(target, build.StaticLibrary):
- if isinstance(target, build.SharedModule):
- extra_link_args += compiler.get_std_shared_module_link_args()
- # Add link args added using add_project_link_arguments()
- extra_link_args += self.build.get_project_link_args(compiler, target.subproject)
- # Add link args added using add_global_link_arguments()
- # These override per-project link arguments
- extra_link_args += self.build.get_global_link_args(compiler)
- if not target.is_cross:
- # Link args added from the env: LDFLAGS. We want these to
- # override all the defaults but not the per-target link args.
- extra_link_args += self.environment.coredata.external_link_args[compiler.get_language()]
- # Only non-static built targets need link args and link dependencies
- 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():
- # Extend without reordering or de-dup to preserve `-L -l` sets
- # https://github.com/mesonbuild/meson/issues/1718
- extra_link_args.extend_direct(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.extend_direct(dep.get_link_args())
- # Add link args for c_* or cpp_* build options. Currently this only
- # adds c_winlibs and cpp_winlibs when building for Windows. This needs
- # to be after all internal and external libraries so that unresolved
- # symbols from those can be found here. This is needed when the
- # *_winlibs that we want to link to are static mingw64 libraries.
- extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options)
- (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native())
- 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)
- # Add more libraries to be linked if needed
- for t in target.get_dependencies():
- lobj = self.build.targets[t.get_id()]
- linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
- if t in target.link_whole_targets:
- linkname = compiler.get_link_whole_for(linkname)[0]
- 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)))
- additional_objects = []
- for o in self.flatten_object_list(target, down):
- assert(isinstance(o, str))
- additional_objects.append(o)
- for o in custom_objs:
- additional_objects.append(o)
- if len(additional_links) > 0:
- additional_links.append('%(AdditionalDependencies)')
- ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links)
- ofile = ET.SubElement(link, 'OutputFile')
- ofile.text = '$(OutDir)%s' % target.get_filename()
- subsys = ET.SubElement(link, 'SubSystem')
- subsys.text = subsystem
- if (isinstance(target, build.SharedLibrary) or
- isinstance(target, build.Executable)) and target.get_import_filename():
- # 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()
- if isinstance(target, build.SharedLibrary):
- # 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')
- 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 = 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)
- for h in target.extra_files:
- relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src))
- ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
- if len(sources) + len(gen_src) + len(pch_sources) > 0:
- inc_src = ET.SubElement(root, 'ItemGroup')
- 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(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(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)
- 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]
- 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')
- for s in objects:
- 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)
- self.add_generated_objects(inc_objs, gen_objs)
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
- # Reference the regen target.
- ig = ET.SubElement(root, 'ItemGroup')
- pref = ET.SubElement(ig, 'ProjectReference', Include=os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj'))
- ET.SubElement(pref, 'Project').text = self.environment.coredata.regen_guid
- self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
- def gen_regenproj(self, project_name, ofname):
- root = ET.Element('Project', {'DefaultTargets': 'Build',
- 'ToolsVersion': '4.0',
- 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'})
- confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'})
- prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
- {'Include': self.buildtype + '|' + self.platform})
- p = ET.SubElement(prjconf, 'Configuration')
- p.text = self.buildtype
- pl = ET.SubElement(prjconf, 'Platform')
- pl.text = self.platform
- globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
- guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
- guidelem.text = '{%s}' % self.environment.coredata.test_guid
- kw = ET.SubElement(globalgroup, 'Keyword')
- kw.text = self.platform + 'Proj'
- p = ET.SubElement(globalgroup, 'Platform')
- p.text = self.platform
- pname = ET.SubElement(globalgroup, 'ProjectName')
- pname.text = project_name
- if self.windows_target_platform_version:
- ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
- type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
- ET.SubElement(type_config, 'ConfigurationType').text = "Utility"
- ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
- ET.SubElement(type_config, 'UseOfMfc').text = 'false'
- if self.platform_toolset:
- ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
- direlem = ET.SubElement(root, 'PropertyGroup')
- fver = ET.SubElement(direlem, '_ProjectFileVersion')
- fver.text = self.project_file_version
- outdir = ET.SubElement(direlem, 'OutDir')
- outdir.text = '.\\'
- intdir = ET.SubElement(direlem, 'IntDir')
- intdir.text = 'regen-temp\\'
- tname = ET.SubElement(direlem, 'TargetName')
- tname.text = project_name
- action = ET.SubElement(root, 'ItemDefinitionGroup')
- midl = ET.SubElement(action, 'Midl')
- ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)'
- ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)'
- ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h'
- ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb'
- ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c'
- ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c'
- regen_command = [sys.executable,
- self.environment.get_build_command(),
- '--internal',
- 'regencheck']
- private_dir = self.environment.get_scratch_dir()
- cmd_templ = '''setlocal
- "%s" "%s"
- if %%errorlevel%% neq 0 goto :cmEnd
- :cmEnd
- endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone
- :cmErrorLevel
- exit /b %%1
- :cmDone
- if %%errorlevel%% neq 0 goto :VCEnd'''
- igroup = ET.SubElement(root, 'ItemGroup')
- rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule')
- if not os.path.exists(rulefile):
- with open(rulefile, 'w') as f:
- f.write("# Meson regen file.")
- custombuild = ET.SubElement(igroup, 'CustomBuild', Include=rulefile)
- message = ET.SubElement(custombuild, 'Message')
- message.text = 'Checking whether solution needs to be regenerated.'
- ET.SubElement(custombuild, 'Command').text = cmd_templ % \
- ('" "'.join(regen_command), private_dir)
- ET.SubElement(custombuild, 'Outputs').text = Vs2010Backend.get_regen_stampfile(self.environment.get_build_dir())
- deps = self.get_regen_filelist()
- ET.SubElement(custombuild, 'AdditionalInputs').text = ';'.join(deps)
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
- ET.SubElement(root, 'ImportGroup', Label='ExtensionTargets')
- self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
- def gen_testproj(self, target_name, ofname):
- project_name = target_name
- root = ET.Element('Project', {'DefaultTargets': "Build",
- 'ToolsVersion': '4.0',
- 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'})
- confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'})
- prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
- {'Include': self.buildtype + '|' + self.platform})
- p = ET.SubElement(prjconf, 'Configuration')
- p.text = self.buildtype
- pl = ET.SubElement(prjconf, 'Platform')
- pl.text = self.platform
- globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
- guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
- guidelem.text = '{%s}' % self.environment.coredata.test_guid
- kw = ET.SubElement(globalgroup, 'Keyword')
- kw.text = self.platform + 'Proj'
- p = ET.SubElement(globalgroup, 'Platform')
- p.text = self.platform
- pname = ET.SubElement(globalgroup, 'ProjectName')
- pname.text = project_name
- if self.windows_target_platform_version:
- ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
- type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
- ET.SubElement(type_config, 'ConfigurationType')
- ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
- ET.SubElement(type_config, 'UseOfMfc').text = 'false'
- if self.platform_toolset:
- ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
- direlem = ET.SubElement(root, 'PropertyGroup')
- fver = ET.SubElement(direlem, '_ProjectFileVersion')
- fver.text = self.project_file_version
- outdir = ET.SubElement(direlem, 'OutDir')
- outdir.text = '.\\'
- intdir = ET.SubElement(direlem, 'IntDir')
- intdir.text = 'test-temp\\'
- tname = ET.SubElement(direlem, 'TargetName')
- tname.text = target_name
- action = ET.SubElement(root, 'ItemDefinitionGroup')
- midl = ET.SubElement(action, 'Midl')
- ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)'
- ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)'
- ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h'
- ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb'
- ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c'
- ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c'
- postbuild = ET.SubElement(action, 'PostBuildEvent')
- ET.SubElement(postbuild, 'Message')
- # FIXME: No benchmarks?
- test_command = [sys.executable,
- get_meson_script(self.environment, 'mesontest'),
- '--no-rebuild']
- if not self.environment.coredata.get_builtin_option('stdsplit'):
- test_command += ['--no-stdsplit']
- if self.environment.coredata.get_builtin_option('errorlogs'):
- test_command += ['--print-errorlogs']
- cmd_templ = '''setlocal
- "%s"
- if %%errorlevel%% neq 0 goto :cmEnd
- :cmEnd
- endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone
- :cmErrorLevel
- exit /b %%1
- :cmDone
- if %%errorlevel%% neq 0 goto :VCEnd'''
- self.serialize_tests()
- ET.SubElement(postbuild, 'Command').text =\
- cmd_templ % ('" "'.join(test_command))
- ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
- self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
|