gcl-2.7.1 released [stable]

33 views
Skip to first unread message

Camm Maguire

unread,
Apr 11, 2025, 12:14:58 PMApr 11
to info...@gnu.org, ca...@maguirefamily.org, gcl-...@gnu.org, Matt Kaufmann, Warren A. Hunt Jr., Gordon Shaw Novak, Waldek Hebisch, fricas...@googlegroups.com, Robert Dodier, <maxima-discuss@lists.sourceforge.net>, Tim Daly, axiom-d...@nongnu.org, Chun Tian (binghe), Jerry James

GCL is an implementation of Common Lisp. Among other uses the program
serves as a compiler and runtime host for various end user programs like
maxima, ACL2, axiom, FriCAS,and hol88.

Please see the release notes at

https://www.gnu.org/software/gcl/RELEASE-2.7.1.html.

Here are the compressed sources and a GPG detached signature:
https://www.gnu.org/software/gcl//gcl-2.7.1.tar.gz
https://www.gnu.org/software/gcl//gcl-2.7.1.tar.gz.sig

Use a mirror for higher download bandwidth:
https://www.gnu.org/order/ftp.html

Here are the SHA1 and SHA256 checksums:

bdfa103d62824de6037f1153867dbd95b8e1e934 gcl-2.7.1.tar.gz
edC7Zbgt+BwHi8VcTNo/5Ndm2H47/hD94LL3KCBOEBU gcl-2.7.1.tar.gz

The SHA256 checksum is base64 encoded, instead of the
hexadecimal encoding that most checksum tools default to.

Use a .sig file to verify that the corresponding file (without the
.sig suffix) is intact. First, be sure to download both the .sig file
and the corresponding tarball. Then, run a command like this:

gpg --verify gcl-2.7.1.tar.gz.sig

The signature should match the fingerprint of the following key:

pub ed25519 2023-01-10 [SC]
6A74 659F 1F23 191E 97F9 B65E 1AF2 9494 BE51 2BAE
uid Camm Maguire <ca...@maguirefamily.org>

If that command fails because you don't have the required public key,
or that public key has expired, try the following commands to retrieve
or refresh it, and then rerun the 'gpg --verify' command.

gpg --recv-keys 6A74659F1F23191E97F9B65E1AF29494BE512BAE

As a last resort to find the key, you can try the official GNU
keyring:

wget -q https://ftp.gnu.org/gnu/gnu-keyring.gpg
gpg --keyring gnu-keyring.gpg --verify gcl-2.7.1.tar.gz.sig


--
Camm Maguire ca...@maguirefamily.org
==========================================================================
"The earth is but one country, and mankind its citizens." -- Baha'u'llah
signature.asc

Waldek Hebisch

unread,
Apr 15, 2025, 12:02:31 AMApr 15
to Camm Maguire, fricas...@googlegroups.com
Thanks for info. For me current FriCAS trunk build fine, however
there are two regressions compared to gcl-2.6.14.

1) The FriCAS snippet below gives no output using gcl-2.7.1:

x+-> if x < 0 then - x else x
abs1 := %
(x,y) +-> abs1(x) > abs1(y)
sort(%,[3,9,-4,10,-3,-1,-9,5])

2) The FriCAS snippet below in final step gives old (stale) output
corresponding to n==10, instead of output corresponding to n==15:

)set functions cache all
n==10
v==[i for i in 0..n]
v
n==15
v


--
Waldek Hebisch

Camm Maguire

unread,
Apr 17, 2025, 2:15:15 PMApr 17
to Waldek Hebisch, ca...@maguirefamiy.org, fricas...@googlegroups.com
Greetings, and thanks for the report!

Is this part of the regression tests? If not, where did it come from?

Take care,

Waldek Hebisch

unread,
Apr 17, 2025, 3:35:58 PMApr 17
to Camm Maguire, Waldek Hebisch, ca...@maguirefamiy.org, fricas...@googlegroups.com
On Thu, Apr 17, 2025 at 02:13:39PM -0400, Camm Maguire wrote:
> Greetings, and thanks for the report!
>
> Is this part of the regression tests? If not, where did it come from?
>
> Take care,
>
> Waldek Hebisch <de...@fricas.org> writes:
>
> > Thanks for info. For me current FriCAS trunk build fine, however
> > there are two regressions compared to gcl-2.6.14.
> >
> > 1) The FriCAS snippet below gives no output using gcl-2.7.1:
> >
> > x+-> if x < 0 then - x else x
> > abs1 := %
> > (x,y) +-> abs1(x) > abs1(y)
> > sort(%,[3,9,-4,10,-3,-1,-9,5])

This one is from FriCAS Book, Chapter 6, section 6.17.1

> > 2) The FriCAS snippet below in final step gives old (stale) output
> > corresponding to n==10, instead of output corresponding to n==15:
> >
> > )set functions cache all
> > n==10
> > v==[i for i in 0..n]
> > v
> > n==15
> > v

This one is an extract from test file 'src/input/stream2.input'

--
Waldek Hebisch

Camm Maguire

unread,
Apr 27, 2025, 1:55:21 PMApr 27
to Waldek Hebisch, ca...@maguirefamily.org, ca...@maguirefamiy.org, fricas...@googlegroups.com
Greetings! I'm wondering if you can help me map this to a lisp function
failure, or at least point me in the right direction. I think the two
are related. The sort is fine with abs1 -> abs. Or if abs1(x: Integer):
Integer == abs(x). I cannot trace this. |abs1| is not fboundp. I do
not understand how axiom handles anonymous function calls, or why these
are considered anonymous, as abs1 is a name.

Waldek Hebisch

unread,
Apr 27, 2025, 7:16:59 PMApr 27
to Camm Maguire, Waldek Hebisch, ca...@maguirefamiy.org, fricas...@googlegroups.com
On Sun, Apr 27, 2025 at 01:55:13PM -0400, Camm Maguire wrote:
> Greetings! I'm wondering if you can help me map this to a lisp function
> failure, or at least point me in the right direction. I think the two
> are related. The sort is fine with abs1 -> abs. Or if abs1(x: Integer):
> Integer == abs(x). I cannot trace this. |abs1| is not fboundp. I do
> not understand how axiom handles anonymous function calls, or why these
> are considered anonymous, as abs1 is a name.
>
> >> > 1) The FriCAS snippet below gives no output using gcl-2.7.1:
> >> >
> >> > x+-> if x < 0 then - x else x
> >> > abs1 := %
> >> > (x,y) +-> abs1(x) > abs1(y)
> >> > sort(%,[3,9,-4,10,-3,-1,-9,5])

Tracing like below:

x+-> if x < 0 then - x else x
abs1 := %
(x,y) +-> abs1(x) > abs1(y)
)lisp (trace |evalTargetedADEF1|)
)lisp (trace |compileTargetedADEF|)
)lisp (trace |compileBody|)
)lisp (trace |compileADEFBody|)
)lisp (trace |compileInteractive|)
)lisp (trace |timedOptimization|)
)lisp (trace |compQuietly|)
)lisp (trace |COMP|)
)lisp (trace |COMP_2|)
)lisp (trace |COMP370|)
)lisp (trace compile-defun)
)lisp (trace compile)
sort(%,[3,9,-4,10,-3,-1,-9,5])

gives me as the last part:

9> (COMPILE-DEFUN
|*2;anonymousFunction;0;frame0;internal|
(DEFUN
|*2;anonymousFunction;0;frame0;internal|
(#1=#:G12 #2=#:G13 |envArg|)
(>
(SPADCALL #1# '(#<function 0000000001d08e20>))
(SPADCALL #2# '(#<function 0000000001d092d0>)))))
10> (COMPILE
|*2;anonymousFunction;0;frame0;internal|)

So it seems that trouble is in 'compile' called from 'compile-defun'.
'compile-defun' is:

(defun compile-defun (name body) (eval body) (compile name))

I also have:

)lisp (describe #'|*2;anonymousFunction;0;frame0;internal|)

#<function 0000000001d09300> - SYSTEM:INTERPRETED-FUNCTION

which confirms that 'eval' part worked, but 'compile' failed.
Calling |*2;anonymousFunction;0;frame0;internal| seem to work.

--
Waldek Hebisch

Camm Maguire

unread,
Apr 28, 2025, 11:25:43 AMApr 28
to Waldek Hebisch, fricas...@googlegroups.com, ca...@maguirefamiy.org
Greetings, and thanks so much for this very helpful report! I've found
the cause and am testing the fix now.

Alas, this does not fix the other issue:

> > 2) The FriCAS snippet below in final step gives old (stale) output
> > corresponding to n==10, instead of output corresponding to n==15:
> >
> > )set functions cache all
> > n==10
> > v==[i for i in 0..n]
> > v
> > n==15
> > v

You probably already know what with a second

n==15
v

we get the expected results. Might you isolate this one as well as you
did with the last?

Take care,


Waldek Hebisch <de...@fricas.org> writes:

Waldek Hebisch

unread,
Apr 28, 2025, 5:05:41 PMApr 28
to Camm Maguire, Waldek Hebisch, fricas...@googlegroups.com
On Mon, Apr 28, 2025 at 11:25:37AM -0400, Camm Maguire wrote:
> Greetings, and thanks so much for this very helpful report! I've found
> the cause and am testing the fix now.

Good, thanks.

> Alas, this does not fix the other issue:
>
> > > 2) The FriCAS snippet below in final step gives old (stale) output
> > > corresponding to n==10, instead of output corresponding to n==15:
> > >
> > > )set functions cache all
> > > n==10
> > > v==[i for i in 0..n]
> > > v
> > > n==15
> > > v
>
> You probably already know what with a second
>
> n==15
> v
>
> we get the expected results. Might you isolate this one as well as you
> did with the last?

AFAICS the attached Lisp file is doing the same sequence of Lisp
operations and exhibits the same problem. It depends on FriCAS
macros, run via

)read ttt3b.lisp

at FriCAS prompt.

--
Waldek Hebisch
ttt3b.lisp

Camm Maguire

unread,
Apr 28, 2025, 5:32:36 PMApr 28
to Waldek Hebisch, fricas...@googlegroups.com
Greetings, and thanks so much!

Waldek Hebisch <de...@fricas.org> writes:

> AFAICS the attached Lisp file is doing the same sequence of Lisp
> operations and exhibits the same problem. It depends on FriCAS
> macros, run via
>
> )read ttt3b.lisp
>
> at FriCAS prompt.

These may be the same operations, and my fix for the first issue may
address a hidden compiler failure if any, but something else appears to
be going on:


=============================================================================
(sid)camm@glory:/mnt/sda4/debian/fricas$ fricas
openServer result 0
FriCAS Computer Algebra System
Version: FriCAS 1.3.11 built with gcl 2.7.1
Timestamp: Sun Apr 27 01:41:50 UTC 2025
-----------------------------------------------------------------------------
Issue )copyright to view copyright notices.
Issue )summary for a summary of useful system commands.
Issue )quit to leave FriCAS and return to shell.
-----------------------------------------------------------------------------


(1) -> )read /home/camm/ttt3b.lisp
(0 1 2 3 4 5 6 7 8 9 10)
(0 1 2 3 4 5 6 7 8 9 10)
(1) -> )read /home/camm/ttt3b.lisp
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(0 1 2 3 4 5 6 7 8 9 10)
(1) -> )read /home/camm/ttt3b.lisp
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(0 1 2 3 4 5 6 7 8 9 10)
(1) -> )quit


(sid)camm@glory:/mnt/sda4/debian/fricas$ fricas
openServer result 0
FriCAS Computer Algebra System
Version: FriCAS 1.3.11 built with gcl 2.7.1
Timestamp: Sun Apr 27 01:41:50 UTC 2025
-----------------------------------------------------------------------------
Issue )copyright to view copyright notices.
Issue )summary for a summary of useful system commands.
Issue )quit to leave FriCAS and return to shell.
-----------------------------------------------------------------------------


(1) -> )fin
GCL (GNU Common Lisp) 2.7.1 Thu Apr 10 09:38:27 PM EDT 2025 ANSI git: Version_2_7_2ore2
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License: GPL due to GPL'ed components: (XGCL UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/

BOOT>(in-package :compiler)

#<"COMPILER" package>

COMPILER>(defun encap-src-val (val)
(typecase val
(function (afe (cons 'df nil) (mf (fle val))))
(cons (cons (encap-src-val (car val)) (encap-src-val (cdr val))))
(t val)))

(defun c1constant-value (val always &aux (val (if (exit-to-fmla-p) (not (not val)) val)))
(case
val
((nil) (c1nil))
((t) (c1t))
(otherwise
(let ((l (c1constant-value-object val (or always (when *compiler-compile* (not *keep-gaz*))))))
(when l
`(location
,(make-info :type (or (ltvp val)
(object-type (encap-src-val val))))
,l))))))

ENCAP-SRC-VAL

COMPILER>
C1CONSTANT-VALUE

COMPILER>(in-package :boot)

#<"BOOT" package>

BOOT>(|fricas_restart|)
FriCAS Computer Algebra System
Version: FriCAS 1.3.11 built with gcl 2.7.1
Timestamp: Sun Apr 27 01:41:50 UTC 2025
-----------------------------------------------------------------------------
Issue )copyright to view copyright notices.
Issue )summary for a summary of useful system commands.
Issue )quit to leave FriCAS and return to shell.
-----------------------------------------------------------------------------


(1) -> )read /home/camm/ttt3b.lisp
(0 1 2 3 4 5 6 7 8 9 10)
(0 1 2 3 4 5 6 7 8 9 10)
(1) -> )read /home/camm/ttt3b.lisp
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(0 1 2 3 4 5 6 7 8 9 10)
(1) -> )read /home/camm/ttt3b.lisp
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(0 1 2 3 4 5 6 7 8 9 10)
(1) -> )set functions cache all
In general, interpreter functions will cache all values.
(1) -> n==10
Type: Void
(2) -> v==[i for i in 0..n]
Type: Void
(3) -> v
Compiling body of rule n to compute value of type PositiveInteger
n will cache all previously computed values.
Compiling body of rule v to compute value of type List(
NonNegativeInteger)
v will cache all previously computed values.

(3) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Type: List(NonNegativeInteger)
(4) -> n==15
Compiled code for n has been cleared.
Compiled code for v has been cleared.
1 old definition(s) deleted for function or rule n
Type: Void
(5) -> v
Compiling body of rule n to compute value of type PositiveInteger
n will cache all previously computed values.
Compiling body of rule v to compute value of type List(
NonNegativeInteger)
v will cache all previously computed values.

(5) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Type: List(NonNegativeInteger)
(6) -> n==15
Compiled code for n has been cleared.
Compiled code for v has been cleared.
1 old definition(s) deleted for function or rule n
Type: Void
(7) -> v
Compiling body of rule n to compute value of type PositiveInteger
n will cache all previously computed values.
Compiling body of rule v to compute value of type List(
NonNegativeInteger)
v will cache all previously computed values.

(7) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
Type: List(NonNegativeInteger)
(8) ->
=============================================================================

Please let me know if I'm missing something....

Take care,

Waldek Hebisch <de...@fricas.org> writes:

Waldek Hebisch

unread,
Apr 28, 2025, 7:00:48 PMApr 28
to Camm Maguire, Waldek Hebisch, fricas...@googlegroups.com
On Mon, Apr 28, 2025 at 05:32:29PM -0400, Camm Maguire wrote:
> Greetings, and thanks so much!
>
> Waldek Hebisch <de...@fricas.org> writes:
>
> > AFAICS the attached Lisp file is doing the same sequence of Lisp
> > operations and exhibits the same problem. It depends on FriCAS
> > macros, run via
> >
> > )read ttt3b.lisp
> >
> > at FriCAS prompt.
>
> These may be the same operations, and my fix for the first issue may
> address a hidden compiler failure if any, but something else appears to
> be going on:

I am not sure what you want to say above.

> =============================================================================
> (sid)camm@glory:/mnt/sda4/debian/fricas$ fricas
> openServer result 0
> FriCAS Computer Algebra System
> Version: FriCAS 1.3.11 built with gcl 2.7.1
> Timestamp: Sun Apr 27 01:41:50 UTC 2025
> -----------------------------------------------------------------------------
> Issue )copyright to view copyright notices.
> Issue )summary for a summary of useful system commands.
> Issue )quit to leave FriCAS and return to shell.
> -----------------------------------------------------------------------------
>
>
> (1) -> )read /home/camm/ttt3b.lisp
> (0 1 2 3 4 5 6 7 8 9 10)
> (0 1 2 3 4 5 6 7 8 9 10)
> (1) -> )read /home/camm/ttt3b.lisp
> (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
> (0 1 2 3 4 5 6 7 8 9 10)
> (1) -> )read /home/camm/ttt3b.lisp
> (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
> (0 1 2 3 4 5 6 7 8 9 10)
> (1) -> )quit

That is what I see with gcl. Expected output (and what I get with
sbcl) is:

(0 1 2 3 4 5 6 7 8 9 10)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(0 1 2 3 4 5 6 7 8 9 10)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(0 1 2 3 4 5 6 7 8 9 10)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)

So on first run gcl uses correct (current) value of n. But
susequent runs apparently use n from previous iteration.
That is the same result as previously.
This is slightly different sequence of operations, but consistent
with "uses n from previous run". Running Lisp version multiple
times corresponds to:

n==10
v==[i for i in 0..n]
v
n==15
v
n==10
v
n==15
v
n==10
v
n==15
v

There is a difference which probably is insignificant: FriCAS uses
fresh gensyms for local variables. In Lisp code I use ordinary
variables.

Looking more at the issue, I suspect that gcl is inlining definition
of |*0;n;1;frame1;AUX|. I am not sure if Lisp standard allows
such inlining (those are discrete definitions via separate evals,
not parts of single file). In this case I can (re)define called
function first and after that (re)define caller. Such change
seem to fix this problem. However, FriCAS in many places
assumes that redefinitions on the fly work as expected.

--
Waldek Hebisch

Camm Maguire

unread,
Apr 29, 2025, 10:13:01 AMApr 29
to Waldek Hebisch, ca...@maguirefamily.org, fricas...@googlegroups.com
Greetings!

Waldek Hebisch <de...@fricas.org> writes:

> Looking more at the issue, I suspect that gcl is inlining definition
> of |*0;n;1;frame1;AUX|. I am not sure if Lisp standard allows
> such inlining (those are discrete definitions via separate evals,
> not parts of single file). In this case I can (re)define called
> function first and after that (re)define caller. Such change
> seem to fix this problem. However, FriCAS in many places
> assumes that redefinitions on the fly work as expected.

Yes, this is it. GCL collects a lot of information about compiled
functions and uses it (hopefully effectively) when optimizing the
caller. For example, 'reverse returns a sequence, and GCL will assume
this when compiling code that calls 'reverse, but if someone
subsequently changes 'reverse to return a number, that number will be
returned to the caller but will likely not be properly handled.

The ideal is if one can arrange to define (and optimally compile) the
callee before the caller. If the callee is expected to change, this
definition should be generic enough to encompass all allowed subsequent
changes.

Alternatively, one can set the assumed signature info with a
declaration:

(DEFUN |*0;n;1;frame1| (|envArg|)
(declare (ftype (function (t) t) |*0;n;1;frame1;AUX|))
(PROG (XG7)
(RETURN
(COND ((LETT XG7 (HGET |*0;n;1;frame1;AL| NIL)) XG7)
((QUOTE T) (HPUT |*0;n;1;frame1;AL| NIL (|*0;n;1;frame1;AUX| |envArg|)))))))

One could use (function (t) integer) or (function (t) fixnum) as
appropriate. One can also declaim these declarations at the toplevel.

Other relevant function call declarations include (declare (notinline
fun)) and (declare (inline fun)). GCL will not inline the fun call
unless (declaim (inline fun)) was issued somewhere at the toplevel, but
one can override this setting with local declarations.

Not really relevant yet but on the horizon are other function
properties, including 'side-effects'. Many functions are known to
return atomic values given certain inputs, and further have no
'side-effects' as in making other changes to the global state. In such
situations GCL can skip the call altogether. I suppose we will have to
invent another declaration, as the spec allows, to override this
determination in the caller if/when this goes online.

One can see the current (default) signature info with (si::signature
'fun) or (si::signature #'fun).

With the |*0;n;1;frame1| above the test works as expected. Please let
me know if this clears the path for fricas or if we need to provide some
other facility.

Take care,

Waldek Hebisch

unread,
Apr 29, 2025, 4:31:53 PMApr 29
to Camm Maguire, Waldek Hebisch, fricas...@googlegroups.com
On Tue, Apr 29, 2025 at 10:12:54AM -0400, Camm Maguire wrote:
> Greetings!
>
> Waldek Hebisch <de...@fricas.org> writes:
>
> > Looking more at the issue, I suspect that gcl is inlining definition
> > of |*0;n;1;frame1;AUX|. I am not sure if Lisp standard allows
> > such inlining (those are discrete definitions via separate evals,
> > not parts of single file). In this case I can (re)define called
> > function first and after that (re)define caller. Such change
> > seem to fix this problem. However, FriCAS in many places
> > assumes that redefinitions on the fly work as expected.
>
> Yes, this is it. GCL collects a lot of information about compiled
> functions and uses it (hopefully effectively) when optimizing the
> caller. For example, 'reverse returns a sequence, and GCL will assume
> this when compiling code that calls 'reverse, but if someone
> subsequently changes 'reverse to return a number, that number will be
> returned to the caller but will likely not be properly handled.

That is very good when done within a single Lisp file. Between
files it is a tradeof: FriCAS also is a developement system
and important part is ability to separately compile modified
files. Assumption that Lisp type will not change is somewhat
limiting for developement.

The case in question deals with user defined functions. Here
user should be free to redefine functions in arbitrary ways,
including arbitrary change to types.

FYI: FriCAS tracks dependencies between functions and variables.
When a function or a variable changes it recompiles all functions
which depend on it. This probably avoids most problems. But
FriCAS encourages recursion and for recursive functions some
callers needs to be compiled before called functions.

> The ideal is if one can arrange to define (and optimally compile) the
> callee before the caller. If the callee is expected to change, this
> definition should be generic enough to encompass all allowed subsequent
> changes.

In case of user defined functions types depend on user. Current
type machinery puts enough load on users, IMO extra restricitons
would be too much.
I have commited patch changing order of definition, that should
solve the second regression. And you wrote that you solved the
first one, that fixes current troubles.

Concerning longer term (after next gcl release), there are
potential troubles. ATM I do not know how serious they are.
We probably can add 'notinline' declaration for user defined
functions.

--
Waldek Hebisch

Camm Maguire

unread,
Apr 30, 2025, 10:32:06 AMApr 30
to Waldek Hebisch, ca...@maguirefamily.org, gcl-...@gnu.org, fricas...@googlegroups.com
Greetings! It looks like we're all set. Just wanted to comment on:

Waldek Hebisch <de...@fricas.org> writes:

> On Tue, Apr 29, 2025 at 10:12:54AM -0400, Camm Maguire wrote:
>> Greetings!
>>
>> Waldek Hebisch <de...@fricas.org> writes:
>>
> FYI: FriCAS tracks dependencies between functions and variables.
> When a function or a variable changes it recompiles all functions
> which depend on it. This probably avoids most problems. But
> FriCAS encourages recursion and for recursive functions some
> callers needs to be compiled before called functions.
>

This would also take care of the problem. At one time, GCL experimented
with automatically recompiling callers with signature conflicts on load
of a signature-changed callee. This proved too disconcerting and was
dropped, but the hooks remain in the code.
Reply all
Reply to author
Forward
0 new messages