James Jenkinson
James Jenkinson

Reputation: 1651

Including files in Clojure without Leiningen: Could not locate file

Trying to do a simple clojure program without that includes a function defined in another file. It is unable to find the file in the same directory.

helloInclude
    src
        main.clj
        importer.clj

main.clj

(ns main
  (:gen-class)
(:require [importer]))

(defn -main
  [& args]
  (println "Hello, World!"))

(-main) 
(println (func 5 6))

importer.clj

(ns importer
  (:gen-class))

(defn func
    [a b]
    (+ a b 1))

Executed from within the src directory with:

java -jar "Path\To\Clojure\clojure-1.8.0\clojure-1.8.0.jar" -i main.clj

Returns error:

Exception in thread "main" java.io.FileNotFoundException: Could not locate importer__init.class or importer.clj on classpath., compiling:(C:\Users\jamesjenkinson\Clojure\helloInclude\src\main.clj:1:1)
        at clojure.lang.Compiler.load(Compiler.java:7391)
        at clojure.lang.Compiler.loadFile(Compiler.java:7317)
        at clojure.main$load_script.invokeStatic(main.clj:275)
        at clojure.main$init_opt.invokeStatic(main.clj:277)
        at clojure.main$init_opt.invoke(main.clj:277)
        at clojure.main$initialize.invokeStatic(main.clj:308)
        at clojure.main$null_opt.invokeStatic(main.clj:342)
        at clojure.main$null_opt.invoke(main.clj:339)
        at clojure.main$main.invokeStatic(main.clj:421)
        at clojure.main$main.doInvoke(main.clj:384)
        at clojure.lang.RestFn.invoke(RestFn.java:421)
        at clojure.lang.Var.invoke(Var.java:383)
        at clojure.lang.AFn.applyToHelper(AFn.java:156)
        at clojure.lang.Var.applyTo(Var.java:700)
        at clojure.main.main(main.java:37)
Caused by: java.io.FileNotFoundException: Could not locate import__init.class or import.clj on classpath.
        at clojure.lang.RT.load(RT.java:456)
        at clojure.lang.RT.load(RT.java:419)
        at clojure.core$load$fn__5677.invoke(core.clj:5893)
        at clojure.core$load.invokeStatic(core.clj:5892)
        at clojure.core$load.doInvoke(core.clj:5876)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.core$load_one.invokeStatic(core.clj:5697)
        at clojure.core$load_one.invoke(core.clj:5692)
        at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
        at clojure.core$load_lib.invokeStatic(core.clj:5736)
        at clojure.core$load_lib.doInvoke(core.clj:5717)
        at clojure.lang.RestFn.applyTo(RestFn.java:142)
        at clojure.core$apply.invokeStatic(core.clj:648)
        at clojure.core$load_libs.invokeStatic(core.clj:5774)
        at clojure.core$load_libs.doInvoke(core.clj:5758)
        at clojure.lang.RestFn.applyTo(RestFn.java:137)
        at clojure.core$apply.invokeStatic(core.clj:648)
        at clojure.core$require.invokeStatic(core.clj:5796)
        at clojure.core$require.doInvoke(core.clj:5796)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at src.main$eval3$loading__5569__auto____4.invoke(main.clj:1)
        at src.main$eval3.invokeStatic(main.clj:1)
        at src.main$eval3.invoke(main.clj:1)
        at clojure.lang.Compiler.eval(Compiler.java:6927)
        at clojure.lang.Compiler.eval(Compiler.java:6916)
        at clojure.lang.Compiler.load(Compiler.java:7379)
        ... 14 more

Also tried explicitly calling classpath to be the current directory with:

java -classpath . -jar "Path\To\Clojure\clojure-1.8.0\clojure-1.8.0.jar" -i main.clj

I am unable to use Leiningen for this. How should I properly reference the file?

Edit: Changed namespaces to top level.

Upvotes: 3

Views: 1499

Answers (2)

Amir Eldor
Amir Eldor

Reputation: 1357

I hope I'm getting you correctly and we have the similar problem which I seem to have solved. My current directory structure is (forgive the humorous nature of things):

.
├── chikaka
│   ├── main.clj
│   └── tools
│       └── dog.clj
├── core.clj
└── deps.edn

The key for me was deps.edn file which had the following contents:

{:paths ["."]}

Source: https://clojure.org/reference/deps_and_cli#_paths

When you add paths to the deps file, each is added the to glorious CLASSPATH that Java likes so much. Then you will have requires like this working for example:

(ns chikaka.main
  (:require [chikaka.tools.dog :refer [bark]]))

Upvotes: 1

noisesmith
noisesmith

Reputation: 20194

require only finds files that are under your classpath. If you want to be able to use require, the path to your code relative to the classpath has to match the package and name of the namespace. The -cp arg to java can add directories to the classpath, and the current directory is not implicitly in the classpath.

If the file is just import it must be directly in the top directory, and its package must be changed so it is a top level namespace. To require it with its current location and package, you must use src.import instead of import.

Also, top level namespaces are not recommended.

Finally, the proper option to run a -main is -m.

+$ ls
import.clj  main.clj
+$ cat import.clj 
(ns import)

(defn foo
  []
  (println "hello"))
+$ cat main.clj
(ns main
  (:require [import])
  (:gen-class))

(defn -main
  [& args]
  (import/foo))
:$ java -cp ~/bin/clojure.jar:. clojure.main -m main
hello

Upvotes: 0

Related Questions