Unverified Commit b0839a66 authored by lassulus's avatar lassulus Committed by GitHub
Browse files

writers: add writeGuile[Bin] (#364531)

parents c0f32c90 239a22c9
Loading
Loading
Loading
Loading
+129 −0
Original line number Diff line number Diff line
@@ -613,6 +613,135 @@ rec {
  */
  writeBabashkaBin = name: writeBabashka "/bin/${name}";

  /**
    `writeGuile` returns a derivation that creates an executable Guile script.

    # Inputs

    `nameOrPath` (String)
    : Name of or path to the script. The semantics is the same as that of
     `makeScriptWriter`.

    `config` (AttrSet)
    : `guile` (Optional, Derivation, Default: `pkgs.guile`)
      : Guile package used for the script.
    : `libraries` (Optional, [ Derivation ], Default: [])
      : Extra Guile libraries exposed to the script.
    : `r6rs` and `r7rs` (Optional, Boolean, Default: false)
      : Whether to adapt Guile’s initial environment to better support R6RS/
        R7RS. See the [Guile Reference Manual](https://www.gnu.org/software/guile/manual/html_node/index.html)
        for details.
    : `srfi` (Optional, [ Int ], Default: [])
      : SRFI module to be loaded into the interpreter before evaluating a
        script file or starting the REPL. See the Guile Reference Manual to
        know which SRFI are supported.
    : Other attributes are directly passed to `makeScriptWriter`.

    `content` (String)
    : Content of the script.

    # Examples

    :::{.example}
    ## `pkgs.writers.writeGuile` with default config

    ```nix
    writeGuile "guile-script" { }
    ''
      (display "Hello, world!")
    ''
    ```
    :::

    :::{.example}
    ## `pkgs.writers.writeGuile` with SRFI-1 enabled and extra libraries

    ```nix
    writeGuile "guile-script" {
      libraries = [ pkgs.guile-semver ];
      srfi = [ 1 ];
    }
    ''
      (use-modules (semver))
      (make-semver 1 (third '(2 3 4)) 5) ; => #<semver 1.4.5>
    ''
    ```
    :::
  */
  writeGuile =
    nameOrPath:
    {
      guile ? pkgs.guile,
      libraries ? [ ],
      r6rs ? false,
      r7rs ? false,
      srfi ? [ ],
      ...
    }@config:
    content:
    assert builtins.all builtins.isInt srfi;
    let
      finalGuile = pkgs.buildEnv {
        name = "guile-env";
        paths = [ guile ] ++ libraries;
        passthru = {
          inherit (guile) siteDir siteCcacheDir;
        };
        meta.mainProgram = guile.meta.mainProgram or "guile";
      };
    in
    makeScriptWriter
      (
        (builtins.removeAttrs config [
          "guile"
          "libraries"
          "r6rs"
          "r7rs"
          "srfi"
        ])
        // {
          interpreter = "${lib.getExe finalGuile} \\";
          makeWrapperArgs = [
            "--set"
            "GUILE_LOAD_PATH"
            "${finalGuile}/${finalGuile.siteDir}:${finalGuile}/lib/scheme-libs"
            "--set"
            "GUILE_LOAD_COMPILED_PATH"
            "${finalGuile}/${finalGuile.siteCcacheDir}:${finalGuile}/lib/libobj"
            "--set"
            "LD_LIBRARY_PATH"
            "${finalGuile}/lib/ffi"
            "--set"
            "DYLD_LIBRARY_PATH"
            "${finalGuile}/lib/ffi"
          ];
        }
      )
      nameOrPath
      /*
        Spaces, newlines and tabs are significant for the "meta switch" of Guile, so
        certain complication must be made to ensure correctness.
      */
      (
        lib.concatStringsSep "\n" [
          (lib.concatStringsSep " " (
            [ "--no-auto-compile" ]
            ++ lib.optional r6rs "--r6rs"
            ++ lib.optional r7rs "--r7rs"
            ++ lib.optional (srfi != [ ]) ("--use-srfi=" + concatMapStringsSep "," builtins.toString srfi)
            ++ [ "-s" ]
          ))
          "!#"
          content
        ]
      );

  /**
    writeGuileBin takes the same arguments as writeGuile but outputs a directory
    (like writeScriptBin)
  */
  writeGuileBin = name: writeGuile "/bin/${name}";

  /**
    writeHaskell takes a name, an attrset with libraries and haskell version (both optional)
    and some haskell source code and returns an executable.
+55 −0
Original line number Diff line number Diff line
{
  haskellPackages,
  lib,
  guile-lib,
  akkuPackages,
  nodePackages,
  perlPackages,
  python3Packages,
@@ -26,6 +28,8 @@ let
    writeFish
    writeFishBin
    writeFSharp
    writeGuile
    writeGuileBin
    writeHaskell
    writeHaskellBin
    writeJS
@@ -109,6 +113,12 @@ recurseIntoAttrs {
      ''
    );

    guile = expectSuccessBin (
      writeGuileBin "test-writers-guile-bin" { } ''
        (display "success\n")
      ''
    );

    rust = expectSuccessBin (
      writeRustBin "test-writers-rust-bin" { } ''
        fn main(){
@@ -249,6 +259,51 @@ recurseIntoAttrs {
      ''
    );

    guile = expectSuccess (
      writeGuile "test-writers-guile"
        {
          libraries = [ guile-lib ];
          srfi = [ 1 ];
        }
        ''
          (use-modules (unit-test))
          (assert-true (= (second '(1 2 3))
                       2))
          (display "success\n")
        ''
    );

    guileR6RS = expectSuccess (
      writeGuile "test-writers-guile-r6rs"
        {
          r6rs = true;
          libraries = with akkuPackages; [ r6rs-slice ];
        }
        ''
          (import (rnrs base (6))
                  (rnrs io simple (6))
                  (slice))
          (assert (equal? (slice '(1 2 3) 0 2)
                          '(1 2)))
          (display "success\n")
        ''
    );

    guileR7RS = expectSuccess (
      writeGuile "test-writers-guile-r7rs"
        {
          r7rs = true;
        }
        ''
          (import (scheme write)
                  (srfi 1))
          (unless (= (second '(1 2 3))
                     2)
                  (error "The value should be 2."))
          (display "success\n")
        ''
    );

    haskell = expectSuccess (
      writeHaskell "test-writers-haskell" { libraries = [ haskellPackages.acme-default ]; } ''
        import Data.Default