Theory Environment

(*:maxLineLen=78:*)

theory Environment
imports Base
begin

chapter ‹The Isabelle system environment›

text ‹
  This manual describes Isabelle together with related tools as seen from a
  system oriented view. See also the ‹Isabelle/Isar Reference Manual› cite"isabelle-isar-ref" for the actual Isabelle input language and related
  concepts, and ‹The Isabelle/Isar Implementation Manual› cite"isabelle-implementation" for the main concepts of the underlying
  implementation in Isabelle/ML.
›


section ‹Isabelle settings \label{sec:settings}›

text ‹
  Isabelle executables may depend on the ‹Isabelle settings› within the
  process environment. This is a statically scoped collection of environment
  variables, such as @{setting ISABELLE_HOME}, @{setting ML_SYSTEM}, @{setting
  ML_HOME}. These variables are ‹not› intended to be set directly from the
  shell, but are provided by Isabelle ‹components› within their ‹settings
  files›, as explained below.
›


subsection ‹Bootstrapping the environment \label{sec:boot}›

text ‹
  Isabelle executables need to be run within a proper settings environment.
  This is bootstrapped as described below, on the first invocation of one of
  the outer wrapper scripts (such as @{executable_ref isabelle}). This happens
  only once for each process tree, i.e.\ the environment is passed to
  subprocesses according to regular Unix conventions.

     The special variable @{setting_def ISABELLE_HOME} is determined
    automatically from the location of the binary that has been run.

    You should not try to set @{setting ISABELLE_HOME} manually. Also note
    that the Isabelle executables either have to be run from their original
    location in the distribution directory, or via the executable objects
    created by the @{tool install} tool. Symbolic links are admissible, but a
    plain copy of the 🗀‹$ISABELLE_HOME/bin› files will not work!

     The file 🗏‹$ISABELLE_HOME/etc/settings› is run as a @{executable_ref
    bash} shell script with the auto-export option for variables enabled.

    This file holds a rather long list of shell variable assignments, thus
    providing the site-wide default settings. The Isabelle distribution
    already contains a global settings file with sensible defaults for most
    variables. When installing the system, only a few of these may have to be
    adapted (probably @{setting ML_SYSTEM} etc.).

     The file path‹$ISABELLE_HOME_USER/etc/settings› (if it
    exists) is run in the same way as the site default settings. Note that the
    variable @{setting ISABELLE_HOME_USER} has already been set before ---
    usually to something like ‹$USER_HOME/.isabelle/Isabelle2024›.

    Thus individual users may override the site-wide defaults. Typically, a
    user settings file contains only a few lines, with some assignments that
    are actually changed. Never copy the central
    🗏‹$ISABELLE_HOME/etc/settings› file!

  Since settings files are regular GNU @{executable_def bash} scripts, one may
  use complex shell commands, such as ‹if› or ‹case› statements to set
  variables depending on the system architecture or other environment
  variables. Such advanced features should be added only with great care,
  though. In particular, external environment references should be kept at a
  minimum.

  
  A few variables are somewhat special, e.g.\ @{setting_def ISABELLE_TOOL} is
  set automatically to the absolute path name of the @{executable isabelle}
  executables.

  
  Note that the settings environment may be inspected with the @{tool getenv}
  tool. This might help to figure out the effect of complex settings scripts.
›


subsection ‹Common variables›

