D
David Blume
I'm very grateful to Roger Burnham for his Visual Studio 6.0 build
script listed here:
http://mail.python.org/pipermail/python-list/2001-December/076881.html
Now that I'm building projects in .NET 2003, I thought I'd post an
update to his DoBuild() function that does the same thing with
Solutions. Note the differences:
1. Instead of having a RebuildAll() function, we have to Clean() then
Build(). This function does the cleaning of all the targets in one
pass, then the building of all the targets, in case some targets share
dependencies.
2. On a compile-time error, instead of raising SystemExit, which is
much cleaner, this script returns the BuildLog.htm of the component
that failed. (Which may not have been the target that was built, but
a sub-project.) I didn't really know how to determine exactly which
subproject failed, so I parse the contents of the output window to
find it. (VC6 is much easier, the .plg file showed the build status
of the target and all its dependencies.)
Anyway, here's BuildSolution() with similar parameters as Roger's
DoBuild(). Please fix any line-wrapping errors that have occurred
between my sending of the post and your reception of it. Sorry about
those.
import win32com.client.dynamic
import string
import pywintypes
import win32clipboard
import win32con
def BuildSolution(VC, solution, projectList, configSuffix, force):
"""Build Visual C++ 7.1 Solutions
returns None if successful, or the build log if
there were compile time errors."""
if VC is None:
VC = win32com.client.Dispatch('VisualStudio.DTE')
VC.MainWindow.Visible = True
VCDocs = VC.Documents
VCDocs.CloseAll(3)
sln = VC.Solution
sln.Open(solution)
slnBuild = sln.SolutionBuild
tailLen = len(configSuffix)
# First, clean everything if doing a forced rebuild
if force:
for projectName in projectList:
for project in sln.Projects:
if str(project.Name) == projectName:
for config in slnBuild.SolutionConfigurations:
name = str(config.Name)
if name[-tailLen:] == configSuffix:
for context in config.SolutionContexts:
if projectName + "." in context.ProjectName:
context.ShouldBuild = True
break
break
slnBuild.Clean(True)
# Then, build the specified projects
for projectName in projectList:
projFound = 0
for project in sln.Projects:
if str(project.Name) == projectName:
projFound = 1
for config in slnBuild.SolutionConfigurations:
confFound = 0
name = str(config.Name)
if name[-tailLen:] == configSuffix:
confFound = 1
slnBuild.BuildProject(config.Name, project.UniqueName,
True)
if slnBuild.BuildState == 3:
if slnBuild.LastBuildInfo != 0:
print 'There were', slnBuild.LastBuildInfo, 'errors
building', projectName + '.\n'
# We have to jump through some hoops to determine
which
# subproject actually failed, because the BuildLog.htm
# associated with this target does not reflect the
# compiled state of the subprojects.Here's what we do:
# 1. Obtain the OutputWindow from MSDev.
# 2. Copy the text to the clipboard, and extract that
# into a "lines" array.
# 3. Search for lines containing the word "error" and
# assume that's the first failed project.
# 4. Extract and return the filename of the
# BuildLog.htm for the assumed failed project.
outputPane =
VC.Windows.Item('{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}').Object.ActivePane
# vsWindowKindOutput
outputPane.TextDocument.Selection.SelectAll()
outputPane.TextDocument.Selection.Copy()
outputPane = None
win32clipboard.OpenClipboard(0)
lines =
win32clipboard.GetClipboardData(win32con.CF_TEXT)
win32clipboard.CloseClipboard()
bFoundErrorMessages = False
LogfileString = "Build log was saved at \"file://"
for line in string.split(lines, "\n"):
if not bFoundErrorMessages and line.find(" : error
") != -1:
print "This is the first error:"
print line + "\n"
bFoundErrorMessages = True
if bFoundErrorMessages and
line.startswith(LogfileString):
return line[len(LogfileString):line.rfind('"')]
raise "Could not locate the failing project's
logfile."
else:
raise "BuildProject is returning asynchronously!"
break
if not confFound:
print 'Build failed: Could not find the', configSuffix,
'for', projectName + '.'
break
if not projFound:
print 'Build failed: Could not find the project', projectName +
'.'
return None
script listed here:
http://mail.python.org/pipermail/python-list/2001-December/076881.html
Now that I'm building projects in .NET 2003, I thought I'd post an
update to his DoBuild() function that does the same thing with
Solutions. Note the differences:
1. Instead of having a RebuildAll() function, we have to Clean() then
Build(). This function does the cleaning of all the targets in one
pass, then the building of all the targets, in case some targets share
dependencies.
2. On a compile-time error, instead of raising SystemExit, which is
much cleaner, this script returns the BuildLog.htm of the component
that failed. (Which may not have been the target that was built, but
a sub-project.) I didn't really know how to determine exactly which
subproject failed, so I parse the contents of the output window to
find it. (VC6 is much easier, the .plg file showed the build status
of the target and all its dependencies.)
Anyway, here's BuildSolution() with similar parameters as Roger's
DoBuild(). Please fix any line-wrapping errors that have occurred
between my sending of the post and your reception of it. Sorry about
those.
import win32com.client.dynamic
import string
import pywintypes
import win32clipboard
import win32con
def BuildSolution(VC, solution, projectList, configSuffix, force):
"""Build Visual C++ 7.1 Solutions
returns None if successful, or the build log if
there were compile time errors."""
if VC is None:
VC = win32com.client.Dispatch('VisualStudio.DTE')
VC.MainWindow.Visible = True
VCDocs = VC.Documents
VCDocs.CloseAll(3)
sln = VC.Solution
sln.Open(solution)
slnBuild = sln.SolutionBuild
tailLen = len(configSuffix)
# First, clean everything if doing a forced rebuild
if force:
for projectName in projectList:
for project in sln.Projects:
if str(project.Name) == projectName:
for config in slnBuild.SolutionConfigurations:
name = str(config.Name)
if name[-tailLen:] == configSuffix:
for context in config.SolutionContexts:
if projectName + "." in context.ProjectName:
context.ShouldBuild = True
break
break
slnBuild.Clean(True)
# Then, build the specified projects
for projectName in projectList:
projFound = 0
for project in sln.Projects:
if str(project.Name) == projectName:
projFound = 1
for config in slnBuild.SolutionConfigurations:
confFound = 0
name = str(config.Name)
if name[-tailLen:] == configSuffix:
confFound = 1
slnBuild.BuildProject(config.Name, project.UniqueName,
True)
if slnBuild.BuildState == 3:
if slnBuild.LastBuildInfo != 0:
print 'There were', slnBuild.LastBuildInfo, 'errors
building', projectName + '.\n'
# We have to jump through some hoops to determine
which
# subproject actually failed, because the BuildLog.htm
# associated with this target does not reflect the
# compiled state of the subprojects.Here's what we do:
# 1. Obtain the OutputWindow from MSDev.
# 2. Copy the text to the clipboard, and extract that
# into a "lines" array.
# 3. Search for lines containing the word "error" and
# assume that's the first failed project.
# 4. Extract and return the filename of the
# BuildLog.htm for the assumed failed project.
outputPane =
VC.Windows.Item('{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}').Object.ActivePane
# vsWindowKindOutput
outputPane.TextDocument.Selection.SelectAll()
outputPane.TextDocument.Selection.Copy()
outputPane = None
win32clipboard.OpenClipboard(0)
lines =
win32clipboard.GetClipboardData(win32con.CF_TEXT)
win32clipboard.CloseClipboard()
bFoundErrorMessages = False
LogfileString = "Build log was saved at \"file://"
for line in string.split(lines, "\n"):
if not bFoundErrorMessages and line.find(" : error
") != -1:
print "This is the first error:"
print line + "\n"
bFoundErrorMessages = True
if bFoundErrorMessages and
line.startswith(LogfileString):
return line[len(LogfileString):line.rfind('"')]
raise "Could not locate the failing project's
logfile."
else:
raise "BuildProject is returning asynchronously!"
break
if not confFound:
print 'Build failed: Could not find the', configSuffix,
'for', projectName + '.'
break
if not projFound:
print 'Build failed: Could not find the project', projectName +
'.'
return None