只要您的库有一个知名、有文档记录且相对可移植的构建设置,打包 C/C++ 就并不困难。OpenSSL 在不同的操作系统中构建方式差异很大,使用了不同的工具和命令。因此,以可移植的方式从源代码创建二进制包,对于不熟悉其构建系统的人来说,具有挑战性,仅仅因为构建它本身就具有挑战性。

本文介绍如何在多个平台上实现 OpenSSL 包的完全自动化构建。

OpenSSL 需求

实现库的轻松构建面临的最大挑战之一是定义一种简单的方法来安装其所需的依赖项。

OpenSSL 对 ZLib 具有可选的依赖关系,可以在构建时将其配置为**可选需求**。可以构建不同的 OpenSSL 二进制文件,使用或不使用 ZLib 压缩。

在 Windows 中,OpenSSL 使用 Perl 和 Nasm(Native Assembler)进行构建。在 Nix 系统中,OpenSSL 使用 configure 和 make。虽然我们可以假设编译器(例如 Visual Studio)是先决条件,并且已安装在开发人员的机器上,但将 Perl 和 Nasm 作为 C 或 C++ 开发人员的默认先决条件则要求过高。

虽然在开发人员将代码链接到 OpenSSL 时必须安装 ZLib,但在开发时,Perl 和 Nasm 仅在从源代码构建 OpenSSL 时才需要。如果我们已经有了 OpenSSL 的预构建二进制包,那么 Perl 和 Nasm 就不再需要,开发人员甚至不需要安装它们。因此,我们将 Perl 和 Nasm 称为构建需求。您可以在 Bintray 的 Conan-Center 中找到这两个包的 Conan 包:NasmStrawberryPerl

Conan 具有内置机制来定义这两种场景。以下是 OpenSSL Conan 包配方中的相关部分

def build_requirements(self):
    # useful for example for conditional build_requires
    if self.settings.os == "Windows":
        self.build_requires("strawberryperl/5.26.0@conan/stable")
        self.build_requires("nasm/2.13.01@conan/stable")

def requirements(self):
    if not self.options.no_zlib:
        self.requires("zlib/1.2.11@conan/stable")

跨平台 OpenSSL 包构建

如上所述,OpenSSL 在不同的平台上具有不同的构建命令和参数。Conan 包配方基本上将这些步骤转换为可读的 Python 脚本,而不是在 README 文件中定义构建说明,并让开发人员手动遵循它们。

       if self.settings.os == "Linux":
           self.linux_build(config_options_string)
       elif self.settings.os == "Macos":
           self.osx_build(config_options_string)
       elif ...
 
   def linux_build(self, config_options_string):
       m32_suff = " -m32" if self.settings.arch == "x86" else ""
       if self.settings.build_type == "Debug":
           config_options_string = "-d no-asm -g3 -O0 -fno-omit-frame-pointer " \
                                   "-fno-inline-functions" + config_options_string
 
       m32_pref = "setarch i386" if self.settings.arch == "x86" else ""
       config_line = "%s ./config -fPIC %s %s" % (m32_pref, config_options_string, m32_suff)
       self.output.warn(config_line)
       self.run_in_src(config_line)
       self.run_in_src("make depend")
       self.run_in_src("make")
 
   def osx_build(self, config_options_string):
       m32_suff = " -m32" if self.settings.arch == "x86" else ""
       if self.settings.arch == "x86_64":
           command = "./Configure darwin64-x86_64-cc %s" % config_options_string
       else:
           command = "./config %s %s" % (config_options_string, m32_suff)

由于这种可变性,OpenSSL Conan 配方拥有超过 240 行代码,是复杂且最长的配方之一。它结合了 ZLib 条件需求以及对 StrawberryPerl 和 Nasm 的构建需求的自动化,允许为 Windows、Linux 和 OSX 中的多个编译器和版本创建超过 80 个不同的二进制文件。以下是 Conan-Center 中 OpenSSL 包 的当前矩阵

以上矩阵是即将在下一个 Conan 版本 v0.25 中提供的全新功能的抢先预览 :)

创建二进制文件、测试它们并自动将它们上传到 Bintray 是一个完全自动化的过程,使用 Travis 和 Appveyor 公共且免费的持续集成服务。查看 Conan OpenSSL 包配方 存储库以了解如何实现。

构建其他配置

以上矩阵显示了当前存储在 Bintray 中的二进制文件,但这并不意味着其他配置将无法工作。如果您尝试在 Windows 中为旧版本的 Visual Studio(版本 9)安装 Conan,您将收到以下错误

$ conan install OpenSSL/1.0.2l@conan/stable -s compiler="Visual Studio" -s compiler.version=9 -s arch=x86
> ERROR: Missing prebuilt package for 'OpenSSL/1.0.2l@conan/stable'

这意味着此配置没有预编译的二进制文件。但是,您可以尝试使用以下命令从源代码构建它

$ conan install OpenSSL/1.0.2l@conan/stable -s compiler="Visual Studio" -s compiler.version=9 -s arch=x86 --build=missing

ZLib 也会从源代码构建,因为 VS 9 也没有 ZLib 的预构建二进制文件。

当然,此命令也会触发在 Windows 中安装 StrawberryPerl 和 Nasm。获得 OpenSSL 包后,您可以安全地将其删除,然后再次安装,您会注意到它们不会再次被检索。

结论

在本博文中,我们介绍了如何实现可重复构建,其中包括条件(仅限 Windows)自动安装所需的开发工具,如 Nasm 和 Perl。这些工具是本地安装的,仅适用于 OpenSSL 构建,从而保持开发机器不受污染。我们还演示了如何自动管理 Windows、Linux 和 OSX 等主要操作系统的 ZLib 依赖项。

据报道,OpenSSL 包配方也适用于其他配置,包括 MinGW(它在 Appveyor 中有效,但请记住它没有经过充分测试)。请自行尝试,并在必要时在 github 存储库 中报告,以改进对其他平台的支持。