text ‹
  This is a reference of common Isabelle settings variables. Note that the
  list is somewhat open-ended. Third-party utilities or interfaces may add
  their own selection. Variables that are special in some sense are marked
  with *.

  [@{setting_def USER_HOME}*] Is the cross-platform user home directory.
  On Unix systems this is usually the same as @{setting HOME}, but on Windows
  it is the regular home directory of the user, not the one of within the
  Cygwin root file-system.‹Cygwin itself offers another choice whether its
  HOME should point to the path‹/home› directory tree or the Windows user
  home.›

  [@{setting_def ISABELLE_HOME}*] is the location of the top-level
  Isabelle distribution directory. This is automatically determined from the
  Isabelle executable that has been invoked. Do not attempt to set @{setting
  ISABELLE_HOME} yourself from the shell!

  [@{setting_def ISABELLE_HOME_USER}] is the user-specific counterpart of
  @{setting ISABELLE_HOME}. The default value is relative to path‹$USER_HOME/.isabelle›, under rare circumstances this may be changed in the
  global setting file. Typically, the @{setting ISABELLE_HOME_USER} directory
  mimics @{setting ISABELLE_HOME} to some extend. In particular, site-wide
  defaults may be overridden by a private ‹$ISABELLE_HOME_USER/etc/settings›.

  [@{setting_def ISABELLE_PLATFORM_FAMILY}*] is automatically set to the
  general platform family (‹linux›, ‹macos›, ‹windows›). Note that
  platform-dependent tools usually need to refer to the more specific
  identification according to @{setting ISABELLE_PLATFORM64}, @{setting
  ISABELLE_WINDOWS_PLATFORM64}, @{setting ISABELLE_APPLE_PLATFORM64}.

  [@{setting_def ISABELLE_PLATFORM64}*] indicates the standard Posix
  platform (‹x86_64›, ‹arm64›), together with a symbolic name for the
  operating system (‹linux›, ‹darwin›, ‹cygwin›).

  [@{setting_def ISABELLE_WINDOWS_PLATFORM64}*, @{setting_def
  ISABELLE_WINDOWS_PLATFORM32}*] indicate the native Windows platform: both
  64\,bit and 32\,bit executables are supported here.

  In GNU bash scripts, a preference for native Windows platform variants may
  be specified like this (first 64 bit, second 32 bit):

  @{verbatim [display] ‹"${ISABELLE_WINDOWS_PLATFORM64:-${ISABELLE_WINDOWS_PLATFORM32:-
  $ISABELLE_PLATFORM64}}"›}

  [@{setting_def ISABELLE_APPLE_PLATFORM64}*] indicates the native Apple
  Silicon platform (‹arm64-darwin› if available), instead of Intel emulation
  via Rosetta (‹ISABELLE_PLATFORM64=x86_64-darwin›).

  [@{setting ISABELLE_TOOL}*] is automatically set to the full path name
  of the @{executable isabelle} executable.

  [@{setting_def ISABELLE_IDENTIFIER}*] refers to the name of this
  Isabelle distribution, e.g.\ ``‹Isabelle2024›''.

  [@{setting_def ML_SYSTEM}, @{setting_def ML_HOME}, @{setting_def
  ML_OPTIONS}, @{setting_def ML_PLATFORM}, @{setting_def ML_IDENTIFIER}*]
  specify the underlying ML system to be used for Isabelle. There is only a
  fixed set of admissable @{setting ML_SYSTEM} names (see the
  🗏‹$ISABELLE_HOME/etc/settings› file of the distribution).

  The actual compiler binary will be run from the directory @{setting
  ML_HOME}, with @{setting ML_OPTIONS} as first arguments on the command line.
  The optional @{setting ML_PLATFORM} may specify the binary format of ML heap
  images, which is useful for cross-platform installations. The value of
  @{setting ML_IDENTIFIER} is automatically obtained by composing the values
  of @{setting ML_SYSTEM}, @{setting ML_PLATFORM} and the Isabelle version
  values.

  [@{setting_def ISABELLE_JDK_HOME}] points to a full JDK (Java Development
  Kit) installation with ‹javac› and ‹jar› executables. Note that
  conventional ‹JAVA_HOME› points to the JRE (Java Runtime Environment), not
  the JDK.

  [@{setting_def ISABELLE_JAVA_PLATFORM}] identifies the hardware and
  operating system platform for the Java installation of Isabelle. That is
  always the (native) 64 bit variant: ‹x86_64-linux›, ‹x86_64-darwin›,
  ‹x86_64-windows›.

  [@{setting_def ISABELLE_BROWSER_INFO}] is the directory where HTML and PDF
  browser information is stored (see also \secref{sec:info}); its default is
  path‹$ISABELLE_HOME_USER/browser_info›. For ``system build mode'' (see
  \secref{sec:tool-build}), @{setting_def ISABELLE_BROWSER_INFO_SYSTEM} is
  used instead; its default is path‹$ISABELLE_HOME/browser_info›.

  [@{setting_def ISABELLE_HEAPS}] is the directory where session heap images,
  log files, and session build databases are stored; its default is
  path‹$ISABELLE_HOME_USER/heaps›. If @{system_option system_heaps} is
  ‹true›, @{setting_def ISABELLE_HEAPS_SYSTEM} is used instead; its default
  is path‹$ISABELLE_HOME/heaps›. See also \secref{sec:tool-build}.

  [@{setting_def ISABELLE_LOGIC}] specifies the default logic to load if none
  is given explicitly by the user. The default value is ‹HOL›.

  [@{setting_def ISABELLE_LINE_EDITOR}] specifies the line editor for the
  @{tool_ref console} interface.

  [@{setting_def ISABELLE_PDFLATEX}, @{setting_def ISABELLE_LUALATEX},
  @{setting_def ISABELLE_BIBTEX}, @{setting_def ISABELLE_MAKEINDEX}] refer to
  {\LaTeX}-related tools for Isabelle document preparation (see also
  \secref{sec:tool-document}).

  [@{setting_def ISABELLE_TOOLS}] is a colon separated list of directories
  that are scanned by @{executable isabelle} for external utility programs
  (see also \secref{sec:isabelle-tool}).

  [@{setting_def ISABELLE_DOCS}] is a colon separated list of directories
  with documentation files.

  [@{setting_def PDF_VIEWER}] specifies the program to be used for displaying
  ‹pdf› files.

  [@{setting_def ISABELLE_TMP_PREFIX}*] is the prefix from which any
  running Isabelle ML process derives an individual directory for temporary
  files.

  [@{setting_def ISABELLE_TOOL_JAVA_OPTIONS}] is passed to the ‹java›
  executable when running Isabelle tools (e.g.\ @{tool build}). This is
  occasionally helpful to provide more heap space, via additional options like
  ‹-Xms1g -Xmx4g›.
›


subsection ‹Additional components \label{sec:components}›

text ‹
  Any directory may be registered as an explicit ‹Isabelle component›. The
  general layout conventions are that of the main Isabelle distribution
  itself, and the following two files (both optional) have a special meaning:

     ‹etc/settings› holds additional settings that are initialized when
    bootstrapping the overall Isabelle environment, cf.\ \secref{sec:boot}. As
    usual, the content is interpreted as a GNU bash script. It may refer to
    the component's enclosing directory via the ‹COMPONENT› shell variable.

    For example, the following setting allows to refer to files within the
    component later on, without having to hardwire absolute paths:
    @{verbatim [display] ‹MY_COMPONENT_HOME="$COMPONENT"›}

    Components can also add to existing Isabelle settings such as
    @{setting_def ISABELLE_TOOLS}, in order to provide component-specific
    tools that can be invoked by end-users. For example:
    @{verbatim [display] ‹ISABELLE_TOOLS="$ISABELLE_TOOLS:$COMPONENT/lib/Tools"›}

     ‹etc/components› holds a list of further sub-components of the same
    structure. The directory specifications given here can be either absolute
    (with leading ‹/›) or relative to the component's main directory.

  The root of component initialization is @{setting ISABELLE_HOME} itself.
  After initializing all of its sub-components recursively, @{setting
  ISABELLE_HOME_USER} is included in the same manner (if that directory
  exists). This allows to install private components via
  path‹$ISABELLE_HOME_USER/etc/components›, although it is often more
  convenient to do that programmatically via the
  bash_functioninit_component shell function in the ‹etc/settings›
  script of ‹$ISABELLE_HOME_USER› (or any other component directory). For
  example:
  @{verbatim [display] ‹init_component "$HOME/screwdriver-2.0"›}

  This is tolerant wrt.\ missing component directories, but might produce a
  warning.

  
  More complex situations may be addressed by initializing components listed
  in a given catalog file, relatively to some base directory:
  @{verbatim [display] ‹init_components "$HOME/my_component_store" "some_catalog_file"›}

  The component directories listed in the catalog file are treated as relative
  to the given base directory.

  See also \secref{sec:tool-components} for some tool-support for resolving
  components that are formally initialized but not installed yet.
›


section ‹The Isabelle tool wrapper \label{sec:isabelle-tool}›

text ‹
  The main ‹Isabelle tool wrapper› provides a generic startup environment for
  Isabelle-related utilities, user interfaces, add-on applications etc. Such
  tools automatically benefit from the settings mechanism
  (\secref{sec:settings}). Moreover, this is the standard way to invoke
  Isabelle/Scala functionality as a separate operating-system process.
  Isabelle command-line tools are run uniformly via a common wrapper ---
  @{executable_ref isabelle}:
  @{verbatim [display]
‹Usage: isabelle TOOL [ARGS ...]

  Start Isabelle TOOL with ARGS; pass "-?" for tool-specific help.

Available tools:
  ...›}

  Tools may be implemented in Isabelle/Scala or as stand-alone executables
  (usually as GNU bash scripts). In the invocation of ``@{executable
  isabelle}~tool›'', the named tool› is resolved as follows (and in the
  given order).

     An external tool found on the directories listed in the @{setting
    ISABELLE_TOOLS} settings variable (colon-separated list in standard POSIX
    notation). It is invoked as stand-alone program with the command-line
    arguments provided as ‹argv› array.

     An internal tool that is declared via class
    scala_type‹isabelle.Isabelle_Scala_Tools› and registered via
    ‹services› in path‹etc/build.props›. See \secref{sec:scala-build} for
    more details.

  There are also various administrative tools that are available from a bare
  repository clone of Isabelle, but not in regular distributions.
›


subsubsection ‹Examples›

text ‹
  Show the list of available documentation of the Isabelle distribution:
  @{verbatim [display] ‹isabelle doc›}

  View a certain document as follows:
  @{verbatim [display] ‹isabelle doc system›}

  Query the Isabelle settings environment:
  @{verbatim [display] ‹isabelle getenv ISABELLE_HOME_USER›}


section ‹The raw Isabelle ML process›

subsection ‹Batch mode \label{sec:tool-process}›

text ‹
  The @{tool_def process} tool runs the raw ML process in batch mode:
  @{verbatim [display]
‹Usage: isabelle process [OPTIONS]

  Options are:
    -T THEORY    load theory
    -d DIR       include session directory
    -e ML_EXPR   evaluate ML expression on startup
    -f ML_FILE   evaluate ML file on startup
    -l NAME      logic session name (default ISABELLE_LOGIC="HOL")
    -m MODE      add print mode for output
    -o OPTION    override Isabelle system OPTION (via NAME=VAL or NAME)

  Run the raw Isabelle ML process in batch mode.›}

  
  Options ‹-e› and ‹-f› allow to evaluate ML code, before the ML process is
  started. The source is either given literally or taken from a file. Multiple
  ‹-e› and ‹-f› options are evaluated in the given order. Errors lead to
  a premature exit of the ML process with return code 1.

  
  Option ‹-T› loads a specified theory file. This is a wrapper for ‹-e› with
  a suitable MLuse_thy invocation.

  
  Option ‹-l› specifies the logic session name. Option ‹-d› specifies
  additional directories for session roots, see also \secref{sec:tool-build}.

  
  The ‹-m› option adds identifiers of print modes to be made active for this
  session. For example, ‹-m ASCII› prefers ASCII replacement syntax over
  mathematical Isabelle symbols.

  
  Option ‹-o› allows to override Isabelle system options for this process,
  see also \secref{sec:system-options}.
›


subsubsection ‹Examples›

text ‹
  The subsequent example retrieves the ‹Main› theory value from the theory
  loader within ML:
  @{verbatim [display] ‹isabelle process -e 'Thy_Info.get_theory "Main"'›}

  Observe the delicate quoting rules for the GNU bash shell vs.\ ML. The
  Isabelle/ML and Scala libraries provide functions for that, but here we need
  to do it manually.

  
  This is how to invoke a function body with proper return code and printing
  of errors, and without printing of a redundant ‹val it = (): unit› result:
  @{verbatim [display] ‹isabelle process -e 'Command_Line.tool (fn () => writeln "OK")'›}
  @{verbatim [display] ‹isabelle process -e 'Command_Line.tool (fn () => error "Bad")'›}


subsection ‹Interactive mode›

text ‹
  The @{tool_def console} tool runs the raw ML process with interactive
  console and line editor:
  @{verbatim [display]
‹Usage: isabelle console [OPTIONS]

  Options are:
    -d DIR       include session directory
    -i NAME      include session in name-space of theories
    -l NAME      logic session name (default ISABELLE_LOGIC)
    -m MODE      add print mode for output
    -n           no build of session image on startup
    -o OPTION    override Isabelle system OPTION (via NAME=VAL or NAME)
    -r           bootstrap from raw Poly/ML

  Build a logic session image and run the raw Isabelle ML process
  in interactive mode, with line editor ISABELLE_LINE_EDITOR.›}

  
  Option ‹-l› specifies the logic session name. By default, its heap image is
  checked and built on demand, but the option ‹-n› skips that.

  Option ‹-i› includes additional sessions into the name-space of theories:
  multiple occurrences are possible.

  Option ‹-r› indicates a bootstrap from the raw Poly/ML system, which is
  relevant for Isabelle/Pure development.

  
  Options ‹-d›, ‹-m›, ‹-o› have the same meaning as for @{tool process}
  (\secref{sec:tool-process}).

  
  The Isabelle/ML process is run through the line editor that is specified via
  the settings variable @{setting ISABELLE_LINE_EDITOR} (e.g.\
  @{executable_def rlwrap} for GNU readline); the fall-back is to use plain
  standard input/output.

  The user is connected to the raw ML toplevel loop: this is neither
  Isabelle/Isar nor Isabelle/ML within the usual formal context. The most
  relevant ML commands at this stage are MLuse (for ML files) and
  MLuse_thy (for theory files).
›


section ‹The raw Isabelle Java process \label{sec:isabelle-java}›

