I need some help with lein.
I need to compile my program to build/classes/main/
Lein append /classes to whatever folder I specify at project.clj :target-path.
For example, if I set:
:target-path "build"
files will be generated at build/classes instead of build/classes/main
If I set:
:target-path "build/classes/main"
files will be generated at build/classes/main/classes
build/classes/main/ is where my grails project compile all Groovy and Java classes before packaging the war file. My Clojure .class must be there too.
In your project.clj set :compile-path
:target-path "build"
:compile-path "%s/classes/main"
Related
I have a project where I want certain parts of the code to be able to run on a local environment, and other parts which depend on libraries that only run on a remote environment. E.g.
src/app/core.clj <- can run anywhere
src/app/sandbox/remote_only.clj <- depnds on libs that only function in remote environ
where src/app/core.clj is
(ns app.core
(:gen-class))
(defn -main [] (println "Hello, World!"))
and src/app/sandbox/remote_only.clj is
(ns app.sandbox.remote-only
(:require
[uncomplicate.commons.core :refer [with-release]]
[uncomplicate.neanderthal
[native :refer [dv dge]]
[core :refer [mv mv!]]]))
I want to be able to uberjar and run the code located in core.clj on my local machine without pulling in remote_only.clj which will cause the program to fail locally. According to the docs, Leiningen should be able to accomplish this using profiles and uberjar exclusions e.g.:
(defproject app "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.10.1"]]
:profiles {:uberjar {:main app.core
:init-ns app.core
:aot :all}
:remote {:init-ns app.sandbox.remote_only
:dependencies [[uncomplicate/neanderthal "0.43.1"]]}} ; these deps will fail locally
:uberjar-exclusions [#".*sandbox.*"]
:repl-options {:init-ns app.core})
compiling the uberjar here will result in:
❯ lein uberjar
Compiling app.core
Compiling app.sandbox.remote-only
Syntax error macroexpanding at (remote_only.clj:1:1).
Execution error (FileNotFoundException) at app.sandbox.remote-only/loading (remote_only.clj:1).
Could not locate uncomplicate/commons/core__init.class, uncomplicate/commons/core.clj or uncomplicate/commons/core.cljc on classpath.
So, explicitly its trying to compile the class that was specifically excluded.
I thought that this kind of problem could be avoided by removing the :all tag from :aot compilation. E.g.:
(defproject app "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.10.1"]]
:profiles {:uberjar {:main app.core
:init-ns app.core
:aot [app.core]}
:remote {:init-ns app.sandbox.remote_only
:dependencies [[uncomplicate/neanderthal "0.43.1"]]}} ; these deps will fail locally
:uberjar-exclusions [#".*sandbox.*"]
:repl-options {:init-ns app.core})
which causes other problems:
❯ lein uberjar
Compiling app.core
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT.jar
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT-standalone.jar
~/Projects/app 5s 15:47:37
❯ java -jar ./target/app-0.1.0-SNAPSHOT.jar
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var
I've tried playing around with all kinds of :exclusions, :jar-exclusions and regexes. Variations of this question have been asked multiple times (1, 2) Nothing works.
How do I get Leiningen to compile uberjars and ignore the specified file(s)?
You are on the right track with changing :aot :all to :aot [app.core] but when you tried to run the JAR, you are running the library version instead of the whole application version:
java -jar ./target/app-0.1.0-SNAPSHOT.jar
That doesn't include Clojure or any dependencies. You want:
java -jar ./target/app-0.1.0-SNAPSHOT-standalone.jar
I haven't tried this particular setup with the "exclusions" features.
One workaround would be to create sub-projects for the "local" & "remote" parts of your app, which could then be used by a higher-level "total" project.
app
app-local
app-remote
where each of the 3 is a separate Lein project. app-local and app-remote could be developed in isolation. The top-level app project then uses has the 2 sub-projects as dependencies (and therefore only works in the remote/full environment).
The Lein feature checkouts allows you to develop in all 3 repos simultaneously, which is a huge help. It is much faster than the alternative of using lein install, which is slow, manual, repetitive, and error-prone.
P.S. Did you experiment with using lein jar instead of lein uberjar?
I am trying to link a local project to another local project that is under development using tools.deps :local/root option in deps.edn. It isn't working. I can't require the library's namespaces, and the path is correct.
The deps.edn entry looks like:
{:paths ["src" "resources"]
:deps {...
...
...
mylib {:local/root "../../../mylib"}
}}
The classpath that is generated, however, is incorrect:
../../../mylib/src/main/clojure
For some reason clojure/main is added on to the classpath for this library, and I don't know why. Then when I run clj to start the repl I am unable to load the library, and I get the FileNotFoundException.
To test that the addition of main/clojure to the lib path is the problem, I manually removed that part of the path in the cache file in .cpcache directory and was able to require the library namespaces once I'd removed clojure/main.
Does anyone know where the main/clojure is coming from and how I can stop it being added?
UPDATE
I did a new test that leads me to think this has something to do with the use of project.clj as opposed to deps.edn in the target project. In the test I had a project b with a deps.edn like this:
{:deps {a-proj {:local/root "../a-proj"}}}
While a-proj had a project.clj like this:
(defproject a-proj "0.1.0-SNAPSHOT"
:description "blah"
:url "http://example.com/FIXME"
:license {:name "The MIT Licence"
:url "https://opensource.org/licenses/MIT"}
:source-paths ["src"]
:dependencies [])
I then ran clj -Sforece -Spath and got:
~/Projects/b > clj -Sforce -Spath ethan at rembrandt.local
src:/Users/ethan/.m2/repository/org/clojure/clojure/1.10.0/clojure-1.10.0.jar:/Users/ethan/Projects/b/src:/Users/ethan/Projects/a-proj/src/main/clojure:/Users/ethan/.m2/repository/org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar:/Users/ethan/.m2/repository/org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar
You can see there that the /main/clojure path has been aded on. When I instead use an essentially deps.edn in a-proj:
{:deps {}}
I get the following path, which seems correct:
~/Projects/b > clj -Sforce -Spath
src:/Users/ethan/.m2/repository/org/clojure/clojure/1.10.0/clojure-1.10.0.jar:/Users/ethan/Projects/b/../a-proj/src:/Users/ethan/.m2/repository/org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar:/Users/ethan/.m2/repository/org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar
My deps.edn in ~/.clojure has only this:
{
:aliases {
:new {:extra-deps {seancorfield/clj-new {:mvn/version "0.9.0"}}
:main-opts ["-m" "clj-new.create"]}
:deps {:extra-deps {org.clojure/tools.deps.alpha {:mvn/version "0.5.435"}}}
:test {:extra-paths ["test"]}
}
}
project.clj is not supported as a project type by the Clojure CLI via deps.edn.
I have a Clojure application that is using a library which is symlinked from inside the "checkouts" directory.
This lets me work on both the app and the library at the same time. And lein knows how to compile and run the program without any problems.
But I want to make a standalone with lein uberjar, and it's complaining
Caused by: java.io.FileNotFoundException: Could not locate mylib/core__init.class, mylib/core.clj or mylib/core.cljc on classpath.
I assume that that is because mylib isn't mentioned in my project.clj file. It isn't, precisely because I want to use the version of mylib symlinked inside "checkouts".
But the uberjar command doesn't seem to be able to see it.
How can I solve this?
You can accomplish this by installing mylib in your local repository (~/.m2/repository).
Run lein install in the dependent project to install it in your local repository.
Add the project to :dependencies: in project.clj:
[mylib "version"]
Run lein uberjar in the main project.
The project will find the jar in your local repository.
/Edit
If you want to develop two libraries at the same time you can use a checkouts folder where checkouts contains a symlink to the dependent library.
mkdir checkouts
ln -nfs full-path-other-lib-dir full-path-checkouts-dir
Now changes in other-lib are immediately available in the main project.
See [https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies](the Leiningen checkouts documentation).
OK, it appears that the "checkouts" feature of lein works with lein test and lein run but not with lein uberjar.
I added the following to the local source code of a lib tupelo.core:
(def dummy-sample-data "Bogus!")
In the consuming project demo.core we can access the new Var:
(ns demo.core
(:use tupelo.core tupelo.test))
(defn -main [& args]
(println :foo-enter)
(spyx dummy-sample-data)
(println :foo-leave))
lein run produces:
:foo-enter
dummy-sample-data => "Bogus!"
:foo-leave
project.clj remains unchanged:
(defproject demo "0.1.0-SNAPSHOT"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [
[criterium "0.4.5"]
[org.clojure/math.combinatorics "0.1.6"]
[org.clojure/clojure "1.10.1"]
[prismatic/schema "1.1.12"]
[tupelo "0.9.201"]
<snip>
where "0.9.201" is the latest version of tupelo on Clojars. Checkouts looks like:
~/expr/demo > ls -ldF checkouts/*
lrwxrwxrwx 1 alan alan 17 May 12 13:57 checkouts/tupelo -> /home/alan/tupelo/
but uberjar fails:
~/expr/demo > lein clean ; lein uberjar
Compiling demo.core
Syntax error compiling at (demo/core.clj:6:3).
Syntax error compiling at (demo/core.clj:6:3).
Unable to resolve symbol: dummy-sample-data in this context
Full report at:
/tmp/clojure-10416346559924917196.edn
Compilation failed: Subprocess failed
Options
If you are wanting to deploy an application, you have 2 options:
If the lib exists on Clojars or Maven, you should probably deploy a release there before making a uberjar. If the lib is not ready for Clojars or Maven, maybe you aren't ready to use it in a uberjar...?
Simply copy the source tree of mylib (or use a symlink!) under the ./src dir in your project. You'll also have to copy in the dependencies into myproj/project.clj. You are effectively merging myproj and mylib, at least temporarily with this approach. If the are coupled tightly enough to require co-development, perhaps it should be a permanent merge?
Can anyone tell me some working dependencies to get up and running with zeromq and clojure?
I've tried several but leiningen isn't able to fetch them:
(Could not find artifact org.zmq:zmq:jar:2.1.0 in central (http://repo1.maven.org/maven2))
[org.zmq/zmq "2.1.0"]
[org.zmq/jzmq "1.0.0"]
I have compiled jzmq (/usr/local/share/java/jzmq.jar) and added this to my project.clj:
:native-path "/usr/local/lib"
There's a 2.0-SNAPSHOT here:
Lein should already have the clojars repo loaded.
What I propose is a mixture of what's already been proposed, but for the sake of completeness and hopefully to give a final answer I give it a try.
Since the dependency is not in the online repos I would include the jar(s) in the project's directory structure itself, e.g. in the directory repository and keep it in the source control system as the other files of the project. It's an important part of the project and without the dependency it won't run.
In this directory I would save the jar with the help of Maven Install plugin.
mvn install:install-file \
-Dfile=/usr/local/share/java/jzmq.jar \
-DgroupId=org.zeromq \
-DartifactId=jzmq \
-Dversion=2.1.0 \
-Dpackaging=jar \
-DlocalRepositoryPath=repository
When the jar file gets copied to the local repository, you define it and the dependency in project.clj as follows:
(defproject clojure-interal-repo-test "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.4.0"]
[org.zeromq/jzmq "2.1.0"]]
:repositories [["zeromq-repository" {:url "file:repository"
:snapshots false
:checksum :ignore
:update :never}]])
Within the project, run lein2 deps :tree to verify its correctness.
$ lein2 deps :tree
Retrieving org/zeromq/jzmq/2.1.0/jzmq-2.1.0.jar (4k) from file:repository/
[org.clojure/clojure "1.4.0"]
[org.zeromq/jzmq "2.1.0"]
Please note that the 4k above is the size of a fake file I created to test it out.
Read the document Repeatability in Leiningen's wiki should you need a bit more.
The only way I could get it to work was to use jeromq.
[org.zeromq/jeromq "0.3.2"]
Jeromq is native Java.
You can create a Maven local repository, install the compiled library into your local repo, and then, add the following to your project.clj
:repositories {"local" ~(str (.toURI (java.io.File. "your_local_repository_path")))}
Similar question, I have answered earlier here
Unfortunately, ZeroMQ is not present in public repository, at least at the last time I checked (a month ago I think). So you have to install the jar manually:
mvn install:install-file -Dfile=/usr/local/share/java/jzmq.jar -DgroupId=org.zeromq \
-DartifactId=jzmq -Dversion=2.1.0 -Dpackaging=jar
Then you can use the artifact as [org.zeromq/jzmq "2.1.0"] in your project.clj.
I have a lein project in one directory, and instead of using the .jar that gets downloaded when I run
> lein deps
I want to use the source from a cloned github repository (It has recent fixes not in the current jar). What is the canonical way to do this with leiningen?
Here is my project file:
(defproject oroboros "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.2.1"]
[org.clojure/clojure-contrib "1.2.0"]
[clojure-source "1.2.1"]
[overtone "0.3.0"]
[penumbra "0.6.0-SNAPSHOT"]]
:native-dependencies [[penumbra/lwjgl "2.4.2"]]
:dev-dependencies [[native-deps "1.0.5"]
[swank-clojure "1.4.0-SNAPSHOT"]])
I want to use the overtone repo from github, rather than the one from clojars.
https://github.com/overtone/overtone
Is this possible?
You can use checkout dependencies. From Leiningen's README:
Q: I want to hack two projects in parallel, but it's annoying to
switch between them.
A: Use a feature called checkout dependencies. If you create a
directory called checkouts in your project root and symlink some other
project roots into it, Leiningen will allow you to hack on them in
parallel. That means changes in the dependency will be visible in the
main project without having to go through the whole
install/switch-projects/deps/restart-repl cycle. Note that this is not
a replacement for listing the project in :dependencies; it simply
supplements that for tighter change cycles.
Back when I was using lein I simply put symlinks in my project directory to the checked out Overtone source dir.
I use cake for my Overtone hacking these days which has support for adding external projects to the class path. You just need to add the path to project.classpath in your project's .cake/config file:
project.classpath = /Users/sam/Development/improcess/lib/overtone/src: