Post-Chez 10 Distro & Release Considerations

A couple weeks ago, Chez Scheme 10.0 was released, incorporating all of the changes from Racket's branch of Chez Scheme. I'm especially excited about this because Guix has been distributing Racket's branch to support architectures that hadn't been supported upstream: I'm looking forward to simplifying our packaging.

I have a few questions about how to handle distro packaging going forward. I'm asking here because I think all of them concern things developed under the Racket project: a distro that packaged Chez Scheme only could keep doing everything as before, which seems like another testament to the excellent work that's gone in to upstreaming Racket's changes to Chez Scheme.

Release cycles and (not) using Chez as a library

I think I know the answer to this question from previous conversations, but I anticipate it coming up in review, and it would help to have a definitive answer to link to.

My understanding is that there is no plan to align the Chez Scheme and Racket release cycles, and a given released version of Racket will continue to depend on a specific pre-release version of Chez Scheme (except perhaps by coincidence), so distros should not try to link their Racket packages against libkernel.a, scheme.h, or any other such files from their Chez Scheme package.

Even if somehow a distro managed to produce an apparently-running Racket by doing so, my understanding is that the specific Chez Scheme version used is effectively part of Racket's "ABI", so a distro building Racket X against an unexpected Chez version would produce something incompatible with Racket X builds using the correct Chez version, in addition to more subtle potential bugs that seem too painful to contemplate.

In general, distros prefer to remove "bundled" or "vendored" copies of libraries they already have packaged, for good reasons—for example, to enable timely security updates for a library without having to rebuild all dependent packages. But my understanding is that trying to build the latest Racket release against the latest Chez Scheme release is not viable, so distros will need to make an exception.

Zuo releases and stability

Zuo has been in a somewhat unique position with respect to the Racket release process. On the one hand, the most upstream source for Zuo is within the main Racket Git repository, and it has been part of the release at least insomuch as other build scripts are "part of the release". On the other hand, Zuo itself hasn't explicitly been released in quite the same sense as the core Racket runtime system and Racket packages in the main distribution. For example, to my knowledge there hasn't been regression testing à la Release Regressions for v8.12 · Issue #4898 · racket/racket · GitHub, and the extracted repository at GitHub - racket/zuo: A tiny Racket for scripting hasn't been getting release tags—at least, it hadn't had any tags until the relatively recent v1.8 and v1.9, which I saw for the first time while writing this. It hasn't been completely clear where Zuo's compatibility status falls on the continuum from most build scripts (which I'd assume are completely internal and can be changed at will) to the very high emphasis on compatibility for other things that are part of the Racket release process.

Now that upstream Chez Scheme also uses Zuo, it would help to clarify Zuo's status. Guix in fact distributes a package of Zuo, both for end-users and because making it visible to our tooling turns out to be useful: the later was the original motivation, and I suspect other distros may also want to package Zuo for that reason.

From a distro packaging perspective, the most useful compatibility property would be that there exists some version of Zuo—ideally, the most recently released version of Zuo—that is able to build the most recently released versions both of Racket and of Chez Scheme. Racket's usual compatibility approach would satisfy that property, but it could also be satisfied by weaker levels of compatibility.

It would also help to clarify what "counts" as a Zuo release. Continuing to create new tags like the recent v1.8 and v1.9 when incrementing ZUO_VERSION or ZUO_MINOR_VERSION (and doing so like a Racket package version, i.e., updating it when there is something new someone might want to depend on) would work well from my perspective: in fact, Guix has tooling that recognizes that tag pattern and can automatically detect new releases.

The only time I've run into issues with mismatched Zuo versions so far was when the dry-run support added in Zuo 1.8 was used in upstream Chez Scheme before it had been in a Racket release. That wouldn't be a problem if tags like v1.8 constitute Zuo releases, but the rather confusing error message I got at the time made me wonder if Zuo should have something like cmake_minimum_required or AC_PREREQ.

Repository management

