首页 文章

编写依赖于本地目录中的堆栈库的快速Haskell测试程序的首选方法是什么?

提问于
浏览
2

我有一个Haskell库,我正在使用Stack开发 . 在我开发库时,我喜欢编写使用该库的小型测试/实验程序 . 我在本地目录中为自己保留了这些测试程序的集合 . 这些测试模块非常快速且非正式,不适合在已提交的库代码中包含单元测试 . 通常,它们中的大多数甚至都没有维护,也不会针对最新版本的库进行编译,但我会保留它们,以防我以后想要更新它们 . 当我正在开发一个测试程序时,我希望它能够根据我的库的工作副本进行构建,并对我在本地对库进行的任何更改进行构建 .

How should I set up my Stack build environment for this situation? 以下是我尝试过的一些选项,以及每个选项的问题 .

  • 两个Cabal包,一个Stack配置 . stack.yaml文件列出了两个包,并一次定义了两个包的构建环境 .

  • 问题:stack.yaml文件需要作为已提交库源代码的一部分包含在内,以便其他开发人员可以从源代码中重复构建库 . 我不希望我的库的公共stack.yaml文件包含我本地测试项目的构建信息 .

  • 问题:据我所知,为了完成这项工作,我需要一个.cabal文件,列出我的测试程序的所有可执行文件和模块 . 每当我想要将一个快速的实验脚本放在一起时,这很烦人,如果我有一个单独的模块没有没有任何部分的.cabal文件,那么将无法构建任何测试程序,因为Cabal给出了"No executables, libraries,tests, or benchmarks found. Nothing to do." ,因为这无处可列出 build-depends .

  • 为测试程序创建Cabal沙箱 . 使用 cabal sandbox add-source 将本地库添加为包 . 另见this answer .

  • 问题:使用Cabal沙箱而不是Stack重新引入了Stack应该修复的许多依赖性问题,例如使用系统全局GHC而不是解析器定义的GHC .

  • 为测试程序单独使用stack.yaml . 将 packages 下的库添加为 location: 'C:\Path\To\Local\Library' ,并为该依赖项设置 extra-dep: true . (有关此功能的更多信息,请参阅here . )不要将任何其他Cabal软件包放在 packages 下,用于测试程序的stack.yaml . 使用 stack runghc 调用其stack.yaml范围内的测试程序 .

  • 问题:我无法让这个工作 . 在测试程序目录中运行 stack build 给出"Error parsing targets: The project contains no local packages (packages not marked with 'extra-dep')" . 运行 stack runghc 就好像根本没有依赖关系一样 . 我不想为测试程序添加一个Cabal包,因为这与选项1有相同的问题,需要构造一个描述要构建的模块的显式.cabal文件 .

  • 问题:我想在库和测试程序之间保持一致的堆栈构建配置信息必须手动复制 . 例如,如果我更改了库的stack.yaml中的解析器,我还需要在stack.yaml中为我的测试程序单独更改它 .

  • 在我的工作副本中有一个目录,其中包含我的所有测试程序 . 使用 stack runghc 在库的上下文中调用测试程序 .

  • 问题:我必须告诉我的库的版本控制忽略我的测试代码,并且可以只为测试程序拥有自己的本地版本控制 .

  • 问题:仅适用于单个本地库依赖项 . 如果我的测试程序需要依赖于具有自己的stack.yaml文件的两个不同库的本地工作副本,那我就不走运了 .

  • 在我的工作副本中添加一个符号链接到一个包含我所有测试程序的单独目录 . 浏览符号链接并使用 stack runghc 在库的上下文中调用测试程序 .

  • 问题:超级难以使用,特别是因为我在Windows和Windows上有很糟糕的符号链接支持 .

  • 问题:仍然需要告诉我的版本控制系统忽略符号链接 .

  • 问题:仍然只能使用单个库依赖项 .

2 回答

  • 2

    如果只涉及一个本地库,我使用选项4.您可以将测试放在库的目录之外,并从库的目录调用堆栈,或使用 --stack-yaml path/to/library/stack.yaml .

    否则,我使用选项3,创建一个单独的堆栈项目设置 extra-dep .

    ...
    packages:
    - 'path/to/package1'
    - 'path/to/package2'
    ...
    

    对于配置重复问题,我想不出一个好的解决方法 . 如果多个包指定了不同的解析器/包版本,则会发生冲突 .

  • 1

    Edit: 实际上,存根库效果更好,所以编辑后添加 .

    我认为让#3工作的方法是 - 在你的 scratch 程序目录下 - (1)在 stack.yaml 下的 packages 下添加 . 并与 location / extra-dep: true 包一起:

    packages:
    - '.'
    - location: ../mylib
      extra-dep: true
    

    (2)在 scratch.cabal 中创建一个 executable 子句,指向存根主程序(即编译但不需要执行任何操作的"Hello World"程序),这取决于您的库:

    executable main
      hs-source-dirs:      src
      main-is:             Stub.hs
      build-depends:       base
                         , mylib
      default-language:    Haskell2010
    

    或者没有暴露模块的 library 子句,这取决于你的 mylib 库:

    library
      hs-source-dirs:      src
      build-depends:       base >= 4.7 && < 5
                         , mylib
      default-language:    Haskell2010
    

    (3)在 scratch 目录中运行 stack build . 这应该构建并注册 mylib ,现在 stack runghc Prog1.hs 应该可以正常运行依赖于 mylib 模块的程序 .

    如果使用 executable 方法,则存根程序将编译为副作用,否则将被忽略 . 如果使用 library 方法,则看起来甚至没有构建存根库;然后你可以选择实际构建一个 scratch 库,为你的测试程序添加一些公开的共享代码模块,如果方便的话,那么存根库可能是最好的 .

    这些都没有解决保持 stack.yaml 信息像解析器版本同步的问题,但它似乎解决了您在1,2,4和5中列出的所有问题 . 特别是,它应该适用于依赖于的测试程序您正在开发的多个本地库 .

相关问题