如果包在 opam 中有特定版本,则安装依赖项
Install dependency if a package has a specific version in opam
如果 ocaml
包版本高于 4.14.0
,我想指定我的 opam 包依赖于 camlp-streams
。在我的 opam 文件中,我放置了以下行:
depends: [
"ocaml" {>= "4.07.0"}
"dune" {build & >= "2.8.0"}
"camlp-streams" {>= "5.0" & "ocaml" >= "4.14.0" }
]
但是即使 ocaml
版本低于 4.14.0
,当我 opam install --deps-only package.opam
它会安装 camlp-streams
.
有没有办法告诉 opam 在存在特定版本的另一个包时不要安装该包?由于我不知道如何告诉 opam 向我展示它如何解决我的约束,因此调试我的 opam 文件有点困难。
我想我找到了可行的解决方案:
depends: [
( "ocaml" {>= "4.07.0" & < "4.14.0" } | ( "ocaml" { >= "4.14.0" } & "camlp-streams" ))
"dune" {build & >= "2.8.0"}
]
这允许我指定仅当 ocaml
版本低于 4.14.0
时我依赖于 ocaml
和 camlp-streams
如果 ocaml
版本大于4.14.0
"ocaml" >= "4.14.0"
表达式只是使用 Debian 版本排序将字符串 "ocaml"
与字符串 "4.14.0"
进行比较。由于 "ocaml"
大于 "4.14.0"
,它始终计算为真,因此始终安装依赖项。
depends
字段使用 filtered package formulas. A filtered package formula allows us to specify both filters and package version constraints 指定依赖项。该公式分两个阶段进行评估。在第一阶段,对公式中的所有过滤器进行评估,并将过滤器表达式评估为 true 的那些包从列表中删除。第一阶段后,过滤表达式从公式中移除,生成的仅包含版本约束的包公式被传递给约束求解器。
例如,
depends: [
"linux-support-package" {>= "4.0.0" & os = "linux"}
]
将仅在 Linux 操作系统上安装 linux-support-package
。在第一阶段,如果全局变量 os
等于 linux
,过滤器将评估为真并产生最终包公式 {>= "4.0.0" & os = "linux"}
.
请注意,过滤器中的变量未被引用,过滤器中只能使用全局变量和开关变量(有关此类列表,请参阅 opam var
)。不幸的是,OCaml 版本没有全局或开关变量,因为它被认为只是一个包。此外,如果允许在 depends
字段的过滤器表达式中引用包,那么正确的语法将是 ocaml.version >= "4.14.0"
.
现在,当我们具备这些知识时,我们有哪些选择?您自己的答案中引用的第一个选项是使用互斥公式的析取。它会起作用,但有一些警告。首先是,如果您的析取不是排他性的,即有一组满足这两个子句的包,那么求解器将以 non-deterministic 的方式选择一个任意集合,这绝对不是您想要的!当公式增长时,很难保持唯一不变性。另一个警告是你的包的依赖集不再是静态的 属性 而是开关状态的函数。这将使维护和调试包成为一项更艰巨的任务。最后,在你的包公式中(而不是在版本约束中)有分离和连接会给约束求解器带来很大压力,最终会导致性能问题甚至超时。
传统的解决方案,但具有不同的语义,将使用 depopts
字段。它仍然不允许您对 OCaml 版本进行参数化,但您可以在配置脚本中使用过滤器来执行此操作,例如
build: [
[
"./configure"
"--%{camlp-streams:installed}%-streams" {ocaml:version >= "4.14.0"}
]
[make]
]
depopts: [
"camlp-streams" {>= "5.0"}
]
现在,当您安装包(我们将其命名为 foo
)时,camlp-streams
将永远不会被显式安装。但是,如果您明确指定 camlp-streams
,例如,
opam install foo camlp-streams
或者如果 camlp-streams
已经安装,那么只有当 OCaml 的版本大于 4.14.0 时,构建期间你的 configure
脚本才会用 --enable-camlp-streams
调用。此外,camlp-streams
将在您的包之前构建,如果 camlp-streams
包在您的包之后安装,那么您的包将被重建。
这是指定您可以在 opam-repository 中找到的可选依赖项的默认方法。在 post-install 消息中宣传增强主包的可选包也是一个好习惯。
在极少数情况下,当且仅当存在其他包时才真正需要您的包,那么您可以依赖析取(来自您的答案)或通过虚拟包指定此类依赖项。事实上,一个包有两个替代方案,版本 1 不引入对 camlp-streams
、
的依赖
opam-version: "2.0"
name: "conf-foo-camlp-streams"
version: "1"
conflicts: [
"ocaml" {>= "4.14.0"}
]
和版本 2,
opam-version: "2.0"
name: "conf-foo-camlp-streams"
version: "2"
depends: [
"camlp-streams" {>= "5.0"}
]
conflicts: [
"ocaml" {< "4.14.0"}
]
并指定 conf-foo-camlp-streams
(在任何地方用你的包名替换 foo
标签)作为你的包的依赖而不限制它的版本。现在,求解器很容易 select 基于与 OCaml 版本的冲突的正确替代方案,并且只有在选择第二个替代方案时才安装 camlp-streams
。这接近析取解决方案,但更冗长。另一方面,它应该减轻求解器的压力。
如果 ocaml
包版本高于 4.14.0
,我想指定我的 opam 包依赖于 camlp-streams
。在我的 opam 文件中,我放置了以下行:
depends: [
"ocaml" {>= "4.07.0"}
"dune" {build & >= "2.8.0"}
"camlp-streams" {>= "5.0" & "ocaml" >= "4.14.0" }
]
但是即使 ocaml
版本低于 4.14.0
,当我 opam install --deps-only package.opam
它会安装 camlp-streams
.
有没有办法告诉 opam 在存在特定版本的另一个包时不要安装该包?由于我不知道如何告诉 opam 向我展示它如何解决我的约束,因此调试我的 opam 文件有点困难。
我想我找到了可行的解决方案:
depends: [
( "ocaml" {>= "4.07.0" & < "4.14.0" } | ( "ocaml" { >= "4.14.0" } & "camlp-streams" ))
"dune" {build & >= "2.8.0"}
]
这允许我指定仅当 ocaml
版本低于 4.14.0
时我依赖于 ocaml
和 camlp-streams
如果 ocaml
版本大于4.14.0
"ocaml" >= "4.14.0"
表达式只是使用 Debian 版本排序将字符串 "ocaml"
与字符串 "4.14.0"
进行比较。由于 "ocaml"
大于 "4.14.0"
,它始终计算为真,因此始终安装依赖项。
depends
字段使用 filtered package formulas. A filtered package formula allows us to specify both filters and package version constraints 指定依赖项。该公式分两个阶段进行评估。在第一阶段,对公式中的所有过滤器进行评估,并将过滤器表达式评估为 true 的那些包从列表中删除。第一阶段后,过滤表达式从公式中移除,生成的仅包含版本约束的包公式被传递给约束求解器。
例如,
depends: [
"linux-support-package" {>= "4.0.0" & os = "linux"}
]
将仅在 Linux 操作系统上安装 linux-support-package
。在第一阶段,如果全局变量 os
等于 linux
,过滤器将评估为真并产生最终包公式 {>= "4.0.0" & os = "linux"}
.
请注意,过滤器中的变量未被引用,过滤器中只能使用全局变量和开关变量(有关此类列表,请参阅 opam var
)。不幸的是,OCaml 版本没有全局或开关变量,因为它被认为只是一个包。此外,如果允许在 depends
字段的过滤器表达式中引用包,那么正确的语法将是 ocaml.version >= "4.14.0"
.
现在,当我们具备这些知识时,我们有哪些选择?您自己的答案中引用的第一个选项是使用互斥公式的析取。它会起作用,但有一些警告。首先是,如果您的析取不是排他性的,即有一组满足这两个子句的包,那么求解器将以 non-deterministic 的方式选择一个任意集合,这绝对不是您想要的!当公式增长时,很难保持唯一不变性。另一个警告是你的包的依赖集不再是静态的 属性 而是开关状态的函数。这将使维护和调试包成为一项更艰巨的任务。最后,在你的包公式中(而不是在版本约束中)有分离和连接会给约束求解器带来很大压力,最终会导致性能问题甚至超时。
传统的解决方案,但具有不同的语义,将使用 depopts
字段。它仍然不允许您对 OCaml 版本进行参数化,但您可以在配置脚本中使用过滤器来执行此操作,例如
build: [
[
"./configure"
"--%{camlp-streams:installed}%-streams" {ocaml:version >= "4.14.0"}
]
[make]
]
depopts: [
"camlp-streams" {>= "5.0"}
]
现在,当您安装包(我们将其命名为 foo
)时,camlp-streams
将永远不会被显式安装。但是,如果您明确指定 camlp-streams
,例如,
opam install foo camlp-streams
或者如果 camlp-streams
已经安装,那么只有当 OCaml 的版本大于 4.14.0 时,构建期间你的 configure
脚本才会用 --enable-camlp-streams
调用。此外,camlp-streams
将在您的包之前构建,如果 camlp-streams
包在您的包之后安装,那么您的包将被重建。
这是指定您可以在 opam-repository 中找到的可选依赖项的默认方法。在 post-install 消息中宣传增强主包的可选包也是一个好习惯。
在极少数情况下,当且仅当存在其他包时才真正需要您的包,那么您可以依赖析取(来自您的答案)或通过虚拟包指定此类依赖项。事实上,一个包有两个替代方案,版本 1 不引入对 camlp-streams
、
opam-version: "2.0"
name: "conf-foo-camlp-streams"
version: "1"
conflicts: [
"ocaml" {>= "4.14.0"}
]
和版本 2,
opam-version: "2.0"
name: "conf-foo-camlp-streams"
version: "2"
depends: [
"camlp-streams" {>= "5.0"}
]
conflicts: [
"ocaml" {< "4.14.0"}
]
并指定 conf-foo-camlp-streams
(在任何地方用你的包名替换 foo
标签)作为你的包的依赖而不限制它的版本。现在,求解器很容易 select 基于与 OCaml 版本的冲突的正确替代方案,并且只有在选择第二个替代方案时才安装 camlp-streams
。这接近析取解决方案,但更冗长。另一方面,它应该减轻求解器的压力。