Haskell 子模块中的条件编译

Eri*_*ler 4 haskell haskell-stack

我试图在我的程序中有条件地编译一个子模块,以在发布版本和开发版本之间切换代码的​​一小部分。

目前我正在尝试使用cpphs但是当我更改传递给 GHC 的标志以定义变量并更改 ifdef 语句堆栈时,不会重新编译这些文件。

例如,我有一个端口号,我想根据我构建的目标进行切换。我定义这个数字的代码看起来像这样。

#ifdef StableRelease 
  port = 12345
#else 
  port = 54321 
#endif
Run Code Online (Sandbox Code Playgroud)

稳定版本的 cabal 文件中有以下选项

ghc-options: -threaded -rtsopts -with-rtsopts=-N -pgmP cpphs -optP "-DStableRelease"
Run Code Online (Sandbox Code Playgroud)

当我运行时,stack build它似乎并没有真正预处理上面的代码。有没有人有使用 cpphs 或其他预处理解决方案的经验?

eps*_*lbe 5

我会在标志的帮助下解决这个问题

cppstuf.cabal-文件

name:                cppstuf
version:             0.1.0.0
...
cabal-version:       >=1.10

flag StableRelease {
  Description: Stable release settings like port ...
  Default:     False
  }

executable cppstuf
  main-is:             Main.hs
  build-depends:       base >=4.9 && <5.00
  default-language:    Haskell2010
  extensions: CPP
  if flag(StableRelease) {
    GHC-Options: -DSTABLE
  }
Run Code Online (Sandbox Code Playgroud)

Main.hs

module Main where

main :: IO ()
main =
#if STABLE
  putStrLn "Hello, Haskell!"
#else
  putStrLn "Hello, Haskell?"
#endif
Run Code Online (Sandbox Code Playgroud)

并编译它

stack build
Run Code Online (Sandbox Code Playgroud)

或者

stack build --flag cppstuf:stablerelease
Run Code Online (Sandbox Code Playgroud)

除了答案之外的个人笔记

我不会用CPP来管理配置选择-要么提供的命令行选项我喜欢optparse,应用性,但也有cmdargs,和或配置文件我用配置,但有几个选择那里的hackage。一个是configurator-ng正如@Shersh 所说, - 另一个不再被开发。

CPP 另一方面,我倾向于用于使库跨多个 GHC/库版本工作。

更新 - 关于评论。

  • 如果我交付一个程序,运维团队应该能够更改端口、主机名或处理输入文件的文件位置等,而无需了解 haskell,更不用说重新编译项目了。
  • 如果您的生产源代码与您的开发源代码没有不同,那么它会使错误追踪变得更加容易,比如您将在开发模式下使用 postgres 数据库,但在生产中使用 oracle - 您永远不会找到特定于 oracle 的错误。
  • 对于优化级别之类的事情 - 我不太介意。
  • 但是请确保您正确测试了多线程的东西,我曾经用完文件句柄,因为我打开了很多但关闭速度不够快 - 如果您的开发设置是单线程的,您将提供一个错误。