|
| 1 | +/- |
| 2 | +Copyright (c) 2022 Mac Malone. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Mac Malone |
| 5 | +-/ |
| 6 | +import Lake.Build.Module1 |
| 7 | +import Lake.Build.Topological |
| 8 | +import Lake.Util.EStateT |
| 9 | + |
| 10 | +/-! |
| 11 | +# The Lake Build Index |
| 12 | +
|
| 13 | +The Lake build index is the complete map of Lake build keys to |
| 14 | +Lake build functions, which is used by Lake to build any Lake build info. |
| 15 | +
|
| 16 | +This module contains the definitions used to formalize this concept, |
| 17 | +and it leverages the index to perform topological-based recursive builds. |
| 18 | +-/ |
| 19 | + |
| 20 | +open Std Lean |
| 21 | +namespace Lake |
| 22 | + |
| 23 | +/-! |
| 24 | +## Facet Build Maps |
| 25 | +-/ |
| 26 | + |
| 27 | +/-- A map from module facet names to build functions. -/ |
| 28 | +abbrev ModuleBuildMap (m : Type → Type v) := |
| 29 | + DRBMap WfName (cmp := WfName.quickCmp) fun k => |
| 30 | + Module → IndexBuildFn m → m (ModuleData k) |
| 31 | + |
| 32 | +@[inline] def ModuleBuildMap.empty : ModuleBuildMap m := DRBMap.empty |
| 33 | + |
| 34 | +/-- A map from package facet names to build functions. -/ |
| 35 | +abbrev PackageBuildMap (m : Type → Type v) := |
| 36 | + DRBMap WfName (cmp := WfName.quickCmp) fun k => |
| 37 | + Package → IndexBuildFn m → m (PackageData k) |
| 38 | + |
| 39 | +@[inline] def PackageBuildMap.empty : PackageBuildMap m := DRBMap.empty |
| 40 | + |
| 41 | +/-! |
| 42 | +## Build Function Constructor Helpers |
| 43 | +-/ |
| 44 | + |
| 45 | +/-- |
| 46 | +Converts a conveniently typed module facet build function into its |
| 47 | +dynamically typed equivalent. |
| 48 | +-/ |
| 49 | +@[inline] def mkModuleFacetBuild {facet : WfName} |
| 50 | +(build : Module → IndexBuildFn m → m α) [h : DynamicType ModuleData facet α] |
| 51 | +: Module → IndexBuildFn m → m (ModuleData facet) := |
| 52 | + cast (by rw [← h.eq_dynamic_type]) build |
| 53 | + |
| 54 | +/-- |
| 55 | +Converts a conveniently typed package facet build function into its |
| 56 | +dynamically typed equivalent. |
| 57 | +-/ |
| 58 | +@[inline] def mkPackageFacetBuild {facet : WfName} |
| 59 | +(build : Package → IndexBuildFn m → m α) [h : DynamicType PackageData facet α] |
| 60 | +: Package → IndexBuildFn m → m (PackageData facet) := |
| 61 | + cast (by rw [← h.eq_dynamic_type]) build |
| 62 | + |
| 63 | +section |
| 64 | +variable [Monad m] [MonadLiftT BuildM m] [MonadBuildStore m] |
| 65 | + |
| 66 | +/-! |
| 67 | +## Initial Facet Maps |
| 68 | +-/ |
| 69 | + |
| 70 | +/-- |
| 71 | +A module facet name to build function map that contains builders for |
| 72 | +the initial set of Lake module facets (e.g., `lean.{imports, c, o, dynlib]`). |
| 73 | +-/ |
| 74 | +@[specialize] def moduleBuildMap : ModuleBuildMap m := |
| 75 | + have : MonadLift BuildM m := ⟨liftM⟩ |
| 76 | + ModuleBuildMap.empty.insert |
| 77 | + -- Compute unique imports (direct × transitive) |
| 78 | + &`lean.imports (mkModuleFacetBuild <| fun mod recurse => do |
| 79 | + mod.recParseImports recurse |
| 80 | + ) |>.insert |
| 81 | + -- Build module (`.olean` and `.ilean`) |
| 82 | + &`lean (mkModuleFacetBuild <| fun mod recurse => do |
| 83 | + mod.recBuildLean false recurse |
| 84 | + ) |>.insert |
| 85 | + &`olean (mkModuleFacetBuild <| fun mod recurse => do |
| 86 | + mod.recBuildFacet &`lean recurse |
| 87 | + ) |>.insert |
| 88 | + &`ilean (mkModuleFacetBuild <| fun mod recurse => do |
| 89 | + mod.recBuildFacet &`lean recurse |
| 90 | + ) |>.insert |
| 91 | + -- Build module `.c` (and `.olean` and `.ilean`) |
| 92 | + &`lean.c (mkModuleFacetBuild <| fun mod recurse => do |
| 93 | + mod.recBuildLean true recurse <&> (·.withInfo mod.cFile) |
| 94 | + ) |>.insert |
| 95 | + -- Build module `.o` |
| 96 | + &`lean.o (mkModuleFacetBuild <| fun mod recurse => do |
| 97 | + let cTarget ← mod.recBuildFacet &`lean.c recurse |
| 98 | + mod.mkOTarget (Target.active cTarget) |>.activate |
| 99 | + ) |>.insert |
| 100 | + -- Build shared library for `--load-dynlb` |
| 101 | + &`lean.dynlib (mkModuleFacetBuild <| fun mod recurse => do |
| 102 | + mod.recBuildDynLib recurse |
| 103 | + ) |
| 104 | + |
| 105 | +/-- |
| 106 | +A package facet name to build function map that contains builders for |
| 107 | +the initial set of Lake package facets (e.g., `extraDep`). |
| 108 | +-/ |
| 109 | +@[specialize] def packageBuildMap : PackageBuildMap m := |
| 110 | + have : MonadLift BuildM m := ⟨liftM⟩ |
| 111 | + PackageBuildMap.empty.insert |
| 112 | + -- Build the `extraDepTarget` for the package and its transitive dependencies |
| 113 | + &`extraDep (mkPackageFacetBuild <| fun pkg recurse => do |
| 114 | + let mut target := ActiveTarget.nil |
| 115 | + for dep in pkg.dependencies do |
| 116 | + if let some depPkg ← findPackage? dep.name then |
| 117 | + let extraDepTarget ← depPkg.recBuildFacet &`extraDep recurse |
| 118 | + target ← target.mixOpaqueAsync extraDepTarget |
| 119 | + target.mixOpaqueAsync <| ← pkg.extraDepTarget.activate |
| 120 | + ) |
| 121 | + |
| 122 | +/-! |
| 123 | +## Topologically-based Recursive Build Using the Index |
| 124 | +-/ |
| 125 | + |
| 126 | +/-- The type of a recursive build function for the Lake build index. -/ |
| 127 | +abbrev RecIndexBuildFn (m) := |
| 128 | + DRecBuildFn BuildInfo (BuildData ·.key) m |
| 129 | + |
| 130 | +/-- Recursive build function for anything in the Lake build index. -/ |
| 131 | +@[specialize] def recBuildIndex : RecIndexBuildFn m := fun info recurse => do |
| 132 | + have : MonadLift BuildM m := ⟨liftM⟩ |
| 133 | + match info with |
| 134 | + | .module mod facet => |
| 135 | + if let some build := moduleBuildMap.find? facet then |
| 136 | + build mod recurse |
| 137 | + else |
| 138 | + error s!"do not know how to build module facet `{facet}`" |
| 139 | + | .package pkg facet => |
| 140 | + if let some build := packageBuildMap.find? facet then |
| 141 | + build pkg recurse |
| 142 | + else |
| 143 | + error s!"do not know how to build package facet `{facet}`" |
| 144 | + | _ => |
| 145 | + error s!"do not know how to build `{info.key}`" |
| 146 | + |
| 147 | +/-- |
| 148 | +Recursively build the given info using the Lake build index |
| 149 | +and a topological / suspending scheduler. |
| 150 | +-/ |
| 151 | +@[specialize] def buildIndexTop (info : BuildInfo) : CycleT BuildKey m (BuildData info.key) := |
| 152 | + buildDTop BuildData BuildInfo.key recBuildIndex info |
| 153 | + |
| 154 | +/-- |
| 155 | +Build the package's specified facet recursively using a topological-based |
| 156 | +scheduler, storing the results in the monad's store and returning the result |
| 157 | +of the top-level build. |
| 158 | +-/ |
| 159 | +@[inline] def buildPackageTop (pkg : Package) (facet : WfName) |
| 160 | +[h : DynamicType PackageData facet α] : CycleT BuildKey m α := |
| 161 | + have of_data := by unfold BuildData, BuildInfo.key; simp [h.eq_dynamic_type] |
| 162 | + cast of_data <| buildIndexTop (m := m) <| BuildInfo.package pkg facet |
| 163 | + |
| 164 | +end |
| 165 | + |
| 166 | +/-! |
| 167 | +## Package Facet Builders |
| 168 | +-/ |
| 169 | + |
| 170 | +/-- |
| 171 | +Recursively build the specified facet of the given package, |
| 172 | +returning the result. |
| 173 | +-/ |
| 174 | +def buildPackageFacet |
| 175 | +(pkg : Package) (facet : WfName) |
| 176 | +[DynamicType PackageData facet α] : BuildM α := do |
| 177 | + failOnBuildCycle <| ← EStateT.run' BuildStore.empty do |
| 178 | + buildPackageTop pkg facet |
0 commit comments