diff mbox series

[bug#53878,04/11] gnu: chez-and-racket-bootstrap: Add utilities for Chez machine types.

Message ID 20220213215127.218952-5-philip@philipmcgrath.com
State Accepted
Headers show
Series Update Racket to 8.4. Adjust Chez Scheme packages. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

Philip McGrath Feb. 13, 2022, 9:51 p.m. UTC
* gnu/packages/chez-and-racket-bootstrap.scm (chez-machine->unthreaded,
chez-machine->upstream-restriction, chez-machine->nix-system,
nix-system->chez-machine): New private functions.
(%nix-arch-to-chez-alist, %nix-os-to-chez-alist): New private constants.
(chez-scheme)[supported-systems]: Compute based on
'nix-system->chez-machine' and 'chez-machine->upstream-restriction'.
---
 gnu/packages/chez-and-racket-bootstrap.scm | 142 ++++++++++++++++++++-
 1 file changed, 140 insertions(+), 2 deletions(-)

Comments

Liliana Marie Prikler Feb. 14, 2022, 2:34 p.m. UTC | #1
Hi,

Am Sonntag, dem 13.02.2022 um 16:51 -0500 schrieb Philip McGrath:
> [...]
> +(define (chez-machine->upstream-restriction mach)
> +  "Given a string MACH naming a Chez Scheme machine type, returns a
> symbol
> +naming a restriction on the upstream Chez Scheme implementation
> compared to
> +the Racket variant, or @code{#f} if no such restriction exists.  The
> +restriction is reported for the architecture--OS pair, regardless of
> whether
> +MACH specifies a threaded or an unthreaded variant.
> +
> +Possible restrictions currently include:
> +@itemize @bullet
> +@item
> +@code{'no-threads}: Support for native threads is not available
> upstream.
> +@item
> +@code{'no-support}: The upstream release doesn't claim to support
> this
> +architecture--OS combination at all.
> +@end itemize
> +
> +See @code{chez-machine->nix-system} for more details about
> acceptable values
> +for MACH."
> +  (let ((mach (chez-machine->unthreaded mach)))
> +    (cond
> +     ((string-prefix? "arm64" mach)
> +      'no-support)
> +     ((string-prefix? "arm32" mach)
> +      (if (string-suffix? "le" mach)
> +          'no-threads
> +          'no-support))
> +     ((string-prefix? "ppc32" mach)
> +      (if (string-suffix? "le" mach)
> +          #f
> +          'no-support))
> +     (else
> +      #f))))
-> is a conversion operator, not an "accessor".
"upstream-restriction" sounds rather negative, I'd rather have (chez-
machine-features), which yields #f if the machine is unsupported and a
(possibly empty) list of features otherwise, such as '(threads).

I'm also not quite sure what the point is behind using chez machines
here.  Why not simply test the systems with the predicates we already
have, i.e. target-arm64?, target-arm32?, target-linux?, target-ppc32?,
...

And as a minor pet peeve, you ought to spell out machine.


> +(define* (nix-system->chez-machine #:optional (system (%current-
> system))
> +                                   #:key (threads? 'always))
> +  "Return the Chez Scheme machine type corresponding to the Nix
> system
> +identifier SYSTEM, or @code{#f} if the translation of SYSTEM to a
> Chez Scheme
> +machine type is undefined.
> +
> +When THREADS? is @code{'always} (the default), the threaded variant
> of the
> +machine type will be returned: note that the package returned by
> +@code{chez-scheme-for-system} will always support native threads. 
> When
> +THREADS? is @code{#f}, the unthreaded machine type will be
> returned.  If
> +THREADS? is @code{'upstream} (the default), the threaded variant of
> the
> +machine type will be returned if and only if it is supported by
> upstream Chez
> +Scheme (see @code{chez-machine->upstream-restriction}).  If THREADS?
> is any
> +other value, an exception is raised."
What's the point in having THREADS? 'always?  In any case, assuming
chez-machine-features is to be exported, this can easily be checked --
even if not, we can add the check internally by writing 
  #:key (threads? (chez-supports-threads? system))

> +  (let* ((hyphen (string-index system #\-))
> +         (nix-arch (substring system 0 hyphen))
> +         (nix-os (substring system (+ 1 hyphen)))
> +         (chez-arch (assoc-ref %nix-arch-to-chez-alist nix-arch))
> +         (chez-os (assoc-ref %nix-os-to-chez-alist nix-os))
> +         (mach (and chez-arch chez-os (string-append chez-arch chez-
> os))))
This series of let-bindings should probably be done in a separate
function called nix-system->chez-machine.

Cheers
Philip McGrath Feb. 16, 2022, 10:54 p.m. UTC | #2
Hi,

On 2/14/22 09:34, Liliana Marie Prikler wrote:
> Hi,
> 
> Am Sonntag, dem 13.02.2022 um 16:51 -0500 schrieb Philip McGrath:
>> [...]
>> +(define (chez-machine->upstream-restriction mach)
>> +  "Given a string MACH naming a Chez Scheme machine type, returns a
>> symbol
>> +naming a restriction on the upstream Chez Scheme implementation
>> compared to
>> +the Racket variant, or @code{#f} if no such restriction exists.  The
>> +restriction is reported for the architecture--OS pair, regardless of
>> whether
>> +MACH specifies a threaded or an unthreaded variant.
>> +
>> +Possible restrictions currently include:
>> +@itemize @bullet
>> +@item
>> +@code{'no-threads}: Support for native threads is not available
>> upstream.
>> +@item
>> +@code{'no-support}: The upstream release doesn't claim to support
>> this
>> +architecture--OS combination at all.
>> +@end itemize
>> +
>> +See @code{chez-machine->nix-system} for more details about
>> acceptable values
>> +for MACH."
>> +  (let ((mach (chez-machine->unthreaded mach)))
>> +    (cond
>> +     ((string-prefix? "arm64" mach)
>> +      'no-support)
>> +     ((string-prefix? "arm32" mach)
>> +      (if (string-suffix? "le" mach)
>> +          'no-threads
>> +          'no-support))
>> +     ((string-prefix? "ppc32" mach)
>> +      (if (string-suffix? "le" mach)
>> +          #f
>> +          'no-support))
>> +     (else
>> +      #f))))
> -> is a conversion operator, not an "accessor".

I thought of this as a conversion more than an accessor.

> "upstream-restriction" sounds rather negative, I'd rather have (chez-
> machine-features), which yields #f if the machine is unsupported and a
> (possibly empty) list of features otherwise, such as '(threads).
> 
> I'm also not quite sure what the point is behind using chez machines
> here.  Why not simply test the systems with the predicates we already
> have, i.e. target-arm64?, target-arm32?, target-linux?, target-ppc32?,
> ...

I agree that the name of this procedure should avoid sounding negative: 
'restriction' was the best I'd come up with so far. I think I like 
'chez-machine-features' somewhat better, but with a few reservations.

Using predicates like 'target-arm32?' makes some sense overall, and I'll 
try it. One subtly is that systems supported by neither upstream nor 
Racket are currently handled by `and=>` in clients.

Also, I guess it's odd to have this function operate on Chez Scheme 
machine types anyway, since a machine type specifies threaded or unthreaded.

I'm currently thinking something like:

--8<---------------cut here---------------start------------->8---
(define* (chez-upstream-features-for-system #:optional
                                             (system (or 
(%current-target-system)
 
(%current-system))))
   (cond
    ((not (nix-system->chez-machine system))
     #f)
    ((target-arm64? system)
     #f)
    ((target-arm32? system)
     (and (target-linux? system)
          '()))
    ((target-ppc32? system)
     (and (target-linux? system)
          '(threads)))
    (else
     '(threads))))
--8<---------------cut here---------------end--------------->8---

Alternatively, there could be an argument called something like 
"variant", where the default would be 'upstream or maybe #f, and 
supplying 'racket would always return '(threads). (Racket CS requires 
the threaded version of Chez Scheme, so the chez-scheme-for-racket has 
consistently added thread support immediately upon adding any new target.)

> 
> And as a minor pet peeve, you ought to spell out machine.
> 

Ok, will do.

> 
>> +(define* (nix-system->chez-machine #:optional (system (%current-
>> system))

This should have been (or (%current-target-system) (%current-system)).

>> +                                   #:key (threads? 'always))
>> +  "Return the Chez Scheme machine type corresponding to the Nix
>> system
>> +identifier SYSTEM, or @code{#f} if the translation of SYSTEM to a
>> Chez Scheme
>> +machine type is undefined.
>> +
>> +When THREADS? is @code{'always} (the default), the threaded variant
>> of the
>> +machine type will be returned: note that the package returned by
>> +@code{chez-scheme-for-system} will always support native threads.
>> When
>> +THREADS? is @code{#f}, the unthreaded machine type will be
>> returned.  If
>> +THREADS? is @code{'upstream} (the default), the threaded variant of
>> the
>> +machine type will be returned if and only if it is supported by
>> upstream Chez
>> +Scheme (see @code{chez-machine->upstream-restriction}).  If THREADS?
>> is any
>> +other value, an exception is raised."
> What's the point in having THREADS? 'always?  In any case, assuming
> chez-machine-features is to be exported, this can easily be checked --
> even if not, we can add the check internally by writing
>    #:key (threads? (chez-supports-threads? system))
> 
>> +  (let* ((hyphen (string-index system #\-))
>> +         (nix-arch (substring system 0 hyphen))
>> +         (nix-os (substring system (+ 1 hyphen)))
>> +         (chez-arch (assoc-ref %nix-arch-to-chez-alist nix-arch))
>> +         (chez-os (assoc-ref %nix-os-to-chez-alist nix-os))
>> +         (mach (and chez-arch chez-os (string-append chez-arch chez-
>> os))))
> This series of let-bindings should probably be done in a separate
> function called nix-system->chez-machine.

On the one hand, the result of 'chez-scheme-for-system' will always 
support threads, so being threaded by default is convenient. On the 
other hand, it looks like I've reduced the use of this function (by 
searching for files rather than coding in the machine type directory) 
enough that it doesn't have a big impact either way. It will be more 
important when we support cross-compilation, and I think we should keep 
these functions internal and defer as much as possible of their API 
design until then.

For now, I think I'll say that it's unspecified whether the result is a 
threaded or unthreaded machine type and add 
`chez-machine->{un,}threaded` as needed.

-Philip
Liliana Marie Prikler Feb. 17, 2022, 7:24 a.m. UTC | #3
Hi,

Am Mittwoch, dem 16.02.2022 um 17:54 -0500 schrieb Philip McGrath:
> > > +See @code{chez-machine->nix-system} for more details about
> > > acceptable values
> > > +for MACH."
> > > +  (let ((mach (chez-machine->unthreaded mach)))
> > > +    (cond
> > > +     ((string-prefix? "arm64" mach)
> > > +      'no-support)
> > > +     ((string-prefix? "arm32" mach)
> > > +      (if (string-suffix? "le" mach)
> > > +          'no-threads
> > > +          'no-support))
> > > +     ((string-prefix? "ppc32" mach)
> > > +      (if (string-suffix? "le" mach)
> > > +          #f
> > > +          'no-support))
> > > +     (else
> > > +      #f))))
> > -> is a conversion operator, not an "accessor".
> 
> I thought of this as a conversion more than an accessor.
Conversion follows the lines of "is (roughly) a", whereas this is a
"has a" relation, which would imply accessing things.

> > "upstream-restriction" sounds rather negative, I'd rather have
> > (chez-machine-features), which yields #f if the machine is
> > unsupported and a (possibly empty) list of features otherwise, such
> > as '(threads).
> > 
> > I'm also not quite sure what the point is behind using chez
> > machines here.  Why not simply test the systems with the predicates
> > we already have, i.e. target-arm64?, target-arm32?, target-linux?,
> > target-ppc32?,
> > ...
> 
> I agree that the name of this procedure should avoid sounding
> negative:  'restriction' was the best I'd come up with so far. I
> think I like 'chez-machine-features' somewhat better, but with a few
> reservations.
> 
> Using predicates like 'target-arm32?' makes some sense overall, and
> I'll try it. One subtly (sic) is that systems supported by neither
> upstream nor Racket are currently handled by `and=>` in clients.
> 
> Also, I guess it's odd to have this function operate on Chez Scheme 
> machine types anyway, since a machine type specifies threaded or
> unthreaded.
Not sure how to deal with these reservations or what they'd imply, so
following along.

> I'm currently thinking something like:
> 
> --8<---------------cut here---------------start------------->8---
> (define* (chez-upstream-features-for-system #:optional
>                                              (system (or 
> (%current-target-system)
>  
> (%current-system))))
>    (cond
>     ((not (nix-system->chez-machine system))
>      #f)
>     ((target-arm64? system)
>      #f)
>     ((target-arm32? system)
>      (and (target-linux? system)
>           '()))
>     ((target-ppc32? system)
>      (and (target-linux? system)
>           '(threads)))
>     (else
>      '(threads))))
> --8<---------------cut here---------------end--------------->8---
Haven't tested this, but LGTM.

> Alternatively, there could be an argument called something like 
> "variant", where the default would be 'upstream or maybe #f, and 
> supplying 'racket would always return '(threads). (Racket CS requires
> the threaded version of Chez Scheme, so the chez-scheme-for-racket
> has consistently added thread support immediately upon adding any new
> target.)
I don't think delegating to racket this soon is a good idea.

> > And as a minor pet peeve, you ought to spell out machine.
> > 
> 
> Ok, will do.
> 
> > 
> > > +(define* (nix-system->chez-machine #:optional (system (%current-
> > > system))
> 
> This should have been (or (%current-target-system) (%current-
> system)).
> 
> > > +                                   #:key (threads? 'always))
> > > +  "Return the Chez Scheme machine type corresponding to the Nix
> > > system
> > > +identifier SYSTEM, or @code{#f} if the translation of SYSTEM to
> > > a
> > > Chez Scheme
> > > +machine type is undefined.
> > > +
> > > +When THREADS? is @code{'always} (the default), the threaded
> > > variant
> > > of the
> > > +machine type will be returned: note that the package returned by
> > > +@code{chez-scheme-for-system} will always support native
> > > threads.
> > > When
> > > +THREADS? is @code{#f}, the unthreaded machine type will be
> > > returned.  If
> > > +THREADS? is @code{'upstream} (the default), the threaded variant
> > > of
> > > the
> > > +machine type will be returned if and only if it is supported by
> > > upstream Chez
> > > +Scheme (see @code{chez-machine->upstream-restriction}).  If
> > > THREADS?
> > > is any
> > > +other value, an exception is raised."
> > What's the point in having THREADS? 'always?  In any case, assuming
> > chez-machine-features is to be exported, this can easily be checked
> > --
> > even if not, we can add the check internally by writing
> >    #:key (threads? (chez-supports-threads? system))
> > 
> > > +  (let* ((hyphen (string-index system #\-))
> > > +         (nix-arch (substring system 0 hyphen))
> > > +         (nix-os (substring system (+ 1 hyphen)))
> > > +         (chez-arch (assoc-ref %nix-arch-to-chez-alist nix-
> > > arch))
> > > +         (chez-os (assoc-ref %nix-os-to-chez-alist nix-os))
> > > +         (mach (and chez-arch chez-os (string-append chez-arch
> > > chez-
> > > os))))
> > This series of let-bindings should probably be done in a separate
> > function called nix-system->chez-machine.
> 
> On the one hand, the result of 'chez-scheme-for-system' will always 
> support threads, so being threaded by default is convenient. On the 
> other hand, it looks like I've reduced the use of this function (by 
> searching for files rather than coding in the machine type directory)
> enough that it doesn't have a big impact either way. It will be more 
> important when we support cross-compilation, and I think we should
> keep these functions internal and defer as much as possible of their
> API design until then.
> 
> For now, I think I'll say that it's unspecified whether the result is
> a threaded or unthreaded machine type and add 
> `chez-machine->{un,}threaded` as needed.
I think you can keep (chez-supports-threads? system) hidden even when
using it to instantiate defaults.  I currently don't see the relation
between chez-scheme-for-system and nix-system->chez-machine, so if
that's relevant, you'd have to clarify.

Cheers
Philip McGrath Feb. 17, 2022, 7:37 a.m. UTC | #4
Hi,

On 2/17/22 02:24, Liliana Marie Prikler wrote:
> I currently don't see the relation
> between chez-scheme-for-system and nix-system->chez-machine, so if
> that's relevant, you'd have to clarify.

It's relevant only in that, unless you as a user have done some 
transformation to specifically build an unthreaded variant, you will be 
using the threaded machine type.

-Philip
diff mbox series

Patch

diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm
index 11d570059b..fc1da53178 100644
--- a/gnu/packages/chez-and-racket-bootstrap.scm
+++ b/gnu/packages/chez-and-racket-bootstrap.scm
@@ -28,7 +28,9 @@  (define-module (gnu packages chez-and-racket-bootstrap)
   #:use-module (guix utils)
   #:use-module (guix gexp)
   #:use-module (ice-9 match)
+  #:use-module (ice-9 regex)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
   #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
   #:use-module (gnu packages compression)
@@ -61,6 +63,134 @@  (define-module (gnu packages chez-and-racket-bootstrap)
 ;;
 ;; Code:
 
+(define (chez-machine->unthreaded mach)
+  "Given a string MACH naming a Chez Scheme machine type, returns a string
+naming the unthreaded machine type for the same architecture and OS as MACH.
+The returned string may share storage with MACH."
+  (if (eqv? #\t (string-ref mach 0))
+      (substring mach 1)
+      mach))
+(define (chez-machine->threaded mach)
+  "Like @code{chez-machine->unthreaded}, but returns the threaded machine
+type."
+  (if (eqv? #\t (string-ref mach 0))
+      mach
+      (string-append "t" mach)))
+
+;; Based on the implementation from raco-cross-lib/private/cross/platform.rkt
+;; in https://github.com/racket/raco-cross.
+;; For supported platforms, refer to release_notes/release_notes.stex in the
+;; upstream Chez Scheme repository or to racket/src/ChezScheme/README.md
+;; in https://github.com/racket/racket.
+(define %nix-arch-to-chez-alist
+  `(("x86_64" . "a6")
+    ("i386" . "i3")
+    ("aarch64" . "arm64")
+    ("armhf" . "arm32") ;; Chez supports ARM v6+
+    ("ppc" . "ppc32")))
+(define %nix-os-to-chez-alist
+  `(("w64-mingw32" . "nt")
+    ("darwin" . "osx")
+    ("linux" . "le")
+    ("freebsd" . "fb")
+    ("openbsd" . "ob")
+    ("netbsd" . "nb")
+    ("solaris" . "s2")))
+
+(define (chez-machine->upstream-restriction mach)
+  "Given a string MACH naming a Chez Scheme machine type, returns a symbol
+naming a restriction on the upstream Chez Scheme implementation compared to
+the Racket variant, or @code{#f} if no such restriction exists.  The
+restriction is reported for the architecture--OS pair, regardless of whether
+MACH specifies a threaded or an unthreaded variant.
+
+Possible restrictions currently include:
+@itemize @bullet
+@item
+@code{'no-threads}: Support for native threads is not available upstream.
+@item
+@code{'no-support}: The upstream release doesn't claim to support this
+architecture--OS combination at all.
+@end itemize
+
+See @code{chez-machine->nix-system} for more details about acceptable values
+for MACH."
+  (let ((mach (chez-machine->unthreaded mach)))
+    (cond
+     ((string-prefix? "arm64" mach)
+      'no-support)
+     ((string-prefix? "arm32" mach)
+      (if (string-suffix? "le" mach)
+          'no-threads
+          'no-support))
+     ((string-prefix? "ppc32" mach)
+      (if (string-suffix? "le" mach)
+          #f
+          'no-support))
+     (else
+      #f))))
+
+(define (chez-machine->nix-system mach)
+  "Return the Nix system type corresponding to the Chez Scheme machine type
+MACH.  If MACH is not a string representing a known machine type, an exception
+is raised.  This function does not distinguish between threaded and unthreaded
+variants of MACH.
+
+Note that this function only handles Chez Scheme machine types in the
+strictest sense, not other kinds of descriptors sometimes used in place of a
+Chez Scheme machine type by the Racket, such as @code{\"pb\"}, @code{#f}, or
+@code{\"racket\"}.  (When using such extensions, the Chez Scheme machine type
+for the host system is often still relevant.)"
+  (let ((mach (chez-machine->unthreaded mach)))
+    (let find-arch ((alist %nix-arch-to-chez-alist))
+      (match alist
+        (((nix . chez) . alist)
+         (if (string-prefix? chez mach)
+             (string-append
+              nix "-" (let ((mach-os (substring mach (string-length chez))))
+                        (let find-os ((alist %nix-os-to-chez-alist))
+                          (match alist
+                            (((nix . chez) . alist)
+                             (if (equal? chez mach-os)
+                                 nix
+                                 (find-os alist)))))))
+             (find-arch alist)))))))
+
+(define* (nix-system->chez-machine #:optional (system (%current-system))
+                                   #:key (threads? 'always))
+  "Return the Chez Scheme machine type corresponding to the Nix system
+identifier SYSTEM, or @code{#f} if the translation of SYSTEM to a Chez Scheme
+machine type is undefined.
+
+When THREADS? is @code{'always} (the default), the threaded variant of the
+machine type will be returned: note that the package returned by
+@code{chez-scheme-for-system} will always support native threads.  When
+THREADS? is @code{#f}, the unthreaded machine type will be returned.  If
+THREADS? is @code{'upstream} (the default), the threaded variant of the
+machine type will be returned if and only if it is supported by upstream Chez
+Scheme (see @code{chez-machine->upstream-restriction}).  If THREADS? is any
+other value, an exception is raised."
+  (let* ((hyphen (string-index system #\-))
+         (nix-arch (substring system 0 hyphen))
+         (nix-os (substring system (+ 1 hyphen)))
+         (chez-arch (assoc-ref %nix-arch-to-chez-alist nix-arch))
+         (chez-os (assoc-ref %nix-os-to-chez-alist nix-os))
+         (mach (and chez-arch chez-os (string-append chez-arch chez-os))))
+    (and mach
+         (match threads?
+           ('always
+            (chez-machine->threaded mach))
+           (#f
+            mach)
+           ('upstream
+            (if (chez-machine->upstream-restriction mach)
+                mach
+                (chez-machine->threaded mach)))))))
+
+;;
+;; Chez Scheme:
+;;
+
 (define nanopass
   (let ((version "1.9.2"))
     (origin
@@ -264,8 +394,16 @@  (define* (stex-make #:optional (suffix ""))
     ;; We should too. It is the Chez machine type arm32le
     ;; (no threaded version upstream yet, though there is in
     ;; Racket's fork), more specifically (per the release notes) ARMv6.
-    (supported-systems (fold delete %supported-systems
-                             '("mips64el-linux" "armhf-linux")))
+    (supported-systems
+     (delete
+      "armhf-linux" ;; <-- should work, but reportedly broken
+      (filter
+       (lambda (system)
+         (and=> (nix-system->chez-machine system)
+                (lambda (mach)
+                  (not (eq? 'no-support
+                            (chez-machine->upstream-restriction mach))))))
+       %supported-systems)))
     (home-page "https://cisco.github.io/ChezScheme/")
     (synopsis "R6RS Scheme compiler and run-time")
     (description