为多个配置构建:Release、Debug、Static 和 Shared¶
请首先克隆源代码以重新创建此项目。您可以在 GitHub 的 examples2 仓库中找到它们。
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/consuming_packages/different_configurations
到目前为止,我们构建了一个简单的 CMake 项目,该项目依赖于 zlib 库,并了解了 tool_requires,这是一种用于构建工具(如 CMake)的特殊类型的 requirements。 在这两种情况下,我们都没有指定希望以 Release 或 Debug 模式构建应用程序,或者希望链接到 static 或 shared 库。 这是因为 Conan,如果没有另行指示,将使用在“默认 profile”中声明的默认配置。 该默认 profile 在第一个示例中,当我们运行 conan profile detect 命令时创建。 Conan 将此文件存储在 Conan 用户主目录中的 /profiles 文件夹中。 您可以通过运行 conan config home 命令来获取 Conan 用户主目录的位置,然后显示 /profiles 文件夹中的默认 profile 内容
$ conan config home
Current Conan home: /Users/tutorial_user/.conan2
# output the file contents
$ cat /Users/tutorial_user/.conan2/profiles/default
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=14.0
compiler.libcxx=libc++
compiler.cppstd=gnu11
build_type=Release
[options]
[tool_requires]
[env]
# The default profile can also be checked with the command "conan profile show"
如您所见,该 profile 具有不同的部分。 [settings] 部分包含有关操作系统、架构、编译器和构建配置等信息。
当您调用带有 --profile 参数的 Conan 命令时,Conan 将获取 profile 中的所有信息并将其应用于您想要构建或安装的软件包。 如果您没有指定该参数,则等效于使用 --profile=default 调用它。 这两个命令的行为相同
$ conan install . --build=missing
$ conan install . --build=missing --profile=default
您可以存储不同的 profile 并使用它们为不同的设置构建。 例如,要使用 build_type=Debug,或将 tool_requires 添加到您使用该 profile 构建的所有软件包。 我们将创建一个 debug profile 来尝试使用不同的配置进行构建
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=14.0
compiler.libcxx=libc++
compiler.cppstd=gnu11
build_type=Debug
修改设置:为应用程序及其依赖项使用 Debug 配置¶
使用 profile 并不是设置要使用的配置的唯一方法。 您还可以使用 --settings 参数覆盖 profile 设置。 例如,您可以以 Debug 配置而不是 Release 配置构建前一个示例中的项目。
在构建之前,请检查我们是否修改了前一个示例中的源代码,以显示构建源所用的构建配置
#include <stdlib.h>
...
int main(void) {
...
#ifdef NDEBUG
printf("Release configuration!\n");
#else
printf("Debug configuration!\n");
#endif
return EXIT_SUCCESS;
}
现在让我们为 Debug 配置构建我们的项目
$ conan install . --output-folder=build --build=missing --settings=build_type=Debug
如上所述,这等效于拥有 debug profile 并使用 --profile=debug 参数而不是 --settings=build_type=Debug 参数运行这些命令。
此 conan install 命令将检查我们是否已经在本地缓存中拥有 Debug 配置所需的库(Zlib),如果还没有,则获取它们。 它还将更新 conan_toolchain.cmake 和 CMakePresets.json 文件中的构建配置,这些文件由 CMakeToolchain 生成器创建,以便在构建应用程序时以 Debug 配置构建。 现在像以前的示例一样构建您的项目,并检查输出以了解它是如何以 Debug 配置构建的
# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cd build
$ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
$ cmake --build . --config Debug
$ Debug\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.3.1
Debug configuration!
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug
$ cmake --build .
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.3.1
Debug configuration!
修改选项:将应用程序依赖项链接为共享库¶
到目前为止,我们一直在我们的应用程序中静态链接 Zlib。 这是因为在 Zlib 的 Conan 包中,有一个属性设置为默认以这种模式构建。 我们可以通过将 shared 选项设置为 True 使用 --options 参数从 static 更改为 shared 链接。 为此,请运行
$ conan install . --output-folder=build --build=missing --options=zlib/1.3.1:shared=True
这样,Conan 将安装 Zlib 共享库,生成使用它们构建文件的文件,以及定位在运行应用程序时这些动态库所需的必要文件。
注意
选项是按包定义的。 在这种情况下,我们定义了我们想要特定版本的 zlib/1.3.1 作为共享库。 如果我们有其他依赖项,并且想要尽可能地将所有依赖项作为共享库,我们将使用 -o *:shared=True,其中 * 模式匹配所有包引用。
让我们在配置为将 Zlib 链接为共享库后再次构建应用程序
$ cd build
# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
$ cmake --build . --config Release
...
[100%] Built target compressor
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
[100%] Built target compressor
现在,如果您尝试运行编译的可执行文件,您将看到一个错误,因为可执行文件找不到我们刚刚安装的 Zlib 共享库。
$ Release\compressor.exe
(on a pop-up window) The code execution cannot proceed because zlib1.dll was not found. Reinstalling the program may fix this problem.
# This error depends on the console being used and may not always pop up.
# It could run correctly if the console gets the zlib dll from a different path.
$ ./compressor
./compressor: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
$ ./compressor
./compressor: dyld[41259]: Library not loaded: @rpath/libz.1.dylib
这是因为共享库(在 windows 中为 .dll,在 macOS 中为 .dylib,在 Linux 中为 .so)是在运行时加载的。 这意味着应用程序可执行文件需要在运行时知道所需的共享库在哪里。 在 Windows 上,动态链接器将在同一目录中搜索,然后在 PATH 目录中搜索。 在 macOS 上,它将在 DYLD_LIBRARY_PATH 中声明的目录中搜索,在 Linux 上它将使用 LD_LIBRARY_PATH。
Conan 提供了一种定义这些变量并使可执行文件能够找到和加载这些共享库的机制。 该机制是 VirtualRunEnv 生成器。 如果您检查输出文件夹,您将看到 Conan 生成了一个名为 conanrun.sh/bat 的新文件。 这是在激活 shared 选项进行 conan install 时自动调用该 VirtualRunEnv 生成器生成的脚本。 此生成的脚本将设置 PATH、LD_LIBRARY_PATH、DYLD_LIBRARY_PATH 和 DYLD_FRAMEWORK_PATH 环境变量,以便可执行文件可以找到共享库。
激活虚拟环境,然后再次运行可执行文件
$ conanrun.bat
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
...
$ source conanrun.sh
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
...
正如在之前的 VirtualBuildEnv 生成器的示例中一样,当我们运行 conanrun.sh/bat 脚本时,将创建一个名为 deactivate_conanrun.sh/bat 的脚本来恢复环境。 来源或运行它以执行此操作
$ deactivate_conanrun.bat
$ source deactivate_conanrun.sh
设置和选项之间的区别¶
您可能已经注意到,为了在 Debug 和 Release 配置之间切换,我们使用了 Conan setting,但当我们设置可执行文件的 shared 模式时,我们使用了 Conan option。 请注意 settings 和 options 之间的区别
settings 通常是客户端机器定义的项目范围的配置。 像操作系统、编译器或构建配置这样的东西,对于几个 Conan 包来说是通用的,并且对于仅对其中一个包定义一个默认值没有意义。 例如,Conan 包声明“Visual Studio”作为默认编译器是没有意义的,因为这是由最终用户定义的,并且如果他们在 Linux 上工作,则可能没有意义。
options 旨在用于可以设置为配方中默认值的特定于包的配置。 例如,一个包可以定义其默认链接是静态的,如果消费者没有指定,则应使用此链接。
介绍 Package ID 的概念¶
在使用不同的 settings 和 options 消耗 Zlib 等包时,您可能想知道 Conan 如何确定从远程检索哪个二进制文件。 答案在于 package_id 的概念。
package_id 是 Conan 用于确定包的二进制兼容性的标识符。 它基于几个因素计算得出,包括包的 settings、options 和依赖项。 当您修改这些因素中的任何一个时,Conan 会计算一个新的 package_id 以引用相应的二进制文件。
以下是流程分解
确定设置和选项:Conan 首先检索用户的输入设置和选项。 这些可以来自命令行或配置文件,例如 –settings=build_type=Debug 或 –profile=debug。
计算包 ID:使用当前 settings、options 和依赖项的值,Conan 计算出一个哈希值。 此哈希值作为 package_id,代表二进制包的唯一标识。
获取二进制文件:Conan 然后检查其缓存或指定的远程是否存在具有计算出的 package_id 的二进制包。 如果找到匹配项,它将检索该二进制文件。 如果没有,Conan 可以从源代码构建包,或者指示缺少二进制文件。
在我们的教程中,当我们使用不同的 settings 和 options 消耗 Zlib 时,Conan 使用 package_id 来确保它获取与我们指定的配置匹配的正确二进制文件。