From: Ian Eure <ian@retrospec.tv>
To: Steve George <steve@futurile.net>
Cc: r0man <roman@burningswell.com>,
Reilly Siegel <mail@reilysiegel.com>,
Maxime Devos <maximedevos@telenet.be>,
guix-devel@gnu.org
Subject: Re: Proposal to turn off AOT in clojure-build-system
Date: Sat, 09 Mar 2024 14:27:56 -0800 [thread overview]
Message-ID: <878r2qx1x2.fsf@meson> (raw)
In-Reply-To: <ZdM/rSucBwQr5/cl@t25sg>
Hello,
I’ve been following along with this discussion, as well as a
discussion on Clojureverse, and thought it might be helpful to
pull together some threads and design decisions around Clojure’s
behavior.
Clojure is designed to ship libraries as source artifacts, not
bytecode ("pretty much all other Clojure libraries ... are all
source code by design[1]."; "Clojure is ... a source-first
language[2]"), and the view of the community is that shipping AOT
artifacts "is an anti-pattern[1]." Clojure library JARs are more
akin to source tarballs than binaries. The original design and
intent of Clojure’s AOT compiler is to compile "just a few
things... for the interop case" or "Everything... For the
'Application delivery', 'Syntax check', and 'reflection warnings'
cases[3]."
Clojure’s compiler is transitive and "does not support separate
compilation"[3], meaning when a namespace is compiled, anything it
uses is compiled and emitted with it. This is the crux of why
mixing AOT and non-AOT code is troublesome: it causes dependency
diamonds, where the AOT’d library contains a duplicate, older
version of code used elsewhere in the project.
The Clojure reference on compiling[4] gives some reasons you might
want to AOT: "To deliver your application without source," "To
speed up application startup," "To generate named classes for use
by Java," "To create an application that does not need runtime
bytecode generation and custom classloaders." Note that there’s
no mention of compiling libraries for any reason; only
applications.
When AOT is used "for the interop case," it’s typical to AOT only
those namespaces[5], not the entire library.
Shipping AOT-compiled Clojure libraries has caused real and very
weird and hard-to-debug problems in the past:
https://clojure.atlassian.net/browse/CLJ-1886?focusedCommentId=15290
https://github.com/clj-commons/byte-streams/issues/68 and
https://clojure.atlassian.net/browse/CLJ-1741
Clojure doesn’t have guarantees around ABI stability[6][7]. To
date, most ABI changes have been additive, but there are no
guarantees that the ABI will be compatible from any one version of
Clojure to any other. The understanding of the Clojure community
is that the design of the current compiler can’t offer a stable
ABI[8] at all. Because nobody in the Clojure community AOTs
intermediate (that is, library) code, this hasn’t been a problem
and is unlikely to change.
"Clojure tries very hard to provide source compatibility but not
bytecode compatibility across versions[9]."
Correctly handling the ABI concerns — which Guix currently does
not do — would result in a combinatorial explosion of Clojure
packages should multiple versions of Clojure ever be available in
Guix at the same time. For example, if someone wanted to package
Clojure 1.12.0-alpha9, you’d need to duplicate every package
taking Clojure as an input so they use the correct version. While
ABI breakage has been rare thus far, it seems likely that it’ll
occur at some point; perhaps if Clojure reaches version 2.0.0. If
Guix disables AOT for Clojure libraries, we have source
compatibility, and the AOT/ABI problems are moot.
Clojure’s compiler is non-deterministic[10]: the same compiler can
will produce different bytecode for the same input across multiple
runs. I’m not sure if this is a problem for Guix at this point in
time, but it seems out of line with Guix expectations for
compilation generally.
Opinions follow:
If we’re taking votes, mine is to *not* AOT Clojure libraries,
both for the technical reasons laid out in, and also for the
social reason of not violating the principle of least surprise. I
understand that Guix and Clojure have very different approaches,
and some balance must be struck. However, the lack of ABI
guarantees, the compiler’s behavior, the promise of source
compatibility, and matching the expectation of the audience these
tools are meant for all convince me that disabling AOT is the
right course here.
AOT’ing Clojure applications (which means, more or less, "the
Clojure tooling") is desirable, and should be maintained.
— Ian
[1]:
https://clojureverse.org/t/should-linux-distributions-ship-clojure-byte-compiled-aot-or-not/10595/8
[2]:
https://clojureverse.org/t/should-linux-distributions-ship-clojure-byte-compiled-aot-or-not/10595/30
[3]: https://clojure.org/reference/compilation
[4]:
https://archive.clojure.org/design-wiki/display/design/Transitive%2BAOT%2BCompilation.html
[5]: https://clojure.org/guides/deps_and_cli#aot_compilation
[6]:
https://clojureverse.org/t/should-linux-distributions-ship-clojure-byte-compiled-aot-or-not/10595/30
[7]:
https://gist.github.com/hiredman/c5710ad9247c6da12a99ff6c26dd442e
[8]:
https://clojureverse.org/t/should-linux-distributions-ship-clojure-byte-compiled-aot-or-not/10595/4
[9]:
https://clojureverse.org/t/should-linux-distributions-ship-clojure-byte-compiled-aot-or-not/10595/18
[10]:
https://ask.clojure.org/index.php/12249/bytecode-not-100-deterministic-given-identical-inputs
Steve George <steve@futurile.net> writes:
> Hi,
>
> Guix's clojure-build-system turns on AOT compilation by
> default. I would like to advocate that 'as a distributor' we
> should *not* ship Clojure code AOT'd, so we should change the
> default.
>
> This has been discussed previously. In #56604 r0man noted that
> AOT compilation should not be on by default [0], Reilly makes
> the same point in #53765 [1].
>
> Maxime makes the point that where a compiler is available it
> should be used [2] and that if it doesn't work it's a bug:
>
> "if a Clojure library misbehaves when AOT-compiled, without
> additional context, that seems like a bug in the Clojure
> library to me (or the AOT-compilation code).
>
> The perspective in the Clojure community is quite different from
> Guix's on a number of fronts. There's not much discussion about
> offline builds, reproducibility or code coming from
> Distributions. The internalised perspective is that you use the
> build tools to download libraries directly from Clojars (a Maven
> repo) and developers create a final uberjar for production usage
> Consequently, there is no specific statement saying
> 'Distributors should not AOT libraries' that I can point
> to. But, I would like to draw attention to this thread on
> Clojureverse as the best source I could find:
>
> Alex Miller is the main community manager for Clojure, and is a
> maintainer of the core libraries, so his perspective is key. He
> notes that, AOT code is tied to *specific versions of Clojure*:
>
> "AOT'ed code is that it is inherently the product of a
> particular version of tthe Clojure compiler ... I would
> recommend NOT AOT compiling libraries" [4]
>
> In the same thread thheller, who is the maintainer of the most
> popular ClojureScript tooling, notes you cannot mix AOT and
> non-AOT libraries [5]:
>
> "you cannot just ship your library AOT compiles as it would
> also contain clojure.core. Clojure AOT current ... can not
> load clj files from .class files. So AOT produces the class
> files and will fail if one of the dependent classes is
> missing although the .clj file is present"
>
> I believe this means that with AOT code on, any user who
> installs a different version of Clojure from the one that we
> used to AOT the libraries *may* have problems. And, that we
> can't have trees where some part is AOT'd but a dependency is
> not. Finally, there is no expectation in the Clojure community
> that this is a bug, consequently it will not be
> fixed. Therefore, we should change to default to AOT off.
>
> What do people think, does this make sense?
>
> Thanks,
>
> Steve / Futurile
>
> [0] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=56604#5
> [1] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=53765#290
> [2] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=53765#293
> [4]
> https://clojureverse.org/t/deploying-aot-compiled-libraries/2545/6
> [5]
> https://clojureverse.org/t/deploying-aot-compiled-libraries/2545/3
> [5]
> https://gist.github.com/hiredman/c5710ad9247c6da12a99ff6c26dd442e
next prev parent reply other threads:[~2024-03-10 2:46 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-19 11:46 Proposal to turn off AOT in clojure-build-system Steve George
2024-02-19 14:44 ` Maxime Devos
2024-02-21 11:29 ` Steve George
2024-02-22 14:57 ` Maxime Devos
2024-02-22 15:33 ` Andreas Enge
2024-02-22 15:47 ` Felix Lechner via Development of GNU Guix and the GNU System distribution.
2024-02-22 17:44 ` Maxime Devos
2024-02-23 2:13 ` Maxim Cournoyer
2024-02-22 17:12 ` Maxime Devos
2024-02-23 12:41 ` Felix Lechner via Development of GNU Guix and the GNU System distribution.
2024-02-23 16:49 ` Steve George
2024-02-19 18:13 ` Ryan Sundberg
2024-02-19 21:38 ` Carlo Zancanaro
2024-02-24 3:39 ` 宋文武
2024-03-09 22:27 ` Ian Eure [this message]
2024-03-12 12:12 ` Jean-Pierre De Jesus Diaz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=878r2qx1x2.fsf@meson \
--to=ian@retrospec.tv \
--cc=guix-devel@gnu.org \
--cc=mail@reilysiegel.com \
--cc=maximedevos@telenet.be \
--cc=roman@burningswell.com \
--cc=steve@futurile.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/guix.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.