65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Visual Studio (MSBuild) 中构建和配置 OpenSSL。

starIconstarIconstarIconstarIconstarIcon

5.00/5 (11投票s)

2015 年 3 月 30 日

CPOL

7分钟阅读

viewsIcon

78208

downloadIcon

4064

将第三方工具和库集成到 Visual Studio (MSBuild) 配置环境中。

引言

在本文中,我将展示如何使用 Visual Studio 和 MSBuild 系统配置和构建 OpenSSL 库。本文的目标是解决以下问题:

  • 提供针对 openssl 库的专用 UI 属性页,以便只能设置有效选项
  • 提供一种简单的方法来微调构建并传递编译器选项
  • 没有硬编码
  • 按顺序构建多个平台(x86、x64...)
  • 在源代码树之外构建
  • 与 Visual Studio 集成,允许项目与 OpenSSL 相互引用
  • 无缝调试和符号加载

背景

OpenSSL 项目是一个开源项目,实现了安全套接字层 (SSL v2/v3) 和传输层安全 (TLS) 协议,以及一个通用加密库。它是一个跨平台库,因此编写时会兼容多种构建工具和操作系统。

构建说明非常简单

perl Configure VC-WIN32 --prefix=C:\Build-OpenSSL-VC-32
ms\do_ms
nmake -f ms\nt.mak
nmake -f ms\nt.mak install

看起来很简单,但正如往常一样,总有陷阱

  • 它会在 OpenSSL 发行版的根目录下构建所有二进制文件和对象文件。
  • 如果需要构建多个配置(Release、Debug 等),则必须逐个进行。
  • 它不以任何方式与 Visual Studio 集成

在这里,我们将尝试修复所有这些问题。

配置

在我之前的文章中,我描述了如何为第三方工具创建自定义属性页。更多信息请参阅 此处此处。长话短说,我们创建了以下属性页:

“常规”页面允许设置常规项目属性,例如输出和中间目录,以及大多数 OpenSSL 选项。它还提供了一个 UI,用于在“命令行”控件中添加任何任意参数。
输出、中间和包含目录将在构建过程中用于放置相应的文件。如果为空,构建将使用 OpenSSL 根文件夹中的默认位置(例如,如果“包含”为空,则为 inc32)。

展开左侧窗格中的“选项”会产生以下视图:

此页面允许禁用密码。如果页面上缺少某个密码,仍可通过提供
“常规”页面上的“命令行”中的 `no-missing_cither` 选项来禁用它。

Kerberos 5 页面提供了一种将 Kerberos 5 库添加到构建中的方法。

“C++”页面允许微调构建并将其他开关和定义发送给编译器。

通过这些属性页,我们可以配置所有 OpenSSL 选项,以及传递一些额外的参数给编译器。

从属性页获取正确的值并将其传递给配置的详细说明请参阅 此处。配置由 `GetXmlConfig` 目标处理,并返回一个参数字符串,该字符串被传递给相应的脚本。

现在我们准备好构建了。

构建

检查 _Configure_ 脚本和批处理文件,揭示了以下步骤:

perl Configure VC-WIN32 --prefix=C:\Build-OpenSSL-VC-32

在 OpenSSL 目录的根目录下创建 Makefile。

ms\do_ms

创建 MINFO 文件。
创建模块定义和资源文件。
创建合并的 Makefile。

nmake -f ms\nt.mak

构建库。

将这些任务包装到原生的 MSBuild 目标中可以更精确地控制构建过程。我们创建了以下目标:

  <Target Name="Configure" ... />
  <Target Name="MINFO" ... />
  <Target Name="ModuleDefinitions" ... />
  <Target Name="CreateMakefile" ... />
  <Target Name="CompileAsm" ... />
  <Target Name="Build" ... />
  <Target Name="Rebuild" ... />
  <Target Name="Clean" ... />

添加目标之间的必要依赖关系,插入相应的 Perl 脚本的 `` 任务,为 Configure 和 Makefile 脚本添加配置,然后就完成了。一切都很简单,并且完全遵循 OpenSSL 的常规构建流程。指定输入和输出允许在源代码树没有更改的情况下执行增量构建。

配置选项

OpenSSL 构建分两步配置:在 `Configure` 目标和 `CreateMakefile` 目标中。

`Configure` 目标处理来自 UI 属性页的参数,并将它们传递给 Configure 脚本。配置值通过执行 `ConfGen.targets` 中实现的 `GetXmlConfig` 目标来检索。有关该过程的详细解释,请参阅此 帖子

`CreateMakefile` 目标执行 **mk1mf.pl** 脚本,并设置输出、包含和中间目录的位置。它还指示脚本创建静态或共享库,以及是否使用汇编器。

Clean

构建后的清理工作有点棘手。执行 **nmake -f ms\nt.mak clean** 会通过运行 **del *.*** 来擦除所有内容。

对于 Visual Studio 来说,这种行为是不可接受的。同一目录中可能存在其他项目的​​文件。为了避免删除错误的文件,Makefile 会被解析以获取它构建的目标列表。Makefile 的格式定义良好,因此相对容易找到所有这些文件(请注意,为简化起见,脚本已修改)。

<ReadLinesFromFile File="$(BuildDir)\openssl.mak" Condition="Exists('$(BuildDir)\openssl.mak')">
  <Output ItemName="ConfigLines" TaskParameter="Lines"/>
</ReadLinesFromFile>

