At the following link Calling clojure from java , it is illustrated how to write a piece of clojure code, whose functionality we can then invoke directly in java source code. To reproduce, we have a clojure project called tiny, which within it has a tiny.clj source file. The tiny.clj file contains the following code :
(ns tiny
(:gen-class
:name com.domain.tiny
:methods [#^{:static true} [binomial [int int] double]]))
(defn binomial
"Calculate the binomial coefficient."
[n k]
(let [a (inc n)]
(loop [b 1
c 1]
(if (> b k)
c
(recur (inc b) (* (/ (- a b) b) c))))))
(defn -binomial
"A Java-callable wrapper around the 'binomial' function."
[n k]
(binomial n k))
(defn -main []
(println (str "(binomial 5 3): " (binomial 5 3)))
(println (str "(binomial 10042 111): " (binomial 10042 111)))
)
This is then exported into a ttt.jar file, which is then added to the "Referenced Libraries" of the tinyJava project (which is a java project). Inside the tinyJava project there is a Main.java file, which has the following code :
import com.domain.tiny;
public class Main {
public static void main(String[] args) {
int j;
j = (int)tiny.binomial(5, 3);
System.out.println("(binomial 5 3): " + j);
System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
}
}
The output is then :
(binomial 5 3): 10
(binomial 10042, 111): 4.9068389575068143E263
My question is, at the following point in Main.java :
j = (int)tiny.binomial(5, 3);
is it possible to step into the clojure source code? I have tried and it did not work.
Thanks
[EDIT] : the way I added the jar to the Referenced Libraries was as follows :
1)Rightclick on project tinyJava & choose properties
2)Choose : Java Build Path
3)Choose : Libraries
4)Click : "Add External Jars"
5)Then go to the location of ttt.jar
[EDIT 2] : For a scala project it seems that one can achieve this in a slightly different manner (see below), whereby one links the projects rather than explicitly exporting a jar file.
For example this seems to be quite easy to do with Scala (note the following article also discusses interop : How do you call Scala objects from Java?).
What I did was as follows :
1)Set up a Scala project called firstScala, and add a file MyPrinter.scala with the following code :
class MyPrinter{
def printTerm() {
print("hello");
}
}
2)Then I created a Java project called firstScalaJava, to which I then added a file called Main.java with the following code :
class Main {
public static void main(String args[]) {
MyPrinter myPrint = new MyPrinter();
myPrint.printTerm();
}
}
3)Then I right clicked on firstScalaJava, selected Properties, chose Java Build Path, chose Projects tab, clicked "Add", and then selected the firstScala project.
4)Then if I put a breakpoint at "myPrint.printTerm();" and clicked F5 when the debugger has stopped at this point, the debugger automatically walks into the Scala source file.
The nice thing about this is that I did not need to export any jar files or anything like that. This is appealing because upon changing the Scala code one does not need to do anything (eclipse automatically rebuilds the scala project when one attempts to run the java project thereafter), whereas if I changed the Clojure code I would need to re-export the jar etc... (note that linking the projects in the manner described above does not work for the clojure case)
Related
My objective was to use JNI to access functions from kernel32.dll. As you can see below, I was doing pretty bad. I wrote down the whole procedure in the answer.
Kernel32.java :
package tn.kernel;
public final class Kernel32 {
public static boolean loadKernel32(){
System.loadLibrary("kernel32");
return true;
}
public static native boolean K32EnumProcesses(int[] pProcessIds, int cb, int[] pBytesReturned);
}
MainClass.java :
package tn.kernel;
public class MainClass {
public static void main(String[] args) {
System.out.println("Program started.");
if(Kernel32.loadKernel32())
System.out.println("Kernel32.dll loaded.");
int n = 2000;
int[] procs = new int[n];
int ls = Integer.SIZE;
int[] rs = new int[1];
if(Kernel32.K32EnumProcesses(procs, ls * n, rs)){
System.out.println("Success");
}
System.out.println("Done.");
}
}
OUTPUT :
Program started.
Kernel32.dll loaded.
Exception in thread "main" java.lang.UnsatisfiedLinkError: tn.kernel.Kernel32.K32EnumProcesses([II[I)Z
at tn.kernel.Kernel32.K32EnumProcesses(Native Method)
at tn.kernel.MainClass.main(MainClass.java:15)
This the syntax for EnumProcesses :
BOOL WINAPI EnumProcesses(
_Out_ DWORD *pProcessIds,
_In_ DWORD cb,
_Out_ DWORD *pBytesReturned
);
If PSAPI_VERSION is 2 or greater, this function is defined as K32EnumProcesses in Psapi.h and exported in Kernel32.lib and Kernel32.dll. If PSAPI_VERSION is 1, this function is defined as EnumProcesses in Psapi.h and exported in Psapi.lib and Psapi.dll as a wrapper that calls K32EnumProcesses. Source : msnd.microsoft.com
I tried with both K32EnumProcesses and EnumProcesses. Same results.
Creating a 64 bits Dynamic-Link Library for Windows
Prerequisites: Visual Studio
1/ Create a Visual Studio C++ project (ex: dllexample)
• Select “Win32 Consol Application”
Select “DLL”
Select “Empty project”
2/ In “Solution explorer” right-click on “Header Files” > “Add” > “New Item…” > choose a name (ex: dllexample.h) > “Add”
• Define the headers of your functions in “dllexample.h” this way:
__declspec(dllexport) <type> funcName(parameters…);
…
3/ In “Solution explorer” right-click on “Source Files” > “Add” > “New Item…” > choose a name (ex: dllexample.cpp) > “Add”
• Use:
#include “dllexample.h”
• Define the body of your functions (from the “dllexample.h” header file) in the “dllexample.cpp” source file:
<type> funcName(parameters…){
//body instructions
}
• In the upper toolbar select “x64”
• Select “Build” > “Build Solution”
4/ Done
• You can find “dllexample.dll” and “dllexample.lib” in “projects/dllexample/x64/Debug”
• You can find “dllexample.h” in “projects/dllexample/dllexample”
Calling a 64 bits DLL file (ex: dllexample.dll) from another 64 bits DLL or executable file on Windows
Prerequisites: “dllexample.dll”, “dllexample.lib” and “dllexample.h” or a precise functions description or guide and Visual Studio
1/ Create a Visual Studio C++ project (ex: dllcall)
• Select “Win32 Consol Application”
Select “DLL” to create a DLL file, “Consol Application” to create an executable file
Select “Empty project”
2/ Copy “dllexample.dll”, “dllexample.lib” and “dllexample.h” to “projects/dllcall/dllcall”
3/ In “Solution explorer” right-click on “Header Files” > “Add” > “Existing Item…” > select ”dllexample.h” > “Add”
• If you’re making a DLL file, create a new header file (ex: dllcall.h) in which you define the headers of your functions this way:
__declspec(dllexport) <type> funcName(parameters…);
…
4/ In “Solution explorer” right-click on “Source Files” > “Add” > “New Item…” > choose a name (ex: dllcall.cpp) > “Add”
• Use:
#include “dllexample.h”
• If you’re creating a DLL file, use:
#include “dllcall.h”
And then define the body of the functions (from the “dllcall.h” header file) in the “dllcall.cpp” source file. At the same time you can call functions from “dllexample.h”:
<type> funcName(parameters…){
//body instructions
}
• In the upper toolbar select “x64”
• In “Solution explorer”, right-click on “dllcall” > “Properties” > “Linker” > “Input” > “Additional Dependencies” > “Edit” > add “dllexample.lib” (this option will be set only for the x64 debugger of the current Visual Studio project)
• Select “Build” > “Build Solution” to generate the DLL and the Import Library (.lib) files, “Run” to generate the executable file and test it
5/ Done
• You can find “dllcall.dll” and “dllcall.lib” or “dllcall.exe” in “projects/dllcall/x64/Debug”
• You can find “dllcall.h” in “projects/dllcall/dllcall”
Calling a 64 bits DLL file (ex: dllexample.dll) from a 64 bits Java program through JNI
Prerequisites: “dllexample.dll”, “dllexample.lib” and “dllexample.h” or a precise functions description or guide. Visual Studio, Eclipse with JNI plugin
1/ Create an Eclipse Java project (ex: dlltest)
2/ Create a class (ex: my.package.JNIClass)
• Define methods headers as close as the functions definitions in “dllexample.h” using keywords:
public static final native <type> funcName(parameters..);
…
• Run the project to generate “JNIClass.class”
3/ Open Command Line in folder “workspace/dllcall/src”
• Generate “my_package_JNIClass.h” header file by running command:
javah my.package.JNIClass
4/ Create a 64 bits DLL file (ex: dllcall.dll) that calls “dllexample.dll” and includes “my_package_JNIClass.h”
• In the “dllcall.cpp” source file, define the bodies of functions that are defined in the “my_package_JNIClass.h” header file
• “my_package_JNIClass.h” includes “jni.h”, to make it work, you must go to “Solution explorer” in Visual Studio and right-click on “Properties” > “Configuration Properties” > “C/C++” > “General” > “Additional Include Directories” > add the 64 bits “java/include” and “java/include/win32” paths (this option will be set only for the x64 debugger of the current Visual Studio project)
5/ Copy “dllcall.dll” and “dllexample.dll” to “workspace/dllcall/src”
• In “Package explorer”, right-click on “dlltest” > “Properties” > “Java Build Path” > “Source” > expand “my/package/src” > select “Native Library Location” > “Edit” > add “my/package/src” as location path
• Import the DLL files in “JNIClass.java” using:
static {
System.loadLibrary(“dllexample”);
System.loadLibrary(“dllcall”);
}
6/ If the 64 bits JRE is not selected, then go to “Run” > “Run Configurations” > “JRE” > “Alternate JREs” > “Installed JREs” > put the 64 bits Java JDK directory (Should be something like: “C:\Program Files\Java \jdk”, while 32 bits Java JDK can be found in the “Program Files (x86)” folder
7/ Done
• Now you can use the methods you defined in step 2
I'm using Leiningen 2.5.2 (Java 1.8.0_45-internal Open JDK 64-bit), and the reagent-template (i.e. lein new reagent foo).
This runs okay with lein figwheel as expected.
Next, the first thing I do is break out the "Views" functions into separate files and add them to the app namespace:
core.cljs snippet:
;; -------------------------
;; Views
(:require home-page)
home-page.cljs (whole file):
(ns foo.core)
(defn home-page []
[:div [:h2 "Welcome to foo"]
[:div [:a {:href "#/about"} "go to about page"]]])
When I go to view the app in the browser (chromium or firefox), it gets stuck at "ClojureScript has not been compiled!" despite seemingly compiling successfully in the terminal. If I enter commands in the figwheel REPL, I see the green Clojure logo when it is working in the browser, so I know it's connected.
I had this working in a reagent app some months ago--what happened? How should I separate my view code? (A single file is unmanageable; that's a lot of Hiccup.)
If you really have only the line (:require home-page) in core.cljs, this should be the culprit. The colon notation :require is only valid inside a namespace declaration with ns. Also, you declare the core namespace in the wrong file (home-page.cljs, not core.cljs). Take a look at this article on namespaces in Clojure for a thorough explanation.
You will want the following in core.cljs:
(ns foo.core
(:require [foo.home-page :as hp :refer [home-page]]))
.... more core.cljs code ...
and then simply in home-page.cljs:
(ns foo.home-page
(:require ....reagent namespaces as needed ....
(defn home-page [] ....
I am getting the following error when I try to run my program: Exception in thread "main" java.io.FileNotFoundException: Could not locate apply
/clojure/core/vector__init.class or apply/clojure/core/vector.clj on classpath:
, compiling:(erbium/compile.clj:1:1). It seems to be pointing to file below and suggests that I need to put clojure.core/vector in my dependencies. Is it not included by default?
(ns erbium.compile
(require `[clojure.string :as string])
)
(defn produce-out "Convert 'command %1 %2 %3' with stack [5 6 7] to 'command 5 6 7'" [word stack definitions]
(let [
code (definitions word) ; dictionary/hash lookup. eg. "println" -> "echo $1"
replacement (fn [match] (-> match second Long/parseLong dec stack str))
]
; evaluate arguments. eg. "echo %1"
; stack=["blah"]
; -> "echo blah"
(string/replace code #"%(\d)" replacement)
)
)
(defn parse-word "Verifies that word is in defintitions and then returns (produce-out word stack)" [word stack definitions]
(if (some #{word} (keys definitions))
(produce-out word stack)
)
)
(defn compile "Main compile function" [code]
(let [
split-code (string/split code #"\s")
definitions {
"println" "echo %1"
"+" "%1 + %2"
"-" "%1 - %2"
}
stack []
]
(for [word [split-code]]
(if (integer? (read-string word))
(do
(println "Found integer" word)
(def stack (conj stack (read-string word)))
(println "Adding to argument stack:" stack)
)
; else
(do
(parse-word word stack definitions)
(def stack [])
)
)
)
)
)
This file is loaded by the core file via (load "compile") if that makes a difference.
the first error I see is this:
(require `[clojure.string :as string])
It should be like this:
(:require [clojure.string :as string])
in a regular clojure source file. This fixed it for me.
That said, here comes some general advices:
There are a lot of formatting "mistakes". Of course you can format your code as you would like to, however, it's easier for others to follow if you stick to basic formatting principles. Here is a nice collection of them: https://github.com/bbatsov/clojure-style-guide Most editors implement some formatting tool.
split-code (str/split code #"\s") this won't work as you required [clojure.string :as string] So change it to: split-code (string/split code #"\s")
I am not sure about (load ...) and in which context one uses that generally. However, for starting to learn clojure I recommend Lighttable as it has instant feedback built in which is very valuable when learning something new.
To expand on the answer, the "require" appears in the namespace declaration "ns". ns is actually a macro that expands to a series of statements to create the namespace, and do some setup.
This macro treats statements like (:require ...) as calls to a function with the name require, and automatically quotes any following arguments. Since you had specified a quote yourself:
(ns erbium.compile
(require '[clojure.string :as string]))
Then the result ends up being double-quoted, and the call to require ends up being:
... (require (quote (quote [clojure.string :as string])))
So it ends up trying to load a namespace called "quote" followed by a vector that was syntactically in the wrong place. :)
The ns macro is a standard and convenient way to set up namespaces, but it took me a long time to learn it properly. I found the best way was to copy other people's setup code until I learnt how to do it right.
Incidentally, the use of require instead of :require does not matter, though the standard is to use :require so it does not look like a direct call to that function.
I have found a source of Java compiler written in Ocaml which should work.
But when I do make, it finished with an error:
unzip.o: In function `camlUnzip__59':
(.data+0x540): undefined reference to `camlzip_deflateEnd'
unzip.o: In function `camlUnzip__59':
(.data+0x544): undefined reference to `camlzip_deflate'
unzip.o: In function `camlUnzip__59':
(.data+0x548): undefined reference to `camlzip_deflateInit'
collect2: ld returned 1 exit status
File "caml_startup", line 1, characters 0-1:
Error: Error during linking
make: *** [javacx] Error 2
It is odd that the file "caml_startup" even does not exist in the folder. Could anyone help? Thank you very much.
caml_startup is part of the OCaml runtime.
The project's website mentions that it works with OCaml 3.09, which is quite old. It worked for me with 3.10 (which is still quite old; latest release is 3.12) - maybe it just doesn't work with more recent versions.
However, as a first guess, I would try simply deleting these definitions from unzip.ml - they are never called, and declare external routines which are not actually implemented (whereas other external routines in unzip.ml are implemented in zlib.c):
external deflate_init: int -> bool -> stream = "camlzip_deflateInit"
external deflate:
stream -> string -> int -> int -> string -> int -> int -> flush_command
-> bool * int * int
= "camlzip_deflate_bytecode" "camlzip_deflate"
external deflate_end: stream -> unit = "camlzip_deflateEnd"
I'm very new in learning Clojure. This intended to be my first and very simple Clojure tries in which I call a simple Clojure method from inside java code. Unfortunately it does not work. The Compilation is successful and from the Clojure REPL the written function does as it was ordered, but when calling from Java it says the following:
Exception in thread "main" java.lang.IllegalArgumentException: Wrong number of args (2) passed to: ClojNum$-myinc
at clojure.lang.AFn.throwArity(AFn.java:439)
at clojure.lang.AFn.invoke(AFn.java:43)
at com.experimental.clojure.test.ClojNum.myinc(Unknown Source)
at com.experimental.clojure.java.JavaCaller.main(JavaCaller.java:14)
Here is the very simple Clojure code:
(ns com.experimental.clojure.test.ClojNum
(:gen-class
:init init
:name com.experimental.clojure.test.ClojNum
:methods [
[myinc [int] int]
]))
(defn -init [] [[] (atom [])])
(defn myinc "comment" [x] (+ x 1))
(defn -myinc "comment" [x] (myinc x))
And the java part:
package com.experimental.clojure.java;
import com.experimental.clojure.test.ClojNum;
public class JavaCaller {
/**
* #param args
*/
public static void main(String[] args) {
int i = 0;
System.out.println(i);
ClojNum c = new ClojNum();
i = c.myinc(0);
System.out.println(i);
}
}
What did I do wrong?
(Note again: This is primitve test code just to make a first successful function call)
Thanks for the help, I'm clueless.
Jeremy's link in the comments show you one way to call a static method in a clojure class. If you want to call a clojure function on an object instance, you need to add a parameter to your wrapper method definition:
(defn -myinc "comment" [this x] (myinc x))
The 'this' parameter is required for any non-static wrapper function. Clojure threw an exception because it received two parameters for a function only defined with one. Note, you do not change anything in your :gen-class :methods section or the myinc function definition itself.
The documentation is a bit sparse, but examples of this can be found at:
http://clojure.org/compilation (the last example on the page shows instance methods).