在不编译源代码的情况下构建 Haddock 文档

Building Haddock documentation without compiling the source

我正在开发一个 Haskell 库,其中包含使用 Asterius 以 WebAssembly (WASM) 为目标的部分。这些部分不能用正常的 ghc 编译,因此我们有 exclude/include WASM 部分的标志。

尝试使用 Asterius 的 ahc-cabal new-haddock 构建文档失败。它似乎恢复到 Haddock 命令的正常 ghc

我的问题是:我可以在不编译 Haddock 描述的源代码的情况下构建 Haddock 文档吗?


我的文件中可能相关的摘录:

我的 cabal 文件部分:

flag wasm
  description:         Eanbles builds targeting WASM.
  default:             False
  manual:              True

library
  exposed-modules:     Boardgame
  build-depends:       base >= 4.12 && < 5.0
  if flag(wasm)
    exposed-modules:   Boardgame.Web
    build-depends:
        aeson >= 1.4 && < 1.6
      , asterius-prelude == 0.0.1
      , scientific >= 0.3 && < 0.4
    CPP-options:       "-DWASM"

Boardgame.hs 部分:

#ifdef WASM
import Data.Aeson (ToJSON(toJSON), Value(Number, Null))
import Data.Scientific (fromFloatDigits)
#endif

-- | Represents one of the two players.
data Player = Player1 | Player2
  deriving (Show, Eq)

#ifdef WASM
instance ToJSON Player where
  toJSON = Number . fromFloatDigits . fromIntegral . playerToInt
#endif

Boardgame/Web.hs 部分:

module Boardgame.Web (
    addWebGame
) where

foreign import javascript "wrapper" jsMakeCallback :: IO () -> IO JSVal
foreign import javascript "boardgame.games[] = " jsSetGame :: JSVal -> JSVal -> IO ()

-- | Adds a named game to the list of games accessible from JavaScript.
addWebGame :: (ToJSON a, ToJSON c, FromJSON c, PositionalGame a c) => String -> a -> IO ()
addWebGame name startState = do
  callback <- jsMakeCallback $ playWeb startState
  jsSetGame (jsonToJSVal name) callback

我的主文件 (Boardgame.hs) 包含“隐藏”在 WASM 标志后面的代码,但没有代码有任何文档。 Boardgame/Web.hs 仅在指定 WASM 标志时包含并且具有文档的一些功能。

我想为 Boardgame.hsBoardgame/Web.hs 中所有记录的函数构建文档。

您可以在 Boardgame/Web.hs 中使用 CPP 有条件地设置所有非-GHC 兼容符号 undefined.

我的做法是将所有类型签名移动到模块的顶部,并进行两组定义,如下所示:

module Boardgame.Web (
    addWebGame
) where

addWebGame :: (ToJSON a, ToJSON c, FromJSON c, PositionalGame a c) => String -> a -> IO ()
-- other signatures...

#ifdef WASM
foreign import javascript "wrapper" jsMakeCallback :: IO () -> IO JSVal
foreign import javascript "boardgame.games[] = " jsSetGame :: JSVal -> JSVal -> IO ()

addWebGame name startState = do
  callback <- jsMakeCallback $ playWeb startState
  jsSetGame (jsonToJSVal name) callback

-- other definitions...

#else

addWebGame = undefined

#endif

Boardgame.Web 应无条件导入。

这应该使用 GHC 构建。如果 运行 没有做任何有用的事情,它显然会出错,但足以让 cabal/haddock 提取文档。

缺点是改变了代码结构的方式。

我确信这可以通过 awk 脚本之类的东西实现自动化,但这超出了我的范围。

或者,如果只是 FFI 声明有问题,您可以更简单(并且更自动化):

module Boardgame.Web (
    addWebGame
) where

#ifdef WASM
foreign import javascript "wrapper" jsMakeCallback :: IO () -> IO JSVal
foreign import javascript "boardgame.games[] = " jsSetGame :: JSVal -> JSVal -> IO ()

#else
jsMakeCallback = undefined
jsSetGame = undefined
#endif

-- addWebGame and others unmodified.

为了让您开始自动化,像 cat Boardgame/Web.hs | sed "s/foreign import javascript \"[^\"]*\" \([^ ]*\).*/ = undefined/" 这样的命令将提取 javascript 导入列表并将它们转换为未定义的分配。

Haskelling 快乐!