3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
7 # Avalanche Studios 2009-2011
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
15 1. Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the distribution.
22 3. The name of the author may not be used to endorse or promote products
23 derived from this software without specific prior written permission.
25 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
26 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 POSSIBILITY OF SUCH DAMAGE.
39 To add this tool to your project:
43 It can be a good idea to add the sync_exec tool too.
45 To generate solution files:
48 To customize the outputs, provide subclasses in your wscript files::
50 from waflib.extras import msvs
51 class vsnode_target(msvs.vsnode_target):
52 def get_build_command(self, props):
53 # likely to be required
54 return "waf.bat build"
55 def collect_source(self):
56 # likely to be required
58 class msvs_bar(msvs.msvs_generator):
60 msvs.msvs_generator.init(self)
61 self.vsnode_target = vsnode_target
63 The msvs class re-uses the same build() function for reading the targets (task generators),
64 you may therefore specify msvs settings on the context object::
67 bld.solution_name = 'foo.sln'
68 bld.waf_command = 'waf.bat'
69 bld.projects_dir = bld.srcnode.make_node('.depproj')
70 bld.projects_dir.mkdir()
72 For visual studio 2008, the command is called 'msvs2008', and the classes
73 such as vsnode_target are wrapped by a decorator class 'wrap_2008' to
74 provide special functionality.
76 To customize platform toolsets, pass additional parameters, for example::
78 class msvs_2013(msvs.msvs_generator):
82 platform_toolset_ver = 'v120'
85 * a project can be either a directory or a target, vcxproj files are written only for targets that have source files
86 * each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path
90 import uuid # requires python 2.5
91 from waflib.Build import BuildContext
92 from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options
94 HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
96 PROJECT_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>
97 <Project DefaultTargets="Build" ToolsVersion="4.0"
98 xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
100 <ItemGroup Label="ProjectConfigurations">
101 ${for b in project.build_properties}
102 <ProjectConfiguration Include="${b.configuration}|${b.platform}">
103 <Configuration>${b.configuration}</Configuration>
104 <Platform>${b.platform}</Platform>
105 </ProjectConfiguration>
109 <PropertyGroup Label="Globals">
110 <ProjectGuid>{${project.uuid}}</ProjectGuid>
111 <Keyword>MakeFileProj</Keyword>
112 <ProjectName>${project.name}</ProjectName>
114 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
116 ${for b in project.build_properties}
117 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'" Label="Configuration">
118 <ConfigurationType>Makefile</ConfigurationType>
119 <OutDir>${b.outdir}</OutDir>
120 <PlatformToolset>${project.platform_toolset_ver}</PlatformToolset>
124 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
125 <ImportGroup Label="ExtensionSettings">
128 ${for b in project.build_properties}
129 <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
130 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
134 ${for b in project.build_properties}
135 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
136 <NMakeBuildCommandLine>${xml:project.get_build_command(b)}</NMakeBuildCommandLine>
137 <NMakeReBuildCommandLine>${xml:project.get_rebuild_command(b)}</NMakeReBuildCommandLine>
138 <NMakeCleanCommandLine>${xml:project.get_clean_command(b)}</NMakeCleanCommandLine>
139 <NMakeIncludeSearchPath>${xml:b.includes_search_path}</NMakeIncludeSearchPath>
140 <NMakePreprocessorDefinitions>${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
141 <IncludePath>${xml:b.includes_search_path}</IncludePath>
142 <ExecutablePath>$(ExecutablePath)</ExecutablePath>
144 ${if getattr(b, 'output_file', None)}
145 <NMakeOutput>${xml:b.output_file}</NMakeOutput>
147 ${if getattr(b, 'deploy_dir', None)}
148 <RemoteRoot>${xml:b.deploy_dir}</RemoteRoot>
153 ${for b in project.build_properties}
154 ${if getattr(b, 'deploy_dir', None)}
155 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
157 <DeploymentType>CopyToHardDrive</DeploymentType>
159 </ItemDefinitionGroup>
164 ${for x in project.source}
165 <${project.get_key(x)} Include='${x.win32path()}' />
168 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
169 <ImportGroup Label="ExtensionTargets">
174 FILTER_TEMPLATE = '''<?xml version="1.0" encoding="UTF-8"?>
175 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
177 ${for x in project.source}
178 <${project.get_key(x)} Include="${x.win32path()}">
179 <Filter>${project.get_filter_name(x.parent)}</Filter>
180 </${project.get_key(x)}>
184 ${for x in project.dirs()}
185 <Filter Include="${project.get_filter_name(x)}">
186 <UniqueIdentifier>{${project.make_uuid(x.win32path())}}</UniqueIdentifier>
193 PROJECT_2008_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>
194 <VisualStudioProject ProjectType="Visual C++" Version="9,00"
195 Name="${xml: project.name}" ProjectGUID="{${project.uuid}}"
196 Keyword="MakeFileProj"
197 TargetFrameworkVersion="196613">
199 ${if project.build_properties}
200 ${for b in project.build_properties}
201 <Platform Name="${xml: b.platform}" />
204 <Platform Name="Win32" />
210 ${if project.build_properties}
211 ${for b in project.build_properties}
213 Name="${xml: b.configuration}|${xml: b.platform}"
214 IntermediateDirectory="$ConfigurationName"
215 OutputDirectory="${xml: b.outdir}"
216 ConfigurationType="0">
219 BuildCommandLine="${xml: project.get_build_command(b)}"
220 ReBuildCommandLine="${xml: project.get_rebuild_command(b)}"
221 CleanCommandLine="${xml: project.get_clean_command(b)}"
222 ${if getattr(b, 'output_file', None)}
223 Output="${xml: b.output_file}"
225 PreprocessorDefinitions="${xml: b.preprocessor_definitions}"
226 IncludeSearchPath="${xml: b.includes_search_path}"
228 ForcedUsingAssemblies=""
229 AssemblySearchPath=""
235 <Configuration Name="Release|Win32" >
242 ${project.display_filter()}
244 </VisualStudioProject>
247 SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver}
248 # Visual Studio ${project.vsver}
249 ${for p in project.all_projects}
250 Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}"
253 GlobalSection(SolutionConfigurationPlatforms) = preSolution
254 ${if project.all_projects}
255 ${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()}
256 ${configuration}|${platform} = ${configuration}|${platform}
260 GlobalSection(ProjectConfigurationPlatforms) = postSolution
261 ${for p in project.all_projects}
262 ${if hasattr(p, 'source')}
263 ${for b in p.build_properties}
264 {${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform}
265 ${if getattr(p, 'is_active', None)}
266 {${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform}
268 ${if getattr(p, 'is_deploy', None)}
269 {${p.uuid}}.${b.configuration}|${b.platform}.Deploy.0 = ${b.configuration}|${b.platform}
275 GlobalSection(SolutionProperties) = preSolution
276 HideSolutionNode = FALSE
278 GlobalSection(NestedProjects) = preSolution
279 ${for p in project.all_projects}
281 {${p.uuid}} = {${p.parent.uuid}}
288 COMPILE_TEMPLATE = '''def f(project):
290 def xml_escape(value):
291 return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
295 #f = open('cmd.txt', 'w')
300 reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M)
301 def compile_template(line):
303 Compile a template expression into a python function (like jsps, but way shorter)
313 extr.append(g('code'))
317 line2 = reg_act.sub(repl, line)
318 params = line2.split('<<|@|>>')
327 buf.append(indent * '\t' + txt)
329 for x in range(len(extr)):
331 app("lst.append(%r)" % params[x])
334 if f.startswith(('if', 'for')):
337 elif f.startswith('py:'):
339 elif f.startswith(('endif', 'endfor')):
341 elif f.startswith(('else', 'elif')):
345 elif f.startswith('xml:'):
346 app('lst.append(xml_escape(%s))' % f[4:])
348 #app('lst.append((%s) or "cannot find %s")' % (f, f))
349 app('lst.append(%s)' % f)
353 app("lst.append(%r)" % params[-1])
355 fun = COMPILE_TEMPLATE % "\n\t".join(buf)
357 return Task.funex(fun)
360 re_blank = re.compile('(\n|\r|\\s)*\n', re.M)
361 def rm_blank_lines(txt):
362 txt = re_blank.sub('\r\n', txt)
367 BOM = bytes(BOM, 'latin-1') # python 3
371 def stealth_write(self, data, flags='wb'):
375 data = data.encode('utf-8') # python 3
377 data = data.decode(sys.getfilesystemencoding(), 'replace')
378 data = data.encode('utf-8')
380 if self.name.endswith(('.vcproj', '.vcxproj')):
384 txt = self.read(flags='rb')
386 raise ValueError('must write')
387 except (IOError, ValueError):
388 self.write(data, flags=flags)
390 Logs.debug('msvs: skipping %s', self.win32path())
391 Node.Node.stealth_write = stealth_write
393 re_win32 = re.compile(r'^([/\\]cygdrive)?[/\\]([a-z])([^a-z0-9_-].*)', re.I)
396 m = re_win32.match(p)
398 return "%s:%s" % (m.group(2).upper(), m.group(3))
400 Node.Node.win32path = win32path
402 re_quote = re.compile("[^a-zA-Z0-9-]")
404 return re_quote.sub("_", s)
406 def xml_escape(value):
407 return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
409 def make_uuid(v, prefix = None):
411 simple utility function
413 if isinstance(v, dict):
414 keys = list(v.keys())
416 tmp = str([(k, v[k]) for k in keys])
419 d = Utils.md5(tmp.encode()).hexdigest().upper()
421 d = '%s%s' % (prefix, d[8:])
422 gid = uuid.UUID(d, version = 4)
423 return str(gid).upper()
425 def diff(node, fromnode):
426 # difference between two nodes, but with "(..)" instead of ".."
446 while id(c1) != id(c2):
458 class build_property(object):
461 class vsnode(object):
463 Abstract class representing visual studio elements
464 We assume that all visual studio nodes have a uuid and a parent
466 def __init__(self, ctx):
467 self.ctx = ctx # msvs context
468 self.name = '' # string, mandatory
469 self.vspath = '' # path in visual studio (name for dirs, absolute path for projects)
470 self.uuid = '' # string, mandatory
471 self.parent = None # parent node for visual studio nesting
475 Override in subclasses...
477 return 'cd /d "%s" & %s' % (self.ctx.srcnode.win32path(), getattr(self.ctx, 'waf_command', 'waf.bat'))
481 Return a special uuid for projects written in the solution file
487 Write the project file, by default, do nothing
491 def make_uuid(self, val):
493 Alias for creating uuid values easily (the templates cannot access global variables)
495 return make_uuid(val)
497 class vsnode_vsdir(vsnode):
499 Nodes representing visual studio folders (which do not match the filesystem tree!)
501 VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
502 def __init__(self, ctx, uuid, name, vspath=''):
503 vsnode.__init__(self, ctx)
504 self.title = self.name = name
506 self.vspath = vspath or name
509 return self.VS_GUID_SOLUTIONFOLDER
511 class vsnode_project(vsnode):
513 Abstract class representing visual studio project elements
514 A project is assumed to be writable, and has a node representing the file to write to
516 VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
518 return self.VS_GUID_VCPROJ
520 def __init__(self, ctx, node):
521 vsnode.__init__(self, ctx)
523 self.uuid = make_uuid(node.win32path())
524 self.name = node.name
525 self.platform_toolset_ver = getattr(ctx, 'platform_toolset_ver', None)
526 self.title = self.path.win32path()
527 self.source = [] # list of node objects
528 self.build_properties = [] # list of properties (nmake commands, output dir, etc)
532 Get the list of parent folders of the source files (header files included)
533 for writing the filters
537 if x.height() > self.tg.path.height() and x not in lst:
540 for x in self.source:
545 Logs.debug('msvs: creating %r', self.path)
547 # first write the project file
548 template1 = compile_template(PROJECT_TEMPLATE)
549 proj_str = template1(self)
550 proj_str = rm_blank_lines(proj_str)
551 self.path.stealth_write(proj_str)
553 # then write the filter
554 template2 = compile_template(FILTER_TEMPLATE)
555 filter_str = template2(self)
556 filter_str = rm_blank_lines(filter_str)
557 tmp = self.path.parent.make_node(self.path.name + '.filters')
558 tmp.stealth_write(filter_str)
560 def get_key(self, node):
562 required for writing the source files
565 if name.endswith(('.cpp', '.c')):
569 def collect_properties(self):
571 Returns a list of triplet (configuration, platform, output_directory)
574 for c in self.ctx.configurations:
575 for p in self.ctx.platforms:
582 x.preprocessor_definitions = ''
583 x.includes_search_path = ''
585 # can specify "deploy_dir" too
587 self.build_properties = ret
589 def get_build_params(self, props):
590 opt = '--execsolution=%s' % self.ctx.get_solution_node().win32path()
591 return (self.get_waf(), opt)
593 def get_build_command(self, props):
594 return "%s build %s" % self.get_build_params(props)
596 def get_clean_command(self, props):
597 return "%s clean %s" % self.get_build_params(props)
599 def get_rebuild_command(self, props):
600 return "%s clean build %s" % self.get_build_params(props)
602 def get_filter_name(self, node):
603 lst = diff(node, self.tg.path)
604 return '\\'.join(lst) or '.'
606 class vsnode_alias(vsnode_project):
607 def __init__(self, ctx, node, name):
608 vsnode_project.__init__(self, ctx, node)
610 self.output_file = ''
612 class vsnode_build_all(vsnode_alias):
614 Fake target used to emulate the behaviour of "make all" (starting one process by target is slow)
615 This is the only alias enabled by default
617 def __init__(self, ctx, node, name='build_all_projects'):
618 vsnode_alias.__init__(self, ctx, node, name)
619 self.is_active = True
621 class vsnode_install_all(vsnode_alias):
623 Fake target used to emulate the behaviour of "make install"
625 def __init__(self, ctx, node, name='install_all_projects'):
626 vsnode_alias.__init__(self, ctx, node, name)
628 def get_build_command(self, props):
629 return "%s build install %s" % self.get_build_params(props)
631 def get_clean_command(self, props):
632 return "%s clean %s" % self.get_build_params(props)
634 def get_rebuild_command(self, props):
635 return "%s clean build install %s" % self.get_build_params(props)
637 class vsnode_project_view(vsnode_alias):
639 Fake target used to emulate a file system view
641 def __init__(self, ctx, node, name='project_view'):
642 vsnode_alias.__init__(self, ctx, node, name)
643 self.tg = self.ctx() # fake one, cannot remove
644 self.exclude_files = Node.exclude_regs + '''
653 ''' % Options.lockfile
655 def collect_source(self):
656 # this is likely to be slow
657 self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files)
659 def get_build_command(self, props):
660 params = self.get_build_params(props) + (self.ctx.cmd,)
661 return "%s %s %s" % params
663 def get_clean_command(self, props):
666 def get_rebuild_command(self, props):
667 return self.get_build_command(props)
669 class vsnode_target(vsnode_project):
671 Visual studio project representing a targets (programs, libraries, etc) and bound
674 def __init__(self, ctx, tg):
676 A project is more or less equivalent to a file/folder
678 base = getattr(ctx, 'projects_dir', None) or tg.path
679 node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node
680 vsnode_project.__init__(self, ctx, node)
681 self.name = quote(tg.name)
682 self.tg = tg # task generator
684 def get_build_params(self, props):
686 Override the default to add the target name
688 opt = '--execsolution=%s' % self.ctx.get_solution_node().win32path()
689 if getattr(self, 'tg', None):
690 opt += " --targets=%s" % self.tg.name
691 return (self.get_waf(), opt)
693 def collect_source(self):
695 source_files = tg.to_nodes(getattr(tg, 'source', []))
696 include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', []))
698 for x in include_dirs:
699 if isinstance(x, str):
700 x = tg.path.find_node(x)
702 lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)]
703 include_files.extend(lst)
706 self.source.extend(list(set(source_files + include_files)))
707 self.source.sort(key=lambda x: x.win32path())
709 def collect_properties(self):
711 Visual studio projects are associated with platforms and configurations (for building especially)
713 super(vsnode_target, self).collect_properties()
714 for x in self.build_properties:
715 x.outdir = self.path.parent.win32path()
716 x.preprocessor_definitions = ''
717 x.includes_search_path = ''
720 tsk = self.tg.link_task
721 except AttributeError:
724 x.output_file = tsk.outputs[0].win32path()
725 x.preprocessor_definitions = ';'.join(tsk.env.DEFINES)
726 x.includes_search_path = ';'.join(self.tg.env.INCPATHS)
728 class msvs_generator(BuildContext):
729 '''generates a visual studio 2010 solution'''
732 numver = '11.00' # Visual Studio Version Number
733 vsver = '2010' # Visual Studio Version Year
734 platform_toolset_ver = 'v110' # Platform Toolset Version Number
738 Some data that needs to be present
740 if not getattr(self, 'configurations', None):
741 self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc
742 if not getattr(self, 'platforms', None):
743 self.platforms = ['Win32']
744 if not getattr(self, 'all_projects', None):
745 self.all_projects = []
746 if not getattr(self, 'project_extension', None):
747 self.project_extension = '.vcxproj'
748 if not getattr(self, 'projects_dir', None):
749 self.projects_dir = self.srcnode.make_node('.depproj')
750 self.projects_dir.mkdir()
752 # bind the classes to the object, so that subclass can provide custom generators
753 if not getattr(self, 'vsnode_vsdir', None):
754 self.vsnode_vsdir = vsnode_vsdir
755 if not getattr(self, 'vsnode_target', None):
756 self.vsnode_target = vsnode_target
757 if not getattr(self, 'vsnode_build_all', None):
758 self.vsnode_build_all = vsnode_build_all
759 if not getattr(self, 'vsnode_install_all', None):
760 self.vsnode_install_all = vsnode_install_all
761 if not getattr(self, 'vsnode_project_view', None):
762 self.vsnode_project_view = vsnode_project_view
764 self.numver = self.__class__.numver
765 self.vsver = self.__class__.vsver
766 self.platform_toolset_ver = self.__class__.platform_toolset_ver
773 if not self.all_envs:
775 self.recurse([self.run_dir])
777 # user initialization
780 # two phases for creating the solution
781 self.collect_projects() # add project objects into "self.all_projects"
782 self.write_files() # write the corresponding project and solution files
784 def collect_projects(self):
786 Fill the list self.all_projects with project objects
787 Fill the list of build targets
789 self.collect_targets()
792 default_project = getattr(self, 'default_project', None)
794 if x.name == default_project:
796 return getattr(x, 'path', None) and x.path.win32path() or x.name
797 self.all_projects.sort(key=sortfun)
799 def write_files(self):
801 Write the project and solution files from the data collected
802 so far. It is unlikely that you will want to change this
804 for p in self.all_projects:
807 # and finally write the solution file
808 node = self.get_solution_node()
810 Logs.warn('Creating %r', node)
811 template1 = compile_template(SOLUTION_TEMPLATE)
812 sln_str = template1(self)
813 sln_str = rm_blank_lines(sln_str)
814 node.stealth_write(sln_str)
816 def get_solution_node(self):
818 The solution filename is required when writing the .vcproj files
819 return self.solution_node and if it does not exist, make one
822 return self.solution_node
823 except AttributeError:
826 solution_name = getattr(self, 'solution_name', None)
827 if not solution_name:
828 solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln'
829 if os.path.isabs(solution_name):
830 self.solution_node = self.root.make_node(solution_name)
832 self.solution_node = self.srcnode.make_node(solution_name)
833 return self.solution_node
835 def project_configurations(self):
837 Helper that returns all the pairs (config,platform)
840 for c in self.configurations:
841 for p in self.platforms:
845 def collect_targets(self):
847 Process the list of task generators
849 for g in self.groups:
851 if not isinstance(tg, TaskGen.task_gen):
854 if not hasattr(tg, 'msvs_includes'):
855 tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', []))
857 if not getattr(tg, 'link_task', None):
860 p = self.vsnode_target(self, tg)
861 p.collect_source() # delegate this processing
862 p.collect_properties()
863 self.all_projects.append(p)
865 def add_aliases(self):
867 Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7
868 We also add an alias for "make install" (disabled by default)
870 base = getattr(self, 'projects_dir', None) or self.tg.path
872 node_project = base.make_node('build_all_projects' + self.project_extension) # Node
873 p_build = self.vsnode_build_all(self, node_project)
874 p_build.collect_properties()
875 self.all_projects.append(p_build)
877 node_project = base.make_node('install_all_projects' + self.project_extension) # Node
878 p_install = self.vsnode_install_all(self, node_project)
879 p_install.collect_properties()
880 self.all_projects.append(p_install)
882 node_project = base.make_node('project_view' + self.project_extension) # Node
883 p_view = self.vsnode_project_view(self, node_project)
884 p_view.collect_source()
885 p_view.collect_properties()
886 self.all_projects.append(p_view)
888 n = self.vsnode_vsdir(self, make_uuid(self.srcnode.win32path() + 'build_aliases'), "build_aliases")
889 p_build.parent = p_install.parent = p_view.parent = n
890 self.all_projects.append(n)
892 def collect_dirs(self):
894 Create the folder structure in the Visual studio project view
897 def make_parents(proj):
898 # look at a project, try to make a parent
899 if getattr(proj, 'parent', None):
900 # aliases already have parents
904 proj.parent = seen[x]
907 # There is not vsnode_vsdir for x.
908 # So create a project representing the folder "x"
909 n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.win32path()), x.name)
910 n.iter_path = x.parent
911 self.all_projects.append(n)
913 # recurse up to the project directory
914 if x.height() > self.srcnode.height() + 1:
917 for p in self.all_projects[:]: # iterate over a copy of all projects
918 if not getattr(p, 'tg', None):
919 # but only projects that have a task generator
922 # make a folder for each task generator
923 p.iter_path = p.tg.path
928 def __init__(self, *k, **kw):
929 cls.__init__(self, *k, **kw)
930 self.project_template = PROJECT_2008_TEMPLATE
932 def display_filter(self):
934 root = build_property()
936 root.sourcefiles = []
944 child = build_property()
945 child.subfilters = []
946 child.sourcefiles = []
950 par = add_path(lst[:-1])
951 par.subfilters.append(child)
954 for x in self.source:
955 # this crap is for enabling subclasses to override get_filter_name
956 tmp = self.get_filter_name(x.parent)
957 tmp = tmp != '.' and tuple(tmp.split('\\')) or ()
964 buf.append('<File RelativePath="%s" FileType="%s"/>\n' % (xml_escape(x.win32path()), self.get_key(x)))
965 for x in n.subfilters:
966 buf.append('<Filter Name="%s">' % xml_escape(x.name))
967 buf.append(display(x))
968 buf.append('</Filter>')
969 return '\n'.join(buf)
973 def get_key(self, node):
975 If you do not want to let visual studio use the default file extensions,
976 override this method to return a value:
977 0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form,
978 4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File,
979 8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File,
980 13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon,
981 18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service,
982 22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File,
983 26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document,
984 29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC
989 Logs.debug('msvs: creating %r', self.path)
990 template1 = compile_template(self.project_template)
991 proj_str = template1(self)
992 proj_str = rm_blank_lines(proj_str)
993 self.path.stealth_write(proj_str)
997 class msvs_2008_generator(msvs_generator):
998 '''generates a visual studio 2008 solution'''
1000 fun = msvs_generator.fun
1005 if not getattr(self, 'project_extension', None):
1006 self.project_extension = '_2008.vcproj'
1007 if not getattr(self, 'solution_name', None):
1008 self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln'
1010 if not getattr(self, 'vsnode_target', None):
1011 self.vsnode_target = wrap_2008(vsnode_target)
1012 if not getattr(self, 'vsnode_build_all', None):
1013 self.vsnode_build_all = wrap_2008(vsnode_build_all)
1014 if not getattr(self, 'vsnode_install_all', None):
1015 self.vsnode_install_all = wrap_2008(vsnode_install_all)
1016 if not getattr(self, 'vsnode_project_view', None):
1017 self.vsnode_project_view = wrap_2008(vsnode_project_view)
1019 msvs_generator.init(self)
1023 If the msvs option is used, try to detect if the build is made from visual studio
1025 ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file')
1027 old = BuildContext.execute
1028 def override_build_state(ctx):
1030 uns = ctx.options.execsolution.replace('.sln', rm)
1031 uns = ctx.root.make_node(uns)
1037 uns = ctx.options.execsolution.replace('.sln', add)
1038 uns = ctx.root.make_node(uns)
1041 except EnvironmentError:
1044 if ctx.options.execsolution:
1045 ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio)
1046 lock('.lastbuildstate', '.unsuccessfulbuild')
1048 lock('.unsuccessfulbuild', '.lastbuildstate')
1051 BuildContext.execute = override_build_state