lean4-htt/src/Lean/Setup.lean
Mac Malone dd64678f07
feat: server support for new module setup (#8699)
This PR adds support to the server for the new module setup process by
changing how `lake setup-file` is used.

In the new server setup, `lake setup-file` is invoked with the file name
of the edited module passed as a CLI argument and with the parsed header
passed to standard input in JSON form. Standard input is used to avoid
potentially exceeding the CLI length limits on Windows. Lake will build
the module's imports along with any other dependencies and then return
the module's workspace configuration via JSON (now in the form of
`ModuleSetup`). The server then post-processes this configuration a bit
and returns it back to the Lean language processor.

The server's header is currently only fully respected by Lake for
external modules (files that are not part of any workspace library). For
workspace modules, the saved module header is currently used to build
imports (as has been done since #7909). A follow-up Lake PR will align
both cases to follow the server's header.

Lean search paths (e.g., `LEAN_PATH`, `LEAN_SRC_PATH`) are no longer
negotiated between the server and Lake. These environment variables are
already configured during sever setup by `lake serve` and do not change
on a per-file basis. Lake can also pre-resolve the `.olean` files of
imports via the `importArts` field of `ModuleSetup`, limiting the
potential utility of communicating `LEAN_PATH`.
2025-06-23 18:00:14 +00:00

111 lines
3.8 KiB
Text

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Mac Malone
-/
prelude
import Lean.Data.Json
import Lean.Util.LeanOptions
/-!
# Module Setup Information
Data types used by Lean module headers and the `--setup` CLI.
-/
namespace Lean
/- Abstract structure of an `import` statement. -/
structure Import where
module : Name
/-- `import all`; whether to import and expose all data saved by the module. -/
importAll : Bool := false
/-- Whether to activate this import when the current module itself is imported. -/
isExported : Bool := true
/-- Whether all definitions (transitively) reachable through the -/
isMeta : Bool := false
deriving Repr, Inhabited, ToJson, FromJson
instance : Coe Name Import := ⟨({module := ·})⟩
instance : ToString Import := ⟨fun imp => toString imp.module⟩
/-- Abstract structure of a module's header. -/
structure ModuleHeader where
/-- The module's direct imports (i.e., those listed in the header). -/
imports : Array Import
/-- Whether the module is participating in the module system. -/
isModule : Bool
deriving Repr, Inhabited, ToJson, FromJson
/--
Module data files used for an `import` statement.
This structure is designed for efficient JSON serialization.
-/
structure ImportArtifacts where
oleanParts : Array System.FilePath
deriving Repr, Inhabited
instance : ToJson ImportArtifacts := ⟨(toJson ·.oleanParts)⟩
instance : FromJson ImportArtifacts := ⟨(.mk <$> fromJson? ·)⟩
def ImportArtifacts.olean? (arts : ImportArtifacts) :=
arts.oleanParts[0]?
def ImportArtifacts.oleanServer? (arts : ImportArtifacts) :=
arts.oleanParts[1]?
def ImportArtifacts.oleanPrivate? (arts : ImportArtifacts) :=
arts.oleanParts[2]?
/-- Files containing data for a single module. -/
structure ModuleArtifacts where
lean? : Option System.FilePath := none
olean? : Option System.FilePath := none
oleanServer? : Option System.FilePath := none
oleanPrivate? : Option System.FilePath := none
ilean? : Option System.FilePath := none
c? : Option System.FilePath := none
bc? : Option System.FilePath := none
deriving Repr, Inhabited, ToJson, FromJson
def ModuleArtifacts.oleanParts (arts : ModuleArtifacts) : Array System.FilePath := Id.run do
let mut fnames := #[]
if let some mFile := arts.olean? then
fnames := fnames.push mFile
if let some sFile := arts.oleanServer? then
fnames := fnames.push sFile
if let some pFile := arts.oleanPrivate? then
fnames := fnames.push pFile
return fnames
/-- A module's setup information as described by a JSON file. -/
structure ModuleSetup where
/-- Name of the module. -/
name : Name
/--
Whether the module, by default, participates in the module system.
Even if `false`, a module can still choose to participate by using `module` in its header.
-/
isModule : Bool := false
/--
The module's direct imports.
If `none`, uses the imports from the module header.
-/
imports? : Option (Array Import) := none
/-- Pre-resolved artifacts of transitively imported modules. -/
importArts : NameMap ImportArtifacts := {}
/-- Dynamic libraries to load with the module. -/
dynlibs : Array System.FilePath := #[]
/-- Plugins to initialize with the module. -/
plugins : Array System.FilePath := #[]
/-- Additional options for the module. -/
options : LeanOptions := {}
deriving Repr, Inhabited, ToJson, FromJson
/-- Load a `ModuleSetup` from a JSON file. -/
def ModuleSetup.load (path : System.FilePath) : IO ModuleSetup := do
let contents ← IO.FS.readFile path
match Json.parse contents >>= fromJson? with
| .ok info => pure info
| .error msg => throw <| IO.userError s!"failed to load header from {path}: {msg}"