feat: preliminary custom targets
This commit is contained in:
parent
24fd2e37e1
commit
2ccd41ac82
16 changed files with 126 additions and 20 deletions
|
|
@ -165,6 +165,13 @@ the initial set of Lake package facets (e.g., `extraDep`).
|
|||
| .package pkg facet =>
|
||||
if let some build := packageBuildMap.find? facet then
|
||||
build pkg
|
||||
else if let some config := pkg.findTargetConfig? facet then
|
||||
if h : facet = config.name then
|
||||
have : DynamicType PackageData facet (ActiveBuildTarget config.resultType) :=
|
||||
⟨by simp [h, eq_dynamic_type]⟩
|
||||
mkPackageFacetBuild config.build pkg
|
||||
else
|
||||
error "target's name in the configuration does not match the name it was registered with"
|
||||
else
|
||||
error s!"do not know how to build package facet `{facet}`"
|
||||
| .staticLeanLib lib =>
|
||||
|
|
@ -179,8 +186,6 @@ the initial set of Lake package facets (e.g., `extraDep`).
|
|||
mkTargetBuild ExternLib.sharedFacet do
|
||||
let staticTarget := Target.active <| ← lib.static.recBuild
|
||||
staticToLeanDynlibTarget staticTarget |>.activate
|
||||
| _ =>
|
||||
error s!"do not know how to build `{info.key}`"
|
||||
|
||||
/--
|
||||
Recursively build the given info using the Lake build index
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ inductive BuildInfo
|
|||
| leanExe (exe : LeanExe)
|
||||
| staticExternLib (lib : ExternLib)
|
||||
| sharedExternLib (lib : ExternLib)
|
||||
| custom (package : Package) (target : WfName) (facet : WfName)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
/-! ## Build Info & Keys -/
|
||||
|
|
@ -67,7 +66,6 @@ abbrev BuildInfo.key : (self : BuildInfo) → BuildKey
|
|||
| leanExe x => x.buildKey
|
||||
| staticExternLib l => l.staticBuildKey
|
||||
| sharedExternLib l => l.sharedBuildKey
|
||||
| custom p t f => ⟨p.name, t, f⟩
|
||||
|
||||
/-! ### Instances for deducing data types of `BuildInfo` keys -/
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ def resolveExeTarget (exe : LeanExe) (facet : String) : Except CliError OpaqueTa
|
|||
throw <| CliError.unknownFacet "executable" facet
|
||||
|
||||
def resolveTargetInPackage (ws : Workspace) (pkg : Package) (target : Name) (facet : String) : Except CliError OpaqueTarget :=
|
||||
if let some exe := pkg.findLeanExe? target then
|
||||
if let some target := pkg.findTargetConfig? target then
|
||||
return pkg.facet target.name |>.target
|
||||
else if let some exe := pkg.findLeanExe? target then
|
||||
resolveExeTarget exe facet
|
||||
else if let some lib := pkg.findExternLib? target then
|
||||
if facet.isEmpty then
|
||||
|
|
@ -96,7 +98,9 @@ def resolvePackageTarget (ws : Workspace) (pkg : Package) (facet : String) : Exc
|
|||
throw <| CliError.unknownFacet "package" facet
|
||||
|
||||
def resolveTargetInWorkspace (ws : Workspace) (spec : String) (facet : String) : Except CliError OpaqueTarget :=
|
||||
if let some exe := ws.findLeanExe? spec.toName then
|
||||
if let some (pkg, target) := ws.findTargetConfig? spec then
|
||||
return pkg.facet target.name |>.target
|
||||
else if let some exe := ws.findLeanExe? spec.toName then
|
||||
resolveExeTarget exe facet
|
||||
else if let some lib := ws.findExternLib? spec.toName then
|
||||
if facet.isEmpty then
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Lean.Elab.Frontend
|
|||
import Lake.DSL.Attributes
|
||||
import Lake.DSL.Extensions
|
||||
import Lake.Config.ModuleFacetConfig
|
||||
import Lake.Config.TargetConfig
|
||||
|
||||
namespace Lake
|
||||
open Lean System
|
||||
|
|
@ -124,6 +125,10 @@ unsafe def loadUnsafe (dir : FilePath) (args : List String := [])
|
|||
match env.evalConst ModuleFacetConfig leanOpts declName with
|
||||
| .ok config => pure <| OpaqueModuleFacetConfig.mk config
|
||||
| .error e => throw <| IO.userError e
|
||||
let opaqueTargetConfigs ← mkTagMap targetAttr fun declName =>
|
||||
match env.evalConst TargetConfig leanOpts declName with
|
||||
| .ok config => pure <| OpaqueTargetConfig.mk config
|
||||
| .error e => throw <| IO.userError e
|
||||
let defaultTargets := defaultTargetAttr.ext.getState env |>.toArray
|
||||
-- Construct the Package
|
||||
if leanLibConfigs.isEmpty && leanExeConfigs.isEmpty && config.defaultFacet ≠ .none then
|
||||
|
|
@ -132,7 +137,7 @@ unsafe def loadUnsafe (dir : FilePath) (args : List String := [])
|
|||
return {
|
||||
dir, config, scripts,
|
||||
leanLibConfigs, leanExeConfigs, externLibConfigs,
|
||||
opaqueModuleFacetConfigs,
|
||||
opaqueModuleFacetConfigs, opaqueTargetConfigs,
|
||||
defaultTargets
|
||||
}
|
||||
| _ => error s!"configuration file has multiple `package` declarations"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import Lake.Build.Store
|
|||
namespace Lake
|
||||
open Lean System
|
||||
|
||||
/-- A Module facet's declarative configuration. -/
|
||||
/-- A module facet's declarative configuration. -/
|
||||
structure ModuleFacetConfig where
|
||||
/-- The name of the facet. -/
|
||||
facet : WfName
|
||||
|
|
|
|||
|
|
@ -15,3 +15,6 @@ declare_opaque_type OpaqueWorkspace
|
|||
|
||||
/-- Opaque reference to a `ModuleFacetConfig` used for forward declaration. -/
|
||||
declare_opaque_type OpaqueModuleFacetConfig
|
||||
|
||||
/-- Opaque reference to a `TargetConfig` used for forward declaration. -/
|
||||
declare_opaque_type OpaqueTargetConfig
|
||||
|
|
|
|||
|
|
@ -263,8 +263,10 @@ structure Package where
|
|||
leanExeConfigs : NameMap LeanExeConfig := {}
|
||||
/-- External library targets for the package. -/
|
||||
externLibConfigs : NameMap ExternLibConfig := {}
|
||||
/-- (Opaque) module facets defined in the package. -/
|
||||
/-- (Opaque references to) module facets defined in the package. -/
|
||||
opaqueModuleFacetConfigs : NameMap OpaqueModuleFacetConfig := {}
|
||||
/-- (Opaque references to) targets defined in the package. -/
|
||||
opaqueTargetConfigs : NameMap OpaqueTargetConfig := {}
|
||||
/--
|
||||
The names of the package's targets to build by default
|
||||
(i.e., on a bare `lake build` of the package).
|
||||
|
|
|
|||
39
Lake/Config/TargetConfig.lean
Normal file
39
Lake/Config/TargetConfig.lean
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/-
|
||||
Copyright (c) 2022 Mac Malone. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mac Malone
|
||||
-/
|
||||
import Lake.Build.Info
|
||||
import Lake.Build.Store
|
||||
|
||||
namespace Lake
|
||||
|
||||
/-- A custom target's declarative configuration. -/
|
||||
structure TargetConfig where
|
||||
/-- The name of the target. -/
|
||||
name : WfName
|
||||
/-- The type of the target's build result. -/
|
||||
resultType : Type
|
||||
/-- The target's build function. -/
|
||||
build : {m : Type → Type} →
|
||||
[Monad m] → [MonadLift BuildM m] → [MonadBuildStore m] →
|
||||
Package → IndexT m (ActiveBuildTarget resultType)
|
||||
/-- Proof that target's build result is the correctly typed target.-/
|
||||
data_eq_target : PackageData name = ActiveBuildTarget resultType
|
||||
|
||||
instance : Inhabited TargetConfig := ⟨{
|
||||
name := &`extraDep
|
||||
resultType := PUnit
|
||||
build := default
|
||||
data_eq_target := eq_dynamic_type
|
||||
}⟩
|
||||
|
||||
hydrate_opaque_type OpaqueTargetConfig TargetConfig
|
||||
|
||||
instance {cfg : TargetConfig}
|
||||
: DynamicType PackageData cfg.name (ActiveBuildTarget cfg.resultType) :=
|
||||
⟨cfg.data_eq_target⟩
|
||||
|
||||
/-- Try to find a target configuration in the package with the given name . -/
|
||||
def Package.findTargetConfig? (name : Name) (self : Package) : Option TargetConfig :=
|
||||
self.opaqueTargetConfigs.find? name |>.map (·.get)
|
||||
|
|
@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
|||
Authors: Mac Malone
|
||||
-/
|
||||
import Lean.Util.Paths
|
||||
import Lake.Config.TargetConfig
|
||||
import Lake.Config.ModuleFacetConfig
|
||||
|
||||
open System
|
||||
|
|
@ -90,6 +91,10 @@ def findExternLib? (name : Name) (self : Workspace) : Option ExternLib :=
|
|||
def findModuleFacetConfig? (name : Name) (self : Workspace) : Option ModuleFacetConfig :=
|
||||
self.packageArray.findSome? fun pkg => pkg.findModuleFacetConfig? name
|
||||
|
||||
/-- Try to find a target configuration in the workspace with the given name. -/
|
||||
def findTargetConfig? (name : Name) (self : Workspace) : Option (Package × TargetConfig) :=
|
||||
self.packageArray.findSome? fun pkg => pkg.findTargetConfig? name <&> (⟨pkg, ·⟩)
|
||||
|
||||
/-- The `LEAN_PATH` of the workspace. -/
|
||||
def oleanPath (self : Workspace) : SearchPath :=
|
||||
self.packageList.map (·.oleanDir)
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ import Lake.DSL.Script
|
|||
import Lake.DSL.Require
|
||||
import Lake.DSL.Targets
|
||||
import Lake.DSL.ModuleFacet
|
||||
import Lake.DSL.Target
|
||||
|
|
|
|||
|
|
@ -23,13 +23,17 @@ initialize leanExeAttr : TagAttribute ←
|
|||
initialize externLibAttr : TagAttribute ←
|
||||
registerTagAttribute `externLib "mark a definition as a Lake external library target"
|
||||
|
||||
initialize targetAttr : TagAttribute ←
|
||||
registerTagAttribute `target "mark a definition as a custom Lake target"
|
||||
|
||||
initialize defaultTargetAttr : TagAttribute ←
|
||||
registerTagAttribute `defaultTarget "mark a Lake target as the package's default"
|
||||
fun name => do
|
||||
let valid ← getEnv <&> fun env =>
|
||||
leanLibAttr.hasTag env name ||
|
||||
leanExeAttr.hasTag env name ||
|
||||
externLibAttr.hasTag env name
|
||||
externLibAttr.hasTag env name ||
|
||||
targetAttr.hasTag env name
|
||||
unless valid do
|
||||
throwError "attribute `defaultTarget` can only be used on a target (e.g., `lean_lib`, `lean_exe`)"
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ syntax declValTyped :=
|
|||
syntax declValOptTyped :=
|
||||
(Term.typeSpec)? declValSimple
|
||||
|
||||
syntax simpleDeclSig :=
|
||||
ident Term.typeSpec declValSimple
|
||||
|
||||
def expandAttrs (attrs? : Option Attributes) : Array AttrInstance :=
|
||||
if let some attrs := attrs? then
|
||||
match attrs with
|
||||
|
|
|
|||
|
|
@ -9,15 +9,12 @@ import Lake.Config.ModuleFacetConfig
|
|||
namespace Lake.DSL
|
||||
open Lean Parser Command
|
||||
|
||||
syntax moduleFacetDeclSpec :=
|
||||
ident Term.typeSpec declValSimple
|
||||
|
||||
scoped macro (name := moduleFacetDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
"module_facet " spec:moduleFacetDeclSpec : command => do
|
||||
match spec with
|
||||
| `(moduleFacetDeclSpec| $id:ident : $ty := $defn $[$wds?]?) =>
|
||||
let attr ← `(Term.attrInstance| moduleFacet)
|
||||
kw:"module_facet " sig:simpleDeclSig : command => do
|
||||
match sig with
|
||||
| `(simpleDeclSig| $id:ident : $ty := $defn $[$wds?]?) =>
|
||||
let attr ← withRef kw `(Term.attrInstance| moduleFacet)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let axm := mkIdentFrom id <| ``Lake.ModuleData ++ id.getId
|
||||
`(module_data $id : ActiveBuildTarget $ty
|
||||
|
|
|
|||
27
Lake/DSL/Target.lean
Normal file
27
Lake/DSL/Target.lean
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/-
|
||||
Copyright (c) 2022 Mac Malone. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mac Malone
|
||||
-/
|
||||
import Lake.DSL.DeclUtil
|
||||
import Lake.Config.TargetConfig
|
||||
|
||||
namespace Lake.DSL
|
||||
open Lean Parser Command
|
||||
|
||||
scoped macro (name := targetDecl)
|
||||
doc?:optional(docComment) attrs?:optional(Term.attributes)
|
||||
kw:"target " sig:simpleDeclSig : command => do
|
||||
match sig with
|
||||
| `(simpleDeclSig| $id:ident : $ty := $defn $[$wds?]?) =>
|
||||
let attr ← withRef kw `(Term.attrInstance| target)
|
||||
let attrs := #[attr] ++ expandAttrs attrs?
|
||||
let axm := mkIdentFrom id <| ``Lake.PackageData ++ id.getId
|
||||
`(package_data $id : ActiveBuildTarget $ty
|
||||
$[$doc?]? @[$attrs,*] def $id : TargetConfig := {
|
||||
name := $(WfName.quoteFrom id (WfName.ofName id.getId))
|
||||
resultType := $ty
|
||||
build := $defn
|
||||
data_eq_target := $axm
|
||||
})
|
||||
| stx => Macro.throwErrorAt stx "ill-formed target declaration"
|
||||
|
|
@ -15,3 +15,12 @@ lean_exe b
|
|||
|
||||
@[defaultTarget]
|
||||
lean_exe c
|
||||
|
||||
@[defaultTarget]
|
||||
target meow : PUnit := fun pkg => do
|
||||
IO.FS.writeFile (pkg.buildDir / "meow.txt") "Meow!"
|
||||
return ActiveTarget.nil
|
||||
|
||||
target bark : PUnit := fun _ => do
|
||||
logInfo "Bark!"
|
||||
return ActiveTarget.nil
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
set -e
|
||||
#!/usr/bin/env bash
|
||||
set -exo pipefail
|
||||
|
||||
LAKE=${LAKE:-../../build/bin/lake}
|
||||
|
||||
set -x
|
||||
|
||||
if [ "$OS" = Windows_NT ]; then
|
||||
SHARED_LIB_EXT=dll
|
||||
elif [ "`uname`" = Darwin ]; then
|
||||
|
|
@ -14,6 +13,8 @@ fi
|
|||
|
||||
./clean.sh
|
||||
|
||||
$LAKE build bark | grep -m1 Bark!
|
||||
|
||||
$LAKE build +Foo.Test
|
||||
|
||||
test -f ./build/lib/Foo/Test.olean
|
||||
|
|
@ -27,6 +28,7 @@ $LAKE build
|
|||
|
||||
./build/bin/c
|
||||
test -f ./build/lib/Foo.olean
|
||||
cat ./build/meow.txt | grep -m1 Meow!
|
||||
|
||||
$LAKE build a b
|
||||
|
||||
|
|
@ -38,3 +40,5 @@ $LAKE build bar:shared
|
|||
|
||||
test -f ./build/lib/libFoo.a
|
||||
test -f ./build/lib/Bar.$SHARED_LIB_EXT
|
||||
|
||||
$LAKE build bark | grep -m1 Bark!
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue