Subject: [PATCH 3/5] gnu: Add ECL 16.1.3 for Sage.

From: Jakub Kądziołka <[email-masked]>
Date: Sat, 20 Jun 2020 23:31:58 +0200

* gnu/packages/sagemath.scm (ecl-16): New variable.
* gnu/packages/patches/ecl-16-format-directive-limit.patch,
  gnu/packages/patches/ecl-16-ignore-stderr-write-error.patch,
  gnu/packages/patches/ecl-16-libffi.patch: New files.
* gnu/local.mk (dist_patch_DATA): Register the patches.
---
 gnu/local.mk                                  |  3 +
 .../ecl-16-format-directive-limit.patch       | 83 +++++++++++++++++++
 .../ecl-16-ignore-stderr-write-error.patch    | 17 ++++
 gnu/packages/patches/ecl-16-libffi.patch      | 16 ++++
 gnu/packages/sagemath.scm                     | 23 +++++
 5 files changed, 142 insertions(+)
 create mode 100644 gnu/packages/patches/ecl-16-format-directive-limit.patch
 create mode 100644 gnu/packages/patches/ecl-16-ignore-stderr-write-error.patch
 create mode 100644 gnu/packages/patches/ecl-16-libffi.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 41b92e3830..486e7aa8cc 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -881,6 +881,9 @@ dist_patch_DATA =						\
   %D%/packages/patches/dstat-skip-devices-without-io.patch	\
   %D%/packages/patches/dune-istl-2.7-fix-non-mpi-tests.patch	\
   %D%/packages/patches/dvd+rw-tools-add-include.patch 		\
+  %D%/packages/patches/ecl-16-format-directive-limit.patch	\
+  %D%/packages/patches/ecl-16-ignore-stderr-write-error.patch	\
+  %D%/packages/patches/ecl-16-libffi.patch			\
   %D%/packages/patches/eigen-stabilise-sparseqr-test.patch	\
   %D%/packages/patches/einstein-build.patch			\
   %D%/packages/patches/elfutils-tests-ptrace.patch		\
diff --git a/gnu/packages/patches/ecl-16-format-directive-limit.patch b/gnu/packages/patches/ecl-16-format-directive-limit.patch
new file mode 100644
index 0000000000..237db92722
--- /dev/null
+++ b/gnu/packages/patches/ecl-16-format-directive-limit.patch
@@ -0,0 +1,83 @@
+Patch backported by Sage.
+
+Fix from upstream that happens to work around
+https://trac.sagemath.org/ticket/23011
+diff --git a/src/lsp/format.lsp b/src/lsp/format.lsp
+index 77ca799..53b887c 100644
+--- a/src/lsp/format.lsp
++++ b/src/lsp/format.lsp
+@@ -307,11 +307,13 @@
+                   :start (format-directive-start struct)
+                   :end (format-directive-end struct))))
+ 
++(defconstant +format-directive-limit+ (1+ (char-code #\~)))
++
+ #+formatter
+ (defparameter *format-directive-expanders*
+-  (make-array char-code-limit :initial-element nil))
++  (make-array +format-directive-limit+ :initial-element nil))
+ (defparameter *format-directive-interpreters*
+-  (make-array char-code-limit :initial-element nil))
++  (make-array +format-directive-limit+ :initial-element nil))
+ 
+ (defparameter *default-format-error-control-string* nil)
+ (defparameter *default-format-error-offset* nil)
+@@ -550,24 +552,24 @@
+            (write-string directive stream)
+            (interpret-directive-list stream (cdr directives) orig-args args))
+           (#-ecl format-directive #+ecl vector
++           (multiple-value-bind
++                 (new-directives new-args)
++               (let* ((code (char-code (format-directive-character directive)))
++                      (function
++                        (and (< code +format-directive-limit+)
++                             (svref *format-directive-interpreters* code)))
++                      (*default-format-error-offset*
++                        (1- (format-directive-end directive))))
++                 (unless function
++                   (error 'format-error
++                          :complaint "Unknown format directive."))
+                  (multiple-value-bind
+                        (new-directives new-args)
+-                     (let ((function
+-                            (svref *format-directive-interpreters*
+-                                   (char-code (format-directive-character
+-                                               directive))))
+-                           (*default-format-error-offset*
+-                            (1- (format-directive-end directive))))
+-                       (unless function
+-                         (error 'format-error
+-                                :complaint "Unknown format directive."))
+-                       (multiple-value-bind
+-                             (new-directives new-args)
+-                           (funcall function stream directive
+-                                    (cdr directives) orig-args args)
+-                         (values new-directives new-args)))
+-                   (interpret-directive-list stream new-directives
+-                                             orig-args new-args)))))
++                     (funcall function stream directive
++                              (cdr directives) orig-args args)
++                   (values new-directives new-args)))
++             (interpret-directive-list stream new-directives
++                                       orig-args new-args)))))
+       args))
+ 
+ 
+@@ -639,11 +641,12 @@
+        (values `(write-string ,directive stream)
+                more-directives))
+       (format-directive
+-       (let ((expander
+-              (aref *format-directive-expanders*
+-                    (char-code (format-directive-character directive))))
+-             (*default-format-error-offset*
+-              (1- (format-directive-end directive))))
++       (let* ((code (char-code (format-directive-character directive)))
++              (expander
++                (and (< code +format-directive-limit+)
++                     (svref *format-directive-expanders* code)))
++              (*default-format-error-offset*
++                (1- (format-directive-end directive))))
+          (if expander
+              (funcall expander directive more-directives)
+              (error 'format-error
diff --git a/gnu/packages/patches/ecl-16-ignore-stderr-write-error.patch b/gnu/packages/patches/ecl-16-ignore-stderr-write-error.patch
new file mode 100644
index 0000000000..42d213c0e9
--- /dev/null
+++ b/gnu/packages/patches/ecl-16-ignore-stderr-write-error.patch
@@ -0,0 +1,17 @@
+Patch adapted from Sage.
+diff -Naur ecl-16.1.2.orig/src/c/file.d ecl-16.1.2/src/c/file.d
+--- ecl-16.1.2.orig/src/c/file.d	2016-05-11 13:10:51.867673867 +1200
++++ ecl-16.1.2/src/c/file.d	2016-05-11 14:44:48.121907307 +1200
+@@ -3354,8 +3354,10 @@
+   ecl_disable_interrupts();
+   do {
+     out = fwrite(c, sizeof(char), n, IO_STREAM_FILE(strm));
+-  } while (out < n && restartable_io_error(strm, "fwrite"));
+-  ecl_enable_interrupts();
++  /* Ignore write errors to stderr to avoid an infinite loop */
++  } while (out < n && (IO_STREAM_FILE(strm) != stderr) && restartable_io_error(strm, "fwrite"));
++
++  ecl_enable_interrupts();
+   return out;
+ }
+ 
diff --git a/gnu/packages/patches/ecl-16-libffi.patch b/gnu/packages/patches/ecl-16-libffi.patch
new file mode 100644
index 0000000000..fc06a07606
--- /dev/null
+++ b/gnu/packages/patches/ecl-16-libffi.patch
@@ -0,0 +1,16 @@
+Patch adapted from Sage. Allows building ECL on libffi 3.3.
+diff --git a/src/c/ffi.d b/src/c/ffi.d
+index 8861303e..8a959c23 100644
+--- a/src/c/ffi.d
++++ b/src/c/ffi.d
+@@ -133,8 +133,8 @@ static struct {
+ #elif defined(X86_WIN64)
+   {@':win64', FFI_WIN64},
+ #elif defined(X86_ANY) || defined(X86) || defined(X86_64)
+-  {@':cdecl', FFI_SYSV},
+-  {@':sysv', FFI_SYSV},
++  {@':cdecl', FFI_UNIX64},
++  {@':sysv', FFI_UNIX64},
+   {@':unix64', FFI_UNIX64},
+ #endif
+ };
diff --git a/gnu/packages/sagemath.scm b/gnu/packages/sagemath.scm
index 34fe9e524c..c94020f13e 100644
--- a/gnu/packages/sagemath.scm
+++ b/gnu/packages/sagemath.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2019 Andreas Enge <[email-masked]>
 ;;; Copyright © 2019 Nicolas Goaziou <[email-masked]>
 ;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice <[email-masked]>
+;;; Copyright © 2020 Jakub Kądziołka <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -33,6 +34,7 @@
   #:use-module (gnu packages boost)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages image)
+  #:use-module (gnu packages lisp)
   #:use-module (gnu packages multiprecision)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages python)
@@ -184,6 +186,27 @@ represented as strings.")
     (license license:public-domain)
     (home-page "https://github.com/miguelmarco/libhomfly")))
 
+;; Sage 9.1 doesn't build with ECL 20.  This won't be necessary once 9.2 is
+;; released.  See https://trac.sagemath.org/ticket/22191
+(define-public ecl-16
+  (package
+    (inherit ecl)
+    (version "16.1.3")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append
+             "https://common-lisp.net/project/ecl/static/files/release/ecl"
+             "-" version ".tgz"))
+       (sha256
+        (base32 "0m0j24w5d5a9dwwqyrg0d35c0nys16ijb4r0nyk87yp82v38b9bn"))
+       (patches (search-patches
+                  "ecl-16-libffi.patch"
+                  "ecl-16-ignore-stderr-write-error.patch"
+                  "ecl-16-format-directive-limit.patch"))))
+    ;; Current ECL uses LGPL 2.1+
+    (license license:lgpl2.0+)))
+
 (define-public pynac
   (package
     (name "pynac")
-- 
2.26.2