Suppose I have a Scala compile-time macro that I find useful and would like to share it (I do). How do I create a JAR file that when loaded into another project would execute the macro when compiling the new project?
Specifically, I've made a StaticAnnotation that rewrites the AST of the class that it wraps before compile time. This works in my Maven build (macro defined in the main directory, runs on test cases in the test directory) because I have
<compilerPlugins>
<compilerPlugin>
<groupId>org.scalamacros</groupId>
<artifactId>paradise_2.10.5</artifactId>
<version>2.1.0-M5</version>
</compilerPlugin>
</compilerPlugins>
in my scala-maven-plugin. (I'm starting with a Scala 2.10 project and if it works, will provide both 2.10 and 2.11.)
But if I put the resulting JAR on a Scala console classpath, in a Scala script, or into another Maven project (without special compiler plugins), it simply ignores the macro: the AST does not get overwritten and my compile-time println statements don't execute. If I use the #compileTimeOnly annotation on my macro (new in Scala 2.11), then it complains with the #compileTimeOnly error message.
Do I really need to tell my users to add compiler plugins in their pom.xml files, as well as alternate instructions for SBT and other build tools? Other packages containing macros (MacWire, Log4s) don't come with complicated build instructions: they just say, "point to this dependency in Maven Central." I couldn't find the magic in their build process that makes this work. What am I missing?
If you're relying on a macro-paradise-only feature then yes, you do need to tell your users to add compiler plugins. See http://docs.scala-lang.org/overviews/macros/annotations.html . The projects you mention are only using the scala compiler's built-in (non-paradise) macro features, not macro annotations.
Related
https://docs.scala-lang.org/overviews/compiler-options/index.html says
Scala compiler scalac offers various compiler options, also referred to as compiler flags, to change how to compile your program.
Nowadays, most people are not running scalac from the command line. Instead, they use sbt, an IDE, and other tools as their interface to the compiler. Therefore they may not even have scalac installed, and won’t think to do man scalac.
Does "the compiler" refer to scalac?
If yes, is "they use sbt, an IDE, and other tools as their interface to the compiler" contrary to "therefore they may not even have scalac installed"?
Does sbt rely on scalac?
Thanks.
Scala compiler can be accessed programmatically via an API packaged by scala-compiler.jar dependency, hence tools such as IDEs and SBT can implement their own client frontends over this API to drive compiler functionality. scalac is just a bash script that executes scala.tools.nsc.MainClass class from scala-compiler.jar.
Does sbt rely on scalac?
No, sbt uses compiler API directly. One of the key concepts to understand regarding sbt is that the build definition is itself Scala code, either vanilla or DSL, but Scala nevertheless. The version of Scala used to compile the build definition is separate from the version of Scala used to compile project proper. The build definition source code in build.sbt and project/*.scala will be compiled using Scala version specified indirectly via sbt.version=1.2.8 setting in project/build.properties, whilst project source code proper in src/main/scala/* will be compiled using Scala version specified directly via scalaVersion := "2.13.1" setting in build.sbt. Note how they can indeed differ. Think of the build definition as simply another Scala app which uses sbt API for its implementation.
I am a beginner learning to program in scala-akka and I have had no problems running my scripts on IntelliJ IDE / and 'sbt run'. However, I can't seem to find any resources that teaches me how to manually use scalac and the akka jar dependency to compile and run just from the command-line. Can anyone point me in the right direction?
Let's assume you have Scala and Akka installed somewhere under /home/leo/apps/ and Scala binaries are searchable (e.g. export PATH=$PATH:home/leo/apps/scala-2.11.8/bin)
Next, let's say you have a Scala main app Tweets.scala along with a few supplementary classes packaged in akkastreams under /home/leo/myproject/:
akkastreams/
Tweets.scala
Author.scala
HashTag.scala
Message.scala
...
Here's how you'll compile and run the app:
cd /home/leo/myproject/
# Compile all files in package akkastreams:
scalac -cp "/home/leo/apps/akka-2.4.9/lib/akka/*" akkastreams/*.scala
# Run the main app Tweets (object Tweets extends App):
# Note that classpath includes also current subdir '.'
scala -cp "/home/leo/apps/akka-2.4.9/lib/akka/*:." akkastreams.Tweets
A few notes:
You could include only specific Akka jars instead of all of them.
Without dependencies and versioning being managed by sbt, you'll need to manually maintain version consistency between Scala's bundled Akka libraries versus Akka's own ones.
While it's a good exercise to see how things are done in a crude way, it's obviously unproductive to do this on a regular basis.
In my opinion You should perform scalac and scala with classpath parameter and selected library jar file.
By the way it's still more convenient to use sbt.
We use sbt-clojure in Scala project (https://github.com/Geal/sbt-clojure).
In one subproject there are Scala-code, which are imported in Clojure code.
In this case, Clojure doesn't see Scala-code (by "sbt compile", by default Clojure compiles earlier than Scala).
How can sbt compile Scala-code before Clojure-code?
I've faced the same issue and simply forked and modified the plugin: https://github.com/tomaszym/sbt-clojure Might be just enough also for you, if you don't mind firing clojurec instead of compile.
I would use Maven that supports both Scala and Clojure.
Maven has clojure-maven-plugin for Cloture and the maven-scala-plugin for Scala. You can arrange order of compilation of the both language source code.
I can't launch a scala jar; when I launch it I get the error "Exception in thread "main" java.lang.NoClassDefFoundError: scala/collection/immutable/List" which seems to mean the scala library is not loaded...
this is a screenshot showing a lot of informations on the artifact window.
here is the manifest:
Manifest-Version: 1.0
Class-Path: libs/scala-library-2.10.0.jar libs/commons-logging-1.1.1.j
ar libs/jcip-annotations-1.0.jar libs/jwnl-1.4_rc3.jar libs/laf-plugi
n-7.2.1.jar libs/laf-widget-7.2.1.jar libs/miglayout-core-4.2.jar lib
s/miglayout-swing-4.2.jar libs/scala-actors.jar libs/scala-library.ja
r libs/scala-swing.jar libs/slf4j-api-1.6.4.jar libs/slick_2.10-1.0.0
.jar libs/sqlite-jdbc-3.7.2.jar libs/substance-7.2.1.jar libs/trident
-7.2.1-swing.jar
Main-Class: Fenetre
and when I enter "java xf myJar.jar", there are extracted files in the directory:
- .class files
- in the libs folder, there are the libraries INCLUDING scala-library.jar & scala-library-2.10.0.jar(I specified only one of these two files in the manifest to avoid conflicts)
can you help me?
I'm new to Scala and don't know what the problem is however I've been compiling "fat jars" which include all the required libs.
I've been using https://github.com/sbt/sbt-assembly to do this successfully.
Despite what your manifest is telling you, when you run the application you either do not have the scala-library included in your class path or there's some confusion when you attempt to import List. Scala should automatically import the immutable collection classes in your project with the root Predef implementation.
Predef provides type aliases for types which are commonly used, such as the immutable collection types scala.collection.immutable.Map, scala.collection.immutable.Set, and the scala.collection.immutable.List constructors (scala.collection.immutable.:: and scala.collection.immutable.Nil). The types Pair (a scala.Tuple2) and Triple (a scala.Tuple3), with simple constructors, are also provided.
Predef in core Scaladocs
Try printing the classpath from within your app to confirm.
Although not pertinent to your question, I would recommend using SBT for dependency management now that IntelliJ IDEA 13 has full SBT integration support. Your collaborators not using IntelliJ will also be happier because SBT gives them more options for build technologies, editors, and other tooling when working on the project.
I'm trying to import com.lambdaworks.crypto.SCryptUtil (from crypto) in the Scala REPL. I'm running the REPL from the Java directory containing com/lambdaworks/crypto.
The REPL can't find com.lambdaworks.crypto.SCryptUtil, but it can autocomplete up to com.lambdaworks.crypto but can't find anything after that.
When I used the REPL in the IntelliJ IDEA after including the package in my project, I was able to find the SCryptUtil class.
Am I missing some classpath parameters that are required for import?
The REPL won't compile the Java code for you—it's only autocompleting that far because it's aware of the directory structure, but once it gets to the crypto directory it won't find any class files.
You can see this more dramatically by moving up a directory and opening a new REPL—you'll be able to autocomplete import java.com.lambdaworks.crypto, even though that's obviously not a real package hierarchy.
In this case you can move to the project root, run mvn compile to compile the Java code, and then start the REPL like this (still in the project root):
scala -classpath target/classes
Now you can import com.lambdaworks.crypto.SCryptUtil.
This only works because the project doesn't have any runtime dependencies, though—in other cases you may need either to add other things to the classpath, to build a JAR with the dependencies baked in (e.g. with the Maven Assembly plugin), or to use the mvn scala:console goal of the Maven Scala plugin.