如何遍历build.sc中所有Mill Target并从外部获取target.dest路径
Mill 自定义Target遍历与后处理工具实现方案
已定义Target遍历的最优实现
不要手动解析build.sc源码,也不要扫描./out目录做反向推导,Mill 本身在构建加载阶段就已经完成了所有模块、Target 的注册收集,直接用内置API就能拿到完整的元数据,完全不需要硬编码目标列表:
- 所有构建内容都以根 Module 为起点组成树形结构,通过递归遍历 Module 树就能拿到所有已定义的 Module 实例,遍历过程发生在构建评估阶段之前,不会触发任何任务执行。
- 拿到单个 Module 实例后,通过其
millInternal.targets属性就能直接获取该 Module 下声明的所有 Target 实例,和 Target 是否运行过、是否有输出目录完全无关。 - 过滤逻辑直接用 Scala 类型判断即可,比如筛选所有 ScalaModule 只需要判断
module.isInstanceOf[ScalaModule],筛选特定类型的 Target(比如编译、测试、打包任务)可以直接判断 Target 的值类型,能拿到完整的类型信息,不存在扫描out目录无法识别类型的问题。
最小实现示例,直接写在build.sc中即可:
import mill._ import mill.scalalib._ import os.Path object BuildUtils extends Module { // 递归收集所有子Module private def collectModules(root: Module): Seq[Module] = { root +: root.millInternal.modules.flatMap(collectModules) } // 示例:收集所有ScalaModule的compile目标 def listAllCompileTargets: T[Seq[String]] = T { val rootModule = implicitly[mill.define.BaseModule] val allModules = collectModules(rootModule) allModules.collect { case m: ScalaModule => m.compile } .map(_.toString) } }
运行mill BuildUtils.listAllCompileTargets就能直接输出所有Scala模块的编译目标全限定名,哪怕你是刚拉取代码、从没运行过任何构建任务,结果也是完整准确的。
外部获取Target对应dest目录的方法
Mill 每个 Target 的输出目录路径是根据 Target 全限定名按固定规则计算的,不需要运行 Target,也不需要扫描out目录,直接用官方API就能拿到准确路径:
对于任意 Target/Task 实例,调用mill.eval.PathResolver.dest(task)即可获取其对应的T.dest路径,这个方法是纯路径计算逻辑,不会触发任务执行,也不会检查路径是否存在。
结合这个API你可以很方便地实现结果状态判断:如果计算出的路径不存在,就说明该Target已经定义但从未运行,或者运行结果被clean命令清理了,正好满足你要识别这类状态的需求。
给个扩展的状态检查示例:
def checkAllTargetStatus: T[Seq[(String, Path, String)]] = T { val rootModule = implicitly[mill.define.BaseModule] val allTargets = collectModules(rootModule).flatMap(_.millInternal.targets) allTargets.map { task => val destPath = mill.eval.PathResolver.dest(task) val status = if (os.exists(destPath)) "存在运行结果" else "已定义但无输出" (task.toString, destPath, status) } }
为什么不推荐扫描./out目录
你提到的遍历out目录的方案有三个无法解决的硬伤,正好被上述原生API方案完全规避:
- 无法关联Target的类型信息,不能按模块类型、任务类型做过滤
- 未运行过、或被清理过的Target没有对应out目录,会漏统计已定义的目标
- 改名或删除的Target会残留旧的out目录,会误统计不存在的目标
不要自己手动拼接out路径,不同Mill版本的目录层级规则可能有调整,直接用PathResolver.dest能保证跨版本的路径准确性。
内容的提问来源于stack exchange,提问作者user4955663
相关产品推荐
相关产品推荐

