Kotlinc -- minimal


#1

I'm looking to compile and distribute simple scripts.  I'm currently doing this with Groovy and if Groovy is already installed, it's very simple for a user to run the scripts.  I would like to do the same kind of thing with Kotlin.  Since Kotlin is compiled like Java, all the user needs is to have the JVM installed.  

My requirement is for a minimal compilation and execution format.  No IDE, XML, Ant, Maven, long classpath, etc.  Ideally I would distribute a single .class file.  Can the Kotlin runtime be included in a single class file or does the runtime need to be distributed as a seperate file?

So, for a simple HelloWorld script, what parms should I use on the kotlinc command and the java command to execute the script?


#2

If your class doesn't use anything but JDK classes, you can distribute a single .class file. As soon as you use a function literal or anything from the Kotlin library, you'll need the Kotlin runtime. There's no way to include several classes within one .class file, so the best you can have is a .jar file. Kotlin compiler can produce one for you with the corresponding command line option.

For HelloWorld you just compile it and run like
> java namespace


#3

I do this:

kotlinc -src hw.kt -output .
java namespace

and I get this:

Exception in thread "main" java.lang.NoClassDefFoundError: namespace/class Caused by: java.lang.ClassNotFoundException: namespace.class   at java.net.URLClassLoader$1.run(URLClassLoader.java:202)   at java.security.AccessController.doPrivileged(Native Method)   at java.net.URLClassLoader.findClass(URLClassLoader.java:190)   at java.lang.ClassLoader.loadClass(ClassLoader.java:307)   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)   at java.lang.ClassLoader.loadClass(ClassLoader.java:248) Could not find the main class: namespace.class.  Program will exit.

hw.kt:

fun main(args:Array<String>) {   println("Kotlin: First Contact") }


#4

Kotlinc can build a .jar file with the runtime included allowing you to distribute the .jar to people with only a JRE installed. Currently, the runtime adds around 200K to the size of the jar.

Here’s an example:

echo 'fun main(args: Array&lt;String&gt;) { println("Hello from Kotlin!") }' &gt; hw.kt kotlinc -jar hw.jar -src hw.kt -includeRuntime
$ java -jar hw.jar
Hello from Kotlin!


#5

Thanks.  That example works perfectly.

I’m still unable to figure out how to compile without the -includeRuntime on the kotlinc command and specifying it instead on the -cp parm of the java command.

I’ve tried this:

kotlinc -output . -src hw.kt
java -cp “C:kotlinclibkotlin-runtime.jar” namespace.class


#6

Your example has a couple of problems:

  • You need to specify the current directory in the classpath
  • You need to remove the ".class" extension from "namespace.class"

So you'll end up with:   java -cp ".;C:kotlinclibkotlin-runtime.jar" namespace

Note: I just tested this on windows and it works fine.

Cheers,
Andrew


#7

Again works perfectly.  Thank you.  

There is still one thing I don’t understand.  All the scripts are compiled to “namespace.class”.  
How do I get hw.kt to compile to hw.classs and xyz.kt to xyz.class?
Again, I’d like to do this with a single source file, no IDE, no XML, no Ant.


#8

The short answer is that you get xyz.class when you define "class xyz" in your code.

Consider the following code in hw.kt:

fun main(args: Array<String>) {

  println("Hello from Kotlin!")

}

Note that no package or class has been defined (you can’t do this in Java - all code must belong to a class). As the code has no natural name, Kotlin has to make one up for you. It appears the Kotlin devs have chosen “namespace” for this purpose. (Also note that there’s one namespace per package, not just one namespace).

So if you want something like xyz.class in Java, you need to write:

class xyz {   fun hello() {   println("Hello from Kotlin!")   } } fun main(args: Array<String>) {   xyz().hello() }

You still have to invoke it via “namespace” however (the main method is still within the “namespace” scope).


#9

I tried the module example for Smoke from http://confluence.jetbrains.net/display/Kotlin/Kotlin+Build+Tools

compiled with

kotlinc -module Smoke.kts -jar smoke.jar -includeRuntime

and ran with

java -jar smoke.jar

and received

