Cabal 无法找到本地来源(但已正确安装)的包

Cabal cannot find locally sourced (yet correctly installed) packages

我最近升级到 Cabal 3.2(和 GHC 8.10),我 运行 遇到一些重大问题,这些问题使我的某些项目不再可构建...

问题的详细描述

这是每次都失败的最小(不是)工作配置:

  1. 我从一个干净的 Cabal 配置开始(通过删除 ~/.cabal);其原因稍后会出现在 post 中。我 运行 cabal update 重新创建 .cabal 目录并确保 Cabal 正常工作。

  2. 我使用 cabal init 创建了一个项目(我们称之为 test1)。这是一个库项目,其中包含一个公开模块(方便命名为 Test1),该模块导出一些虚拟函数 foo。我运行cabal build,然后cabal install --lib;一切都 运行 顺利,到目前为止一切顺利。

  3. 为了保险起见,我离开了项目目录并启动了 GHCi。我输入 :m Test1 来加载我之前创建的模块,它起作用了!我可以输入 foo ... 并查看我的函数已执行。另外,我列出~/.cabal/store/ghc-8.10.xxx的内容,看到test1-xxx目录在那里。

  4. 然后我创建了一个新项目,test2,仍然使用 cabal init。这次,我将其配置为可执行文件,并将 test1 添加为依赖项(使用 build-depends 字段)。但是这次当我 运行 cabal build 时,我 运行 遇到了一些问题:

~/projects/haskell/test2> cabal build
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: test2-0.1.0.0 (user goal)
[__1] unknown package: test1 (dependency of test2)
[__1] fail (backjumping, conflict set: test1, test2)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: test2, test1

在我看来找不到包 test1,但是我可以从 GHCi(和 GHC 就此而言)访问它并且它存在于 ~/.cabal/store...

但不幸的是还有更多。

  1. 我创建了第三个项目,test3。这是一个库,它只依赖于 base(所以特别是它 依赖于 test1)。该库公开了一个模块 Test3,并导出了一个函数 bar。我运行cabal build,这里没问题。但是当我想安装 test3cabal install --lib 时,我 运行 出现了一些错误:
~/projects/haskell/test3> cabal install --lib
Wrote tarball sdist to
/home/<user>/projects/haskell/test3/dist-newstyle/sdist/test3-0.1.0.0.tar.gz
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] unknown package: test1 (user goal)
[__0] fail (backjumping, conflict set: test1)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: test1

好像是找不到test1,虽然已经正确安装了;可能这是 test2 构建失败的残余...

  1. 为了确定,我启动了 GHCi 并输入 :m Test3,但 GHCi 告诉我它找不到模块 Test3(甚至暗示这是一个错字我的意思是 Test1),表明 test3 确实没有安装,尽管它已成功构建...

  2. 好吧,整个情况还有一个怪癖:我再次使用 cabal init 创建了一个名为 test4 的新项目,这是一个可执行文件(再次)仅依赖 base。我保留默认值 Main.hs(仅打印 "Hello, Haskell!")。我运行cabal build:没问题。然后我 运行 cabal install 和...没问题吗?我 运行 test4 在一个随机位置,它启动可执行文件,在终端打印 "Hello, Haskell!"...

  3. 还有最后一件事:我去某个随机位置然后我 运行 cabal install xxx --lib 其中 xxx 是 Hackage 上可用的库包(对于例如 xml) 和:

~> cabal install xml --lib
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] unknown package: test1 (user goal)
[__0] fail (backjumping, conflict set: test1)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: test1

这就是我需要定期核对 .cabal 的原因...现在我似乎处于某种陈旧状态,无法再安装任何库。

技术配置及注意事项

我是 运行宁 Cabal 3.2.0.0 和 GHC 8.10.0.20200123。我从 hvr/ghc PPA 安装了它们,并确保我的计算机上没有这些工具的其他版本。

请注意,我正在 运行ning Ubuntu 18.04.4 LTS(使用 XFCE,确切地说是 XUbuntu)。其他一切(似乎是这样)都是最新的。

