Hey, how do I run a code with Clojure AOT? I'm trying to run the following code on http://atcoder.jp but get an error (see at the bottom):
(ns foo
(:gen-class))
(import java.util.Scanner)
(defn -main [& args]
(let [s (Scanner. System/in)
n (.nextLong s)] ; 4
(loop [a (.nextLong s) ;; 4
res 1] ;; 2
(if (<= res n) ;; true
(if (= a 1) ; false
(println res)
(let [cnt (dec a)] ; 3
(if (>= (+ res cnt) n)
(println n)
(do
(dotimes [_ (dec cnt)] (.next s)) ; 1
(recur (.nextLong s) ; 4
(+ res cnt)))))) ; 2
(println res)))))
Here is the error:
; Could not locate foo__init.class, foo.clj or foo.cljc on classpath.
; Execution error (FileNotFoundException) at user/eval153$fn (form-init15451739026821950811.clj:1).
; Could not locate foo__init.class, foo.clj or foo.cljc on classpath.
Without ns I get another error:
Error: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method, or the namespace has not been AOT-compiled.Hi! So for the very basics of AOT you can use clojure https://clojuredocs.org/clojure.core/compile function. You can create a dir like this :
.
├── classes
└── src
└── foo.clj
with your foo file, with a ns like :
(ns foo
(:import [java.util Scanner])
(:gen-class))
The start a repl and compile the file :
$ clj
Clojure 1.12.3
(compile 'foo)
foo
You will get your files there :
$ ls classes
clojure 'foo$fn__128.class' 'foo$loading__6814__auto____126.class' 'foo$_main.class' foo.class foo__init.class
Now to run your foo.class you need the clojure and spec jars, so you can run them like :
$ java -cp /home/USER/.m2/repository/org/clojure/clojure/1.12.3/clojure-1.12.3.jar:/home/USER/.m2/repository/org/clojure/spec.alpha/0.5.238/spec.alpha-0.5.238.jar:. foo
But that is not what people normally do, we build an uberjar (with AOT if needed), and then run with java -jar your-uber-jar.jar
Here is one way to do it using tools build https://clojure.org/guides/tools_build#_compiled_uberjar_application_build
The problem is that I’m trying to run the code on a competitive programming site http://AtCoder.jp that doesn’t allow to create any directories
Then the easiest if you have leiningen installed, just run lein new my-app for it to create a full structure or create a project.clj on your directory (where you have "src/foo.clj", with something like :
(defproject app "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url ""
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url " "}
:dependencies [[org.clojure/clojure "1.11.1"]]
:main foo
:repl-options {:init-ns foo})
Then run lein uberjar. That should create a *-standalone.jar file that you can submit and run with java -jar your-standalone.jarthat will AOT compile by default, which you probably don't need
With that you just submit one file and a command on how to run that file. Whatever they recommend for Java if they don't have Clojure instructions
To summarize one way:
• Run lein new my-app
• Modify the created "src/my_app/core.clj" with your code
• add a :main my-app.core to your project.clj
• run lein uberjar
• run the jar with java -jar my-app-0.1.0-SNAPSHOT-standalone.jar