Failed to load Main-Class manifest attribute from smoke.jar


#10

I've just had a play with it (I've never used modules before).

When building a module, the Main-Class attribute in META-INF/MANIFEST.MF is not set (you can extract it and have a look using “jar xf smoke.jar”).
I don’t know whether this is by design or not.

However, if you want to run the example you can do so using:

java -cp smoke.jar Smoke.namespace 1 2 3


#11

Hello, Ben!

You can try https://github.com/kondratovich/aztec.

It’s a build tool for Kotlin, that I started develop a few days ago.
You need a Python to use it.

It has simple command line interface. You can compile Kotlin sources, build jars, and even make executable files - you can use it then like a binary program.

I started only a few days ago, and now it doesn’t support any dependency managment. But how I can see, you need simple scripts, and I think Aztec can offer such functionality right now.

I hope, you try it and send me your feedback.

Thanks, Andrew.


#12

I could not get it to install properly.  Because I'm on Python 2.7.1, setuptools doesn't install.  I saw somewhere that "distribute" has replaced setuptools.  So, I installed distribute and followed instructions.  There does not appear to be an az command and running the az.py script does nothing.

sigh  I wish you had written this in kotlin instead of python.


#13

You can install setuptools from http://pypi.python.org/pypi/setuptools or from repository: sudo apt-get install python-setuptools. `distribute` is a different package.

About write this tool on kotlin - there are two problems:

  1. Kotlin is in deep alpha, and code that you wrote yesterday may be not compilable today ;]
  2. Kotlin is JVM, and JVM need much time to start, especially in low-performance computers. It’s not good game to spend two or three times more time to start JVM than code would work.

I’m thinking about rewrite it on kotlin, but not now. First problem would be solved by JB team soon I hope =) And I can solve second problem by demonization of JVM (But some piece of code would be written on fast for start script language to proxy parameters).


#14

I used http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11.win32-py2.7.exe from the link you posted.  It refuses to install on python 2.7.1.  

This kind of thing is one of the reasons I really loathe and despise python, but I digress.


#15

Unfortunately, I don't know how to help you in this case :(


#16

You might want to try the scripting approach I've posted here (http://devnet.jetbrains.net/thread/434397?tstart=0) if you're using some variant of unix.

Cheers,
Andrew


#17

kotlinc command doesn't accept a -classpath attribute -- exec() finished with 1 return code

http://confluence.jetbrains.net/display/Kotlin/Kotlin+Build+Tools#KotlinBuildTools-%7B%7B%3Ckotlinc%3E%7D%7Dattributes


#18

The page you are referring to describes an Ant task, not a command on the command line. If you actually meant the Ant task, please file an issue here: http://youtrack.jetbrains.net/issues/KT

Thanks.


#19

Kotlin is designed around modules which define (amongst other things) the classpath.

So to compile with libraries, you need to define a module. e.g.

mymodule.kts:

import kotlin.modules.*

fun project() {
  module(“mymodule”) {
  sources += “mymodule.kt”
  classpath += “/Users/andrew/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar”
  }
}

mymodule.kt:

import org.apache.log4j.*


val logger = Logger.getLogger(“mymodule”).sure();


fun main(args: Array<String>) {
  BasicConfigurator.configure();
  logger.info(“Hello from Kotlin via log4j”)
}

To compile:

$ kotlinc -module mymodule.kts -jar myjar.jar -includeRuntime To run:
$ java -cp myjar.jar:/Users/andrew/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar namespace 0 [main] INFO mymodule  - Hello from Kotlin via log4j

The module system appears fairly basic at the moment, but based on the information in the wiki it looks like it is going to grow into a build system, supporting Maven repositories etc.

Cheers,
Andrew


#20

Thanks.  I tried something like this and got it to work when specifying a specific jar on the classpath.

It didn’t work with a wildcard for jars.

Exception in thread "main" java.lang.IllegalArgumentException: trying to add non -existing file to classpath: C:pathlib*.jar

Also didn’t work if I specify a folder instead of a specific file

ERROR: C:pathTestClass.kt:(2,12) Unresolved reference: myclass