Skip to content

Running the Compiler

gnumonik edited this page Jan 20, 2025 · 2 revisions

NOTE: This documents provides instructions and information regarding the basic operation of the compiler. A typical user will not need to invoke the compiler directly, but should use our build system (which we will document as soon as it is finished, which ought to be soon!)

Plutus Versioning

At the moment, Purus is only capable of emitting Plutus Version 2 (V2) scripts.

Installation & Preliminaries

Purus contains two primary components: 1) A fork of the PureScript compiler which has been modified to emit serialized CoreFn, which has itself been modified to include explicit type annotations sufficient to facilitate further transformation into Plutus Intermediate Representation (PIR). 2) A PureScript -> PIR -> UPLC compilation pipeline which produces a serialized UPLC binary.

Users who which to invoke the compiler directly (i.e. without the build system) should ensure that they do the following:

  1. Install Nix. To avoid egregiously long build times, most users will also want to configure a binary cache to avoid building GHC. (Instructions for this are beyond the scope of our documentation - there are several different providers of suitable binary caches)
  2. Clone this repository
  3. Navigate to the repository directory and enter the nix shell with nix develop
  4. Invoke the compiler with `cabal run purus

Project Directory Structure & Output

A Project Directory is the "top-level" compilation unit for Purus, and consists of a directory with one or more PureScript module (which may be nested inside of child directories).

Purus only supports building Plutus scripts (the build system will support external libraries, but libraries are distributed as modified PureScript CoreFn modules, not as Plutus binaries). In order to indicate to the compiler which PureScript function you wish to compile to a PlutusScript, your Project Directory MUST contain exactly on module named Main, and that module must contain a function named main.

Unlike Haskell or PureScript, the main function can have any type. All of the following are valid main function types:

main :: Int 

main :: Int -> Int 

main :: forall a. a -> Int 

-- A somewhat realistic type for a script intended to be used as a validator. (The return type should not matter since validation succeeds unless the script throws an error) 
main ::  Builtin.BuiltinData -> Builtin.BuiltinData -> Builtin.BuiltinData -> Boolean

After successfully invoking the compiler on your project directory, you should notice a new output subdirectory. This output directory has a particular structure:

  • An output/[MODULE NAME] will be created for each of the modules used during compilation. This directory contains three files, some of which may be of interest to users:
    1. An externs file, which users should never need to inspect and can safely ignore.
    2. A [MODULE NAME].cfn file which contains JSON-serialized type-annotated modified CoreFn for the module. This file is what you should distribute if you intend to write a Purus library, and serves as the input to the Plutus portion of the compilation pipeline. However, this format is not human-readable, and therefore the directory also contains a...
    3. [MODULE NAME].cfn.pretty file which contains the human-readable pretty-printed CoreFn representation of the module. If your script is behaving in an unexpected way, or if you are curious as to how your module has been compiled & desugared by the PureScript compiler, you may wish to take a look at this.
  • A scripts directory, which should contain a single script.uplc file. This file contains the CBOR serialization of the main function in the Main module provided to the compiler. It should probably be noted that functions and expressions are evaluated as far as possible before being serialized. For example, main = (\x -> x + 1) 1 will produce a script.uplc file with a CBOR-serialized representation of the number 2.

Clone this wiki locally