Fork me on GitHub

Just a heads up, I plan to change depstar's behavior for an upcoming 2.0 release. Right now, depstar uses the runtime basis and simply excludes itself from the classpath when building JAR files. This is nice and easy but it means that depstar can't depend on anything so it's had to re-implement CLI argument processing and can't use an XML library to process the pom.xml file etc. On the assumption that the vast majority of JARs built from the core classpath in a given project, without anything from the user deps.edn file (other than the depstar alias), I plan to switch depstar over to using a calculated project basis instead.


The main difference will be switching the depstar alias from :extra-deps to :replace-deps, so that depstar behaves as a "tool" instead of a library. It will depend on tools.deps.alpha directly (and tools.cli and maybe other things), it will read the system and project deps.edn files and compute the project basis. I may add options to allow it to include the user deps.edn and to provide aliases to affect the deps used for building a classpath that in turn will be used to build the JAR.

👍 3
Rowan Barnard05:12:18

Hi Sean, I've just been through some chapters taking me through configuring and building a project with Leiningen, and managed to translate everything to deps.edn, except I'm stuck on the last bit, building an uberjar, or rather running it with java (I've already built the uberjar)

Rowan Barnard05:12:24

Hang on - I'm just about to explain which bit I'm stuck on 😅


Heh, type faster man! 🙂

Rowan Barnard05:12:06

;; uberjar building: ;; - see for a minimalist approach: ;; - clj -A:uberjar result.jar ;; - to run it: ;; - java -cp result.jar clojure.main -m mymain.namespace ;; - build a library JAR: ;; - clj -A:jar result-lib.jar :uberjar {:extra-deps {seancorfield/depstar {:mvn/version "RELEASE"}} :main-opts ["-m" "hf.depstar.uberjar"]}

Rowan Barnard05:12:22

This is the old version of your uberjar alias I'm using

Rowan Barnard05:12:31

And the bit I'm stuck on is

Rowan Barnard05:12:52

mymain.namespace I believe

Rowan Barnard05:12:08

It is throwing a FileNotFoundException

Rowan Barnard05:12:36

I typed in java -cp async_tea_party.jar clojure.main core.async-tea-party


You're missing -m


java -cp result.jar clojure.main -m mymain.namespace

Rowan Barnard05:12:23

Ah OK crikey I missed that 😂

Rowan Barnard05:12:52

I still might be confused about what to put for mymain.namespace though


The namespace that contains your -main function.

Rowan Barnard05:12:21

Is mymain the main function or the class and do I use hyphens or underscores?


mymain.namespace is a namespace.


If core.async-tea-party is the namespace of your app that has a -main function, that's your "main namespace".

Rowan Barnard05:12:30

OK so my file is core.clj in src/async_tea_party/

Rowan Barnard05:12:41

The main function is -main


Then the namespace is async-tea-party.core

Rowan Barnard05:12:02

async-tea-party.core is the namespace in core.clj


java -cp async_tea_party.jar clojure.main core.async-tea-party <- your namespace doesn't match (in addition missing -m).

Rowan Barnard05:12:37

OK thanks so the whole mymain.namespace is async-tea-party.core?

Rowan Barnard05:12:13

OK I'll try that then

Rowan Barnard05:12:10

Sweet, thank you very much Sean, it's working!


Hello, first time depstar user/AOT compiler here. 👋 I'm trying to build a library jar for the TLC model checker, I've tried:

λ clojure -X:jar                   
Ignoring -C / --compile because -m / --main was not specified!
Building thin jar: aoc.jar
I'm having an issue where only the .clj files end-up in my jar file. I was expecting class files, right? Note that I don't have a "main" namespace. Is it required? I've tried from the clojure guide just to check the output:
λ clj -A:local -M -e "(compile 'aoc.day2)"
Which seem to successfully complete and generate a bunch of .class files in my classes/ directory (under aoc/ and clojure.core.spec). Did I forget something? I've pushed my working copy here :


@arnaud_bos depstar will only AOT code if you tell it which namespace to compile -- there's no "aot all" option. I would say that you really should not AOT compile a library, only an uberjar


Please correct me if I'm wrong but wouldn't an uberjar also include the classes of the tla2tools.jar which I'm depending on? Because the classes in this jar will already be provided in the context of a TLC execution (the jar is already in the classpath). Is that not an issue?


An uberjar is a complete standalone program that you can run directly via the java command so it should include all dependencies.


Yes, it's not what I want. TLC is the executable, my library would just provide a few "extensions" via annotated methods.


Here's a project that explicitly compiles a namespace when building the (thin) JAR:


See the :build alias that runs the compile with -e and then runs depstar.


It has "classes" already created and has both "classes" and "src" in :paths.


I try to discourage this so folks don't just AOT libraries because it's "easy" without understanding the consequences, so in depstar itself AOT is tied to -m and pom.xml and uberjar building. But you can manually compile a namespace and have it included in the JAR.


Yes! The :build alias hides the two steps I understand.


Sure, I get that. My use case seems a little bit different.


Thank you so much 🙏


Yeah, that library above has a specific :gen-class because it's building a (Java) class that the non-compiled code needs in order to run -- so the (thin) JAR contains the source files and, for just that one namespace, the .class files as well.


When I build depstar v2, I will probably decouple most of the options so that it will do whatever you tell it to do and just warn you if you're "painting outside the lines".


(and I'll probably make it possible to compile an arbitrary set of namespaces and I may even add an :all option since v2 won't be restricted on the dependencies it can use, unlike v1)


Nice, good to know!