Доступ к инфраструктуре сборки Microsoft можно получить через API. Но я не уверен, что можно сделать это только через командный файл. ИМХО самый простой способ - это автоматизировать сборку, написав надстройку (возможно, с использованием VB.NET) в VS IDE. Это дополнение может быть вызвано из командного файла. Мы автоматизировали сборки VC ++, как это, используя подход addin. В нашем случае другого пути не было, потому что нам также пришлось автоматизировать процесс moc в Qt. Я думаю, что это будет более гибким.
Система сборки (по крайней мере в VS 2005), над которой я работал, была довольно глючной. Обратитесь к этой ссылке , она поможет вам понять подводные камни, а также предоставит фрагменты кода о том, как пройти файлы решения.
После установки надстройки можно создать небольшой исполняемый файл, который вызывает сборку через надстройку. Этот exe-файл можно вызвать из командного файла.
Образец исполняемой программы VS Automator, вызывающей методы надстройки
''' 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
Пример командного файла для запуска exe автомата VS:
@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, который я делал, когда у меня была похожая проблема автоматизации.