This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # 100-days-of-code (2)
- # bangalore-clj (1)
- # beginners (141)
- # cider (33)
- # cljs-dev (13)
- # cljsjs (7)
- # cljsrn (1)
- # clojure (88)
- # clojure-conj (3)
- # clojure-dev (24)
- # clojure-italy (11)
- # clojure-nl (4)
- # clojure-russia (1)
- # clojure-sanfrancisco (1)
- # clojure-spec (4)
- # clojure-uk (53)
- # clojurescript (65)
- # core-logic (2)
- # cursive (28)
- # datomic (33)
- # duct (2)
- # emacs (3)
- # figwheel-main (9)
- # fulcro (44)
- # hoplon (6)
- # leiningen (144)
- # mount (1)
- # nrepl (21)
- # off-topic (102)
- # onyx (2)
- # other-languages (5)
- # pathom (6)
- # planck (3)
- # portkey (1)
- # re-frame (7)
- # reagent (5)
- # reitit (17)
- # shadow-cljs (24)
- # spacemacs (16)
- # tools-deps (64)
- # uncomplicate (2)
- # vim (22)
So after a lot more experimentation with classifiers, dynamic version strings, etc., it looks like the only way I'm going to be able to achieve what I'm after (single
project.clj that can emit two different, JVM-specific artifacts that have different upstream dependencies, depending on which JVM the build is run on) is by twizzling the project name component in the
defproject form. e.g.
But I've been unable to get that to work. Any tips, tricks or pointers?
(def project-name (... logic that calculates a project name based on the JDK we're running on ...)) (defproject project-name "0.1.0-SNAPSHOT" ...)
Maybe you can write a macro that takes the project-name as arg, and returns the defproject form you want?
although that may run into problems with the fact that you want to calculate the project name at run time, not compile time.
Possibly-effective hack: shell/clj/Python/etc. script that writes the project.clj file and does build/deploy/whatever commands, then tweaks the project.clj file and repeats.
@pmonks I thought you were going with a version string change? at this point, the best I can think of is similar to what @andy.fingerhut mentioned concerning having an external script that picks the different jvm’s for you to run lein with, so a
defproject setup similar to this
@andy.fingerhut yeah that thought crossed my mind too, but it felt to me like a bridge too far - like I'm definitely headed down a bad path. 😉
@mikerod it turns out that when you use a version number suffix, the Maven machinery still only has a single POM file, and I need two (recall that my upstream dependencies differ, depending on which JVM is in use).
The a script could run it like
# jvm x LEIN_JAVA_CMD=jvm-x-path lein <task> # jvm y LEIN_JAVA_CMD=jvm-y-path lein <task>
Sure, but I can't make assumptions about which JVM(s) consumers of the library are using.
This is a general purpose library that (hopefully!) many other folks will consume and enjoy. 😉
So I can't just assume they have the same JVMs installed that I do, let alone in the same locations.
Basically it's all fallout from Oracle's "project jigsaw". And it's a huge pain that I'd rather not have to deal with...
a consumer wouldn’t write anything, it’d just build with whatevr jvm they have lein using
But they do need to select which "edition" of my library they wish to consume, to ensure they get the correct upstream dependencies.
So yeah, you use this, and deploy artifacts of the form:
org.mine/some-project 0.1.0-SNAPSHOT-jdk8 org.mine/some-project 0.1.0-SNAPSHOT-jdk10
but that doesn’t align with what you showed from google doing a similarly hacky classifier deployment based on versions
Recall that my dependencies are either included in the JVM (for JVM versions 1.7u6 through 10) or need to be explicitly pulled down (JVM v11+).
completely compile-time built-in due to the eval-syntax of the defproject based on lein jvm
At at the risk of sounding like a broken record, upon deployment to clojars,
LEIN_JAVA_CMD=jvm-y-path lein <task> overwrites the POM file that was previously generated by
LEIN_JAVA_CMD=jvm-x-path lein <task>.
if you use classifiers - they need to deploy at the same time, because you can’t “overwrite” releases
Each pom has to be built on a different JVM version, or else the unit tests won't pass.
If you build one JAR, overwriting pom file, and deploy (in the script), then start over with a different JVM version, it shouldn't matter that the pom file gets overwritten after the deploy?
@mikerod I did exactly that. Perhaps I'm not explaining myself very clearly, but Maven / Clojars elide the "qualifier" on the end of the version string.
If you can find any way to do what you want via a sequence of commands from an interactive shell, that produces the correct results, script that.
if it deployed as a real classifier then you couldn’t deploy 2 separate times to the same coordinate
the maven definition of a classifier has some vague semantics around final repo structure
I need each "build" to use a specific JVM version, and classifiers can't be specified to use a particular JVM.
you showed me some google repo, that used a “classifier version” structure, but it was actually imposed on the directory structure itself - so it sort of “wasn’t a classifier”, but could be used like one as a mvn coordinate
Yep - that's the only way to influence how Leiningen's underlying Maven machinery determines where to write files during deployment.
Do you have a manual sequence of steps you know how to follow that produces the results you want?
or if you don’t care about version that much, could just pick a naming scheme that doesn’t cause it to “look like a classifier”
even if that sequence of steps involves hand-editing the project.clj and/or other files?
Make a script that does those steps, with instead of "hand-edting one or more files" does
sed or any other program to edit those files that you can think of.
1. Select Oracle JVM v1.8 (there are a million ways to do do this, all of them unpleasant) 2. Run unit tests, without the additional dependencies (`lein test`) 3. Build JAR and deploy, without the additional dependencies (`lein deploy clojars`), ensuring the deployed artifacts (BOTH JAR AND POM) have unique GAV coordinates 4. Select Open JDK v11 (there are a million ways to do do this, all of them unpleasant) 5. Run unit tests, with additional dependencies (`lein with-profile +openjfx11 test`) 6. Build JAR and deploy, with additional dependencies (`lein with-profile +openjfx11 deploy clojars`), ensuring the deployed artifacts (BOTH JAR AND POM) have unique GAV coordinates
Could be bash, could be Python, clj, etc. Whatever you are most familiar and comfortable with maintaining.
I don't even need to see what the other steps are, literally. If you can write them as commands in a bash script, Bob's your uncle.
If there are any steps that you don't know how to write as a command in a bash script, please ask -- we can probably figure out a way to do it.
if you need windows support also, for building, then yes, things get more complicated with scripts hah
I’ll probably bow-out of trying to fix this issue, since I don’t feel like I’m adding value at this point 😛
so you could conditional logic, based on jvm or something, the project name if you wanted to
@mikerod that doesn't work:
(def project-name "foo") (defproject #=(symbol project-name) "0.1.0-SNAPSHOT"
$ lein jar Created [snip]/target/project-name-0.1.0-SNAPSHOT.jar
(and yes I guess I could put a mound of logic inside the call to
symbol, but that gets pretty messy)
(defn project-name  (symbol "foo")) (defproject #=(project-name) "0.1.0-SNAPSHOT" ...)
That worked - thanks @mikerod. Next hurdle: https://github.com/technomancy/leiningen/issues/2473
but that is sort of counterintuitive to me how
with-profile can be ignored when not
:leaky. That may be by design, not sure.
I think lein v3 is even opting to always only go with
#= reader dispatch macro instead of the classically used
~, but I have no more details on that. It’s just in a comment I see in the source - https://github.com/technomancy/leiningen/blob/7357010431c926abb559d55b295fe1ba7791ed20/leiningen-core/src/leiningen/core/project.clj#L198
You could write a PowerShell script if you were so inclined (or had a colleague who is)
Going off on a tangent for a moment, are there any thoughts around revisiting build tools, especially in light of
I think the idea of tools.deps is cool that it tried to focus on one small part of what build tools bundle in most of the time - dep mgmt
however, eventually you have to compose a bunch of parts together either yourself via scripts, or a build tool that tries to be all in one
I’m not sure where the tools.deps idea is headed beyond tools.deps itself, but already, looks to be a script-centric view of doing things when I read how people are using it in their stack
I think integrating it with lein and removing that “classpath” part is at least cool/interesting
in terms of revisiting build tools overall, when it comes to complicated build and deployment setup, I’m not sure there is an easy answer for build tools. It seems that many exists and everyone is always unhappy with them all eventually 😛
Definitely -- I see it discussed on the #tools-deps channel, and someone there has been publishing and perhaps maintaining a list of tools.deps based tools
I haven't used them myself, so can't help you with what exists vs. what hasn't been developed yet.
FWIW I've played with the
lein-tools-deps plugin, and it's fine as far as it goes. The issue comes in that most other leiningen plugins can't use deps expressed in
I guess I'm just wondering if the consolidation of dependency management by the core Clojure team will sufficiently break the existing build tools that it's a logical point to re-evaluate build tools more generally...
By 'break existing build tools' you mean because some project you want to build via Leiningen doesn't come with a project.clj file? I don't understand "break" there.
I mean "break" in the sense of "these tools can't directly consume
deps.edn files yet, and it seems like a substantial effort to add support for that and deprecate their own native dependency management mechanisms (given the ripple effect through the plugin ecosystem etc.)".
Sure, but it is "opt-in" breakage, e.g. moving from major version 1 to version 2 on your own time frame (or not)
Leiningen-specific plans for supporting tools.deps seems best discussed here, but at least
lein ancient has a tools.deps-based replacement someone has already developed: https://github.com/RickMoynihan/lein-tools-deps/issues/63