LintProject - 使用 Visual C++ 解决方案和项目提高 PC-Lint 的可用性






4.83/5 (30投票s)
运行 PC-Lint 在 Visual C++ 解决方案和项目上的实用工具,可生成结果的 XML 和 HTML 报告。
引言
LintProject 是一个命令行工具,旨在让使用 PC-Lint 代码分析工具(由 Gimpel software 生产)与 Visual C++ 项目的过程更加轻松和高效。
PC-Lint 分析 C++ 代码以识别潜在问题。与 C++ 编译器(例如 Visual C++ 提供的编译器)相比,它具有高度的可定制性和非常彻底的特性,但(可以理解地)速度明显较慢。它生成的输出是基于文件的,默认情况下会输出到控制台,例如
--- Module: CJFlatHeaderCtrl.cpp
} CJFlatHeaderCtrl.cpp(160): error 1401:
(Warning -- member 'CCJFlatHeaderCtrl::m_bSortAsc'
(line 146, file ..\Include\CJFlatHeaderCtrl.h) not initialized by constructor)
}
CJFlatHeaderCtrl.cpp(166): error 1740:
(Info -- pointer member'CCJFlatHeaderCtrl::m_pParentWnd'
(line 150, file ..\Include\CJFlatHeaderCtrl.h)
not directly freed or zeroed by destructor -- Effective C++ #6) ---
Global Wrap-up error 900: (Note -- Successful completion, 2 messages produced)
虽然 PC-Lint 在分析 C++ 源文件和头文件以查找潜在问题方面做得很好,但它是一个通用的跨平台工具,因此与开发环境的集成有限。例如,与 Visual C++ 一起使用时,PC-Lint 可以用于扫描当前文件以获取警告,并将结果定向到输出窗口,或者扫描文本文件中定义的文件列表。
虽然在某些情况下(例如,在开发新代码时)这种程度的集成几乎足够,但如果您想对整个项目或解决方案进行完整分析,则该集成效果不佳。此外,由于 PC-Lint 不提供任何生成有用的结果报告的手段,因此很难在大量结果中发现潜在问题。
如果您正在处理一个大型项目,这些限制可能会使使用 PC-Lint 分析代码变得耗时且困难,这可能成为定期使用这个非常有用的工具的真正阻碍。因此,您的代码质量可能会因此受到影响。
LintProject 的编写旨在解决其中两个问题。与 PC-Lint 不同,LintProject 可以读取 Visual C++ 项目和解决方案文件。它可以针对完整的解决方案或单个项目运行
- 当针对项目运行时,它会读取 Visual C++ 项目文件(*.dsp, *.vcp, 或 *.vcproj)并指示 PC-Lint 分析哪些文件。对于每个分析过的文件,PC-Lint 的输出都会被捕获并记录在文本文件中以供以后分析。
- 当针对完整解决方案运行时,LintProject 会读取 Visual C++ 解决方案文件(*.sln, *.vcw, 或 *.dsw)并递归分析其中包含的项目。
XML 和 HTML 报告
虽然包含分析结果的文本文件的可用性是该过程的重要结果,但如果没有一种方法来汇总其内容并对其进行索引,解释结果的过程可能会缓慢且费力。
LintProject 通过编写 XML 和 HTML 报告来提供一种方便的解决方案,这些报告链接到结果文件,并显示了在每个实现文件、项目和解决方案中找到的警告数量。
LintProject 的一个关键设计目标是能够在其运行时指示其进程。考虑到 PC-Lint 对大型项目的分析在某些系统上可能需要大量时间,这一点尤其重要。为了实现这一目标,LintProject 生成的输出报告会在分析进行时自动重新生成。更好的是,任何显示相应结果文件的受支持浏览器窗口*都会在每个文件被分析时自动刷新。这提供了对分析进度的即时反馈,并且已被证明是一项非常有用的功能。
* 目前,此功能仅支持 Internet Explorer 和派生浏览器,如 Crazy Browser、Avant browser 等。
安装
安装 LintProject 非常简单。最简单的方法是将可执行文件(LintProject.exe)放在 PC-Lint 可执行文件(lint-nt.exe)的同一文件夹中。如果您更喜欢将 LintProject.exe 放在其他位置,可以使用 /f 开关来告知它在哪里找到 PC-Lint 可执行文件。
使用 LintProject
LintProject 通过简单的命令行调用,例如
-
LintProject <SolutionName.sln> <ResultsFolder> [options]
-
LintProject <ProjectName.vcproj> <ResultsFolder> [options]
或
有几个选项
-
/f<FolderName>
-
/configfile"<filename>"
-
/cfg"<configname>"
-
/exclude"<projectname1>,<projectname2>,..."
-
/l"<parameters>"
-
/s
-
/?
指定 LintProject 可执行文件的位置。仅当 LintProject 安装在与 PC-Lint 可执行文件不同的文件夹中时才需要。
指定要使用的 Lint 间接文件的文件名。如果省略,则假定为 std.lnt。
指定要分析的解决方案配置。
指定要从分析中排除的项目名称。
将以下参数传递给 PC-Lint 可执行文件(lint-nt.exe)。例如,/l" -background" 将指示 PC-Lint 以低优先级执行分析。
指定在分析开始时应在浏览器窗口中自动打开 HTML 输出。
显示帮助信息。
LintProject 单独在每个源文件上运行 PC-Lint 可执行文件(lint-nt.exe),指示它将其输出重定向到一个文本文件,该文本文件从相应的 HTML 报告链接。对于每个文件,都会使用类似以下的命令行:
<lint-folder>\lint-nt.exe -i"<lint-folder>" -b -u std.lnt
env-vc6.lnt -i"Debug" <source file> >Lint\<source file>.txt
std.lnt 和 env-vc6.lnt 是 PC-Lint 安装生成的标准选项文件 - 后者特定于 Visual C++ 6.0 项目。虽然 PC-Lint 安装默认只会将其中一个这样的文件安装到 PC-Lint 安装文件夹中,但其他文件的副本可在 lnt 子文件夹中找到。
LintProject 将为 Visual C++ 5.0 和 6.0 项目(<projectname>.dsp)使用 env-vc6.lnt,为 Visual C++ .NET 项目(<projectname>.vcproj)使用 env-vc7.lnt,因此最好将您期望使用的选项文件放在 PC-Lint 安装文件夹本身中。
源代码
LintProject 是一个相当直接的命令行应用程序,使用 ATL7 构建。最初,MFC 被使用(当时更多是为了方便,而不是其他原因 - 用于解析 Visual C++ 解决方案和项目文件的类最初直接取自 ResOrg,并且最初是在 MFC 下编写的)。依赖 MFC 的情况后来已被移除。
除了解析器和实用工具类之外,LintProject 主要由三个类组成 - CFileLintAnalyser
、CProjectLintAnalyser
和 CSolutionLintAnalyser
- 它们共同控制分析指定项目或解决方案的整个过程。这些类会调用 PC-Lint,索引其输出,并生成 XML 和 HTML 格式的输出报告(后者通过使用 XSLT 样式表转换 XML 实现)。
早期出现的一个问题是,由于其覆盖深度,使用 PC-Lint 分析整个项目所需的时间可能非常长。为了让用户能够看到分析的进度,LintProject 会在分析进行时重新生成其输出报告。一个额外的维度是它能够在其报告显示时刷新主机 PC 上任何显示其报告的浏览器窗口(实际上,看着警告计数稳步攀升是相当令人着迷的……)
实现浏览器刷新是“一旦知道如何就很容易”的技术之一。它是通过使用 SHDocVw::IShellWindows
接口枚举本地计算机上所有打开的 WebBrowser
控件来实现的(参见 MSDN KB 文章 176792 - "如何连接到正在运行的 Internet Explorer 实例")。
对于检索到的每个控件,其显示的 URL 会与刚刚更新的报告的规范化路径名进行比较。如果匹配,则刷新控件,从而显示报告的更新版本。
/// Refresh all WebBrowser controls displaying the file with the given pathname
///
/// Note that this technique currently works
/// for Internet Explorer and derived browsers only
bool RefreshAllOpenBrowserWindows(const CString& sFullPathName)
{
if (sFullPathName.IsEmpty() )
{
return false;
}
// Convert the pathname to a uniform URL ready
// for comparison with the URL in each control
DWORD dwLen = _MAX_PATH;
CString sCompareURL;
if (!::InternetCanonicalizeUrl(sFullPathName,
sCompareURL.GetBufferSetLength(_MAX_PATH),
&dwLen,
ICU_BROWSER_MODE) )
{
return false;
}
sCompareURL.Replace( _T("//"), _T("///") );
sCompareURL.Replace( _T('\\'), _T('/') );
sCompareURL.MakeLower();
SHDocVw::IShellWindowsPtr shellws = NULL;
bool bSuccess = true;
try
{
// Connect to an instance of the shell
HRESULT hr = shellws.CreateInstance(__uuidof(SHDocVw::ShellWindows));
if (FAILED(hr) )
{
throw hr;
}
// Enumerate through current open windows (Internet Explorer and Explorer)
long lCount = shellws->GetCount();
for (int i = 0; i < (int)lCount; i++)
{
// Get a current open shell window
_variant_t vtIndex( (long)i);
IDispatchPtr idisp = shellws->Item(vtIndex);
if (idisp == NULL)
{
continue;
}
// Retrieve an interface to the WebBrowser control
SHDocVw::IWebBrowser2Ptr pWebBrowser = NULL;
hr = idisp->QueryInterface(IID_IWebBrowser2, (LPVOID *)&pWebBrowser);
if (pWebBrowser != NULL)
{
// Which URL is it displaying?
_bstr_t bsURL = pWebBrowser->GetLocationURL();
CString sURL((LPCTSTR)bsURL);
sURL.MakeLower();
// Compare the browser URL to the url to be refreshed
if (sURL == sCompareURL)
{
// This WebBrowser control is displaying the file
// we're interested in, so refresh it
hr = pWebBrowser->Refresh();
if (SUCCEEDED(hr))
{
TRACE("browser refreshed correctly\n");
}
}
}
}
}
catch(...)
{
// There's been a problem during the enumeration
bSuccess = false;
}
// Clean-up
shellws.Release();
return bSuccess;
}
不幸的是,这种技术仅适用于 Internet Explorer 和派生浏览器。当然,可以使用类似的技术来处理任何提供 COM 接口和系统级别枚举窗口方法的其他浏览器。如果您知道任何适用于 Mozilla、Firefox 和 Opera 的类似接口,我们将非常乐意了解它们。
最后,尽管表面看起来并非如此,LintProject 是单线程的。虽然它可以编写成生成多个分析线程(就像 Visual Lint 那样),但考虑到其最初的目标用途是在夜间构建时运行,额外的复杂性似乎并不值得。
常见问题解答
LintProject 可以独立使用吗?
不可以。要使用 LintProject,您必须拥有 PC-Lint 的授权副本。请联系 Gimpel Software 获取 PC-Lint 的订购信息。
LintProject 支持哪些平台?
LintProject 应该可以在任何支持 Windows 2000 或更高版本的系统上运行。此限制完全是由于使用了 Win32 函数 SHCreateDirectoryEx()
;如果您需要一个在 Windows 9x 上运行的 LintProject 版本,请联系我们,我们将很乐意准备一个没有此限制的版本。
LintProject 与哪些 Visual C++ 版本兼容?
LintProject 兼容 Visual C++ 5.0、6.0、Visual Studio .NET 2002、2003、2005 和 2008,以及 eMbedded Visual C++ 4.0 的项目和解决方案。
编译 LintProject 源代码需要 Visual C++ .NET 2003 或更高版本。
LintProject 需要什么配置?
无。只需将可执行文件放在 PC-Lint 可执行文件(lint-nt.exe)的同一文件夹中,它应该就可以正常工作。
如果您更喜欢将 LintProject.exe 放在其他位置,可以使用 /f 开关来告知它在哪里找到 PC-Lint 可执行文件。
我可以将自己的参数传递给 PC-Lint 可执行文件吗?
可以。您可以使用 /l 开关直接将参数传递给 lint-nt.exe。
我安装了 Windows XP Service Pack 2,并且报告中的某些链接无法工作
这是 Windows XP SP2 中引入的“本地计算机区域锁定”策略的直接结果,该策略会阻止本地访问的 HTML 页面运行活动内容(包括 JavaScript 代码,而 JavaScript 代码包含在 HTML 报告中以提供表格排序功能)。
以下文章讨论了锁定策略及其影响
根据我们阅读的有关此问题的文章,应该可以通过在生成的 HTML 中添加“Web 标记”(以 Microsoft 术语来说)来规避此问题。不幸的是,到目前为止,这被证明是不可靠的,或者产生了不希望的副作用。我们将继续寻找一种规避此限制的方法,但目前,可以通过单击警告出现的“信息栏”并选择“允许阻止的内容”选项,或者在“Internet 选项”的“高级”页面中选中“允许在我的计算机上的文件运行活动内容”选项来轻松绕过。
请注意,此问题仅影响 Internet Explorer。其他浏览器应该不受影响。
LintProject 需要哪些其他系统 DLL,以及什么版本?
LintProject 需要 MSXML2 或更高版本才能生成 HTML 报告。虽然它应该默认安装在 Windows XP 系统上,但如果需要,可以通过安装 XML SDK(随 Platform SDK 提供)来手动安装。
除了 MSXML 之外,LintProject 应该不需要安装任何其他系统 DLL。如果您在系统上使用它时遇到困难,请告知我们。
最后...
LintProject 的原始版本由 Anna 在 Sonardyne International Limited 工作期间编写。我们要感谢他们(特别是 Bruce Baker 和 Richard Baldock)同意将源代码的所有权释放给我们,以便我们能够维护和进一步开发它。
LintProject 是免费软件。只要代码和样式表中的所有版权声明保持不变,您就可以无限制地使用它。我们希望它能像对我们一样对您有所帮助,并欢迎您对未来的增强和改进提出建议。
有关 LintProject 的最新信息,请访问 Riverblade 网站。
版本历史
版本 1.4.1.13(2009 年 1 月)
- 修改以支持 VS2002 及更高版本的 $(PlatformName)。感谢 Alex McCarthy 贡献的这些更改。
- LintProject 现在在命令行错误的情况下返回错误代码 1。感谢 Brett Rowbotham 贡献的此更改。
- 项目报告中的已用时间值现在显示小时、分钟和秒(防止项目分析时间超过一小时时报告错误)。感谢 Brett Rowbotham 贡献的此更改。
- 删除了未使用的 LintProject.h。
- 将 stdafx.h 中的 MSXML 导入从 msxml2.dll 更新为 msxml4.dll 并添加了
named_guids
限定符。 - 修改以支持 $(SolutionDir) 和 $(ProjectName)。感谢 Alex McCarthy 贡献的这些更改。
- 删除了 CFileLintAnalyser 中冗余的声明。
- 在 MakeZip.bat 中将 LintProject.zip 更改为 LintProject_1.4.zip。
版本 1.4.0.10(2008 年 7 月)
- 删除了所有 MFC 依赖项。LintProject 现在直接使用 ATL 7,因此源代码现在需要 Visual Studio .NET 2003 或更高版本进行编译(项目文件适用于 Visual Studio .NET 2003 和 Visual Studio 2008,但移植到其他版本应该很简单)。
- 将构建转换为 Unicode。
- 添加了对 eMbedded Visual C++ 4.0 工作区和项目的支持。
- 解决方案和项目特定的环境变量 $(SolutionDir)、$(ProjectDir)、$(InputDir) 和 $(ConfigurationName) 现在在分析期间设置。感谢 Andrej Pohlmann 贡献了实现此功能所需的代码。
- 如果在项目文件夹中找到 .options.lnt 格式的文件,现在将在分析命令行中使用它。感谢 Andrej Pohlmann 贡献了实现此功能所需的代码。
- 添加了解决方案/项目配置的错误检查(尝试分析无效配置现在会导致生成错误)。
- 现在可以正确解析仅包含一个项目配置的 Visual C++ 6.0 项目(*.dsp)文件。
- 添加了 /exclude 参数以允许排除指定的项目不进行分析(感谢 Andrej Pohlmann 贡献了实现此功能的代码)。
- 集成了来自 Visual Lint 的解决方案和项目文件解析器,以及各种实用函数。
- 纠正了加载 XSL 样式表中的潜在缓冲区溢出(感谢 Mark Ridgwell 发现此问题)。
- 纠正了 Visual C++ 项目中解析中间文件文件夹的错误。
- 在分析命令行中恢复了丢失的 -u 选项。
- 在生成的报告中添加了应用程序版本。
- 修复了
Utils::RefreshAllOpenBrowserWindows()
中潜在的 COM 异常。 - 修复了次要的 Lint 问题。
- 代码现已根据 Code Project Open Licence (CPOL) v1.0 发布;文件横幅已相应更新。
版本 1.3.1.7(2007 年 6 月)
- 添加了 /configfile 开关以允许指定 std.lnt 文件的名称。
- 纳入了客户要求的修复和更正。
- 开始移除 MFC 特定代码。
- 修复了大多数未解决的 Lint 问题。
版本 1.3.0.6(2006 年 3 月)
- 添加了对 Visual Studio .NET 解决方案配置的支持。现在可以直接指定解决方案配置,并自动选择每个项目的相应配置。
- 添加了 /cfg? 参数以允许查询解决方案或项目级别的可用配置。
CSolutionLintAnalyser
和CProjectLintAnalyser
现在仅在指定了 /s 参数时尝试刷新浏览器窗口。这可以防止实用程序作为服务运行时出现问题。
版本 1.2.4(2005 年 3 月)
CSolutionLintAnalyser::Analyse()
和CProjectLintAnalyser::Analyse()
现在使用SHCreateDirectoryEx()
而不是mkdir()
来创建分析结果的文件夹,以便自动创建递归文件夹。注意:此函数需要 Windows 2000 或更高版本。- 根据 LintProject CodeProject 论坛的建议进行了 UNC 路径检查的修复。
- 改进了相对路径名的处理。分析和源文件不再需要驻留在同一个逻辑驱动器上。
- 通过新的命令行选项(/l"<params>")添加了对直接将参数传递给 lint-nt.exe 的支持。
- 如果 lint-nt.exe 返回警告计数 255,
CFileLintAnalyser::Analyse()
现在将解析结果文件以尝试检索真实的警告计数。 - 重新实现了
FileExists()
辅助函数。 - 添加了源代码控制解决方案。
- 修改以允许在 PC-Lint 安装在包含空格的路径名(例如,C:\Program Files\Lint)的系统上运行。
版本 1.2.2(2004 年 10 月)
LintProject 版本 1.2.2 发布到 CodeProject。