text ‹
  The @{executable_ref isabelle_java} executable allows to run a Java process
  within the name space of Java and Scala components that are bundled with
  Isabelle, but ‹without› the Isabelle settings environment
  (\secref{sec:settings}).

  After such a JVM cold-start, the Isabelle environment can be accessed via
  ‹Isabelle_System.getenv› as usual, but the underlying process environment
  remains clean. This is e.g.\ relevant when invoking other processes that
  should remain separate from the current Isabelle installation.

  
  Note that under normal circumstances, Isabelle command-line tools are run
  ‹within› the settings environment, as provided by the @{executable
  isabelle} wrapper (\secref{sec:isabelle-tool} and \secref{sec:tool-java}).
›


subsubsection ‹Example›

text ‹
  The subsequent example creates a raw Java process on the command-line and
  invokes the main Isabelle application entry point:
  @{verbatim [display] ‹isabelle_java -Djava.awt.headless=false isabelle.jedit.JEdit_Main›}


section ‹System registry via TOML \label{sec:system-registry}›

text ‹
  Tools implemented in Isabelle/Scala may refer to a global registry of
  hierarchically structured values, which is based on a collection of TOML
  files. TOML is conceptually similar to JSON, but aims at human-readable
  syntax.

  The recursive structure of a TOML ‹value› is defined as follows:
     atom: string, integer, float, bool, date (ISO-8601)
     array: sequence of ‹values› t›, written ‹[›t1‹,›…›‹,›tn‹]›
     table: mapping from ‹names› a› to ‹values› t›, written
      ‹{›a1‹=›t1‹,›…›‹,›an‹=›tn‹}›

  There are various alternative syntax forms for convenience, e.g. to
  construct a table of tables, using ‹header syntax› that resembles
  traditional ‹.INI›-file notation. For example:
  @{verbatim [display, indent = 2]
  ‹[point.A]
x = 1
y = 1
description = "one point"

[point.B]
x = 2
y = -2
description = "another point"

[point.C]
x = 3
y = 7
description = "yet another point"
›}

  Or alternatively like this:
  @{verbatim [display, indent = 2]
  ‹point.A.x = 1
point.A.y = 1
point.A.description = "one point"

point.B.x = 2
point.B.y = -2
point.B.description = "another point"

point.C.x = 3
point.C.y = 7
point.C.description = "yet another point"
›}

  The TOML website🌐‹https://toml.io/en/v1.0.0› provides many examples,
  together with the full language specification. Note that the Isabelle/Scala
  implementation of TOML uses the default ISO date/time format of
  Java.🌐‹https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/format/DateTimeFormatter.html›

  
  The overall system registry is collected from ‹registry.toml› files in
  directories specified via the settings variable @{setting
  "ISABELLE_REGISTRY"}: this refers to path‹$ISABELLE_HOME› and
  path‹$ISABELLE_HOME_USER› by default, but further directories may be
  specified via the GNU bash function bash_functionisabelle_registry
  within path‹etc/settings› of Isabelle components.

  The result is available as Isabelle/Scala object
  scala‹isabelle.Registry.global›. That is empty by default, unless users
  populate path‹$ISABELLE_HOME_USER/etc/registry.toml› or provide other
  component path‹etc/registry.toml› files.
›


section ‹YXML versus XML \label{sec:yxml-vs-xml}›

text ‹
  Isabelle tools often use YXML, which is a simple and efficient syntax for
  untyped XML trees. The YXML format is defined as follows.

     The encoding is always UTF-8.

     Body text is represented verbatim (no escaping, no special treatment of
    white space, no named entities, no CDATA chunks, no comments).

     Markup elements are represented via ASCII control characters X = 5›
    and Y = 6› as follows:

    \begin{tabular}{ll}
      XML & YXML \\\hline
      ‹<›name attribute›‹=›value …›‹>› &
      XYnameYattribute›‹=›value…X \\
      ‹</›name›‹>› & XYX \\
    \end{tabular}

    There is no special case for empty body text, i.e.\ ‹<foo/>› is treated
    like ‹<foo></foo>›. Also note that X and Y may never occur in
    well-formed XML documents.

  Parsing YXML is pretty straight-forward: split the text into chunks
  separated by X, then split each chunk into sub-chunks separated by Y.
  Markup chunks start with an empty sub-chunk, and a second empty sub-chunk
  indicates close of an element. Any other non-empty chunk consists of plain
  text. For example, see 🗏‹~~/src/Pure/PIDE/yxml.ML› or
  🗏‹~~/src/Pure/PIDE/yxml.scala›.

  YXML documents may be detected quickly by checking that the first two
  characters are XY.
›

end