This PR enables the module system, in cooperation with the linker, to separate meta and non-meta code in native binaries. In particular, this ensures tactics merely used in proofs do not make it into the final binary. A simple example using `meta import Lean` has its binary size reduced from 130MB to 1.7MB. # Breaking change `importModules (loadExts := true)` must now be preceded by `enableInitializersExecution`. This was always the case for correct importing but is now enforced and checked eagerly.
167 lines
5.7 KiB
Text
167 lines
5.7 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
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Lean.Data.Json.Parser
|
||
public import Lean.Util.LeanOptions
|
||
|
||
set_option doc.verso true
|
||
|
||
public section
|
||
|
||
/-!
|
||
# 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 to import IR for all definitions (transitively) reachable. -/
|
||
isMeta : Bool := false
|
||
deriving Repr, Inhabited, ToJson, FromJson,
|
||
BEq, Hashable -- needed by Lake (in `Lake.Load.Elab.Lean`)
|
||
|
||
-- TODO: move further up into `Init` by using simpler representation for `imports`
|
||
@[extern "lean_idbg_client_loop"]
|
||
public opaque Idbg.idbgClientLoop {α : Type} [Nonempty α]
|
||
(siteId : String) (imports : Array Import) (apply : α → String) : IO Unit
|
||
|
||
instance : Coe Name Import := ⟨({module := ·})⟩
|
||
|
||
instance : ToString Import := ⟨fun imp =>
|
||
s!"{if imp.isExported then "public " else ""}{if imp.isMeta then "meta " else ""}import \
|
||
{if imp.importAll then "all " else ""}{imp.module}"⟩
|
||
|
||
/-- Phases for which some IR is available for execution. -/
|
||
inductive IRPhases where
|
||
/-- Available for execution in the final native code. -/
|
||
| runtime
|
||
/-- Available for execution during elaboration. -/
|
||
| comptime
|
||
/-- Available during run time and compile time. -/
|
||
| all
|
||
deriving Inhabited, BEq, Repr
|
||
|
||
/-- 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 {lit}`import` statement.
|
||
This structure is designed for efficient JSON serialization.
|
||
-/
|
||
structure ImportArtifacts where
|
||
ofArray ::
|
||
toArray : Array System.FilePath
|
||
deriving Repr, Inhabited
|
||
|
||
instance : ToJson ImportArtifacts := ⟨(toJson ·.toArray)⟩
|
||
instance : FromJson ImportArtifacts := ⟨(.ofArray <$> fromJson? ·)⟩
|
||
|
||
def ImportArtifacts.size (arts : ImportArtifacts) :=
|
||
arts.toArray.size
|
||
|
||
def ImportArtifacts.olean? (arts : ImportArtifacts) :=
|
||
arts.toArray[0]?
|
||
|
||
def ImportArtifacts.ir? (arts : ImportArtifacts) :=
|
||
arts.toArray[1]?
|
||
|
||
def ImportArtifacts.oleanServer? (arts : ImportArtifacts) :=
|
||
arts.toArray[2]?
|
||
|
||
def ImportArtifacts.oleanPrivate? (arts : ImportArtifacts) :=
|
||
arts.toArray[3]?
|
||
|
||
def ImportArtifacts.oleanParts (inServer : Bool) (arts : ImportArtifacts) : 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
|
||
-- For uniformity, Lake always provides us with .olean.server, so load it only when we are in
|
||
-- server mode or we need it to load further files.
|
||
if inServer || arts.oleanPrivate?.isSome then
|
||
fnames := fnames.push sFile
|
||
if let some pFile := arts.oleanPrivate? then
|
||
fnames := fnames.push pFile
|
||
return fnames
|
||
|
||
/-- 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
|
||
ir? : 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
|
||
|
||
/--
|
||
The type of module package identifiers.
|
||
|
||
This is a {name}`String` that is used to disambiguate native symbol prefixes between
|
||
different packages (and different versions of the same package).
|
||
-/
|
||
public abbrev PkgId := String
|
||
|
||
/-- A module's setup information as described by a JSON file. -/
|
||
structure ModuleSetup where
|
||
/-- The name of the module. -/
|
||
name : Name
|
||
/-- The package to which the module belongs (if any). -/
|
||
package? : Option PkgId := none
|
||
/--
|
||
Whether the module, by default, participates in the module system.
|
||
Even if {lean}`false`, a module can still choose to participate by using
|
||
{lit}`module` in its header.
|
||
-/
|
||
isModule : Bool := false
|
||
/--
|
||
The module's direct imports.
|
||
If {lean}`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 {lean}`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}"
|