<ItemGroup>
  <BuildDirSelected  Include="$([Regex]::Match('%(ConfigLines)', (?&lt;=\\)(.*?\b)(?&lt;=\.obj) ))" />
  <BuildDirSelected  Include="$([Regex]::Match('%(ConfigLines)', (?&lt;=\\)(.*?\b)(?&lt;=\.asm) ))" />
  <BuildDirLibrary   Include="$([Regex]::Match('%(ConfigLines)', (?&lt;=\\)(.*?\b)(?&lt;=\.lib) ))" />
  ...
  <OutputDirLibrary  Include="$([Regex]::Match('%(ConfigLines)', (?&lt;=\\)(.*?\b)(?&lt;=\.dll) ))" />
  <OutputDirLibrary  Include="openssl.exe;libeay32.dll;ssleay32.dll" />
</ItemGroup>
    
<CombinePath BasePath="$(BuildDir)" Paths="@(BuildDirSelected)">
  <Output ItemName="DelFiles" TaskParameter="CombinedPaths"/>
</CombinePath>
<CombinePath BasePath="$(OutputDir)" Paths="@(OutputDirSelected)">
  <Output ItemName="DelFiles" TaskParameter="CombinedPaths"/>
</CombinePath>
    
<Delete Files="@(DelFiles)" ContinueOnError="true" />

在此代码中,我们读取 Makefile,通过匹配模式解析所有目标文件,添加这些文件的完整路径,然后删除它们。

构建多个平台

如果中间、包含和输出目录都不同,则可以按顺序构建多个平台。这可以通过使用宏(如 $(Platform) 和 $(Configuration))来实现。例如,请参阅示例项目的 x64 平台配置。

构建既可以从 VisualStudio 执行,也可以从命令提示符执行。

参考文献

此项目的一个目标是将其集成到 Visual Studio 项目引用系统中。

引用依赖项

OpenSSL 依赖于两个外部库:ZLib 和 Kerberos 5。Kerberos 不支持 MSBuild,因此无法集成到原生引用系统中。另一方面,ZLib 带有与库一起分发的 MSBuild 项目,可以轻松集成。
ZLib 也有一个与项目相关的知名 ID,可用于在构建中识别它。

<MSBuild Projects="@(ProjectReference)" Targets="GetResolvedLinkLibs"
         Condition="'%(ProjectReference.Project)'=='{8fd826f8-3739-44e6-8cc8-997122e53b8d}'" >
  <Output ItemName="ZLibPath" TaskParameter="TargetOutputs"/>
</MSBuild>

这会获取 ZLib 库的路径。

构建还需要 ZLib 库的包含目录的路径。通常,它会在 C++ 编译器设置的“附加包含目录”字段中手动设置。如果可以从 zlib.h 文件的位置推断出该位置,我们可以省去手动步骤。此代码获取该位置。

<MSBuild Projects="@(ProjectReference)" Targets="SourceFilesProjectOutputGroup"
         Condition="'%(ProjectReference.Project)'=='{8fd826f8-3739-44e6-8cc8-997122e53b8d}'" >
  <Output ItemName="SourceFiles" TaskParameter="TargetOutputs"/>
</MSBuild>

<PropertyGroup>
  <LibEnvVar Condition="'@(SourceFiles)'!='' And 
                        '%(SourceFiles.Identity)'!='' And 
                        '@(SourceFiles->Contains(&#34;zlib.h&#34;))'=='True'">INCLUDE=%(RelativeDir)/>
</PropertyGroup>

这两个参数都作为环境变量 LIB 和 INCLUDE 传递给构建。

提供引用

为了在上游项目中被引用,需要几个目标:

<Target Name="GetNativeTargetPath"/ >
<Target Name="GetTargetPath" />
<Target Name="GetNativeManifest" />
<Target Name="GetResolvedLinkLibs" />
<Target Name="GetCopyToOutputDirectoryItems" />

有关项目引用的详细说明以及所需内容的说明,请参阅 Visual Studio 中的原生项目引用。OpenSSL 项目遵循文章中描述的指南。

测试应用程序

创建了一个测试应用程序来演示 OpenSSL 集成和引用。该示例来自早期 IBM 文章,此处

示例需要将 OpenSSL 添加到项目依赖项并设置包含目录的路径。完成后,就可以构建和调试测试应用程序。

调试

Visual Studio 的最大优势之一是其强大的调试器。此集成项目使您无需任何额外工作即可利用此工具的所有功能。您可以从应用程序中进入代码,或者可以直接调试 openssl.exe。进入 OpenSSL 代码无需任何额外步骤。 PDB 文件的位置可以从 `GetResolvedLinkLibs` 提供的库文件的位置推断出来。

要调试 `openssl.exe`,请右键单击解决方案资源管理器中的 `openssl` 项目,选择“调试”,然后选择“新实例”。

这将启动新的调试器会话,加载可执行文件并进入 main 方法。

从现在开始,您可以逐行执行代码,设置断点等。

测试

此项目允许执行通常由 `nmake -f makefile test` 命令执行的单元测试。测试由 `Test` 目标运行。Visual Studio 不支持此目标,因此应从命令提示符执行,如下所示:**MSBuild /target:Test openssl.vcxproj**

如果一切顺利,它将如上所示报告成功。

Perl

OpenSSL 需要 Perl 来配置构建和创建 Makefile。Windows 没有内置的语言支持,Visual Studio 也没有。OpenSSL 组织推荐使用 ActivePerl 进行构建。

使用代码

源存档包含用于构建 OpenSSL 的项目文件、目标和 XML 文件。示例包含 Visual Studio 解决方案和其他项目。

您需要下载 OpenSSL 和 ZLib 源代码,并将它们解压到相应的目录中,然后才能构建解决方案。

提供的代码旨在作为示例,未经全面测试。如果您发现任何问题,请告诉我。如果您知道如何修复,请将拉取请求发送到 GitHub

历史

2015 年 3 月 30 日 - 发布
2015 年 3 月 31 日 - 扩展了原生引用,添加了调试和测试部分。

© . All rights reserved.