How do you distribute a Clojure program to non-programmers? - clojure

I'm new to Clojure but I'm learning it. I'd like to know the best way to package and distribute a Clojure program to end users who aren't necessarily programmers. I know in Ruby you can just tell users to download the program with gem install [program name] and then run the command that runs the program. What's the equivalent for Clojure programs?

I you use Leiningen it has an uberjar command to make self contained executable jar files, which your users can just double click. See: http://zef.me/2470/building-clojure-projects-with-leiningen

Clojars is great if you're distributing a library, but I'm not sure if that's the best option for end users.
If you're already using Maven, I believe the best option is to create a uberjar containing all required classes. If you want to make it even more end user friendly, you can then create an installer from this jar using something like IzPack. Just remember that Clojure programs are Java programs, so all distribution options for Java are valid for Clojure as well.

lein uberjar works great for small mostly-Clojure apps, but it doesn't scale when using many Java libraries, including necessary licenses, and other such things. If you use the Maven Clojure plugin, you could take advantage of the vast and terrifying Maven assembly plugin to build and final structure you might conceivably need.
Or you could write a Leiningen plugin to do something similar. I'm not sure if such a thing exists.

Clojars (http://clojars.org/) is the bigger repository of Clojure libraries you can find.
It works perfectly with Leiningen projects or any other Maven based project management tool.

Related

Installing libraries with leiningen without creating project

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.

simple tool for compiling Clojure .clj into .class / .jar

I've found two ways of compiling Clojure *.clj files into *.class files, and while they both work, I have some gripes with both of them.
The first one uses a REPL and so cannot be automated (or can it?)
The second one uses lein. To be frank I don't see why I should use a dependency management tool for something that should be part of the core tool-chain of the language. But in any case, using lein soon forces you to use a local Maven repository if your Clojure code needs to access local jars (which is highly likely).
Is there a better way to generate *.class or *.jar files from Clojure code that involves only core Clojure tools and that can be employed in a scripted, non-interactive way?
Clojure provides clojure.core.Compile, which can be used to compile Clojure code from the command-line.
java -Dclojure.compile.path=<targetdir> -cp <targetdir>;clojure.jar <list of namespaces>
For an example of how to use this from ant, look at the compile-clojure task in Clojure's own build.xml file.
clojure.core/compile can be automated via Clojure

Analogue for maven-resources-plugin or maven-antrun-plugin for leiningen

I use leiningen to manage my clojure project and I want to copy jar file along with some other files into a certain directory as a final part of a build process. Leiningen treats 'resources' as something which should be included into the jar file, and it is unacceptable for me. If I used maven, I could configure it for such task using maven-resource-plugin or fall back to Ant using maven-antrun-plugin, but leiningen is far more convenient tool for clojure projects.
Strangely, I couldn't manage to find anything about similar functionality in leiningen on the internet. This is curious, because one of major clojure applications is web sites, and web sites usually do not include their resources (js, css, etc) into the jar (or do they? That would be weird since slight css tweak will require rather lenghty recompilation). It comes naturally that we have to prepare site environment (copy static resources along with jar bundle into some directory layout), and this task should be done by the build tool.
Is there a plugin to copy files around the filesystem (or something which could substitute it, like running Ant), or I must write one myself? Right now I'm using shell scripts, but it is very inconvenient since I had to run several commands instead of one, and also it is unportable.
did you checkout lein-resource?
in any case. here is a long list of available plugins for lein, maybe you will fine some of them helpful

Clojure, Lein, JavaFx, native deps

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.]

Does Clojure require a JDK?

I want to distribute a Clojure program. Do I need a JDK or can a JRE handle everything in Clojure?
You only need the user to have a JRE (v1.5 or above)
Clojure programs can be compiled into a jar file. You don't have to use something like
leiningen, but it's a lot easier.
Check out this page on the Clojure.org site for how to compile and run a program.
You can compile to a jar file from the REPL:
(compile 'clojure.examples.hello)
Here's how you would run a compile jar:
java -cp ./classes:clojure.jar clojure.examples.instance asdf
You just need a JRE.
https://github.com/technomancy/leiningen/blob/master/TUTORIAL.md explains in more detail, but I believe you just want an "Uberjar" which will contain all the dependencies that you need to distribute your application.
JRE is required! You can easily download it from Internet.