Visual C++ (version 7-9) .vcproj 项目文件格式化程序和规范化程序






4.71/5 (13投票s)
一个 vcproj 格式化程序,可以使 vcproj 的差异/合并变得轻而易举,即使使用简单的文本合并器。可控的文本编码。
引言
本文的目的是讨论 Visual C++ 7、7.1、8、9 扩展名为“.vcproj”的项目文件存在的问题,并提供一个命令行实用程序来解决这些问题。.vcproj 文件本身没有问题,直到您开始与团队合作,并且可能在源代码管理系统中使用 .vcproj。这些项目文件是纯 XML 文件,只有元素和属性,但每次在 Visual Studio 中保存它们时,一些相邻的 XML 元素都可能被重新排序,这使得在存储库中比较您对原始文件的更改变得非常困难,同样,在提交/检入您的更改之前进行合并也同样困难。
问题的深入解释
.vcproj 文件的格式是公开的;您可以在 这里 查阅其 XSD。我之前描述的问题有许多根源
- 根据 XML 规范,元素的属性是无序的。
- .vcproj XSD 使用
<xs:choice/>
声明,该声明允许一系列不同的同级元素在 .vcproj 中以任意顺序出现。 - 如果一个元素的类型(例如,.vcproj 中的
<Configuration/>
节点)在一个序列中可以出现多次,那么 Visual Studio 在您保存 .vcproj 时可能会随机打乱它们的顺序。
我的命令行工具可以根据比 Microsoft 的 .vcproj 文件 XSD 更严格的规则集来重新排列 .vcproj XML 文件。结果是 Visual Studio 仍然可以加载 .vcproj,但是 XML 属性和元素将更加严格地排序。
该工具的命令行参数
这是一个简单的命令行工具,而不是一个插件,因为我没有在插件 SDK 中找到可以拦截 .vcproj 文件保存的正确位置。我甚至不确定是否可以拦截 .vcproj 保存事件。(您或许可以给我一些提示来改进这个程序。)以下是命令行参数
Usage: VcprojFormatter.exe [options...] [-] vcproj1 [, vcproj2 [, ...]]
You can use wildcards to specify vcproj files. (Eg.: c:\code\*.vcproj)
The files must have .vcproj extension!
OPTIONS:
-DECIMAL_POINT:[.|,] Specify a decimal point character that will be used in
the value of the version attribute of your vcproj. It
can be '.' or ',' depending on your locale settings.
This prog keeps the original decimal point in the version
number by default but you can force it to be always
'.' or ',' using this commandline parameter.
-NEWLINE:newline_mode Specifies the newline format of the output file.
Possible newline modes: CR, CRLF, LF, LFCR, AUTO
The default is AUTO which keeps the original newlines.
-ENCODING:encoding Sets the encoding of the output file.
The default is AUTO which keeps the original encoding.
-SAFE_ENCODING Used only with non-UTF encodings. This forces the
character codes above 0x7F to be represented as character
references (like codes below 0x20) in the xml values.
You may need this because the Windows API allows mapping
of some characters above 0x7F to UTF-16 even if the
specified character is not defined in the codepage. For
example: char 0x81 on codepage Windows-1252. However
these non-existing characters should not normally occur
in a file with a codepage that doesn't define them.
-LIST_ENCODINGS Show the list of supported encodings.
该工具可以控制换行符的二进制表示和 XML 的编码。换行符可以是 CRLF 以外的其他字符;例如,如果您使用 Perforce 源代码管理,并将文本文件检出到 Linux,则使用实际平台上的换行符。(实际上,我不得不在 Linux 上通过脚本使用该工具,并使用 wine 来运行它。)如果您的团队有来自不同国家的程序员,他们使用本地化的 Windows,编码是另一个可能让您头疼的事情。使用此工具,您还可以控制上传到 Perforce 的 .vcproj 文件的编码。另一个依赖于区域设置的烦人之处是 Visual Studio 版本号在 .vcproj 文件中的小数点;它可以是点或逗号。您可以要求格式化工具只使用其中一种。
使用该工具
- 将格式化后的 .vcproj 文件上传到您的源代码管理系统。
- 当一个程序员修改并保存 .vcproj 文件时,他/她必须先在将它与存储库中的文件进行差异/合并之前运行 vcproj 格式化工具。Perforce 源代码管理客户端有一个“工具”菜单,您可以在其中轻松地将此 vcproj 格式化工具添加为右键菜单项。
格式化 vcproj 后,Visual Studio 通常会发现 .vcproj 文件已修改,并提示您是否重新加载新版本或忽略它。您可以安全地选择忽略选项。
该工具将 .vcproj 文件保存为一种非常容易与简单的文本工具进行差异/合并的格式。另一点我个人不喜欢 Visual Studio 保存的 .vcproj 文件是,只有单个属性的元素仍然会分成三行。将这些元素保存为单行可以使您的 .vcproj 更简洁易于合并。
这是一个未经格式化的 .vcproj 文件示例
<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="VcprojFormatter"
ProjectGUID="{A1857D12-A8DB-4615-AD0D-BE2BB3519057}"
RootNamespace="VcprojFormatter"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="true"
ExceptionHandling="0"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\smart.h"
>
</File>
<File
RelativePath=".\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\stdafx.h"
>
</File>
<File
RelativePath=".\Vcproj.cpp"
>
</File>
<File
RelativePath=".\Vcproj.h"
>
</File>
<File
RelativePath=".\VcprojFormatter.cpp"
>
</File>
<File
RelativePath=".\VcprojParser.cpp"
>
</File>
<File
RelativePath=".\VcprojParser.h"
>
</File>
<File
RelativePath=".\XmlEncoding.cpp"
>
</File>
<File
RelativePath=".\XmlEncoding.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
格式化后的同一个 .vcproj 文件
<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
Name="VcprojFormatter"
Keyword="Win32Proj"
ProjectGUID="{A1857D12-A8DB-4615-AD0D-BE2BB3519057}"
ProjectType="Visual C++"
RootNamespace="VcprojFormatter"
TargetFrameworkVersion="196613"
Version="9,00"
>
<Platforms>
<Platform Name="Win32"/>
</Platforms>
<ToolFiles/>
<Configurations>
<Configuration
Name="Debug|Win32"
CharacterSet="1"
ConfigurationType="1"
IntermediateDirectory="$(ConfigurationName)"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
>
<Tool Name="VCALinkTool"/>
<Tool Name="VCAppVerifierTool"/>
<Tool Name="VCBscMakeTool"/>
<Tool
Name="VCCLCompilerTool"
BasicRuntimeChecks="3"
DebugInformationFormat="4"
MinimalRebuild="true"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="3"
/>
<Tool Name="VCCustomBuildTool"/>
<Tool Name="VCFxCopTool"/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
LinkIncremental="2"
SubSystem="1"
TargetMachine="1"
/>
<Tool Name="VCMIDLTool"/>
<Tool Name="VCManagedResourceCompilerTool"/>
<Tool Name="VCManifestTool"/>
<Tool Name="VCPostBuildEventTool"/>
<Tool Name="VCPreBuildEventTool"/>
<Tool Name="VCPreLinkEventTool"/>
<Tool Name="VCResourceCompilerTool"/>
<Tool Name="VCWebServiceProxyGeneratorTool"/>
<Tool Name="VCXDCMakeTool"/>
<Tool Name="VCXMLDataGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
CharacterSet="1"
ConfigurationType="1"
IntermediateDirectory="$(ConfigurationName)"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
WholeProgramOptimization="1"
>
<Tool Name="VCALinkTool"/>
<Tool Name="VCAppVerifierTool"/>
<Tool Name="VCBscMakeTool"/>
<Tool
Name="VCCLCompilerTool"
BufferSecurityCheck="false"
CallingConvention="1"
DebugInformationFormat="3"
EnableFunctionLevelLinking="true"
EnableIntrinsicFunctions="true"
ExceptionHandling="0"
FavorSizeOrSpeed="1"
Optimization="3"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
StringPooling="true"
UsePrecompiledHeader="2"
WarningLevel="3"
/>
<Tool Name="VCCustomBuildTool"/>
<Tool Name="VCFxCopTool"/>
<Tool
Name="VCLinkerTool"
EnableCOMDATFolding="2"
GenerateDebugInformation="true"
LinkIncremental="1"
OptimizeReferences="2"
SubSystem="1"
TargetMachine="1"
/>
<Tool Name="VCMIDLTool"/>
<Tool Name="VCManagedResourceCompilerTool"/>
<Tool Name="VCManifestTool"/>
<Tool Name="VCPostBuildEventTool"/>
<Tool Name="VCPreBuildEventTool"/>
<Tool Name="VCPreLinkEventTool"/>
<Tool Name="VCResourceCompilerTool"/>
<Tool Name="VCWebServiceProxyGeneratorTool"/>
<Tool Name="VCXDCMakeTool"/>
<Tool Name="VCXMLDataGeneratorTool"/>
</Configuration>
</Configurations>
<References/>
<Files>
<File RelativePath=".\Vcproj.cpp"/>
<File RelativePath=".\Vcproj.h"/>
<File RelativePath=".\VcprojFormatter.cpp"/>
<File RelativePath=".\VcprojParser.cpp"/>
<File RelativePath=".\VcprojParser.h"/>
<File RelativePath=".\XmlEncoding.cpp"/>
<File RelativePath=".\XmlEncoding.h"/>
<File RelativePath=".\smart.h"/>
<File RelativePath=".\stdafx.cpp">
<FileConfiguration Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File RelativePath=".\stdafx.h"/>
</Files>
<Globals/>
</VisualStudioProject>
已知问题
- Windows 的
WideCharToMultiByte()
和MultiByteToWideChar()
函数用于编码/解码文本,有时它们的工作不符合预期,这取决于您的 Windows 版本。它们可能会编码/解码无效字符。例如,在我的 WinXP 上,代码页 37 编码可能会将 .vcproj 文件弄得一团糟。在坚持使用之前,请尝试您选择的编码!
历史
- 2010 年 12 月 4 日:初始版本。
- 2010 年 12 月 9 日:对编码的支持更好。