我们在设置构建自动化方面还有点早,现在只使用bat文件来获取Win32 C ++解决方案。我们有大约4个解决方案,每个解决方案都有几个vcproj文件。
每次添加新的解决方案或配置时,我都必须更新bat文件以反映要使用MSBuild调用的新解决方案或配置。
我想也许更容易编写一个解析给定路径(及其子树)中所有sln文件的工具,然后解析它为配置引用的所有项目文件,然后以这种方式调用所有构建。
有一种简单的方法吗?
真的这是两个问题:
如何告诉MSBuild只在子树中构建所有解决方案? (我可以对它们进行搜索 - 这是我想写的一个简单工具)
如何告诉MSBuild构建解决方案/ vcproj的所有配置?
我们正在使用MSBuild,bat文件,vc2008,c ++
答案 0 :(得分:1)
作为PowerShell粉丝,以下重新格式化的单行可能会有所帮助:
Get-ChildItem -Recurse -Include *.sln |
ForEach-Object {
$Solution = $_.FullName
Get-Content $_ |
ForEach-Object {
if($_ -match '\{[^\}]+[^=]+= ([^\{\s]*)$') {
$matches[1]
}
} | Sort-Object -Unique |
ForEach-Object {
$config = ([string]$_).Split([char]'|')
& "$env:windir\Microsoft.NET\Framework\v3.5\msbuild.exe" $Solution /p:Configuration="$($config[0])" /p:Platform="$($config[1])"
}
}
此脚本可以保存为ps1文件或粘贴为个人资料中的功能。解释它的作用:
答案 1 :(得分:0)
可以通过API访问Microsoft构建框架。但我不确定是否只能通过批处理文件来完成。恕我直言,最简单的方法是通过将一个插件(使用VB.NET)写入VS IDE来自动化构建。可以从批处理文件中调用此插件。我们使用addin方法自动化VC ++构建。在我们的例子中没有别的办法因为我们必须自动化Qt的 moc 过程。我认为它也会更灵活。
我工作的构建系统(至少在VS 2005中)非常错误。请参阅此link,它将帮助您理解陷阱,并提供有关如何遍历解决方案文件的代码片段。 一旦安装了插件,就可以创建一个小的exe,它通过addin调用构建。这个exe可以从批处理文件中调用。
示例VS Automator exe调用addin方法
''' Summary: Console App to automate MSVS build with special regard to Addin
Imports System
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80
Imports System.Reflection
Imports System.Windows.Forms
Imports System.IO
'''<summary>Module class that automates launching MSVS in silent mode. It disables all user actions. A hidden window is used for MSVS automation. This should work for VS 2008 as well.</summary>
'''<remarks>An STA Thread is used for this console app. Refer http://msmvps.com/blogs/carlosq/archive/2007/10/11/frustrations-with-command-line-add-ins-for-visual-studio.aspx for details </remarks>
Module VSAutomaton
Private Enum VisualStudioSolVersion
Unknown = 0
VSNET2002 = 1
VSNET2003 = 2
VS2005 = 3
VS2008 = 4
End Enum
<STAThread()> _
Sub Main(ByVal args() As String)
Const ADDIN_PROGID As String = "AddIn-Name.Connect"
Const ADDIN_METHOD As String = "SyncSolutionBatch" ' name of your method in addin code
Dim dte As EnvDTE.DTE = Nothing
Dim dteType As Type
Dim commandLineAddIn As AddIn-Name.Connect = Nothing
Dim solutionFullFileName As String
Dim solutionFolder As String
Dim solutionName As String
Dim logFullFileName As String
Dim buildLogFile As String = Nothing
Dim buildConfig As String = Nothing
Dim connectObject As Object = Nothing
Dim connectObjectType As Type
Dim version As VisualStudioSolVersion
Dim progID As String
Dim executableName As String
Dim addIn As EnvDTE.AddIn
Dim msgFilter As MessageFilter.MessageFilter = Nothing
Try
msgFilter = New MessageFilter.MessageFilter
If args.Length = 0 Then
executableName = IO.Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly.Location)
ReportError("Usage: " & executableName & " solution_file_name.sln")
Else
solutionFullFileName = args(0) ' project solution file
If Not IO.File.Exists(solutionFullFileName) Then
ReportError("Solution file '" & solutionFullFileName & "' does not exist.")
Else
solutionFolder = IO.Path.GetDirectoryName(solutionFullFileName)
solutionName = IO.Path.GetFileNameWithoutExtension(solutionFullFileName)
logFullFileName = IO.Path.Combine(solutionFolder, solutionName & ".log")
If IO.File.Exists(logFullFileName) Then
IO.File.Delete(logFullFileName)
End If
version = GetSolutionVersion(solutionFullFileName)
If version = VisualStudioSolVersion.Unknown Then
ReportError("The format version of the solution file is not supported.")
Else
progID = GetVisualStudioProgID(version)
dteType = System.Type.GetTypeFromProgID(progID)
If dteType Is Nothing Then
ReportError("Could not find the ActiveX Server for ProgID '" & progID & "'. Likely the proper version of Visual Studio is not installed.")
Else
dte = DirectCast(System.Activator.CreateInstance(dteType), EnvDTE.DTE)
dte.SuppressUI = True
dte.UserControl = False
addIn = GetAddInByProgID(dte, ADDIN_PROGID)
If addIn Is Nothing Then
ReportError("The Add-in " & ADDIN_PROGID & " was not found in Visual Studio.")
Else
addIn.Connected = True
connectObject = addIn.Object
connectObjectType = connectObject.GetType
' So a copy of the same DLL is necessary in the same dir as this app. exe
connectObjectType.InvokeMember(ADDIN_METHOD, Reflection.BindingFlags.InvokeMethod Or Reflection.BindingFlags.Static Or Reflection.BindingFlags.Public, Nothing, connectObject, New String() {solutionFullFileName})
End If
End If
End If
End If
End If
Catch ex As Exception
ReportError(ex.ToString)
Finally
If Not (dte Is Nothing) Then
Try
dte.Quit()
Catch ex As Exception
End Try
End If
If Not (msgFilter Is Nothing) Then
' this is a tricky aspect. We do not want leaks but .NET can sometimes be extra smart
msgFilter.Dispose() 'If the GC decides to re-collect the garbage from this app, then a crash may result
' but this is the drawback of indeterministic destruction semantics
End If
End Try
End Sub
Private Sub ReportError(ByVal msg As String)
#If DEBUG Then
MsgBox(msg)
#End If
Console.WriteLine(msg)
End Sub
Private Function GetAddInByProgID(ByVal dte As EnvDTE.DTE, ByVal addinProgID As String) As EnvDTE.AddIn
Dim addinResult As EnvDTE.AddIn = Nothing
Dim addin As EnvDTE.AddIn
For Each addin In dte.AddIns
If addin.ProgID = addinProgID Then
addinResult = addin
Exit For
End If
Next
Return addinResult
End Function
Private Function GetSolutionVersion(ByVal solutionFullFileName As String) As VisualStudioSolVersion
Dim version As VisualStudioSolVersion = VisualStudioSolVersion.Unknown
Dim solutionStreamReader As IO.StreamReader = Nothing
Dim firstLine As String = Nothing
Dim format As String
Try
solutionStreamReader = New IO.StreamReader(solutionFullFileName)
firstLine = solutionStreamReader.ReadLine()
format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim
Select Case format
Case "7.00"
version = VisualStudioSolVersion.VSNET2002
Case "8.00"
version = VisualStudioSolVersion.VSNET2003
Case "9.00"
version = VisualStudioSolVersion.VS2005
Case "10.00"
version = VisualStudioSolVersion.VS2008
End Select
Finally
If Not (solutionStreamReader Is Nothing) Then
solutionStreamReader.Close()
End If
End Try
Return version
End Function
Private Function GetVisualStudioProgID(ByVal version As VisualStudioSolVersion) As String
Dim progID As String = ""
Select Case version
Case VisualStudioSolVersion.VSNET2002
progID = "VisualStudio.DTE.7"
Case VisualStudioSolVersion.VSNET2003
progID = "VisualStudio.DTE.7.1"
Case VisualStudioSolVersion.VS2005
progID = "VisualStudio.DTE.8.0"
Case VisualStudioSolVersion.VS2008
progID = "VisualStudio.DTE.9.0"
End Select
Return progID
End Function
End Module
用于调用VS automator exe的示例批处理文件:
@echo off
:: --Usage: $>BatchFileName.bat "<project_name(.sln)>" {Release | Debug} [ Make ]
:: Please remember the "double-quotes".
REM -- check for blank input
if x%1%x == xx goto InputError
if x%2%x == xx goto InputError
echo Automating MSVS-Build for %1% ...
echo .
set arg1=%1%
REM -- remove quotes
for /f "useback tokens=*" %%a in ('%arg1%') do set match=%%~a
set slnFile=%match:~-4%
if %slnFile% == .sln goto lbl_FileOK
:lbl_FileOK
REM build configuration and output file
set SOLFILE=%1%
set BUILDCONFIG=%2%
set CLEANWSOBJS=%3%
REM -- Read necessary registry entries
REM --- Read MSVS installation dir
regedit /e A$B$C$.bxt "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS"
find "VS7CommonDir" <A$B$C$.bxt>A$B$C$.bat
goto :1st
:1st
for /F "tokens=1* delims==" %%A in ('TYPE A$B$C$.bat ^| find "VS7CommonDir"') do set vscomdir=%%B
set vscomdir=%vscomdir:"=%
REM -- Initialize the MSVS environment
set VSENV="%vscomdir%Tools\vsvars32.bat"
call %VSENV% > nul
REM -- remove quotes
for /f "useback tokens=*" %%a in ('%SOLFILE%') do set str=%%~a
set LastFolder=%str%
REM -- Extract the project name
if "%LastFolder:~-1%"=="\" set LastFolder=%LastFolder:~0,-1%
for %%a in ("%LastFolder%") do set LastFolder=%%~nxa
set flname=%LastFolder:.shared=.sln%
set tmpfile=%solPath%\%flname%
REM --- Check if the target '.sln' already exists, if yes delete
if EXIST %NEWSOLFILE% DEL /Q %NEWSOLFILE%
REM -- use the addin functionality
VSAutomator.exe %SOLFILE%
REM --- create log file as projectname_buildconfig.log
set tmplog=%NEWSOLFILE:.sln=%
set OUTLOGFILE=%tmplog%_%BUILDCONFIG%.log
REM -- Now build the newly ready .sln file
echo .
echo Building Solution file - %NEWSOLFILE%, Output log file - %OUTLOGFILE%
echo .
if x%CLEANWSOBJS%x == xMakex goto JustBuild1
devenv.com /useenv %NEWSOLFILE% /CLEAN %BUILDCONFIG% /OUT %OUTLOGFILE% > nul
:JustBuild1
devenv.com /useenv %NEWSOLFILE% /BUILD %BUILDCONFIG% /OUT %OUTLOGFILE% > nul
请记住,上面提到的代码可能并不完美,因为我从我的POC中提到了我在遇到类似自动化问题时所做的事情。