How to compile kotlin with incremental compilation and cache from command line? - kotlin

Is it possible to compile kotlin with incremental compilation and cache, and ideally without building the jar? To make it faster.
Example:
I have two kotlin files in the play folder
user.kt
data class User(val name: String)
play.kt
fun main() {
val user = User("Jim")
println("Hello ${user.name}")
}
The usual way to compile and run is with this command:
kotlinc . -include-runtime -d play.jar && java -jar play.jar
Is there a way to speed it up? By using incremental compilation and cache, avoiding building jar and avoiding merging runtime? How the compile&run command would look like?

Related

Running a Java 11.02 JavaFX .jar application produces strange output

I've been trying to create and run a .jar file that I can run my JavaFX application on any computer running the Java runtime enviroment.
For Java i'm running sdk version 11.02 and for JavaFX i'm running the 11.02 jdk. My IDE is IntellJ IDEA. I've made sure that my Windows enviroment variables have been set up correctly like so:
JAVA_HOME: C:\Program Files\Java\jdk-11.0.2
And in the Path System variables:
c:\program files\java\jdk-11.0.2\bin
c:\program files\javafx-sdk-11.0.2\lib
In Intellj IDEA I've made sure the Path variables have been set like so:
I've also made sure that my project is using the right Java version and that the javafx libraries are being used:
I've also made sure that VM options in the Application runner has the correct command:
With this I can run my JavaFX program with no problems through the IDE's built in Application runner. But this is not the case If I try to create a jar file and run that. I tried following a guide to the first answer of this question, namely the part where he talks about a FAT Jar.
I created a Launcher class as he suggested, with the only difference with mine being that I needed to add a throw exception clause else I got an unhandled exception error on the .main part.
package main;
import com.sun.tools.javac.Main;
public class Launcher {
public static void main(String[] args) throws Exception {
Main.main(args);
}
}
And here is my original JavaFX entry point:
public class Main extends Application
{
private ArmyBuilderRootPane view;
#Override
public void init()
{
Army model = new Army();
view = new ArmyBuilderRootPane();
new ArmyBuilderController(view, model);
}
#Override
public void start(Stage stage)
{
stage.setTitle("Space Marine Army Builder");
stage.setScene(new Scene(view));
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
I then follow how he creates a .jar file by first setting up the Artifacts in the project structure, and then finally building it. When I try to run this .jar in both the internal IDE and using the command: java -jar SpaceMarineArmyBuilder.jar within an external Windows command line: I get the following output:
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" --module-path "C:/Program Files/javafx-sdk-11.0.2/lib" --add-modules javafx.controls,javafx.fxml -Dfile.encoding=windows-1252 -jar "D:\Projects\Code\Space Marine Army Builder (7th Edition)\classes\artifacts\SpaceMarineArmyBuilder_jar\SpaceMarineArmyBuilder.jar"
Usage: javac <options> <source files>
where possible options include:
#<filename> Read options and filenames from file
-Akey[=value] Options to pass to annotation processors
--add-modules <module>(,<module>)*
Root modules to resolve in addition to the initial modules, or all modules
on the module path if <module> is ALL-MODULE-PATH.
--boot-class-path <path>, -bootclasspath <path>
Override location of bootstrap class files
--class-path <path>, -classpath <path>, -cp <path>
Specify where to find user class files and annotation processors
-d <directory> Specify where to place generated class files
-deprecation
Output source locations where deprecated APIs are used
--enable-preview
Enable preview language features. To be used in conjunction with either -source or --release.
-encoding <encoding> Specify character encoding used by source files
-endorseddirs <dirs> Override location of endorsed standards path
-extdirs <dirs> Override location of installed extensions
-g Generate all debugging info
-g:{lines,vars,source} Generate only some debugging info
-g:none Generate no debugging info
-h <directory>
Specify where to place generated native header files
--help, -help, -? Print this help message
--help-extra, -X Print help on extra options
-implicit:{none,class}
Specify whether or not to generate class files for implicitly referenced files
-J<flag> Pass <flag> directly to the runtime system
--limit-modules <module>(,<module>)*
Limit the universe of observable modules
--module <module-name>, -m <module-name>
Compile only the specified module, check timestamps
--module-path <path>, -p <path>
Specify where to find application modules
--module-source-path <module-source-path>
Specify where to find input source files for multiple modules
--module-version <version>
Specify version of modules that are being compiled
-nowarn Generate no warnings
-parameters
Generate metadata for reflection on method parameters
-proc:{none,only}
Control whether annotation processing and/or compilation is done.
-processor <class1>[,<class2>,<class3>...]
Names of the annotation processors to run; bypasses default discovery process
--processor-module-path <path>
Specify a module path where to find annotation processors
--processor-path <path>, -processorpath <path>
Specify where to find annotation processors
-profile <profile>
Check that API used is available in the specified profile
--release <release>
Compile for a specific VM version. Supported targets: 6, 7, 8, 9, 10, 11
-s <directory> Specify where to place generated source files
-source <release>
Provide source compatibility with specified release
--source-path <path>, -sourcepath <path>
Specify where to find input source files
--system <jdk>|none Override location of system modules
-target <release> Generate class files for specific VM version
--upgrade-module-path <path>
Override location of upgradeable modules
-verbose Output messages about what the compiler is doing
--version, -version Version information
-Werror Terminate compilation if warnings occur
Process finished with exit code 2
I have no idea why it's producing this output. It should be running my JavaFX application.
If anybody could help me i'd appreciate it.
Thanks.

add submodule (built with cmake) in qbs project

I'm using cmake to build my project now and I want to migrate to qbs in the future. I have some opensource sub-modules from github, which are currently built with cmake, and are included in my project using cmake's add_subdirectory.
I've tried to research but found no alternatives of add_subdirectory in qbs.
I don't think migrating all sub-modules build system from cmake to qbs is a good idea because that means I have to migrate sub of sub-modules or sub of sub of sub-modules as well :)
Any help? Thanks!
To pull in projects built with a different tool, you'll need some sort of wrapper. For instance, assuming your cmake sub-project is a library, you could write this (untested):
Product {
type: ["dynamiclibrary"]
Group {
files: ["subdir/CMakeLists.txt"]
fileTags: ["cmake_project"]
}
Group {
files: ["subdir/*"]
excludedFiles: ["subdir/CMakeLists.txt"]
fileTags: ["cmake_sources"]
}
Rule {
inputs: ["cmake_project"]
auxiliaryInputs: ["cmake_sources"]
Artifact {
filePath: ... // Whatever cmake produces
fileTags: ["dynamiclibrary"]
}
prepare: {
var cmd = new Command("cmake", [/*cmake arguments*/]);
cmd.description = "building cmake project xyz";
cmd.workingDirectory = product.sourceDirectory + "/subdir";
return [cmd];
}
}
}
You should probably tweak the cmake call so that the generated binaries end up in qbs's build directory.
There might be convenience functionality for this sort of thing in the future, if it turns out that there's a sensible abstraction level.

How can I get the Frege compiler to see Android API classes when using Gradle?

I am attempting to write an Android app using the Frege language. Unfortunately, I'm not aware of any examples of how to do this.
So, I'm using Gradle as my build system, with the Android Gradle plugin. Then to get the Frege code to be compiled, I'm using a javaexec to call the frege compiler before the Java files get compiled, as suggested in this post.
I was successful in building an Android application with Frege code that gets called by Java code, as shown here.
However, the Frege code can only call standard Java APIs. It can't call any of the Android APIs.
I'd like to be able to call Android APIs from Frege. There is a nice repo here that has Frege wrappers for the Android APIs. Unfortunately, it has no build system or instructions.
I believe I've successfully set up my build.gradle to build the FregeAndroid wrappers along with my project's code. The Frege compiler is indeed attempting to build them.
However, the FregeAndroid code fails to compile, because it can't see the Android API classes. I assume I need to somehow find where the Android API classes are, and then add that to the Frege compiler's classpath, so it can see those classes. Unfortunately, this is where I'm stuck. I'm a newbie at Gradle, and can't figure out how to do this.
Here is my project which I have so far, which fails to build, in the following way:
:compileDebugJavaWithJavac
Frege compiler args: "-inline -d src/frege -make -fp /Users/ppelleti/Library/Android/sdk/platforms/android-21/android.jar -sp /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src/frege/android/animation/TimeInterpolator.fr"
calling: javac -cp /Users/ppelleti/.gradle/caches/modules-2/files-2.1/org.frege-lang/frege/3.23.401-g7c45277/716990197271fdc15917b4f8d023d63009ba6e39/frege-3.23.401-g7c45277.jar:/Users/ppelleti/Library/Android/sdk/extras/android/m2repository/com/android/support/multidex/1.0.0/multidex-1.0.0.aar:src/frege:/Users/ppelleti/Library/Android/sdk/platforms/android-21/android.jar -d src/frege -sourcepath /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src -encoding UTF-8 src/frege/frege/android/animation/TimeInterpolator.java
runtime 4.282 wallclock seconds.
Frege compiler args: "-inline -d src/frege -make -fp /Users/ppelleti/Library/Android/sdk/platforms/android-21/android.jar -sp /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src /Users/ppelleti/programming/android/frege-on-android/FregeAndroid/src/frege/android/app/Activity.fr"
Android.app.TaskStackBuilder: build failed because module is not on class path
Android.app.Fragment: build failed because module is not on class path
Android.app.LoaderManager: build failed because module is not on class path
[... omitted a bunch of similar lines ...]
Any ideas would be much appreciated!
It turns out that there were several problems, including problems with both the source path and the classpath. I've updated my repository to fix these problems.
However, ultimately the build fails because there are files missing from the FregeAndroid repo. So to get my example to build, it would be necessary to fix the FregeAndroid wrappers or write new wrappers.

compile mixed Kotlin and Java code from the command line

I'd like to start adding some Kotlin to my Java project. To do that I need to be able to compile both Java and Kotlin files from the command line, which is fine apart from when files of different types depend on each other e.g. A.java depends on B.kt which in turn depends on C.java.
Is there any way to do this without using Gradle, Maven etc?
Edited to clarify thanks #Nikita for pointing out it is not clear that I want both java and Kotlin files in the same source tree
To achieve this, you will need to run two steps.
Run kotlinc targeting *.kt files. Add all required java sources on classpath. Note the destination location.
Run javac targeting *.java files. Add *.class files created by step 1 to classpath.
Result is a combination of *.class files from both steps.
Here is a documetation on Kotlin compiler
Remember to compile Kotlin first, then compile Java with kotlin-build-classpath from first step.
simple like this:
1. kotlinc ./src/* -d ./buildTmp
2. javac ./src/**.java -d ./buildTmp -classpath ./buildTmp

How to run Kotlin class from the command line?

I understand this question has been asked before, but none of the information there has helped me.
Here is my situation: I can't run a compiled Kotlin class. When I try to run it like I would a normal java class I get the following:
C:\Users\User\Desktop>java _DefaultPackage
Exception in thread "main" java.lang.NoClassDefFoundError: jet/runtime/Intrinsics
at _DefaultPackage.main(Finder.kt)
Caused by: java.lang.ClassNotFoundException: jet.runtime.Intrinsics
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 1 more
This led me to believe that the Kotlin runtime was simply missing, given that output. So I tried the following:
C:\Users\User\Desktop>java -cp kotlin-runtime.jar _DefaultPackage
Error: Could not find or load main class _DefaultPackage
Which made me think that maybe I needed to add the class file to my declared classpath so:
C:\Users\User\Desktop>java -cp kotlin-runtime.jar';_DefaultPackage.class _DefaultPackage
Error: Could not find or load main class _DefaultPackage
What am I missing?
Knowing the Name of Your Main Class
To run a Kotlin class you are actually running a special class that is created at the file level that hold your main() and other functions that are top-level (outside of a class or interface). So if your code is:
// file App.kt
package com.my.stuff
fun main(args: Array<String>) {
...
}
Then you can execute the program by running the com.my.stuff.AppKt class. This name is derived from your filename with Kt appended. You can change the name of this class within the file by adding this file-targeted annotation:
#file:JvmName("Foo")
You can also put your main() into a class with a companion object and make it static using the JvmStatic annotation. Therefore your class name is the one you chose:
// file App.kt
package com.my.stuff
class MyApp {
companion object {
#JvmStatic fun main(args: Array<String>) {
...
}
}
}
Now you just run the class com.my.stuff.MyApp
What other JAR files do I need?
You need your application JAR and any dependencies. For Kotlin specific JARs when outside of Maven/Gradle you need a Kotlin distribution which contains:
kotlin-stdlib.jar (the standard library)
kotlin-reflect.jar only if using Kotlin reflection
kotlin-test.jar for unit tests that use Kotlin assertion classes
Running from Intellij
If in Intellij (if it is your IDE) you can right click on the main() function and select Run, it will create a runtime configuration for you and show the fully qualified class name that will be used. You can always use that if you are unsure of the name of the generated class.
Running from Gradle
You can also use the Gradle Application plugin to run a process from Gradle, or to create a runnable system that includes a zip/tgz of your JAR and all of its dependencies, and a startup script. Using the example class above, you would add this to your build.gradle:
apply plugin: 'application'
mainClassName = 'com.my.stuff.AppKt'
// optional: add one string per argument you want as the default JVM args
applicationDefaultJvmArgs = ["-Xms512m", "-Xmx1g"]
And then from the command-line use:
// run the program
gradle run
// debug the program
gradle run --debug-jvm
// create a distribution (distTar, distZip, installDist, ...)
gradle distTar
Running Directly from Java Command-line
If you have a runnable JAR, and assuming KOTLIN_LIB points to a directory where Kotlin runtime library files reside:
java -cp $KOTLIN_LIB/kotlin-stdlib.jar:MyApp.jar com.my.stuff.AppKt
See the notes above about other JAR files you might need. A slight variation if you have a runnable JAR (with the manifest pointing at com.my.stuff.AppKt as the main class):
java -cp $KOTLIN_LIB/kotlin-stdlib.jar -jar MyApp.jar
Running using the Kotlin command-line tool
If you install Kotlin tools via Homebrew or other package manager. (on Mac OS X brew update ; brew install kotlin) Then it is very simple to run:
kotlin -cp MyApp.jar com.my.stuff.AppKt
This command adds the stdlib to the classpath provided, then runs the class. You may need to add additional Kotlin libraries as mentioned in the section above "Running from Java."
Creating runnable JAR with the Kotlin compiler
This is not very common since most people use other build tools, but the Kotlin compiler can create a runnable Jar that solves this for you (see http://kotlinlang.org/docs/tutorials/command-line.html) when it bundles the runtime and your code together. Although this isn't as common when using tools such as Maven and Gradle, or IDE builds. Then run using the normal Java:
java -jar MyApp.jar
You can compile using kotlinc as follows:
$ kotlinc hello.kt -include-runtime -d hello.jar
and then you can run jar file as follows:
$ java -jar hello.jar
I struggled with this for a while as well. You're close, you just need to include your jar in the classpath and pass the qualified name of your "main" class as the primary argument to java.
There are a couple of ways to run Kotlin from the command line, depending on whether you're using the Java bytecode compiler (kotlinc) or the native compiler (kotlinc-native).
If you get an error message about -include-runtime, read the message carefully. You may be using the Kotlin native compiler instead of the Kotlin bytecode compiler. If you want to use the native compiler, see the second section below.
kotlinc (Java bytecode)
It's important to consider that you may not be in the same folder as your main.kt when you try to run your project, and it's not always clear how to tell Kotlin (or Java) to find it.
Assuming that:
You're trying to compile and run from a Windows command prompt.
You have this project structure (after IntelliJ Idea sets up a command-line Kotlin project):
MyNiftyProject
src
main
kotlin
main.kt
You're in the project root.
And you have this main.kt file:
fun main(args: Array<String>) {
println("Hello World!")
}
Compile like this:
kotlinc src/main/kotlin/main.kt -include-runtime -d MyNiftyProject.jar
This puts MyNiftyProject.jar in the root of your project.
Then run like this using the java command-line tool:
java -jar MyNiftyProject.jar
Or run like this using the kotlin command-line tool:
kotlin -classpath MyNiftyProject.jar MainKt
kotlinc-native
For native code, the process is somewhat simpler. Using the same setup as above:
kotlinc-native src/main/kotlin/main.kt -o MyNiftyProject
This puts MyNiftyProject.exe in the root of your project.
Then you just run it as a normal Windows executable:
MyNiftyProject.exe
if you are using a jar file that is generated from IntellijeIdead, you should run the kotlin file like java files but consider that kotlin file name will be something like that :
your file: test.kt
your output in the jar: testKt
java -cp file.jar yourPackage.testKt