Need to create jar file for the compiled clojure classes - clojure

I am learning clojure and already got an assignment.
I need to automate compile and build jar of the classes generated.
Within the clojure code, I need to compile another clojure code, write code to build the jar of the classes generated.
Here is my example.
even_test.clj
(ns clojure.sqe.examples)
(defn pair-test [test-fn n1 n2]
(if (test-fn n1 n2) "sucess" "failed"))
(println (pair-test #(even? (+ %1 %2)) 3 4)) ; -> pass
compile_test.clj
(ns clojure.sqe.examples
(:use clojure.test)
(:require [simple-check.core :as sc])
)
(compile 'clojure.sqe.examples.even_test)
;(println *compile-path*) => classes
;TO-DO - Write code to
;Build the jar for the compiled classes or from classes folder
; upload this jar to a service .

You need to 1. compile the code and then 2. create a JAR file containing the compiled code.
Clojure's compile function compiles code and puts the compiled class files (there can be more than one) under the directory specified by *compile-path*.
You will need to create a JAR file using JarOutputStream (and optionally a Manifest), and write all the files under *compile-path* into the JAR. You will have to massage the paths so that a file like target/repl/classes/clojure/sqe/examples.class is put into the JAR as clojure/seq/examples.class.
The lein jar command more or less does this, so you might want to look at its source code for details: https://github.com/technomancy/leiningen/blob/master/src/leiningen/jar.clj

Why you don't use Leiningen? It is the de facto for doing Clojure development. You can do a lot of things, such as compiling Clojure sources, compiling Java sources, run unit tests, generate POM files from porject.clj and of course, generating JAR files.
lein jar
Package up all the project's files into a jar file.
lein uberjar
Package up the project files and all dependencies into a jar file.

Related

Could not locate clojure/data/json: How do I get my REPL to see this (and similar) dependencies

I am using lein repl without a project so there is no project.clj.
I am running Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM.
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory. Is that why I am getting a FileNotFoundException Could not locate clojure/data/json__init.class or clojure/data/js
on.clj on classpath? I can't find my other Clojure dependencies there either so I don't know where they reside and if this dependancy should be in .m2 or not.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck.
Is this a dependency that I still need to install? If so, how do I install it without going through a project?
I don't understand the JVM as I am new to it, so add a little extra information in your answer.
I have looked at this, this, this, this and this. I don't know if I am overlooking anything so your help will really be appreciated.
I am using lein run without a project so there is no project.clj.
If you're using Leiningen, this'll be much easier if you create a project.clj file that declares your dependencies. Leiningen will read project.clj and handle fetching any missing dependencies to your local Maven repository, and add them to your classpath when you start your REPL/application. (lein run doesn't work for me in a directory without a project.clj; I get an error: No :main namespace specified in project.clj.. Did you mean lein repl?)
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory.
clojure.data.json doesn't ship with Clojure — it's a separate dependency that must be fetched and added to your classpath in order to use it. The classpath tells the JVM where to look when it loads class files. Leiningen will do both of these things for you if you declare the dependency in project.clj:
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/data.json "0.2.6"]]
You can also use the lein deps command if you only want to fetch dependencies.
You can create a new/blank Leiningen project with lein new project_name_goes_here. It will have a project.clj with a few boilerplate entries and a :dependencies key where you can declare dependencies.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck. Is this a dependency that I still need to install? If so, how do I install it without going through a project?
You could manually download it from the internet, then manually add its path to your classpath, but if you're already using Leiningen it's much easier to add a line to a project.clj file and have Leiningen handle this for you.
If using a project.clj file w/Leiningen isn't an option, there are other ways to use Clojure and resolve dependencies/build a classpath at runtime. Boot accommodates this workflow, you can use Leiningen like this with a little added effort, as well as the newer tools.deps tooling. There are examples of each in this ClojureVerse thread, but note that some of these approaches are doing essentially the same thing as declaring the dependency in a file — instead declaring them as CLI arguments.
For example, using Clojure CLI tooling:
$ clj -Sdeps "{:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}}"
Clojure 1.9.0
user=> (require '[clojure.data.json :as json])
nil
user=> (json/write-str {:foo "bar"})
"{\"foo\":\"bar\"}"
user=> (System/getProperty "java.class.path")
"src:
/Users/me/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:
/Users/me/.m2/repository/org/clojure/data.json/0.2.6/data.json-0.2.6.jar:
/Users/me/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:
/Users/me/.m2/repository/org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar"
You could create a deps.edn file containing {:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}} in the same directory, and clj would read that, resolve the dependencies if necessary, and build the classpath accordingly.
This is a great opportunity to use lein try. Once you add it to your ~/.lein/profiles.clj, you'd simply run: lein try org.clojure/data.json and you'll be greeted with a running REPL with that dependency just a require away.

Can I start Gorilla REPL from an uberjar?

I play with this great Gorilla REPL powered project ( https://bitbucket.org/probprog/anglican-examples/ to be specific), and want to use it under certain restricted circumstances.
Is there a way to produce an uberjar that can be started using only a JVM?
Well, I know how to create an uberjar for this project, but can I start a Gorilla REPL from it? If not what do I have to add and how do I start it?
EDITED Note on Juraj's answer:
I added a start file src/gorillaproxy/gorillaproxy.clj with the following content:
(ns gorillaproxy.gorillaproxy
(:use [gorilla-repl.core :only [run-gorilla-server]])
(:gen-class))
(defn -main
[& args]
(run-gorilla-server {:port 8990}))
Then I added [gorilla-repl "0.4.0"] to the dependency list (in project.clj), and the line
:main gorillaproxy.gorillaproxy
In that way the uberjar started the Gorilla REPL, and when I put the worksheets (and data, resources, .. if needed) into the same directory, everything worked fine.
Gorilla is typically run via the lein-gorilla plugin and thus isn't a part of an uberjar.
If you really want to create a bundle containing gorilla repl dependencies, then you need to add it this capability manually to your project.
The question is why would you want to do that.
Do you want to distribute these samples to somebody else? If that's the case, you'll still need to have all those worksheets in the current directory from where your uberjar is run because that's how gorilla repl discovers worksheets.
You can look at lein-gorilla source code to see how gorilla repl can be started.
I'd then at the same code to your project (create new src/core.clj file or whatever) and configure it in your project.clj as :main.
You'll also need to add gorilla-repl as a dependency to your project.clj
Notice however, that you'll need to run that uberjar from a directory where your anglican worksheets are (or a parent directory of such a directory).

How to load Clojure files from directory to REPL while preserving dependency order?

I have 2 external Clojure files in my file system.(a.clj and b.clj)
/Users/e/.somedir/a.clj:
(ns a (:require [b]))
(b/printt)
/Users/e/.somedir/b.clj:
(ns b)
(defn printt [] (println "aaaa"))
The thing is I want to be able to load those files to my REPL(preserving dependency order)
If I load a.clj first I get this exception:
(clojure.main/load-script "/Users/e/.somedir/a.clj"):
CompilerException java.io.FileNotFoundException: Could not locate b__init.class or b.clj on classpath., compiling:(/Users/e/.somedir/a.clj:1:1)
If I load b.clj first there is no problem.
So how can I figure this dependency order out and load b.clj first, imagine that this is a complex dependency graph, are there any code examples?
P.S: I don't want to use leiningen or any other build tool(want to do it programmatically). There could be some kinda library/code snippet that shows me files that needed to get loaded in dependency order. How do build tools like leiningen achieve this thing? They do it in some way.
You don't need to load all the files, just the root file of your dependency tree. The other source files are loaded as needed. So if namespace A requires namespace B and namespace B requires namespace C, then you just:
(load "com/example/A.clj")
and B.clj and C.clj are loaded automatically.
Also, since you're not using a build tool, you'll need to be careful about a few things:
1) You need to make sure your source files folder structure mirrors your namespace declarations so an ns of 'com.example.A' should be in a folder structure like src/com/example/A.clj. If you don't Clojure has no way to know where a dependency is located in the file system.
2) A running Clojure REPL is initiated with a specific class path. If the 'src' folder above was not defined on the classpath, Clojure doesn't know about it. So be careful to add that folder to your classpath: java -jar clojure-1.9.0.jar -cp [need to include your src folder here] clojure.main
One last note, running without a build tool like Leiningen means you'll need to be an expert on java class paths and understanding Clojure's dependency model. That's a lot for someone trying to learn Clojure.
You say do not want to use lein or any other build tool, and that's fine. So you'd be better just to organize your code according to Deps & CLI Guide about the latest CLI tools released with Clojure 1.9.
Briefly, in your folder, create another src folder and put all the .clj files there. The system will find them automatically. For example:
└── your-project
├── deps.edn # your dependencies
└── src
└── a.clj
└── b.clj
Then, in the root of your project, just run clj, and the REPL will appear. There, you may require your modules as well.
Take a look at this article, it would really help.
This is easy if you set up your project using lein. Here is an example project fred. To create a simple project, just type:
> lein new app fred
> cd fred
> cp src/fred/core.clj src/fred/second.clj
It now looks like so:
fred
└── src
├── fred
   ├── core.clj
   └── second.clj
with 2 source files core.clj and second.clj. Add your functions:
> cat src/fred/core.clj
(ns fred.core)
(defn aaa [& args]
(println "aaa - enter")
(println "aaa - exit"))
> cat src/fred/second.clj
(ns fred.second
(:require [fred.core :as fc]))
(defn bbb [& args]
(println "bbb - enter")
(fc/aaa)
(println "bbb - exit"))
Then, you can access both using lein repl:
> lein repl
Clojure 1.9.0
fred.core=> (aaa)
aaa - enter
aaa - exit
nil
fred.core=> (require '[fred.second :as fs])
nil
fred.core=> (fs/bbb)
bbb - enter
aaa - enter
aaa - exit
bbb - exit
nil
fred.core=>
You can also use the following variant to reload a namespace and its dependencies:
(require '[fred.second :as fs] :reload-all)
although this is not perfect and can get into a confused state (see How to reload a clojure file in REPL for more details).
I think I found the solution first of all I created dependency graph then I sorted namespaces in topological order so this is the thing I've been looking for a while. Now I can load Clojure files in that order(increasing dependency order).

exclude certain clj namespaces from compilation in leiningen

I have a project that works fine using lein run. Now I want to compile it into a standalone jar using lein uberjar. However, there are a couple of source files in my src/projectname/ directory called e.g. playground.clj and stats.clj that I use for experimenting with emacs & the repl, but that I don't want to compile for the final project.
With something like make, I would specify all files that should be compiled. With clojure/leiningen, it seems, all files are compiled by default - how can I exclude files? I haven't found anything in the leiningen docs.
I am currently using :aot :all. Is this the place to change something? Again, I couldn't find detailed documentation on this.
UPDATE:
The suggestions so far haven't worked. What has worked, however, is to include all desired namespaces instead of excluding the ones that should not be compiled. E.g.:
(defproject myproject "version"
;; ...
:profiles {:uberjar {:aot [myproject.data
myproject.db
myproject.util]}})
Have a look at leiningen's sample project.clj, which describes how to use :jar-exclusions or :uberjar-exclusions to exclude arbitrary paths when creating jars (resp. uberjars).
;; Files with names matching any of these patterns will be excluded from jars.
:jar-exclusions [#"(?:^|/).svn/"]
;; Files with names matching any of these patterns will included in the jar
;; even if they'd be skipped otherwise.
:jar-inclusions [#"^\.ebextensions"]
;; Same as :jar-exclusions, but for uberjars.
:uberjar-exclusions [#"META-INF/DUMMY.SF"]
Old question, but I think I found the answer for those coming after me.
I found the answer in the link to the sample leiningen project from #amalloy's answer, except instead of :jar-exclusions I use source-paths, here.
The idea is to create two separate source directories, one for stuff you don't care to spread around and one for stuff you do:
dev-src/<your-project>/playground.clj
dev-src/<your-project>/stats.clj
src/<your-project>/<everything-else>
Then, in your project.clj, include src in source-paths normally, and include emacs-src in a special profile where your want it visible, say the usual :dev profile:
{
;; ...
:source-paths ["src"]
:profiles {
:dev {
:source-paths ["src" "dev-src"]
}
}
}
That way when you're messing around on your machine those files will be in the jar, and when you deploy to clojars or compile with uberjar they will not be included in the jar, nor compiled.
Try this (ns ^:skip-aot my-ns)
You can also do
(ns ^{:skip-aot true} my-ns
(require [...]))
Source

How can i minimize the AOT compilation in leiningen (Clojure)

When you create a Clojure project with leiningen all the *.clj-files are compiled AOT. Normally the AOT compilation is not necessary and I would like to minimize it.
This is necessary for me to raise acceptance of Clojure as a complement in a Java-dominated environment. It is easier to "sell" a single class-file as the glue together with a couple of kB clj-files against the alternative of having 250+ kB class-files with strange names and hidden amongst them a little clj-file (which isn't even read any more during execution).
Ideally the result of "lein compile" would be only a single small class file which (together with the clj-files and the clojure-library) implements the needed class-instance.
What is the easiest way to achieve this? I would prefer not to write a single line of Java (of course).
Update after feedback from technomancy
I do not suspect this being a leiningen problem. Let me explain what I am after with an example. Please forgive the length of the example. I am using leiningen 1.3.1 but I think 1.4.0-SNAPSHOOT behaves the same way.
$ lein new dummy
Created new project in: dummy
$ cd dummy
Now change project.clj to (added ":main dummy.core"):
(defproject dummy "1.0.0-SNAPSHOT"
:description "FIXME: write"
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]]
:main dummy.core)
and src/dummy/core.clj to:
(ns dummy.core
(:gen-class))
(defn -main [& args]
(println "This is Clojure code, args=" args))
Now compile it:
$ lein compile
Compiling dummy.core
This generates the following files in classes/dummy:
core.class
core__init.class
core$loading__4410__auto__.class
core$_main.class
This is all correct, I can execute the result:
$ java -cp lib/*:classes dummy.core Hello
This is Clojure code, args= (Hello)
Now comes what I want to have instead, but I do it manually:
I can delete all class-files except core.class and copy the core.clj into classes/dummy which now looks very empty:
$ ls classes/dummy/
core.class
core.clj
The core.class contains code to load the core.clj at runtime and the result is still the same, I still can do:
$ java -cp lib/*:classes dummy.core Hello
This is Clojure code, args= (Hello)
I can also modify core.clj (note: in classes/dummy!) and of course changes do not need to be recompiled.
Now my question boils down to this: Is there an easier way to get just this core.class?
Leiningen has done no AOT by default for quite some time now; perhaps you have an older version? But there is a new feature (in 1.4.0-SNAPSHOT) that ensures .class files created due to transitive AOT get deleted before jar creation, (see Clojure assembla #322) which may also interest you.