最后一件事,关于我用于构建的 *.cabal 文件,它们几乎是由 cabal init 生成的文件,除了我将 executable xxx 切换为 library对于库,我只是添加了一个 exposed-modules 字段来公开库的模块(因此 Test1 分别代表 test1Test3 分别代表 test3 )。我还在 test2 中使用 build-depends 使项目依赖于 test1。除此之外,它们几乎没有受到影响。

笔记和想法

我必须承认我是 Cabal 3 的新手;直到上周我还在使用 Cabal 1(因为我从来没有费心去更新它;是的,我知道这很糟糕)。使用 Cabal 1 我没有任何问题,我完全能够从本地源安装一个包并在其他项目中依赖它...

我觉得我做错了什么;也许我没有使用正确的 Cabal 命令?我在某处看到了一些关于 cabal new-buildcabal new-install 的东西,但它似乎只做 cabal buildcabal install,至少在我的情况下是这样。我也想研究沙箱,但它似乎从 Cabal 的第 2 版开始就消失了。

这也有可能是 Cabal 错误,但我在错误跟踪器上没有发现任何可能与我的问题相关的相关问题...

你怎么看这件事?我究竟做错了什么?您是否看到任何替代或可能的修复方法?

非常感谢!

GHC 环境文件

GHC 安装附带 a certain number of packages out-of-the box. base is one of them but there are others, for example text。如果你单独安装 GHC(没有 cabal 或 stack)并打开 ghci,它应该让你 import Data.Text 没有问题。

如果你想让 GHC 或 ghci 知道你的文件系统中存在的其他编译包怎么办?您可以将 GHC 指向其他 package databases using command-line flags, but there's also the concept of package environment files.

环境是包含与包相关的 GHC 标志列表的纯文本文件。 ~/.ghc/$ARCH-$OS-$GHCVER/environments/default 可能有一个全局环境,也可能存在只影响同一文件夹内调用的 GHC 和 ghci 命令的本地环境。 exact rules for search 在 GHC 用户指南中有描述。

cabal install --lib实际上是做什么的?

默认情况下,它会修改 global 环境文件,以便 GHC 和 ghci 现在可以找到该库。这就是点 3) 起作用的原因。不过,库的实际编译二进制文件仍然驻留在 cabal 存储中。

我们还可以创建本地环境文件。例如 cabal install sop-core --lib --package-env . 将在当前文件夹中创建环境文件 .ghc.environment.xxx,并且库将在 ghc 和 ghci 在那里被调用时可用。

为什么 test1 不能用于 test2?

现代 cabal 区分 local packages and external packages

  • local packages 是你们在一个项目中一起开发的包集,被反复编辑、重新编译和更改。它们是 "inplace" 构建的,在项目之外是看不到的。他们可以互相依赖。
  • 外部包 是来自 build-depends: 的依赖项,其源代码是从包存储库下载的,并且在编译时放入 cabal 存储中,以便其他 Cabal项目可能会在不重新编译的情况下使用它们。

本地包列表和其他项目级配置详细信息在 cabal.project 文件中指定。但是如果你在一个单独的包上工作,你就不需要一个;默认的包列表只是 ./*.cabal.

cabal要完全控制本地包的构建环境,会忽略全局环境文件。在您的情况下,您必须在同一项目中制作 test1 和 test2 本地包(可能是最佳选择)或发布 test1 并将其视为外部包。

请注意,"cabal project" 是一个仅在开发期间相关的概念。包是独立发布的,在 Hackage 或其他存储库中没有 "projects",只有包。

如果我想将 test1 视为外部而不将其发布到 Hackage 怎么办?

您将必须设置一个 本地包存储库 ,基本上是一个非 public Hackage。

你可以tell Cabal about additional package repositories在Cabal的配置文件中,也就是配置cabal本身的文件。它的位置在 cabal --help.

的最后一行给出

但是如何设置存储库? hackage-repo-tool 可以提供帮助。

为什么 test3 失败了?为什么进一步的库安装失败?

这很奇怪,我不知道为什么会这样。您是否偶然删除了步骤 3)5) 之间的 ~/.cabal 文件夹?如果删除全局 GHC 环境文件并重试会怎样?