I am working on a Clojure library. Inside the library is an example app that shows how to use the library. In the example app, which is in a subdirectory, what is the cleanest way to depend on the parent library? I want this to be fast; I want the dependency always be in step with the current library code. That means avoiding deploying to Clojars (or elsewhere).
Use Leiningen "Checkout" Dependencies.
You can add "../src" to the :source-paths in project.clj
Since you always want the current version of the parent's code, and it will always be in the same relative place, it's less a "dependency" to be resolved and more a classpath to be used to find code.
Related
I have been using Clojure, ClojureScript, lein, shadow-cljs, re-frame, reagent, Emacs, and CIDER to work on a Clojure/ClojureScript dynamic web app project.
Currently, the project uses project.clj and shadow-cljs.edn to declare dependencies.
There is a discussion about changing things so that:
1 - We would start using a lein plug-in called lein-tools-deps
2 - Also, we would tweak shadow-cljs.edn file so that the dependencies would be removed and the file only indicate:
:dependencies true
3 - Finally, we would create a new deps.edn file holding all the dependencies.
It is not totally clear the advantages of this process.
I can see one: instead of declaring dependencies on shadow-cljs.edn and on project.clj they would be in a single file: deps.edn.
Is there another benefit of having dependency declaration via deps.edn instead of using shadow-cljs.edn and project.clj via :dependencies?
For instance, would this affect the use of Maven packages hosted on GitHub packages? Is deps.edn better for that?
deps.edn has the benefit that it supports direct git dependencies (ie. :git/url), as well as an easy mechanism for local dependencies (ie. :local/root). It is also more modern and becoming the "default".
shadow-cljs.edn has no support for these features, project.clj has some via plugins or other mechanism (eg. checkouts).
So, if you want those features it make sense to use deps.edn. However, depending on how complex your project is that might not be an easy switch.
shadow-cljs ultimately doesn't care how you manage your dependencies, but if you move things out of shadow-cljs.edn you are taking "power" away from it. If managed via shadow-cljs.edn it tries to prevent certain mistakes (eg. dependency conflicts), it can't do that when running via deps.edn. So, you'll have to sort those out manually potentially. It may just work, really depends on your project.
I know that I can depend on one by adding a line like
[org.clojure/math.numeric-tower "RELEASE"]
to ~/.lein/profiles.clj. However, I'd like to depend on all all the org.clojure libraries (https://github.com/clojure) to make experimentation at the REPL more convenient. Is there a way to do this besides just listing them all explicitly?
Thanks
No, this is not possible because lein needs to know what version of each library you want to use.
Fortunately leinengen when used with the refactor-nrepl middleware (which is included by default in the newest emacs/cider package) can hotload dependencies while your program is running which makes this somewhat more convenient
https://github.com/clojure-emacs/refactor-nrepl/blob/master/README.md#hotload-dependency
I am learning Clojure and coming from a Ruby background.
I am looking for something analogous to gem install <library>. The various incantations of lein install do not seem to fit this bill.
Is there a way to simply install a library locally so that it can be referenced in the REPL without the need to create a project?
Seems like, you want to install a library with lein. Here is the plugin, install it and use like
lein localrepo install <filename> <[groupId/]artifactId> <version>
If your aim is merely to load libraries in the REPL consider using alembic. It loads dynamically classpaths, resolve dependencies and automatically pulls libraries from the repositories.
Here is a use case:
(require 'alembic.still)
(alembic.still/distill '[enlive "1.1.1"])
It simply requires you to add the following entry to your .lein/project.clj:
{:dev {:dependencies [[alembic "0.1.1"]]}}
See this answer.
Java and thus clojure do not generally have the the idea of globally installed libraries. You should always be creating a classpath with the minimal set of dependencies. You need somehow to specify and manage this classpath and the easiest way to do this is with leiningen, which requires a project.
leiningen automates the process of retrieving the remote libraries and placing them in your local repository which is somewhat analogous to gem install, but these libraries do not become automatically available to a REPL.
The easiest way to have a set of libraries always available is to have a 'scratch' project which you use for REPL experiments before starting a new project. It's not too much of an overhead.
In lein 2 you can update profiles.clj with package you want to install:
~\user\.lein\profiles.clj
With the first run of any project with lein, the local repo will be updated with what was incereased in profiles.clj.
Sometimes I just run lein deps without being in a project folder, this will update the local repo for you.
This way you can add any library to your project.clj or call it from repl and it will be extracted from local repo.
If you don’t have a project, you add your dependencies in your global lein user profile instead located at ~/.lein/profiles.clj.
The doc isn’t great for lein to be honest. So this part is confusing. But you edit that file as such:
{:user {:plugins [[lein-pprint "1.1.1"]]
:dependencies [[slamhound "1.3.1"]]}}
In the :plugins vector you add whatever global lein plugin you want to have. And in the :dependencies vector you add whatever library you want available globally.
Then anywhere you start a lein repl you’d have those dependencies available to you. And everywhere you run lein you’ll have the additional plugin features available to you.
If you use tools.deps instead of lein, aka, the clj command instead of the lein command. Then it is a bit different. You instead want to modify your ~/.clojure/deps.edn file. Where you’d add dependencies there instead:
{:deps {clj-time {:mvn/version "0.14.2"}}}
So if you put the above in your user deps.edn whenever you run clj command the clj-time library will be available to you.
Context
I want to use JavaFx with clojure.
I am aware of http://nailthatbug.net/2011/06/clojure-javafx-2-0-simple-app/
Question:
Is there a way to make JavaFX work with Clojure using native-deps in lein instead?
Thanks!
I've created a simple Clojure and JavaFX example on Github. Testing on Ubuntu I had to install the JavaFX runtime into my local Maven repository, using the deploy:deploy-file target (install:install-file did not work for me).
mvn deploy:deploy-file -DgroupId=local.oracle -DartifactId=javafxrt -Dversion=2.2.0 -Dpackaging=jar -Dfile=/usr/lib/jvm/java-7-oracle-amd64/jre/lib/jfxrt.jar -Durl=file:/home/raju/.m2/repository
Make sure you have the following arguments set correctly:
-Dfile={full path to jfxrt.jar in jre/lib folder}
-Durl=file:{full path to Maven repository, e.g. $HOME/m2.repository}
In the project.clj, I added the dependency based on the -DgroupId and -DartifactId values when installing the JAR into the repository. If you use change these values, make sure to change the dependency accordingly:
[local.oracle/javafxrt "2.2.0"]
Java was able to load the binary libraries without any problems. If Java reports problems loading a binary library, e.g.
Caused by: java.lang.UnsatisfiedLinkError: Can't load library:
/usr/lib/jvm/javafx-sdk/rt/lib/amd64/libglass.so
check out these two question on SO:
What is LD_LIBRARY_PATH and how to use it?
java.lang.UnsatisfiedLinkError no *****.dll in java.library.path
Because JavaFx has native dependencies your option are limited to, ]
shipping these dependencies with your project (including them),
creating a package that you can depend on which has them (providing them),
or having your package require the user to install them in some other way.
Because the tutorial you link to covers the case where the user of your package/program installs JavaFx on their own, by using robert.hook and depending on the end-user's package manager to provide the actual native dependencies. I'll cover how to have your package/program include the dependencies.
native-deps can be used to ship native dependencies with your package. You just need to add all the .so, .dll, .etc files in the appropriate directories. I think the projects github page does a better job than I of explaining the structure.
The link in the question is broken so I can't see your example, but with Java 8, JavaFX is now part of the standard JDK/JRE. I therefore expect the native dependency issue to be irrelevant at this point.
Not sure if this will work for others, but this appears (so far) to have worked for me:
mvn install:install-file -DgroupId=javafx -DartifactId=javafx -Dversion=2.1.0 -Dpackaging=jar -Dfile=/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/jre/lib/jfxrt.jar
I have no idea why this works, but I believe jfxrt.jar has the files I need. Then, after this, I kindle it in project.clj as
[javafx "2.1.0"]
in the :dependencies (not :native-deps) section.
[Having written this, I really have no idea why this even appears to work.]
Is there a typical workflow for hacking on Clojure libraries?
Say I have my application "Foo" which relies on a third-party library "Bar", which was obtained from a repository, and included in project Foo via lein deps.
Then, say I want to hack on library "Bar", so I clone it from github.
Now, I would like to hack on my local clone "Bar" while at the same time working on application "Foo" that depends on it. I would like all of the source files for "Bar" to open in Emacs along with all the source files in "Foo", using one instance of swank.
Is there an easy way to do this?
I want to alter my environment and not the project. Therefore I do not want to edit project.clj for "Foo" in order to accomplish this.
Does this require setting the classpath before starting up lein swank, or is there a better way?
Create a checkouts directory in your Foo project and create a symlink to your clone of the Bar project inside this directory.
To quote the Leiningen FAQ:
Q: I want to hack two projects in parallel, but it's annoying to switch between them.
A: 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, and the copy in checkouts will take precedence over the dependency declared in project.clj. Note that this is not a replacement for listing the project in :dependencies; it simply supplements that for convenience.