lean4-htt/Lake/CLI/Build.lean

180 lines
6.9 KiB
Text

/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build
import Lake.CLI.Error
namespace Lake
def Package.defaultTarget (self : Package) : OpaqueTarget :=
match self.defaultFacet with
| .exe => self.exeTarget.withoutInfo
| .staticLib => self.staticLibTarget.withoutInfo
| .sharedLib => self.sharedLibTarget.withoutInfo
| .leanLib => self.leanLibTarget.withoutInfo
| .none => Target.nil
def parsePackageSpec (ws : Workspace) (spec : String) : Except CliError Package :=
if spec.isEmpty then
return ws.root
else
match ws.findPackage? spec.toName with
| some pkg => return pkg
| none => throw <| CliError.unknownPackage spec
open Module in
def resolveModuleTarget (ws : Workspace) (mod : Module) (facet : WfName) : Except CliError OpaqueTarget :=
if facet.isAnonymous || facet == &`bin then
return mod.facetTarget leanBinFacet
else if facet == &`ilean then
return mod.facetTarget ileanFacet
else if facet == &`olean then
return mod.facetTarget oleanFacet
else if facet == &`c then
return mod.facetTarget cFacet
else if facet == &`o then
return mod.facetTarget oFacet
else if facet == &`dynlib then
return mod.facetTarget dynlibFacet
else if let some config := ws.findModuleFacetConfig? facet then
if let some (.up ⟨_, h⟩) := config.result_eq_target? then
have := config.familyDefTarget h
return mod.facetTarget facet
else
throw <| CliError.nonTargetFacet "module" facet
else
throw <| CliError.unknownFacet "module" facet
def resolveLibTarget (lib : LeanLib) (facet : WfName) : Except CliError OpaqueTarget :=
if facet.isAnonymous || facet == &`lean then
return lib.leanTarget
else if facet == &`static then
return lib.staticLibTarget |>.withoutInfo
else if facet == &`shared then
return lib.sharedLibTarget |>.withoutInfo
else
throw <| CliError.unknownFacet "library" facet
def resolveExeTarget (exe : LeanExe) (facet : WfName) : Except CliError OpaqueTarget :=
if facet.isAnonymous || facet == &`exe then
return exe.target |>.withoutInfo
else
throw <| CliError.unknownFacet "executable" facet
def resolveTargetInPackage (ws : Workspace) (pkg : Package) (target : WfName) (facet : WfName) : Except CliError OpaqueTarget :=
if let some config := pkg.findTargetConfig? target then
if !facet.isAnonymous then
throw <| CliError.invalidFacet target facet
else if h : pkg.name = config.package then
have : FamilyDef CustomData (pkg.name, config.name) (ActiveBuildTarget config.resultType) :=
⟨by simp [h]⟩
return pkg.customTarget config.name |>.target
else
throw <| CliError.badTarget pkg.name target config.package config.name
else if let some exe := pkg.findLeanExe? target then
resolveExeTarget exe facet
else if let some lib := pkg.findExternLib? target then
if facet.isAnonymous then
return lib.target.withoutInfo
else
throw <| CliError.invalidFacet target facet
else if let some lib := pkg.findLeanLib? target then
resolveLibTarget lib facet
else if let some mod := pkg.findModule? target then
resolveModuleTarget ws mod facet
else
throw <| CliError.missingTarget pkg.name (target.toString false)
def resolveDefaultPackageTarget (ws : Workspace) (pkg : Package) : Except CliError OpaqueTarget :=
if pkg.defaultTargets.isEmpty then
return pkg.defaultTarget
else
return Target.collectOpaqueArray <| ←
pkg.defaultTargets.mapM (resolveTargetInPackage ws pkg · .anonymous)
def resolvePackageTarget (ws : Workspace) (pkg : Package) (facet : WfName) : Except CliError OpaqueTarget :=
if facet.isAnonymous then
resolveDefaultPackageTarget ws pkg
else if facet == &`exe then
return pkg.exeTarget.withoutInfo
else if facet == &`staticLib then
return pkg.staticLibTarget.withoutInfo
else if facet == &`sharedLib then
return pkg.sharedLibTarget.withoutInfo
else if facet == &`leanLib then
return pkg.leanLibTarget.withoutInfo
else if let some config := ws.findPackageFacetConfig? facet then
if let some (.up ⟨_, h⟩) := config.result_eq_target? then
have := config.familyDefTarget h
return pkg.facet facet |>.target
else
throw <| CliError.nonTargetFacet "package" facet
else
throw <| CliError.unknownFacet "package" facet
def resolveTargetInWorkspace (ws : Workspace) (target : Name) (facet : WfName) : Except CliError OpaqueTarget :=
if let some (pkg, config) := ws.findTargetConfig? target then
if !facet.isAnonymous then
throw <| CliError.invalidFacet config.name facet
else if h : pkg.name = config.package then
have : FamilyDef CustomData (pkg.name, config.name) (ActiveBuildTarget config.resultType) :=
⟨by simp [h]⟩
return pkg.customTarget config.name |>.target
else
throw <| CliError.badTarget pkg.name target config.package config.name
else if let some exe := ws.findLeanExe? target then
resolveExeTarget exe facet
else if let some lib := ws.findExternLib? target then
if facet.isAnonymous then
return lib.target.withoutInfo
else
throw <| CliError.invalidFacet target facet
else if let some lib := ws.findLeanLib? target then
resolveLibTarget lib facet
else if let some pkg := ws.findPackage? target then
resolvePackageTarget ws pkg facet
else if let some mod := ws.findModule? target then
resolveModuleTarget ws mod facet
else
throw <| CliError.unknownTarget target
def resolveTargetBaseSpec (ws : Workspace) (spec : String) (facet : WfName) : Except CliError OpaqueTarget := do
match spec.splitOn "/" with
| [spec] =>
if spec.isEmpty then
resolvePackageTarget ws ws.root facet
else if spec.startsWith "@" then
let pkg ← parsePackageSpec ws <| spec.drop 1
resolvePackageTarget ws pkg facet
else if spec.startsWith "+" then
let mod := spec.drop 1 |>.toName
if let some mod := ws.findModule? mod then
resolveModuleTarget ws mod facet
else
throw <| CliError.unknownModule mod
else
resolveTargetInWorkspace ws spec.toName facet
| [pkgSpec, targetSpec] =>
let pkgSpec := if pkgSpec.startsWith "@" then pkgSpec.drop 1 else pkgSpec
let pkg ← parsePackageSpec ws pkgSpec
if targetSpec.startsWith "+" then
let mod := targetSpec.drop 1 |>.toName
if let some mod := pkg.findModule? mod then
resolveModuleTarget ws mod facet
else
throw <| CliError.unknownModule mod
else
resolveTargetInPackage ws pkg (WfName.ofName targetSpec) facet
| _ =>
throw <| CliError.invalidTargetSpec spec '/'
def parseTargetSpec (ws : Workspace) (spec : String) : Except CliError OpaqueTarget := do
match spec.splitOn ":" with
| [spec] =>
resolveTargetBaseSpec ws spec .anonymous
| [rootSpec, facet] =>
resolveTargetBaseSpec ws rootSpec (WfName.ofString facet)
| _ =>
throw <| CliError.invalidTargetSpec spec ':'