Missing class path under MacOS for Java FFI
drever opened this issue · 7 comments
Description
I'm trying to get the FFI to Java running on MacOS 10.14.3, using the documentation here. The class eta.first.Utils
is not found.
Expected Behavior
The java function should be called from eta.
Actual Behavior
Exception in thread "main" java.lang.NoClassDefFoundError: eta/first/Utils
at main.Main.main1(Main.hs:10)
at main.Main$main1.applyV(Main.hs)
at eta.runtime.exception.Exception.catch_(Exception.java:132)
at main.Main.main3(Main.hs)
at main.Main.DZCmain(Main.hs:10)
at main.Main$DZCmain.applyV(Main.hs:10)
at eta.runtime.stg.Closures$EvalLazyIO.enter(Closures.java:154)
at eta.runtime.stg.Capability.schedule(Capability.java:254)
at eta.runtime.stg.Capability.scheduleClosure(Capability.java:210)
at eta.runtime.Runtime.evalLazyIO(Runtime.java:397)
at eta.runtime.Runtime.main(Runtime.java:390)
at eta.main.main(Unknown Source)
Caused by: java.lang.ClassNotFoundException: eta.first.Utils
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 12 more
Possible Fix
The bash file dist/build/eta-0.8.6.4/test-0.1.0.0/x/test/build/test/test
starts the jvm with the corresponding class path. Adding the path to the class files manually fixes the problem.
Steps to Reproduce
- Install eta on MacOS with etlas
- Implement java FFI according to documentation.
etlas run
Your Environment
- Did you install an older version of Eta/Etlas before?
First installation - Current Eta & Etlas version:
etlas version 1.5.0.0 - Operating System and version:
MacOS 10.14.3
Hi, could you share your .cabal
config? the content should be something like:
name: eta-first
version: 0.1.0.0
license: BSD3
license-file: LICENSE
author: [your name]
maintainer: [your email]
build-type: Simple
extra-source-files: ChangeLog.md
cabal-version: >=1.10
executable eta-first
main-is: Main.hs
other-modules: Primes
build-depends: base >=4.8 && <4.9
hs-source-dirs: src
java-sources: java/eta/first/Utils.java
default-language: Haskell2010
And the tree:
eta-first
-src
-Main.hs
-java
-eta
-first
-Utils.java
-eta-first.cabal
-Setup.hs
For the path of the bash file it seems you named your executable test
and if all would be correct the class should be already inside dist/build/eta-0.8.6.4/test-0.1.0.0/x/test/build/test/test.jar
Sure, the cabal file:
-- Initial test.cabal generated by etlas init. For further documentation,
-- see http://eta-lang.org/docs/
name: test
version: 0.1.0.0
-- synopsis:
-- description:
license: BSD3
license-file: LICENSE
author: Johannes Drever
maintainer:
-- copyright:
-- category:
build-type: Simple
extra-source-files: ChangeLog.md
cabal-version: >=1.10
executable test
main-is: Main.hs
other-modules: Primes Counter
java-sources: java/Counter.java
, java/Utils.java
build-depends: base >=4.11 && <4.12
hs-source-dirs: src
default-language: Haskell2010
And the tree:
.
├── ChangeLog.md
├── LICENSE
├── Setup.hs
├── java
│ ├── Counter.java
│ └── Utils.java
├── src
│ ├── Counter.hs
│ ├── Main.hs
│ └── Primes.hs
└── test.cabal
The executable is named test and there is a file dist/build/eta-0.8.6.4/test-0.1.0.0/x/test/build/test/test.jar
. The problem seems to be that the startup script does not set the class path correctly. When I paste it manually it works as expected.
Thanks for helping!
Johannes
The cabal file and the tree seems to be correct.
In theory the script should not add the class file to classpath, it should be inside dist/build/eta-0.8.6.4/test-0.1.0.0/x/test/build/test/test.jar
.
Could you inspect the content of dist/build/eta-0.8.6.4/test-0.1.0.0/x/test/build/test/test.jar
to check if eta/first/Utils.class
is in it?
In my windows env i've tested it succesfully and my jar contents are:
C:\ws\eta\eta-first\dist\build\eta-0.8.6.4\eta-first-0.1.0.0\x\test\build\test>mkdir jar
C:\ws\eta\eta-first\dist\build\eta-0.8.6.4\eta-first-0.1.0.0\x\test\build\test>copy test.jar jar
1 archivo(s) copiado(s).
C:\ws\eta\eta-first\dist\build\eta-0.8.6.4\eta-first-0.1.0.0\x\test\build\test>cd jar
C:\ws\eta\eta-first\dist\build\eta-0.8.6.4\eta-first-0.1.0.0\x\test\build\test\jar>jar xfv test.jar
inflado: eta/first/Utils.class
inflado: main/Main$$La$1.class
inflado: main/Main$createFile.class
inflado: main/Main$DZCmain.class
inflado: main/Main$main.class
inflado: main/Main$main1.class
inflado: main/Main$main2.class
inflado: main/Main$main3.class
inflado: main/Main$main4.class
inflado: main/Main.class
inflado: eta/main.class
inflado: META-INF/MANIFEST.MF
An important caveat: etlas is not aware of the contents of java files to trigger a fresh build so, for example, if you created the java file with another package you need to do a Ignore that, etlas clean
before etlas run
to trigger the build.etlas
actually trigger the rebuild as i've just tested.
My Utils.java
is:
package eta.first.test;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Utils {
/* This helper method lets us avoid variadic arguments which
are a bit cumbersome to work with in Eta. */
public static void createFile(String path) throws Exception {
Files.createFile(Paths.get(path));
}
}
The class file is not in test.jar
:
tar xfv test.jar
x main/Main$DZCmain.class
x main/Main$main.class
x main/Main$main1.class
x main/Main$main2.class
x main/Main$main3.class
x main/Main.class
x main/Primes$$Llvl1$1.class
x main/Primes$$wfilterPrime.class
x main/Primes$go.class
x main/Primes$primes.class
x main/Primes$sat.class
x main/Primes.class
x main/counter/datacons/Counter.class
x main/counter/tycons/Counter.class
x main/Counter$$fClass_Counter1.class
x main/Counter$$fClass_Counter_$cclassIdentifier.class
x main/Counter$$fClass_Counter_$cunobj.class
x main/Counter$$La$1.class
x main/Counter$$La1$1.class
x main/Counter$$La2$1.class
x main/Counter$$La3$1.class
x main/Counter$$La4$1.class
x main/Counter$$La5$1.class
x main/Counter$$La6$1.class
x main/Counter$$La7$1.class
x main/Counter$cOUNTER_MAX.class
x main/Counter$createFile.class
x main/Counter$DCounter.class
x main/Counter$get.class
x main/Counter$getPublicCounter.class
x main/Counter$increment.class
x main/Counter$newCounter.class
x main/Counter$newCounterWith.class
x main/Counter$set.class
x main/Counter.class
x eta/main.class
x META-INF/MANIFEST.MF
My Utils.java
is more or less the same. When I introduce a syntax error I get a compile error, so I'm pretty sure that it is compiled correctly. The test file is created when the class is put on the class path manually.
Mmm, i wonder if it could be a mac (and linux?) specific issue, maybe @rahulmutt could help us to reproduce it