Are there scripts, or even just a set of commands that could be documented, for synchronizing between repositories shaped like GitHub - racket/racket: The Racket repository, GitHub - racket/zuo: A tiny Racket for scripting, and GitHub - cisco/ChezScheme: Chez Scheme? I think I remember that git subtree is used, but I haven't worked out the right incantations. Sometimes I get into situations where I need to move between repository shapes while developing patches, where different parts of the Guix packaging may be set up to deal with different shapes.

Similarly, is there a particularly good way to find the Racket commit corresponding to a given Chez Scheme commit, or vice versa? Along those lines, I noticed that add `immutable-vector`, `immutable-vector-copy`, etc. · cisco/ChezScheme@c081296 · GitHub gained an additional Co-authored-by: line when it was imported as Chez Scheme: add `immutable-vector`, `immutable-vector-copy`, etc. · racket/racket@c96c62d · GitHub.

1 Like

Good questions! I have no real answers for you. It sounds like the real cost here would probably be coordination time; so, for instance, a breaking change to Zuo would have to be coordinated with new releases of both Chez and Racket. A change to Chez would require waiting for a new release of Chez before building on that change in Racket.

Chez Scheme

Yes, that's correct, for now. I imagine that Racket's copy of Chez Scheme will be more conventionally vendored and aligned with Chez Scheme releases one day, but I don't think we're ready to move to that mode in the near future.

Zuo

The v1.8 and v1.9 tags are meant to count as releases, and the intent is to bump the version and create a new release tag whenever there's a change that some script might depend on (even if that's not an API change). I think we can commit to treating Zuo in the Racket repo as conventionally vendored.

Repository management

For repo syncing, I use git format-patch and git am. In one direction, git am needs --directory, and in the other direction, I remove an unwanted directory prefix with search and replace on the patch text. Sometimes, I use git subtree to first narrow patches to a particular subdirectory, but that's needed less and less, since patches now more often go from Chez Scheme to Racket.

For moving from Racket to Chez Scheme specifically with git subtree, I clone the whole Racket repo to a fresh checkout, use git subtree split --onto d41b86cc04 -P racket/src/ChezScheme there, use git reset --hard with the commit reported by git subtree, and then git format-patch followed by a suitable subtree commit to get patches up to that commit. (The commit d41b86cc04 is a more or less arbitrary choice — new enough to speed things along, but old enough to give me lots of context.)

When I move patches from one side to other, I adjust the release message to, say, add or remove a "Chez Scheme:" prefix, refer to a repo-specific commit, or fix a mistake noticed too late in the original commit message. Adding that Co-authored-by: was an example of fixing a release message (also noted in https://github.com/cisco/ChezScheme/commit/822d815965da538faade8a5508c54b4bd8497d1a).

1 Like

Chez Scheme

Thanks for the confirmation!

Zuo

That works very well for me!

Repository management

Ah, that's the approach I've been using and had been hoping to improve upon :slight_smile:

In Repairs and improvements for building with external dependencies by LiberalArtist · Pull Request #807 · cisco/ChezScheme · GitHub, there were small conflicts in configure and makefiles/Makefile.in that I had to resolve by hand. I did that by making a temporary branch in my Chez Scheme repository, copying the troublesome files from the Racket repository, committing them, rebasing the changes I wanted on top of that commit, fixing the conflicts during in the rebase, and then extracting the rebased patches. Probably there's a more direct way. (I use git format-patch to send patches to Guix, but I use git am only rarely.) Maybe there's also something that could be done to reduce conflicts, or maybe they are already rare enough.

My vague impression is that git subtree, if used in a certain way (that I have not figured out) would consistently produce the same output commits for a given input, and maybe also would make things more automatic. Even if those features exist, though, I can imagine potential reasons they might not work for this use-case.

While updating Guix packaging from Racket 8.13 to 8.14, I noticed that the included Chez Scheme is at version 10.1.0-pre-release.1 in both Racket releases.

It would be slightly helpful in collating changes between Racket and Chez Scheme versions and potentially backported patches if the Chez Scheme pre-release were incremented at least once per Racket release. On the other hand, I see that there are only seven Chez Scheme commits in 8.14 that weren't in 8.13, and none of them stand out as obvious moments to have incremented the version number. I'm not sure how to balance these considerations, but I thought I'd note it here.