如何根据外部因素构造规则名称?

How to construct rule names according to an external factor?

到目前为止我有以下代码:

shakeArgsWith opts additionalFlags $ \flags targets -> return $ Just $ do
    ...
    -- Get target arch from command line flags
    let givenArch = listToMaybe [v | AFlag v <- flags]
    let arch = fromMaybe defArch givenArch
    ...
    -- Set the main target
    let outName = masterOutName projType toolchain projName

    let mainTgt = (case projType of
                    Binary _ -> "bin"
                    Archive  -> "lib")
                  </> prettyShowArch arch
                  </> show variant
                  </> outName

    -- Set the build directory for the current run
    let buildDir = bldDir </> show toolchain </> prettyShowArch arch </> show variant
    ...
    mainTgt %> \out -> do ...
    ...
    buildDir <//> "*.o" %> \out -> do ...
    ...

意思是规则的名称是根据我正在解析的命令行标志构造的(它们包含 arch 变量)。

因此,如果我给出 shake --arch=x64,我将在 bin/x64/Release 目录中构建主要目标,并相应地在 tmp/x64/Release 文件夹中构建我的中间构建文件。

但现在我不使用命令行标志,而是希望根据某些命令的输出来填充用于构造规则名称的共享架构变量,例如,如果我可以定义一些顶级操作会是这样的:

Stdout sout <- quietly $ cmd (EchoStdout False) (EchoStderr False) "gcc -dumpmachine" :: Action (Stdout String)
let foundArch = show (gccTripletToArch sout)

并在构建 mainTgtbuildDir 名称时使用变量 foundArch 而不是 arch。显然这是不可能做到的,因为即使是唯一可以使用 action 函数 returns Rule () 创建的顶级规则。我可以做什么?

我认为你应该可以做到:

shakeArgsWith opts additionalFlags $ \flags targets -> do
     Stdout sout <- cmd (EchoStdout False) (EchoStderr False) "gcc -dumpmachine"
     let arch = show (gccTripletToArch sout)
     return $ Just $ do
         let buildDir = bldDir </> show toolchain </> prettyShowArch arch </> show variant
         ...
         buildDir <//> "*.o" %> \out -> do ...

Shake 中的目标模式必须是静态已知的,因为这确保了一些关于快速重建的重要属性(你可以保证一个地方的变化具有可预测的效果)。但是,您可以 运行 命令来确定 arch、编译器版本等。在您创建构建脚本之前 并将它们烘焙。

另一种观点是,你是基于arch动态生成的构建系统。使用 Shake 作为 Haskell EDSL,这不是什么特别的问题,并且可以说您之前是通过命令行这样做的。