diff options
author | David Robillard <d@drobilla.net> | 2019-04-21 22:56:13 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2019-04-21 22:56:13 +0200 |
commit | bc596356af71d95eb2a341d0324a76e6b7e59a73 (patch) | |
tree | b98fff0fffd6503acd8cb1cd452e055749ac94c0 /waflib/extras/msvs.py | |
parent | 683d47cb7fddf5447de76cdf80041b6b230de93c (diff) | |
download | serd-bc596356af71d95eb2a341d0324a76e6b7e59a73.tar.gz serd-bc596356af71d95eb2a341d0324a76e6b7e59a73.tar.bz2 serd-bc596356af71d95eb2a341d0324a76e6b7e59a73.zip |
Switch to using a submodule for autowaf
Diffstat (limited to 'waflib/extras/msvs.py')
m--------- | waflib | 0 | ||||
-rw-r--r-- | waflib/extras/msvs.py | 1048 |
2 files changed, 0 insertions, 1048 deletions
diff --git a/waflib b/waflib new file mode 160000 +Subproject 2314e236ca6e7d94a26c3c17091da0f25f5867f diff --git a/waflib/extras/msvs.py b/waflib/extras/msvs.py deleted file mode 100644 index 8aa2db0b..00000000 --- a/waflib/extras/msvs.py +++ /dev/null @@ -1,1048 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# Avalanche Studios 2009-2011 -# Thomas Nagy 2011 - -""" -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -""" - -""" -To add this tool to your project: -def options(conf): - opt.load('msvs') - -It can be a good idea to add the sync_exec tool too. - -To generate solution files: -$ waf configure msvs - -To customize the outputs, provide subclasses in your wscript files:: - - from waflib.extras import msvs - class vsnode_target(msvs.vsnode_target): - def get_build_command(self, props): - # likely to be required - return "waf.bat build" - def collect_source(self): - # likely to be required - ... - class msvs_bar(msvs.msvs_generator): - def init(self): - msvs.msvs_generator.init(self) - self.vsnode_target = vsnode_target - -The msvs class re-uses the same build() function for reading the targets (task generators), -you may therefore specify msvs settings on the context object:: - - def build(bld): - bld.solution_name = 'foo.sln' - bld.waf_command = 'waf.bat' - bld.projects_dir = bld.srcnode.make_node('.depproj') - bld.projects_dir.mkdir() - -For visual studio 2008, the command is called 'msvs2008', and the classes -such as vsnode_target are wrapped by a decorator class 'wrap_2008' to -provide special functionality. - -To customize platform toolsets, pass additional parameters, for example:: - - class msvs_2013(msvs.msvs_generator): - cmd = 'msvs2013' - numver = '13.00' - vsver = '2013' - platform_toolset_ver = 'v120' - -ASSUMPTIONS: -* a project can be either a directory or a target, vcxproj files are written only for targets that have source files -* each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path -""" - -import os, re, sys -import uuid # requires python 2.5 -from waflib.Build import BuildContext -from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options - -HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)' - -PROJECT_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" - xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - - <ItemGroup Label="ProjectConfigurations"> - ${for b in project.build_properties} - <ProjectConfiguration Include="${b.configuration}|${b.platform}"> - <Configuration>${b.configuration}</Configuration> - <Platform>${b.platform}</Platform> - </ProjectConfiguration> - ${endfor} - </ItemGroup> - - <PropertyGroup Label="Globals"> - <ProjectGuid>{${project.uuid}}</ProjectGuid> - <Keyword>MakeFileProj</Keyword> - <ProjectName>${project.name}</ProjectName> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - - ${for b in project.build_properties} - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'" Label="Configuration"> - <ConfigurationType>Makefile</ConfigurationType> - <OutDir>${b.outdir}</OutDir> - <PlatformToolset>${project.platform_toolset_ver}</PlatformToolset> - </PropertyGroup> - ${endfor} - - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - - ${for b in project.build_properties} - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - ${endfor} - - ${for b in project.build_properties} - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'"> - <NMakeBuildCommandLine>${xml:project.get_build_command(b)}</NMakeBuildCommandLine> - <NMakeReBuildCommandLine>${xml:project.get_rebuild_command(b)}</NMakeReBuildCommandLine> - <NMakeCleanCommandLine>${xml:project.get_clean_command(b)}</NMakeCleanCommandLine> - <NMakeIncludeSearchPath>${xml:b.includes_search_path}</NMakeIncludeSearchPath> - <NMakePreprocessorDefinitions>${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions> - <IncludePath>${xml:b.includes_search_path}</IncludePath> - <ExecutablePath>$(ExecutablePath)</ExecutablePath> - - ${if getattr(b, 'output_file', None)} - <NMakeOutput>${xml:b.output_file}</NMakeOutput> - ${endif} - ${if getattr(b, 'deploy_dir', None)} - <RemoteRoot>${xml:b.deploy_dir}</RemoteRoot> - ${endif} - </PropertyGroup> - ${endfor} - - ${for b in project.build_properties} - ${if getattr(b, 'deploy_dir', None)} - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'"> - <Deploy> - <DeploymentType>CopyToHardDrive</DeploymentType> - </Deploy> - </ItemDefinitionGroup> - ${endif} - ${endfor} - - <ItemGroup> - ${for x in project.source} - <${project.get_key(x)} Include='${x.win32path()}' /> - ${endfor} - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> -''' - -FILTER_TEMPLATE = '''<?xml version="1.0" encoding="UTF-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - ${for x in project.source} - <${project.get_key(x)} Include="${x.win32path()}"> - <Filter>${project.get_filter_name(x.parent)}</Filter> - </${project.get_key(x)}> - ${endfor} - </ItemGroup> - <ItemGroup> - ${for x in project.dirs()} - <Filter Include="${project.get_filter_name(x)}"> - <UniqueIdentifier>{${project.make_uuid(x.win32path())}}</UniqueIdentifier> - </Filter> - ${endfor} - </ItemGroup> -</Project> -''' - -PROJECT_2008_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?> -<VisualStudioProject ProjectType="Visual C++" Version="9,00" - Name="${xml: project.name}" ProjectGUID="{${project.uuid}}" - Keyword="MakeFileProj" - TargetFrameworkVersion="196613"> - <Platforms> - ${if project.build_properties} - ${for b in project.build_properties} - <Platform Name="${xml: b.platform}" /> - ${endfor} - ${else} - <Platform Name="Win32" /> - ${endif} - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - ${if project.build_properties} - ${for b in project.build_properties} - <Configuration - Name="${xml: b.configuration}|${xml: b.platform}" - IntermediateDirectory="$ConfigurationName" - OutputDirectory="${xml: b.outdir}" - ConfigurationType="0"> - <Tool - Name="VCNMakeTool" - BuildCommandLine="${xml: project.get_build_command(b)}" - ReBuildCommandLine="${xml: project.get_rebuild_command(b)}" - CleanCommandLine="${xml: project.get_clean_command(b)}" - ${if getattr(b, 'output_file', None)} - Output="${xml: b.output_file}" - ${endif} - PreprocessorDefinitions="${xml: b.preprocessor_definitions}" - IncludeSearchPath="${xml: b.includes_search_path}" - ForcedIncludes="" - ForcedUsingAssemblies="" - AssemblySearchPath="" - CompileAsManaged="" - /> - </Configuration> - ${endfor} - ${else} - <Configuration Name="Release|Win32" > - </Configuration> - ${endif} - </Configurations> - <References> - </References> - <Files> -${project.display_filter()} - </Files> -</VisualStudioProject> -''' - -SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver} -# Visual Studio ${project.vsver} -${for p in project.all_projects} -Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}" -EndProject${endfor} -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - ${if project.all_projects} - ${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()} - ${configuration}|${platform} = ${configuration}|${platform} - ${endfor} - ${endif} - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - ${for p in project.all_projects} - ${if hasattr(p, 'source')} - ${for b in p.build_properties} - {${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform} - ${if getattr(p, 'is_active', None)} - {${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform} - ${endif} - ${if getattr(p, 'is_deploy', None)} - {${p.uuid}}.${b.configuration}|${b.platform}.Deploy.0 = ${b.configuration}|${b.platform} - ${endif} - ${endfor} - ${endif} - ${endfor} - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - ${for p in project.all_projects} - ${if p.parent} - {${p.uuid}} = {${p.parent.uuid}} - ${endif} - ${endfor} - EndGlobalSection -EndGlobal -''' - -COMPILE_TEMPLATE = '''def f(project): - lst = [] - def xml_escape(value): - return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") - - %s - - #f = open('cmd.txt', 'w') - #f.write(str(lst)) - #f.close() - return ''.join(lst) -''' -reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M) -def compile_template(line): - """ - Compile a template expression into a python function (like jsps, but way shorter) - """ - extr = [] - def repl(match): - g = match.group - if g('dollar'): - return "$" - elif g('backslash'): - return "\\" - elif g('subst'): - extr.append(g('code')) - return "<<|@|>>" - return None - - line2 = reg_act.sub(repl, line) - params = line2.split('<<|@|>>') - assert(extr) - - - indent = 0 - buf = [] - app = buf.append - - def app(txt): - buf.append(indent * '\t' + txt) - - for x in range(len(extr)): - if params[x]: - app("lst.append(%r)" % params[x]) - - f = extr[x] - if f.startswith(('if', 'for')): - app(f + ':') - indent += 1 - elif f.startswith('py:'): - app(f[3:]) - elif f.startswith(('endif', 'endfor')): - indent -= 1 - elif f.startswith(('else', 'elif')): - indent -= 1 - app(f + ':') - indent += 1 - elif f.startswith('xml:'): - app('lst.append(xml_escape(%s))' % f[4:]) - else: - #app('lst.append((%s) or "cannot find %s")' % (f, f)) - app('lst.append(%s)' % f) - - if extr: - if params[-1]: - app("lst.append(%r)" % params[-1]) - - fun = COMPILE_TEMPLATE % "\n\t".join(buf) - #print(fun) - return Task.funex(fun) - - -re_blank = re.compile('(\n|\r|\\s)*\n', re.M) -def rm_blank_lines(txt): - txt = re_blank.sub('\r\n', txt) - return txt - -BOM = '\xef\xbb\xbf' -try: - BOM = bytes(BOM, 'latin-1') # python 3 -except TypeError: - pass - -def stealth_write(self, data, flags='wb'): - try: - unicode - except NameError: - data = data.encode('utf-8') # python 3 - else: - data = data.decode(sys.getfilesystemencoding(), 'replace') - data = data.encode('utf-8') - - if self.name.endswith(('.vcproj', '.vcxproj')): - data = BOM + data - - try: - txt = self.read(flags='rb') - if txt != data: - raise ValueError('must write') - except (IOError, ValueError): - self.write(data, flags=flags) - else: - Logs.debug('msvs: skipping %s', self.win32path()) -Node.Node.stealth_write = stealth_write - -re_win32 = re.compile(r'^([/\\]cygdrive)?[/\\]([a-z])([^a-z0-9_-].*)', re.I) -def win32path(self): - p = self.abspath() - m = re_win32.match(p) - if m: - return "%s:%s" % (m.group(2).upper(), m.group(3)) - return p -Node.Node.win32path = win32path - -re_quote = re.compile("[^a-zA-Z0-9-]") -def quote(s): - return re_quote.sub("_", s) - -def xml_escape(value): - return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") - -def make_uuid(v, prefix = None): - """ - simple utility function - """ - if isinstance(v, dict): - keys = list(v.keys()) - keys.sort() - tmp = str([(k, v[k]) for k in keys]) - else: - tmp = str(v) - d = Utils.md5(tmp.encode()).hexdigest().upper() - if prefix: - d = '%s%s' % (prefix, d[8:]) - gid = uuid.UUID(d, version = 4) - return str(gid).upper() - -def diff(node, fromnode): - # difference between two nodes, but with "(..)" instead of ".." - c1 = node - c2 = fromnode - - c1h = c1.height() - c2h = c2.height() - - lst = [] - up = 0 - - while c1h > c2h: - lst.append(c1.name) - c1 = c1.parent - c1h -= 1 - - while c2h > c1h: - up += 1 - c2 = c2.parent - c2h -= 1 - - while id(c1) != id(c2): - lst.append(c1.name) - up += 1 - - c1 = c1.parent - c2 = c2.parent - - for i in range(up): - lst.append('(..)') - lst.reverse() - return tuple(lst) - -class build_property(object): - pass - -class vsnode(object): - """ - Abstract class representing visual studio elements - We assume that all visual studio nodes have a uuid and a parent - """ - def __init__(self, ctx): - self.ctx = ctx # msvs context - self.name = '' # string, mandatory - self.vspath = '' # path in visual studio (name for dirs, absolute path for projects) - self.uuid = '' # string, mandatory - self.parent = None # parent node for visual studio nesting - - def get_waf(self): - """ - Override in subclasses... - """ - return 'cd /d "%s" & %s' % (self.ctx.srcnode.win32path(), getattr(self.ctx, 'waf_command', 'waf.bat')) - - def ptype(self): - """ - Return a special uuid for projects written in the solution file - """ - pass - - def write(self): - """ - Write the project file, by default, do nothing - """ - pass - - def make_uuid(self, val): - """ - Alias for creating uuid values easily (the templates cannot access global variables) - """ - return make_uuid(val) - -class vsnode_vsdir(vsnode): - """ - Nodes representing visual studio folders (which do not match the filesystem tree!) - """ - VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8" - def __init__(self, ctx, uuid, name, vspath=''): - vsnode.__init__(self, ctx) - self.title = self.name = name - self.uuid = uuid - self.vspath = vspath or name - - def ptype(self): - return self.VS_GUID_SOLUTIONFOLDER - -class vsnode_project(vsnode): - """ - Abstract class representing visual studio project elements - A project is assumed to be writable, and has a node representing the file to write to - """ - VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" - def ptype(self): - return self.VS_GUID_VCPROJ - - def __init__(self, ctx, node): - vsnode.__init__(self, ctx) - self.path = node - self.uuid = make_uuid(node.win32path()) - self.name = node.name - self.platform_toolset_ver = getattr(ctx, 'platform_toolset_ver', None) - self.title = self.path.win32path() - self.source = [] # list of node objects - self.build_properties = [] # list of properties (nmake commands, output dir, etc) - - def dirs(self): - """ - Get the list of parent folders of the source files (header files included) - for writing the filters - """ - lst = [] - def add(x): - if x.height() > self.tg.path.height() and x not in lst: - lst.append(x) - add(x.parent) - for x in self.source: - add(x.parent) - return lst - - def write(self): - Logs.debug('msvs: creating %r', self.path) - - # first write the project file - template1 = compile_template(PROJECT_TEMPLATE) - proj_str = template1(self) - proj_str = rm_blank_lines(proj_str) - self.path.stealth_write(proj_str) - - # then write the filter - template2 = compile_template(FILTER_TEMPLATE) - filter_str = template2(self) - filter_str = rm_blank_lines(filter_str) - tmp = self.path.parent.make_node(self.path.name + '.filters') - tmp.stealth_write(filter_str) - - def get_key(self, node): - """ - required for writing the source files - """ - name = node.name - if name.endswith(('.cpp', '.c')): - return 'ClCompile' - return 'ClInclude' - - def collect_properties(self): - """ - Returns a list of triplet (configuration, platform, output_directory) - """ - ret = [] - for c in self.ctx.configurations: - for p in self.ctx.platforms: - x = build_property() - x.outdir = '' - - x.configuration = c - x.platform = p - - x.preprocessor_definitions = '' - x.includes_search_path = '' - - # can specify "deploy_dir" too - ret.append(x) - self.build_properties = ret - - def get_build_params(self, props): - opt = '--execsolution=%s' % self.ctx.get_solution_node().win32path() - return (self.get_waf(), opt) - - def get_build_command(self, props): - return "%s build %s" % self.get_build_params(props) - - def get_clean_command(self, props): - return "%s clean %s" % self.get_build_params(props) - - def get_rebuild_command(self, props): - return "%s clean build %s" % self.get_build_params(props) - - def get_filter_name(self, node): - lst = diff(node, self.tg.path) - return '\\'.join(lst) or '.' - -class vsnode_alias(vsnode_project): - def __init__(self, ctx, node, name): - vsnode_project.__init__(self, ctx, node) - self.name = name - self.output_file = '' - -class vsnode_build_all(vsnode_alias): - """ - Fake target used to emulate the behaviour of "make all" (starting one process by target is slow) - This is the only alias enabled by default - """ - def __init__(self, ctx, node, name='build_all_projects'): - vsnode_alias.__init__(self, ctx, node, name) - self.is_active = True - -class vsnode_install_all(vsnode_alias): - """ - Fake target used to emulate the behaviour of "make install" - """ - def __init__(self, ctx, node, name='install_all_projects'): - vsnode_alias.__init__(self, ctx, node, name) - - def get_build_command(self, props): - return "%s build install %s" % self.get_build_params(props) - - def get_clean_command(self, props): - return "%s clean %s" % self.get_build_params(props) - - def get_rebuild_command(self, props): - return "%s clean build install %s" % self.get_build_params(props) - -class vsnode_project_view(vsnode_alias): - """ - Fake target used to emulate a file system view - """ - def __init__(self, ctx, node, name='project_view'): - vsnode_alias.__init__(self, ctx, node, name) - self.tg = self.ctx() # fake one, cannot remove - self.exclude_files = Node.exclude_regs + ''' -waf-2* -waf3-2*/** -.waf-2* -.waf3-2*/** -**/*.sdf -**/*.suo -**/*.ncb -**/%s - ''' % Options.lockfile - - def collect_source(self): - # this is likely to be slow - self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files) - - def get_build_command(self, props): - params = self.get_build_params(props) + (self.ctx.cmd,) - return "%s %s %s" % params - - def get_clean_command(self, props): - return "" - - def get_rebuild_command(self, props): - return self.get_build_command(props) - -class vsnode_target(vsnode_project): - """ - Visual studio project representing a targets (programs, libraries, etc) and bound - to a task generator - """ - def __init__(self, ctx, tg): - """ - A project is more or less equivalent to a file/folder - """ - base = getattr(ctx, 'projects_dir', None) or tg.path - node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node - vsnode_project.__init__(self, ctx, node) - self.name = quote(tg.name) - self.tg = tg # task generator - - def get_build_params(self, props): - """ - Override the default to add the target name - """ - opt = '--execsolution=%s' % self.ctx.get_solution_node().win32path() - if getattr(self, 'tg', None): - opt += " --targets=%s" % self.tg.name - return (self.get_waf(), opt) - - def collect_source(self): - tg = self.tg - source_files = tg.to_nodes(getattr(tg, 'source', [])) - include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', [])) - include_files = [] - for x in include_dirs: - if isinstance(x, str): - x = tg.path.find_node(x) - if x: - lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)] - include_files.extend(lst) - - # remove duplicates - self.source.extend(list(set(source_files + include_files))) - self.source.sort(key=lambda x: x.win32path()) - - def collect_properties(self): - """ - Visual studio projects are associated with platforms and configurations (for building especially) - """ - super(vsnode_target, self).collect_properties() - for x in self.build_properties: - x.outdir = self.path.parent.win32path() - x.preprocessor_definitions = '' - x.includes_search_path = '' - - try: - tsk = self.tg.link_task - except AttributeError: - pass - else: - x.output_file = tsk.outputs[0].win32path() - x.preprocessor_definitions = ';'.join(tsk.env.DEFINES) - x.includes_search_path = ';'.join(self.tg.env.INCPATHS) - -class msvs_generator(BuildContext): - '''generates a visual studio 2010 solution''' - cmd = 'msvs' - fun = 'build' - numver = '11.00' # Visual Studio Version Number - vsver = '2010' # Visual Studio Version Year - platform_toolset_ver = 'v110' # Platform Toolset Version Number - - def init(self): - """ - Some data that needs to be present - """ - if not getattr(self, 'configurations', None): - self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc - if not getattr(self, 'platforms', None): - self.platforms = ['Win32'] - if not getattr(self, 'all_projects', None): - self.all_projects = [] - if not getattr(self, 'project_extension', None): - self.project_extension = '.vcxproj' - if not getattr(self, 'projects_dir', None): - self.projects_dir = self.srcnode.make_node('.depproj') - self.projects_dir.mkdir() - - # bind the classes to the object, so that subclass can provide custom generators - if not getattr(self, 'vsnode_vsdir', None): - self.vsnode_vsdir = vsnode_vsdir - if not getattr(self, 'vsnode_target', None): - self.vsnode_target = vsnode_target - if not getattr(self, 'vsnode_build_all', None): - self.vsnode_build_all = vsnode_build_all - if not getattr(self, 'vsnode_install_all', None): - self.vsnode_install_all = vsnode_install_all - if not getattr(self, 'vsnode_project_view', None): - self.vsnode_project_view = vsnode_project_view - - self.numver = self.__class__.numver - self.vsver = self.__class__.vsver - self.platform_toolset_ver = self.__class__.platform_toolset_ver - - def execute(self): - """ - Entry point - """ - self.restore() - if not self.all_envs: - self.load_envs() - self.recurse([self.run_dir]) - - # user initialization - self.init() - - # two phases for creating the solution - self.collect_projects() # add project objects into "self.all_projects" - self.write_files() # write the corresponding project and solution files - - def collect_projects(self): - """ - Fill the list self.all_projects with project objects - Fill the list of build targets - """ - self.collect_targets() - self.add_aliases() - self.collect_dirs() - default_project = getattr(self, 'default_project', None) - def sortfun(x): - if x.name == default_project: - return '' - return getattr(x, 'path', None) and x.path.win32path() or x.name - self.all_projects.sort(key=sortfun) - - def write_files(self): - """ - Write the project and solution files from the data collected - so far. It is unlikely that you will want to change this - """ - for p in self.all_projects: - p.write() - - # and finally write the solution file - node = self.get_solution_node() - node.parent.mkdir() - Logs.warn('Creating %r', node) - template1 = compile_template(SOLUTION_TEMPLATE) - sln_str = template1(self) - sln_str = rm_blank_lines(sln_str) - node.stealth_write(sln_str) - - def get_solution_node(self): - """ - The solution filename is required when writing the .vcproj files - return self.solution_node and if it does not exist, make one - """ - try: - return self.solution_node - except AttributeError: - pass - - solution_name = getattr(self, 'solution_name', None) - if not solution_name: - solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln' - if os.path.isabs(solution_name): - self.solution_node = self.root.make_node(solution_name) - else: - self.solution_node = self.srcnode.make_node(solution_name) - return self.solution_node - - def project_configurations(self): - """ - Helper that returns all the pairs (config,platform) - """ - ret = [] - for c in self.configurations: - for p in self.platforms: - ret.append((c, p)) - return ret - - def collect_targets(self): - """ - Process the list of task generators - """ - for g in self.groups: - for tg in g: - if not isinstance(tg, TaskGen.task_gen): - continue - - if not hasattr(tg, 'msvs_includes'): - tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', [])) - tg.post() - if not getattr(tg, 'link_task', None): - continue - - p = self.vsnode_target(self, tg) - p.collect_source() # delegate this processing - p.collect_properties() - self.all_projects.append(p) - - def add_aliases(self): - """ - Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7 - We also add an alias for "make install" (disabled by default) - """ - base = getattr(self, 'projects_dir', None) or self.tg.path - - node_project = base.make_node('build_all_projects' + self.project_extension) # Node - p_build = self.vsnode_build_all(self, node_project) - p_build.collect_properties() - self.all_projects.append(p_build) - - node_project = base.make_node('install_all_projects' + self.project_extension) # Node - p_install = self.vsnode_install_all(self, node_project) - p_install.collect_properties() - self.all_projects.append(p_install) - - node_project = base.make_node('project_view' + self.project_extension) # Node - p_view = self.vsnode_project_view(self, node_project) - p_view.collect_source() - p_view.collect_properties() - self.all_projects.append(p_view) - - n = self.vsnode_vsdir(self, make_uuid(self.srcnode.win32path() + 'build_aliases'), "build_aliases") - p_build.parent = p_install.parent = p_view.parent = n - self.all_projects.append(n) - - def collect_dirs(self): - """ - Create the folder structure in the Visual studio project view - """ - seen = {} - def make_parents(proj): - # look at a project, try to make a parent - if getattr(proj, 'parent', None): - # aliases already have parents - return - x = proj.iter_path - if x in seen: - proj.parent = seen[x] - return - - # There is not vsnode_vsdir for x. - # So create a project representing the folder "x" - n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.win32path()), x.name) - n.iter_path = x.parent - self.all_projects.append(n) - - # recurse up to the project directory - if x.height() > self.srcnode.height() + 1: - make_parents(n) - - for p in self.all_projects[:]: # iterate over a copy of all projects - if not getattr(p, 'tg', None): - # but only projects that have a task generator - continue - - # make a folder for each task generator - p.iter_path = p.tg.path - make_parents(p) - -def wrap_2008(cls): - class dec(cls): - def __init__(self, *k, **kw): - cls.__init__(self, *k, **kw) - self.project_template = PROJECT_2008_TEMPLATE - - def display_filter(self): - - root = build_property() - root.subfilters = [] - root.sourcefiles = [] - root.source = [] - root.name = '' - - @Utils.run_once - def add_path(lst): - if not lst: - return root - child = build_property() - child.subfilters = [] - child.sourcefiles = [] - child.source = [] - child.name = lst[-1] - - par = add_path(lst[:-1]) - par.subfilters.append(child) - return child - - for x in self.source: - # this crap is for enabling subclasses to override get_filter_name - tmp = self.get_filter_name(x.parent) - tmp = tmp != '.' and tuple(tmp.split('\\')) or () - par = add_path(tmp) - par.source.append(x) - - def display(n): - buf = [] - for x in n.source: - buf.append('<File RelativePath="%s" FileType="%s"/>\n' % (xml_escape(x.win32path()), self.get_key(x))) - for x in n.subfilters: - buf.append('<Filter Name="%s">' % xml_escape(x.name)) - buf.append(display(x)) - buf.append('</Filter>') - return '\n'.join(buf) - - return display(root) - - def get_key(self, node): - """ - If you do not want to let visual studio use the default file extensions, - override this method to return a value: - 0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form, - 4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File, - 8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File, - 13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon, - 18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service, - 22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File, - 26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document, - 29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC - """ - return '' - - def write(self): - Logs.debug('msvs: creating %r', self.path) - template1 = compile_template(self.project_template) - proj_str = template1(self) - proj_str = rm_blank_lines(proj_str) - self.path.stealth_write(proj_str) - - return dec - -class msvs_2008_generator(msvs_generator): - '''generates a visual studio 2008 solution''' - cmd = 'msvs2008' - fun = msvs_generator.fun - numver = '10.00' - vsver = '2008' - - def init(self): - if not getattr(self, 'project_extension', None): - self.project_extension = '_2008.vcproj' - if not getattr(self, 'solution_name', None): - self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln' - - if not getattr(self, 'vsnode_target', None): - self.vsnode_target = wrap_2008(vsnode_target) - if not getattr(self, 'vsnode_build_all', None): - self.vsnode_build_all = wrap_2008(vsnode_build_all) - if not getattr(self, 'vsnode_install_all', None): - self.vsnode_install_all = wrap_2008(vsnode_install_all) - if not getattr(self, 'vsnode_project_view', None): - self.vsnode_project_view = wrap_2008(vsnode_project_view) - - msvs_generator.init(self) - -def options(ctx): - """ - If the msvs option is used, try to detect if the build is made from visual studio - """ - ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file') - - old = BuildContext.execute - def override_build_state(ctx): - def lock(rm, add): - uns = ctx.options.execsolution.replace('.sln', rm) - uns = ctx.root.make_node(uns) - try: - uns.delete() - except OSError: - pass - - uns = ctx.options.execsolution.replace('.sln', add) - uns = ctx.root.make_node(uns) - try: - uns.write('') - except EnvironmentError: - pass - - if ctx.options.execsolution: - ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio) - lock('.lastbuildstate', '.unsuccessfulbuild') - old(ctx) - lock('.unsuccessfulbuild', '.lastbuildstate') - else: - old(ctx) - BuildContext.execute = override_build_state - |