简体   繁体   中英

“More than one scala library” in Scala/Android project

I have a libgdx android project in eclipse which I've added scala and AndroidProguardScala natures to. This was working great, but suddenly eclipse has started giving me the warning "More than one Scala library found on the build path". I can still build and install the project on a device, but it exits immediately with NoClassDefFoundError: scala.Tuple2$mcZZ$sp , so it looks like the Scala library isn't being included at all.

My project seems to have the Scala library both under "Scala Library [2.10.1]" (as "scala-library.jar") and under "Android Dependencies" (as "scala_library.min.jar") so I guess that the Proguard output is conflicting with the original library, but I have no idea why this has happened or how to fix it.

At this point I could just make a new project and copy the source files over, but it would be great if anyone could shed some light on this.

Edit: After some experimentation it turns out that this code (from within a method of a trait) seems to be causing the problem.

acckeys match {
  case (true, false) => acceleration.set(0, accel).rotate(rotation)
  case (false, true) => acceleration.set(0, -accel).rotate(rotation)
  case _ => acceleration.set(0, 0)
}

(where acckeys is a function returning a tuple and acceleration is a vector)

The multiple libraries warning is still there, so I guess that isn't related to to the problem. Luckily, I don't actually need to reference this code from the android version of the project, but it would still be useful to know why this code compiles but fails to run.

I know exactly what issue you are having. This has to do with the AndroidProgaurdScala not recognizing the class files you have in your main project. The result is, any classes which are defined in the android project are included, but any 'new' ones, such as your tuple, will be missing and because of that you get the wonderful NoClassDefFoundError. I haven't encountered the warning with "More than one Scala library found on the build path", but it probably means you added the scala nature to the project and also added the library.jar on top of it as well. Try to undo your configuration and follow what I have below; otherwise, set up a new project with the steps below and copy your source over.

I found the Scala Nature and Android Proguard Scala are a bit of a pain to fix after they have run a muck. I'm not 100% sure you will be able to salvage an existing project, but we can try and see what happens. First, remove all scala related natures from your projects and get them back into their initial state they would be in for just a plain old Java project.

Let's walk through setting up libGDX with Scala and see where things went wrong:

  1. Make sure your environment is setup correctly. (Note: you will need to get the latest versions)
  2. Set up the libGDX project as normal. (Or use an existing project in your case)
  3. Right-click the android project, "Add Scala nature" then "Add AndroidProgaurdScala nature"
  4. Right-click the main project, "Add Scala nature"
  5. Right-click the desktop project, "Add Scala nature"

Now, this is probably where you have gotten to already, but there is still the issue of AndroidProgaurdScala not knowing what classes you have in your main project. It appears to overlook included projects and doesn't add them to the scala_library.min.jar. To fix this I have found one solution that works well:

  1. Right-click Android Project > Properties > Java Build Path
  2. Go to Projects tab, remove the main project. I know this is counterintuitive, but trust me.
  3. Go to source tab > Link Source...
  4. Navigate and select the "src" folder from your main project
  5. Press OK
  6. Clean and rebuild the projects.

This setup I have tested and used extensively without any issues. Both Android and Desktop versions are happy and work without any complaints with Scala or mixed code. The android project is now fully aware of all the Scala classes you are using in the main project because the source is now copied into the build for the android project. (ie No NoClassDefFoundError should appear with anything Scala related).

I've gotten a similar message when my Proguard configuration file has a problem. You might check:

  • Is Proguard being run
  • Your config file has: -keep public class **.YourPackage.** or something like it
  • Your config file is modified for the Scala libraries, eg.

    \n## SCALA SETTINGS \n\n-dontwarn **$$anonfun$* \n-dontwarn scala.android.** \n-dontwarn scala.beans.ScalaBeanInfo \n-dontwarn scala.collection.generic.GenTraversableFactory \n-dontwarn scala.collection.immutable.RedBlack$Empty \n-dontwarn scala.concurrent.forkjoin.** \n-dontwarn scala.reflect.** \n-dontwarn scala.sys.process.** \n-dontwarn scala.tools.**,plugintemplate.** \n\n\n#(org.xml.sax.EntityResolver)Class.forName(variable).newInstance() \n-dontnote org.xml.sax.EntityResolver \n\n  #(org.apache.james.mime4j.storage.StorageProvider)Class.forName(variable).newInstance() \n-dontnote org.apache.james.mime4j.storage.DefaultStorageProvider \n\n-dontnote scala.android.app.Activity \n\n\n-keep class scala.android.package** \n-keep class * extends scala.android.app.Activity \n\n## Fixes ==> Warning: ... can't find referenced class sun.misc.Unsafe \n-libraryjars D:\\Program Files\\Apache\\m2\\repository\\com\\google\\code\\findbugs\\jsr305\\2.0.1\\jsr305-2.0.1.jar \n-dontwarn sun.misc.Unsafe \n\n\n-keep class * extends scala.runtime.MethodCache { \n    public ; \n} \n\n-keepclassmembers class * { \n    ** MODULE$; \n} \n\n-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { \n    long eventCount; \n    int workerCounts; \n    int runControl; \n    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; \n    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; \n} \n\n-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { \n    int base; \n    int sp; \n    int runState; \n} \n\n-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { \n    int status; \n} \n\n-keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { \n    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; \n    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; \n    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; \n} \n

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM