问题描述
我有以下情况:
-
find-deps
是一个运行速度非常快的外部程序,它类似于ghc -M
发现依赖项信息。其输出是一些文件deps
。 -
compile
是一个外部程序,运行速度非常慢;与ghc --make
不同,即使输入没有任何更改,它也非常慢。
因此,想法是添加一个运行find-deps
的Shake规则以生成deps
,将其解析为文件srcs
的列表,然后编译规则将{{1} },以确保仅在need srcs
发现的任何源已更改的情况下重新运行compile
。
棘手的部分是find-deps
需要find-deps
才能发现新依赖的源文件。因此,现在如果alwaysRerun
规则依赖于compile
来获取文件列表,那么它也将deps
。标准解决方案是使用一个oracle:我们可以添加一个alwaysRerun
的{{1}}的oracle,并将其解析为文件列表,然后need
规则首先会要求源文件列表,仅deps
。因此,compile
的{{1}}链上没有need
。
但是,就我而言,我不是在编写特定的Shakefile。相反,我正在编写一个可重用的alwaysRerun
库,用户可以使用该库来制作自己的主Shakefile。所以我需要将其打包成类似
need
但是我应该将compile
的{{1}}部分放在哪里,并对其进行解析并返回源文件列表?我不能将其放在Rules
中,因为然后使用不同目录的两次myRules :: FilePath -> Rules ()
myRules dir = do
dir </> "deps" %> \depFile -> do
alwaysRerun
cmd_ (Cwd dir) "find-deps" ["-o",depFile]
dir </> "exe" %> \exeFile -> do
srcs <- askOracle $ Sources dir
need srcs
cmd_ (Cwd dir) "compile" ["-o",exeFile]
调用将尝试为同一类型两次安装一个oracle处理程序。而且我无法使addOracle $ \Sources dir -> ...
成为oracle问题类型的一部分,因为它是术语级变量,所以我无法将其提升到查询的need [dir </> "deps"]
索引中。
这给我留下了一些超级含义,例如让用户记住要在其Shakefile中仅包含一次rules
。
所以我的问题是:
- 有没有一种方法可以跟踪依赖关系(即在没有源文件更改的情况下避免运行
rules
)不涉及oracle ? - 或者,是否可以通过某种方式对其进行范围划分来分隔相同类型的oracle ,这样我就可以将此
dir
oracle仅添加到{ {1}}?
解决方法
有没有一种方法可以在不涉及Oracle的情况下跟踪依赖关系?
是-如果find-deps
的输出完全没有变化,则不会重建compile
。您可以通过指定诸如Change
之类的ChangeModtimeAndDigest
值来实现,但这是一个全局设置。另外,您可以将find-deps
的输出放在foo.deps.out
之类的位置,然后调用copyFileChanged "foo.deps.out" "foo.deps"
,如果文件未更改,则不会更新时间戳。
有没有办法分隔相同类型的预言片?
虽然我能理解为什么有用,但并不容易且立即。我可以想到两种可能的解决方法:
- 可以添加
addOracleIdempotent
,而该Rules
会忽略有关重复添加同一oracle的任何错误。对Shake来说,这是一个比较容易的更改(基本上在dir
中设置了一个标志来忽略重复项)。 - 或者,您可以尝试将
copyFileChanged
提升为类型级别,并确保每个oracle具有不同的类型。这可能会使您的API更复杂,并且需要输入魔术。
在所有这些解决方案中,我将使用import logging
logging.basicConfig(filename='tgbot.log',level=logging.INFO)
def log(m: Message):
username = m.from_user.username
logging.info(username)
,因为它简单而本地。