I need to share a namespace between my Clojure (Garden) and my ClojureScript (Reagent).
Currently the project folder looks like this:
src/
clj/
name/
css.clj
cljs/
name/
core.cljs
cljc/
name/
config.cljc
The config.cljc file has the following namespace: (ns name.config).
I've tried to reference this namespace from inside clj/name/css.clj with a require.
(ns name.css
(:require [name.config :as config]))
However, this results in a compile error from Garden.
Caused by: java.io.FileNotFoundException: Could not locate name/config__init.class or name/config.clj on classpath.
I guess it's not even checking for cljc files.
I added "src/cljc" to the :source-paths vector in project.clj and :garden :builds but I get the same error even after restarting the build processes.
I see this behaviour on Clojure 1.7.0 and 1.8.0.
It might also be worth mentioning that it works without issues in ClojureScript (with Figwheel handling the build). I can require and use the new namespace without problems.
It seems like I must be missing something really simple, because none of the documentation around .cljc files even mentions requiring them.
Check if you’re using Clojure 1.7 or above in your project.clj. This error message:
Caused by: java.io.FileNotFoundException: Could not locate name/config__init.class or name/config.clj on classpath.
indicates that you’re using Clojure 1.6 or below, as those versions of Clojure only know to look for .class or .clj files.
I got this same error when I moved a file from .clj to .cljc in my project. I did lein clean but that had no effect. Eventually I renamed the module namespace and that fixed it.
(My guess is that there was some sort of cache of compiled modules and it was referencing a module which no longer existed, but the cljc wasn't re-compiled because a module of that name was still cached.)
When I renamed the module namespace it worked, with no other changes to the code.
Related
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.
When I look at something like, say, the clojure.data.json source code I can see a namespace looking, for example, like this:
(ns clojure.data.json...)
So when I want to :require that in my .clj Clojure files, I simply do something like this:
(ns so.example
(:require [clojure.data.json :as json])
...
However in the dependencies in my .clj I have:
:dependencies [[org.clojure/data.json "0.2.4"]
So the clojure.data.json "became" org.clojure/data.json.
Now for, say, server.socket I have in my dependencies:
[server-socket "1.0.0"]
So this time no ".org" added, no slash, but the dot became a dash.
What's the relation between :require in Clojure source files and :dependencies in project.clj? Is there any "logic"?
How can I find what's the correct line to put in the dependencies?
The dependency vectors in project.clj are the maven artifact coordinates to resolve the dependency by finding the appropriate jar. Leiningen will attempt to find the apropriate jars and add them to your classpath so that namespace definitions and other resources can be loaded from inside their archive contents at runtime. The require statement in your code specifies a resource to look for in the class path. For example if you require clojure.data.json, Clojure will look for a resource with the path clojure/data/json.clj somewhere in your classpath, and attempt to load the definition for the namespace clojure.data.json from that resource.
There is no relationship. Namespace is something defined in the source code file. A dependency is based on a project name and is decided by the author(s) when they publish it. You'll almost always find the proper dependency information on the project github site or at Clojars, or in some cases, maven.
Anytime I fire up a fresh REPL I always get the same message, namely
#<FileNotFoundException java.io.FileNotFoundException: Could not locate test_app/core_init.class or test_app/core.cljon classpath:>
The namespace I've been using is ns test-app.core
The REPL still continues to come up and I am able to execute code with it. I am just unsure if this will lead to future problems, such as trying to work with incanter or other libraries.
Does your project.clj contain the following line, per chance?
...
:main test-app.core
...
Leiningen will try to switch into that namespace before showing the REPL to you. If it cannot find it, you'll see the error you mentioned. Now, the reason it cannot find it is another topic to explore, so first make sure that this is how your directory structure looks like:
.
|-- project.clj
|-- src
|-- test_app
|-- core.clj
If it does, I guess it's time to post Leiningen and Java versions (and ideally your project.clj) to let SO try to tackle this miraculous REPL. :)
Edit: The solution to this problem would - if any of the above suggestions match your case - of course be to either remove the :main line from your project file or to adjust the directory structure.
There needs to be a core.clj file in the folder named test_app in your project structure.
Basically, the file name should apply the naming towards whatever you've declared in your ns form.
As the Clojure Documentation FAQ says,
In order to use a Java class or Clojure namespace in your program,
that class or namespace must be "on the classpath," that is, inside a
directory or JAR file listed in the classpath.
I'm new to Clojure and Leiningen, and I've determined that some of what I'll want to use is located in clojure.contrib.generic.math-functions. I found API information for that at http://richhickey.github.com/clojure-contrib/branch-1.1.x/math-api.html, but I can't find anything that helps me figure out what I should put into my project.clj file for that dependency.
I have tried [clojure.contrib.generic.math-functions "1.1"], [clojure.contrib.generic.math-functions "1.1.x"], and [clojure.contrib.generic.math-functions "1.1.0"]. For each of those, I get something like...
...
Caused by: org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException: Missing:
----------
1) clojure.contrib.generic.math-functions:clojure.contrib.generic.math-functions:jar:1.1
All clojure-contrib namespaces are shipped within a single jar file, for which the dependency has to be listed like:
[org.clojure/clojure-contrib "1.2.0"]
Please note that there are different versions available of that artifact. The 1.2.0 is the current stable release.
In order to use functions coming from the math-functions namespace in your clojure code, you need to either require or use such namespace, usually done within the ns form at the beginning of your source file:
(ns my.namespace
(:use [clojure.contrib.generic.math-functions]))
Have a look here to see the differences between use and require.
The next version of Leiningen will have a search task for precisely this purpose. It will search Clojars, Maven Central, and any other repositories your project has listed, provided they offer up downloadable indices. It's already implemented, so if you run Leiningen from git you can use it.
Also, the Leiningen tutorial covers this. Type "lein help tutorial".
You can generally find what you need at clojars.org - it's the default repository for leiningen. The current stable release of Clojure is 1.2.0, so you'd have this in your leiningen project.clj:
[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]
To use the generic math functions in your clojure, require or use it in your namespace declaration at the top of your source file:
(ns your-namespace
(:use [clojure.contrib.generic.math-functions :as mathf]))
This allows you to refer to the functions in that namespace like this:
(mathf/abs -10) ;; => 10
:use-ing namespaces with :as is the preferred way to use functions from other namespaces in your code. require is ok, but you'd have to prefix your functions with the entire namespace (e.g. clojure.contrib.generic.math-functions/abs) so that's not practical. Using a namespace without :as allows you to use these functions without any prefix at all (e.g. abs), but you're more likely to get namespace clashes and it might be difficult to see where functions come from, especially if you :use many libraries.
You can browse all libraries available from the default leiningen repository by checking out http://clojars.org/repo/. The structure of clojure-contrib will change when 1.3.0 is out, so you'll have to include the specific contrib library if you're using version 1.3.0-alpha-xx:
[org.clojure.contrib/generic "1.3.0-alpha4"]
Now that the clojure.contrib has been broken up, the math functions are in something called math.numeric-tower. The lein dependency is specified like this:
[org.clojure/math.numeric-tower "0.0.1"]
You can use or require as seems appropriate, for example
(use '[clojure.math.numeric-tower])
I have tried putting clojure-contrib.jar various places on my filesystem, I have tried manually specifying the classpath when launching the REPL, I have tried extracting the jar and putting the clj files on the classpath, nothing seems to work. I continue getting something like this:
java.io.FileNotFoundException: Could not locate clojure/contrib/str_utils__init.
class or clojure/contrib/str_utils.clj on classpath: (NO_SOURCE_FILE:0)
When I execute (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader)))) to see the classpath, it does include clojure-contrib:
(#<URL file:/C:/Program%20Files/Java/jre1.6.0_06/lib/clojure-1.0.0.
jar> ... #<URL file:/C:/Program%20Files/Java/jre1.6.0_06/lib/clojure-contrib.jar>)
When I make a .clj file of my own and put it on the classpath I am able to use or require it and have access to its functions as I'd expect.
If I move a .clj file - str-utils.clj for instance - to the pwd (which is on the classpath) it sorta works - it at leasts finds the file, although it generally can't do anything with it because of dependencies on other functions buried in clojure-contrib which it can't find.
Any ideas why this wouldn't work for clojure-contrib?
If you compiled your own clojure-contrib jar, you probably used the main branch which is not 1.0 compatible.
Follow the Using clojure-contrib with Clojure 1.0 doc to checkout the 1.0 tagged revision of clojure-contrib.
There is also a clojure-contrib git branch that maintains 1.0 compatibility.