Haskell子模块中的条件编译

时间:2018-01-08 20:22:02

标签: haskell haskell-stack

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

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

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

#ifdef StableRelease 
  port = 12345
#else 
  port = 54321 
#endif

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

ghc-options: -threaded -rtsopts -with-rtsopts=-N -pgmP cpphs -optP "-DStableRelease"

当我运行stack build时,虽然它似乎没有实际预处理上面的代码。 有没有人有cpphs或其他预处理解决方案的经验?

1 个答案:

答案 0 :(得分:3)

我会在旗帜

的帮助下解决这个问题

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
  }

Main.hs

module Main where

main :: IO ()
main =
#if STABLE
  putStrLn "Hello, Haskell!"
#else
  putStrLn "Hello, Haskell?"
#endif

并编译它

stack build

stack build --flag cppstuf:stablerelease

个人注释除了答案

我不会使用CPP来管理配置选项 - 提供我喜欢的命令行选项optparse-applicative但是还有cmdargs,或者我使用的配置文件 {{3对于那个,但是在hackage上有几个选项。一个是configurator,正如@Shersh所说 - 另一个不再被开发了。

另一方面,

CPP我倾向于使库在多个GHC /库版本中运行。

更新 - 关于评论。

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