依赖关系对 package_id 的影响

当给定软件包依赖于另一个软件包并使用它时,依赖关系的影响可能因软件包类型而异

对于库

  • 非嵌入模式:当应用程序或共享库依赖于另一个共享库,或者当静态库依赖于另一个静态库时,“消费者”库根本不会复制“依赖项”的二进制工件。我们称之为非嵌入模式,依赖项二进制文件不会被链接或嵌入到消费者中。这假设依赖项头文件中没有内联功能,并且头文件是纯接口而不是实现。

  • 嵌入模式:当应用程序或共享库依赖于仅头文件库或静态库时,依赖项二进制文件会被复制或部分复制(取决于链接器)到消费者二进制文件中。此外,当静态库依赖于仅头文件库时,可以认为这些头文件将被嵌入到消费者二进制文件中,因为它们也将包含实现,不可能它们是纯接口。

对于应用程序 (tool_requires)

  • 构建模式:当某些软件包使用另一个软件包的 tool_requires 时,依赖项中的二进制工件永远不会被复制或嵌入。

非嵌入模式

当我们列出像 openssl 这样的软件包及其依赖项的二进制文件时

$ conan list openssl/3.1.2:* -r=conancenter
conancenter
  openssl
    openssl/3.1.2
      revisions
        8879e931d726a8aad7f372e28470faa1 (2023-09-13 18:52:54 UTC)
          packages
            0348efdcd0e319fb58ea747bb94dbd88850d6dd1  # package_id
              info
                options
                  shared: True
                ...
                requires
                  zlib/1.3.Z

此二进制文件是一个 shared 库,与作为共享库的 zlib 链接。这意味着它正在使用“非嵌入”模式。非嵌入模式的默认值是 minor_mode,这意味着

  • 所有 zlib 补丁版本都将映射到相同的 zlib/1.3.Z。这意味着如果我们的 openssl/3.1.2 软件包二进制文件 0348efdcd0e319fb58ea747bb94dbd88850d6dd1 被认为与所有 zlib/1.3.Z 版本(对于任何 Z)二进制兼容,则不需要重建 openssl 二进制文件。

  • 新的 zlib 次要版本,如 zlib/1.4.0 将导致一个 “minor-mode” 标识符,如 zlib/1.4.Z,然后,它将需要一个新的 openssl/3.1.2 软件包二进制文件,具有一个新的 package_id

嵌入模式

以下命令说明了嵌入模式的概念。我们创建一个带有静态库的 dep/0.1 软件包,然后我们创建一个带有可执行文件的 app/0.1 软件包,该可执行文件与 dep/0.1 内的静态库链接。我们可以使用 conan new 命令快速创建这两个软件包

$ mkdir dep && cd dep
$ conan new cmake_lib -d name=dep -d version=0.1
$ conan create . -tf=""
$ cd .. && mkdir app && cd app
$ conan new cmake_exe -d name=app -d version=0.1 -d requires=dep/0.1
$ conan create .
dep/0.1: Hello World Release!
...
app/0.1: Hello World Release!

如果我们现在列出 app/0.1 二进制文件,我们将看到刚刚创建的二进制文件

  $ conan list app/0.1:*
  Local Cache
    app/0.1
      revisions
        632e236936211ac2293ec33339ce582b (2023-09-25 22:34:17 UTC)
          packages
            3ca530d20914cf632eb00efbccc564da48190314
              info
                settings
                  ...
                requires
                  dep/0.1#d125304fb1fb088d5b92d4f8135f4dff:9bdee485ef71c14ac5f8a657202632bdb8b4482b

现在可以清楚地看到,app/0.1 package-id 依赖于 dep/0.1 依赖项的完整标识符,其中包括其配方修订和 package_id

如果我们现在对 dep 代码进行更改,并重新创建 dep/0.1 软件包,即使我们不增加版本号,它也会创建一个新的配方修订

$ cd ../dep
# Change the "src/dep.cpp" code to print a new message, like "Hello Moon"
$ conan create . -tf=""
# New recipe revision dep/0.1#1c90e8b8306c359b103da31faeee824c

因此,如果我们现在尝试安装 app/0.1 二进制文件,它将失败并显示“缺少二进制文件”错误

  $ conan install --requires=app/0.1
  ERROR: Missing binary: app/0.1:ef2b5ed33d26b35b9147c90b27b217e2c7bde2d0

  app/0.1: WARN: Can't find a 'app/0.1' package binary 'ef2b5ed33d26b35b9147c90b27b217e2c7bde2d0' for the configuration:
  [settings]
  ...
  [requires]
  dep/0.1#1c90e8b8306c359b103da31faeee824c:9bdee485ef71c14ac5f8a657202632bdb8b4482b

  ERROR: Missing prebuilt package for 'app/0.1'

由于 app 可执行文件与 dep 静态库链接,因此需要重建它以包含最新的更改,即使 dep/0.1 没有增加其版本号,app/0.1 依赖于 dep/0.1 的 “嵌入模式”,因此它将使用到此类依赖项标识符的 package_id

让我们构建新的 app/0.1 二进制文件

  $ cd ../app
  $ conan create .
  dep/0.1: Hello Moon Release!  # Message changed to Moon
  ...
  app/0.1: Hello World Release!

现在我们将有两个不同的 app/0.1 二进制文件

  $ conan list "app/0.1:*"
  Local Cache
    app
      app/0.1
        revisions
          632e236936211ac2293ec33339ce582b (2023-09-25 22:49:32 UTC)
            packages
              3ca530d20914cf632eb00efbccc564da48190314
                info
                  settings
                    ...
                  requires
                    dep/0.1#d125304fb1fb088d5b92d4f8135f4dff:9bdee485ef71c14ac5f8a657202632bdb8b4482b
              ef2b5ed33d26b35b9147c90b27b217e2c7bde2d0
                info
                  settings
                    ...
                  requires
                    dep/0.1#1c90e8b8306c359b103da31faeee824c:9bdee485ef71c14ac5f8a657202632bdb8b4482b

我们将有两个不同的二进制文件,其中一个与 dep/0.1 依赖项的第一个修订版(带有“Hello World”消息)链接,另一个二进制文件与另一个 package_id 链接,该 package_iddep/0.1 依赖项的第二个修订版(带有“Hello Moon”消息)链接。

上面描述的模式称为 full_mode,它是 embed_mode 的默认模式。