Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Unified Diff: site_scons/site_tools/_Node_MSVS.py

Issue 16447: Initial subset of .vcproj file generation, covering generation of:... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sandbox/sandbox_sln.scons ('k') | site_scons/site_tools/chromium_builders.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: site_scons/site_tools/_Node_MSVS.py
===================================================================
--- site_scons/site_tools/_Node_MSVS.py (revision 7407)
+++ site_scons/site_tools/_Node_MSVS.py (working copy)
@@ -1,23 +1,45 @@
-#!/usr/bin/python2.4
-# Copyright 2008, Google Inc.
-# All rights reserved.
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
__doc__ = """SCons.Node.MSVS
-Microsoft Visual Studio nodes.
+New implementation of Visual Studio project generation for SCons.
"""
-import SCons.Node.FS
-import SCons.Script
-
-
-"""New implementation of Visual Studio project generation for SCons."""
-
import md5
import os
import random
+import re
+import UserList
+import xml.dom
+import xml.dom.minidom
+import SCons.Node.FS
+import SCons.Script
+
# Initialize random number generator
random.seed()
@@ -122,13 +144,81 @@
#------------------------------------------------------------------------------
-class _MSVSFolder(SCons.Node.Node):
- """Folder in a Visual Studio project or solution."""
+class FileList(object):
+ def __init__(self, entries=None):
+ if isinstance(entries, FileList):
+ entries = entries.entries
+ self.entries = entries or []
+ def __getitem__(self, i):
+ return self.entries[i]
+ def __setitem__(self, i, item):
+ self.entries[i] = item
+ def __delitem__(self, i):
+ del self.entries[i]
+ def __add__(self, other):
+ if isinstance(other, FileList):
+ return self.__class__(self.entries + other.entries)
+ elif isinstance(other, type(self.entries)):
+ return self.__class__(self.entries + other)
+ else:
+ return self.__class__(self.entries + list(other))
+ def __radd__(self, other):
+ if isinstance(other, FileList):
+ return self.__class__(other.entries + self.entries)
+ elif isinstance(other, type(self.entries)):
+ return self.__class__(other + self.entries)
+ else:
+ return self.__class__(list(other) + self.entries)
+ def __iadd__(self, other):
+ if isinstance(other, FileList):
+ self.entries += other.entries
+ elif isinstance(other, type(self.entries)):
+ self.entries += other
+ else:
+ self.entries += list(other)
+ return self
+ def append(self, item):
+ return self.entries.append(item)
+ def extend(self, item):
+ return self.entries.extend(item)
+ def index(self, item, *args):
+ return self.entries.index(item, *args)
+ def remove(self, item):
+ return self.entries.remove(item)
+def FileListWalk(top, topdown=True, onerror=None):
+ """
+ """
+ try:
+ entries = top.entries
+ except AttributeError, err:
+ if onerror is not None:
+ onerror(err)
+ return
+
+ dirs, nondirs = [], []
+ for entry in entries:
+ if hasattr(entry, 'entries'):
+ dirs.append(entry)
+ else:
+ nondirs.append(entry)
+
+ if topdown:
+ yield top, dirs, nondirs
+ for entry in dirs:
+ for x in FileListWalk(entry, topdown, onerror):
+ yield x
+ if not topdown:
+ yield top, dirs, nondirs
+
+#------------------------------------------------------------------------------
+
+class _MSVSFolder(FileList):
+ """Folder in a Visual Studio solution."""
+
entry_type_guid = '{2150E333-8FDC-42A3-9474-1A3956D46DE8}'
- def initialize(self, path, name = None, entries = None, guid = None,
- items = None):
+ def initialize(self, path, name = None, entries = None, guid = None, items = None):
"""Initializes the folder.
Args:
@@ -143,6 +233,8 @@
items: List of solution items to include in the folder project. May be
None, if the folder does not directly contain items.
"""
+ super(_MSVSFolder, self).__init__(entries)
+
# For folder entries, the path is the same as the name
self.msvs_path = path
self.msvs_name = name or path
@@ -150,7 +242,6 @@
self.guid = guid
# Copy passed lists (or set to empty lists)
- self.entries = list(entries or [])
self.items = list(items or [])
def get_guid(self):
@@ -171,13 +262,183 @@
#------------------------------------------------------------------------------
+class MSVSConfig(object):
+ """Visual Studio configuration."""
+ def __init__(self, Name, config_type, tools=[], **attrs):
+ """Initializes the configuration.
+ Args:
+ **attrs: Configuration attributes.
+ """
+ # Special handling for attributes that we want to make more
+ # convenient for the user.
+ ips = attrs.get('InheritedPropertySheets')
+ if ips:
+ if isinstance(ips, list):
+ ips = ';'.join(ips)
+ attrs['InheritedPropertySheets'] = ips.replace('/', '\\')
+
+ tools = tools or []
+ if not SCons.Util.is_List(tools):
+ tools = [tools]
+ tool_objects = []
+ for t in tools:
+ if not isinstance(t, MSVSTool):
+ t = MSVSTool(t)
+ tool_objects.append(t)
+
+ self.Name = Name
+ self.config_type = config_type
+ self.tools = tool_objects
+ self.attrs = attrs
+
+ def CreateElement(self, doc):
+ """Creates an element for the configuration.
+
+ Args:
+ doc: xml.dom.Document object to use for node creation.
+
+ Returns:
+ A new xml.dom.Element for the configuration.
+ """
+ node = doc.createElement(self.config_type)
+ node.setAttribute('Name', self.Name)
+ for k, v in self.attrs.items():
+ node.setAttribute(k, v)
+ for t in self.tools:
+ node.appendChild(t.CreateElement(doc))
+ return node
+
+
+class MSVSFileListBase(FileList):
+ """Base class for a file list in a Visual Studio project file."""
+
+ def CreateElement(self, doc, node_func=lambda x: x):
+ """Creates an element for an MSVSFileListBase subclass.
+
+ Args:
+ doc: xml.dom.Document object to use for node creation.
+ node_func: Function to use to return Nodes for objects that
+ don't have a CreateElement() method of their own.
+
+ Returns:
+ A new xml.dom.Element for the MSVSFileListBase object.
+ """
+ node = doc.createElement(self.element_name)
+ for entry in self.entries:
+ if hasattr(entry, 'CreateElement'):
+ n = entry.CreateElement(doc, node_func)
+ else:
+ n = node_func(entry)
+ node.appendChild(n)
+ return node
+
+
+class MSVSFiles(MSVSFileListBase):
+ """Files list in a Visual Studio project file."""
+ element_name = 'Files'
+
+
+class MSVSFilter(MSVSFileListBase):
+ """Filter (that is, a virtual folder) in a Visual Studio project file."""
+
+ element_name = 'Filter'
+
+ def __init__(self, Name, entries=None):
+ """Initializes the folder.
+
+ Args:
+ Name: Filter (folder) name.
+ entries: List of filenames and/or Filter objects contained.
+ """
+ super(MSVSFilter, self).__init__(entries)
+ self.Name = Name
+
+ def CreateElement(self, doc, node_func=lambda x: x):
+ """Creates an element for the Filter.
+
+ Args:
+ doc: xml.dom.Document object to use for node creation.
+ node_func: Function to use to return Nodes for objects that
+ don't have a CreateElement() method of their own.
+
+ Returns:
+ A new xml.dom.Element for the filter.
+ """
+ node = super(MSVSFilter, self).CreateElement(doc, node_func)
+ node.setAttribute('Name', self.Name)
+ return node
+
+
+class MSVSTool(object):
+ """Visual Studio tool."""
+
+ def __init__(self, Name, **attrs):
+ """Initializes the tool.
+
+ Args:
+ Name: Tool name.
+ **attrs: Tool attributes.
+ """
+ self.Name = Name
+ self.attrs = attrs
+
+ def CreateElement(self, doc):
+ """Creates an element for the tool.
+
+ Args:
+ doc: xml.dom.Document object to use for node creation.
+
+ Returns:
+ A new xml.dom.Element for the tool.
+ """
+ node = doc.createElement('Tool')
+ node.setAttribute('Name', self.Name)
+ for k, v in self.attrs.items():
+ node.setAttribute(k, v)
+ return node
+
+
+class MSVSToolFile(object):
+ """Visual Studio tool file specification."""
+
+ def __init__(self, node, **attrs):
+ """Initializes the tool.
+
+ Args:
+ node: Node for the Tool File
+ **attrs: Tool File attributes.
+ """
+ self.node = node
+
+ def CreateElement(self, doc, project):
+ result = doc.createElement('ToolFile')
+ result.setAttribute('RelativePath', project.get_rel_path(self.node))
+ return result
+
+
+#------------------------------------------------------------------------------
+
+def MSVSAction(target, source, env):
+ target[0].Write(env)
+
+MSVSProjectAction = SCons.Script.Action(MSVSAction,
+ "Generating Visual Studio project `$TARGET' ...")
+
class _MSVSProject(SCons.Node.FS.File):
"""Visual Studio project."""
entry_type_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}'
- def initialize(self, path, name = None, dependencies = None, guid = None):
+ def initialize(self, env, path, name = None,
+ dependencies = None,
+ guid = None,
+ buildtargets = [],
+ files = [],
+ root_namespace = None,
+ relative_path_prefix = '',
+ tools = None,
+ configurations = None):
"""Initializes the project.
Args:
@@ -187,15 +448,88 @@
dependencies: List of other Project objects this project is dependent
upon, if not None.
guid: GUID to use for project, if not None.
+ buildtargets: List of target(s) being built by this project.
+ files: List of source files for the project. This will be
+ supplemented by any source files of buildtargets.
+ root_namespace: The value of the RootNamespace attribute of the
+ project, if not None. The default is to use the same
+ string as the name.
+ relative_path_prefix: A prefix to be appended to the beginning of
+ every file name in the list. The canonical use is to specify
+ './' to make files explicitly relative to the local directory.
+ tools: A list of MSVSTool objects or strings representing
+ tools to be used to build this project. This will be used
+ for any configurations that don't provide their own
+ per-configuration tool list.
+ configurations: A list of MSVSConfig objects representing
+ configurations built by this project.
"""
self.msvs_path = path
- self.msvs_name = name or os.path.splitext(os.path.basename(self.name))[0]
+ self.msvs_node = env.File(path)
+ if name is None:
+ if buildtargets:
+ name = os.path.splitext(buildtargets[0].name)[0]
+ else:
+ name = os.path.splitext(os.path.basename(path))[0]
+ self.msvs_name = name
+ self.root_namespace = root_namespace or self.msvs_name
+ self.buildtargets = buildtargets
+ self.relative_path_prefix = relative_path_prefix
+ self.tools = tools
+ self.env = env
self.guid = guid
- # Copy passed lists (or set to empty lists)
self.dependencies = list(dependencies or [])
+ self.configurations = list(configurations or [])
+ self.file_configurations = {}
+ self.tool_files = []
+ if not isinstance(files, MSVSFiles):
+ files = MSVSFiles(self.args2nodes(files))
+ self.files = files
+
+ env.Command(self, [], MSVSSolutionAction)
+
+ def args2nodes(self, entries):
+ result = []
+ for entry in entries:
+ if SCons.Util.is_String(entry):
+ entry = self.env.File(entry)
+ result.append(entry)
+ elif hasattr(entry, 'entries'):
+ entry.entries = self.args2nodes(entry.entries)
+ result.append(entry)
+ elif isinstance(entry, (list, UserList.UserList)):
+ result.extend(self.args2nodes(entry))
+ elif hasattr(entry, 'sources') and entry.sources:
+ result.extend(entry.sources)
+ else:
+ result.append(entry)
+ return result
+
+ def FindFile(self, node):
+ try:
+ flat_file_dict = self.flat_file_dict
+ except AttributeError:
+ flat_file_dict = {}
+ file_list = self.files[:]
+ while file_list:
+ entry = file_list.pop(0)
+ if not isinstance(entry, (list, UserList.UserList)):
+ entry = [entry]
+ for f in entry:
+ if hasattr(f, 'entries'):
+ file_list.extend(f.entries)
+ else:
+ flat_file_dict[f] = True
+ if hasattr(f, 'sources'):
+ for s in f.sources:
+ flat_file_dict[s] = True
+ self.flat_file_dict = flat_file_dict
+
+ return flat_file_dict.get(node)
+
def get_guid(self):
if self.guid is None:
guid = GUIDMap.get(self.msvs_path)
@@ -220,28 +554,321 @@
def get_msvs_path(self, sln):
return sln.rel_path(self).replace('/', '\\')
+ def get_rel_path(self, node):
+ result = self.relative_path_prefix + self.msvs_node.rel_path(node)
+ return result.replace('/', '\\')
+
+ def AddConfig(self, Name, tools=None, **attrs):
+ """Adds a configuration to the parent node.
+
+ Args:
+ Name: The name of the configuration.
+ tools: List of tools (strings or Tool objects); may be None.
+ **attrs: Configuration attributes.
+ """
+ if tools is None:
+ # No tool list specifically for this configuration,
+ # use the Project's as a default.
+ tools = self.tools
+ c = MSVSConfig(Name, 'Configuration', tools=tools, **attrs)
+ self.configurations.append(c)
+
+ def AddFiles(self, files):
+ """Adds files to the project.
+
+ Args:
+ files: A list of Filter objects and/or relative paths to files.
+
+ This makes a copy of the file/filter tree at the time of this call. If you
+ later add files to a Filter object which was passed into a previous call
+ to AddFiles(), it will not be reflected in this project.
+ """
+ # TODO(rspangler) This also doesn't handle adding files to an existing
+ # filter. That is, it doesn't merge the trees.
+ self.files.extend(self.args2nodes(files))
+
+ def AddFileConfig(self, path, Name, tools=None, **attrs):
+ """Adds a configuration to a file.
+
+ Args:
+ path: Relative path to the file.
+ Name: Name of configuration to add.
+ tools: List of tools (strings or MSVSTool objects); may be None.
+ **attrs: Configuration attributes.
+
+ Raises:
+ ValueError: Relative path does not match any file added via AddFiles().
+ """
+ node = self.env.File(path)
+ if not self.FindFile(node):
+ raise ValueError('AddFileConfig: file "%s" not in project' % path)
+ c = MSVSConfig(Name, 'FileConfiguration', tools=tools, **attrs)
+ config_list = self.file_configurations.get(node)
+ if config_list is None:
+ config_list = []
+ self.file_configurations[node] = config_list
+ config_list.append(c)
+
+ def AddToolFile(self, path):
+ """Adds a tool file to the project.
+
+ Args:
+ path: Relative path from project to tool file.
+ """
+ tf = MSVSToolFile(self.env.File(path))
+ self.tool_files.append(tf)
+
+ def Create(self):
+ """Creates the project document.
+
+ Args:
+ name: Name of the project.
+ guid: GUID to use for project, if not None.
+ """
+ # Create XML doc
+ xml_impl = xml.dom.getDOMImplementation()
+ self.doc = xml_impl.createDocument(None, 'VisualStudioProject', None)
+
+ # Add attributes to root element
+ root = self.doc.documentElement
+ root.setAttribute('ProjectType', 'Visual C++')
+ root.setAttribute('Version', '8.00')
+ root.setAttribute('Name', self.msvs_name)
+ root.setAttribute('ProjectGUID', self.get_guid())
+ root.setAttribute('RootNamespace', self.root_namespace)
+ root.setAttribute('Keyword', 'Win32Proj')
+
+ # Add platform list
+ platforms = self.doc.createElement('Platforms')
+ root.appendChild(platforms)
+ n = self.doc.createElement('Platform')
+ n.setAttribute('Name', 'Win32')
+ platforms.appendChild(n)
+
+ # Add tool files section
+ tool_files = self.doc.createElement('ToolFiles')
+ root.appendChild(tool_files)
+ for tf in self.tool_files:
+ tool_files.appendChild(tf.CreateElement(self.doc, self))
+
+ # Add configurations section
+ configs = self.doc.createElement('Configurations')
+ root.appendChild(configs)
+ for c in self.configurations:
+ configs.appendChild(c.CreateElement(self.doc))
+
+ # Add empty References section
+ root.appendChild(self.doc.createElement('References'))
+
+ # Add files section
+ root.appendChild(self.files.CreateElement(self.doc, self.CreateFileElement))
+
+ # Add empty Globals section
+ root.appendChild(self.doc.createElement('Globals'))
+
+ def CreateFileElement(self, file):
+ """Create a DOM node for the specified file.
+
+ Args:
+ file: The file Node being considered.
+
+ Returns:
+ A DOM Node for the File, with a relative path to the current
+ project object, and any file configurations attached to the
+ project.
+ """
+
+ node = self.doc.createElement('File')
+ node.setAttribute('RelativePath', self.get_rel_path(file))
+ for c in self.file_configurations.get(file, []):
+ node.appendChild(c.CreateElement(self.doc))
+ return node
+
+ def _AddFileConfigurationDifferences(self, target, source, base_env, file_env):
+ """Adds a per-file configuration.
+
+ Args:
+ target: The target being built from the source.
+ source: The source to which the file configuration is being added.
+ base_env: The base construction environment for the project.
+ Differences from this will go into the FileConfiguration
+ in the project file.
+ file_env: The construction environment for the target, containing
+ the per-target settings.
+ """
+ pass
+
+ def _AddFileConfigurations(self, env):
+ """Adds per-file configurations for the buildtarget's sources.
+
+ Args:
+ env: The base construction environment for the project.
+ """
+ if not self.buildtargets:
+ return
+
+ bt = self.buildtargets[0]
+ additional_files = []
+ for t in bt.sources:
+ e = t.get_build_env()
+ for s in t.sources:
+ s = env.arg2nodes([s])[0]
+ if not self.FindFile(s):
+ additional_files.append(s)
+ if not env is e:
+ self._AddFileConfigurationDifferences(t, s, env, e)
+ self.AddFiles(additional_files)
+
+ def Write(self, env):
+ """Writes the project file."""
+ self._AddFileConfigurations(env)
+
+ self.Create()
+
+ f = open(str(self.msvs_node), 'wt')
+ f.write(self.formatMSVSProjectXML(self.doc))
+ f.close()
+
+ # Methods for formatting XML as nearly identically to Microsoft's
+ # .vcproj output as we can practically make it.
+ #
+ # The general design here is copied from:
+ #
+ # Bruce Eckels' MindView, Inc: 12-09-04 XML Oddyssey
+ # http://www.mindview.net/WebLog/log-0068
+ #
+ # Eckels' implementation broke up long tag definitions for readability,
+ # in much the same way that .vcproj does, but we've modified things
+ # for .vcproj quirks (like some tags *always* terminating with </Tag>,
+ # even when empty).
+
+ encoding = 'Windows-1252'
+
+ def formatMSVSProjectXML(self, xmldoc):
+ xmldoc = xmldoc.toprettyxml("", "\n", encoding=self.encoding)
+ # Remove trailing whitespace from each line:
+ xmldoc = "\n".join(
+ [line.rstrip() for line in xmldoc.split("\n")])
+ # Remove all empty lines before opening '<':
+ while xmldoc.find("\n\n<") != -1:
+ xmldoc = xmldoc.replace("\n\n<", "\n<")
+ dom = xml.dom.minidom.parseString(xmldoc)
+ xmldoc = dom.toprettyxml("\t", "", encoding=self.encoding)
+ xmldoc = xmldoc.replace('?><', '?>\n<')
+ xmldoc = self.reformatLines(xmldoc)
+ return xmldoc
+
+ def reformatLines(self, xmldoc):
+ result = []
+ for line in [line.rstrip() for line in xmldoc.split("\n")]:
+ if line.lstrip().startswith("<"):
+ result.append(self.reformatLine(line) + "\n")
+ else:
+ result.append(line + "\n")
+ return ''.join(result)
+
+ # Keyword order for specific tags.
+ #
+ # Listed keywords will come first and in the specified order.
+ # Any unlisted keywords come after, in whatever order they appear
+ # in the input config. In theory this means we would only *have* to
+ # list the keywords that we care about, but in practice we'll probably
+ # want to nail down Visual Studio's order to make sure we match them
+ # as nearly as possible.
+
+ order = {
+ 'Configuration' : [
+ 'Name',
+ 'ConfigurationType',
+ 'InheritedPropertySheets',
+ ],
+ 'FileConfiguration' : [
+ 'Name',
+ 'ExcludedFromBuild',
+ ],
+ 'Tool' : [
+ 'Name',
+ 'DisableSpecificWarnings',
+ ],
+ 'VisualStudioProject' : [
+ 'ProjectType',
+ 'Version',
+ 'Name',
+ 'ProjectGUID',
+ 'RootNamespace',
+ 'Keyword',
+ ],
+ }
+
+ force_closing_tag = [
+ 'File',
+ 'Globals',
+ 'References',
+ 'ToolFiles'
+ ]
+
+ oneLiner = re.compile("(\s*)<(\w+)(.*)>")
+ keyValuePair = re.compile('\w+="[^"]*?"')
+ def reformatLine(self, line):
+ """Reformat an xml tag to put each key-value
+ element on a single indented line, for readability"""
+ matchobj = self.oneLiner.match(line.rstrip())
+ if not matchobj:
+ return line
+ baseIndent, tag, rest = matchobj.groups()
+ slash = ''
+ if rest[-1:] == '/':
+ slash = '/'
+ rest = rest[:-1]
+ result = [baseIndent + '<' + tag]
+ indent = baseIndent + "\t"
+ pairs = self.keyValuePair.findall(rest)
+ for key in self.order.get(tag, []):
+ for p in [ p for p in pairs if p.startswith(key+'=') ]:
+ result.append("\n" + indent + p)
+ pairs.remove(p)
+ for pair in pairs:
+ result.append("\n" + indent + pair)
+ result = [''.join(result).rstrip()]
+
+ if tag in self.force_closing_tag:
+ # These force termination with </Tag>, so translate slash.
+ if rest:
+ result.append("\n")
+ result.append(indent)
+ result.append(">")
+ if slash:
+ result.append("\n")
+ result.append(baseIndent + "</" + tag + ">")
+ else:
+ if rest:
+ result.append("\n")
+ if slash:
+ result.append(baseIndent)
+ else:
+ result.append(indent)
+ result.append(slash + ">")
+
+ return ''.join(result)
+
def MSVSProject(env, item, *args, **kw):
if not SCons.Util.is_String(item):
return item
item = env.subst(item)
result = env.fs._lookup(item, None, _MSVSProject, create=1)
- result.initialize(item, *args, **kw)
+ result.initialize(env, item, *args, **kw)
LookupAdd(item, result)
return result
#------------------------------------------------------------------------------
-def MSVSAction(target, source, env):
- target[0].Write(env)
-
MSVSSolutionAction = SCons.Script.Action(MSVSAction,
"Generating Visual Studio solution `$TARGET' ...")
class _MSVSSolution(SCons.Node.FS.File):
"""Visual Studio solution."""
- def initialize(self, env, path, entries = None, variants = None,
- websiteProperties = True):
+ def initialize(self, env, path, entries = None, variants = None, websiteProperties = True):
"""Initializes the solution.
Args:
@@ -432,3 +1059,10 @@
result.initialize(env, item, *args, **kw)
LookupAdd(item, result)
return result
+
+import __builtin__
+
+__builtin__.MSVSFilter = MSVSFilter
+__builtin__.MSVSProject = MSVSProject
+__builtin__.MSVSSolution = MSVSSolution
+__builtin__.MSVSTool = MSVSTool
« no previous file with comments | « sandbox/sandbox_sln.scons ('k') | site_scons/site_tools/chromium_builders.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698