Kotlin是JetBains开发一种基于JVM的新的编程语言。Kotlin可以编译成字节码运行在JVM上,与Java完美兼容,并在Java的基础上添加了很多好用的特性。也正因为kotlin的种种优点,Google将Kotlin选为Android开发的一级语言。
Kotlin Native利用LLVM来将Kotlin代码编译成本地机器代码,使得Kotlin可以脱离JVM运行。借助Kotlin Native,Kotlin也能被打包成lib、exe、dll等格式、运用于嵌入式或其他对性能要求较高的场景。
这个编译器和Kotlin/JVM工程里的不一样,Kotlin/Native工程里是直接把代码编译成机器码而不是运行在虚拟机上的字节码。下载对应的编译器,或者直接从github上下载源码编译。直接下载release目录下的编译器可以略过下面的编译过程。
首先运行下面的命令下载依赖包。
./gradlew dependencies:update
然后运行下面的命令build编译器,因为编译整包的时间较长,所以建议使用下面的第二种方式或直接下载编译器。
./gradlew bundle // 1.编译整包
./gradlew dist // 2.只编译当前系统对应的包
新建一个kotlin工程,选择使用gradle来构建。
在项目根目录下新建一个gradle.properties文件,配置编译器的路径。其中Windows下要注意路径分割符,Linux和mac因为分隔符是”/”所以正常写路径就行了。
konan.home=D\:\\KotlinNative\\kotlin-native-windows-0.6.2 // 1.windows直接下载编译器
konan.home=D\:\\KotlinNative\\kotlin-native\\dist // 2.windows下载源码编译
在根目录下新建src/main/kotlin目录用于存放Kotlin代码,然后随手就是一个hello world。
// Main.kt
fun main(args: Array<String>) {
println("Hello Kotlin Native")
}
编辑build.gradle的内容(其中我注释掉的内容为Kotlin/JVM的配置,可以让Kotlin代码在Intellij上运行,调试Kotlin代码的时候可以用),在把Kotlin编译成机器码的过程中只需要有Kotlin/Native的相关配置就行了。
buildscript {
// ext.kotlin_version = '1.1.4'
repositories {
mavenCentral()
maven {
url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies"
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:0.6"
// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'konan'
//apply plugin: 'kotlin'
repositories {
mavenCentral()
}
//dependencies {
// compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
//}
konanArtifacts {
// 这里只是把src/main/kotlin/Main.kt编译成一个名为foo的可执行文件
program('foo') {
srcFiles 'src/main/kotlin/Main.kt'
}
}
上面build.gradle中的配置,konanArtifacts这个括号里的内容就是控制打包的相关配置,是我们主要关注的,主要有以下配置项,可以根据自己的需要选择(个人翻译,可以去github看英文原版)。
// 默认编译的平台
konan.targets = ['macbook', 'linux', 'wasm32']
// kotlin和api的版本
konan.languageVersion = 'version'
konan.apiVersion = 'version'
konanArtifacts {
// 编译的目标平台 (如果没有的话就是上面konan.targets里面的平台)
// 生成foo.exe(windows)/foo.kexe(linux)
program('foo', targets: ['android_arm32', 'android_arm64']) {
// 源代码路径,默认路径为 src/main/kotlin.
srcDir 'src/other'
// 源文件.
srcFiles project.fileTree('src')
srcFiles 'foo.kt', 'bar.kt'
// 生成文件的名字,如果没有就是上面小括号中的foo.
artifactName 'customName'
// 文件输出的路径,默认为 build/konan/bin
baseDir 'path/to/output/dir'
libraries {
// 库文件
file 'foo.klib'
files 'file1.klib', file2.klib
files project.files('file3.klib', 'file4.klib')
// 当前工程中生成的其他文件
artifact konanArtifacts.bar
artifact 'baz'
// 其他工程中的生成文件
artifact project(':path:to:a:project'), 'artifcatName'
// 其他某个工程中生成的所有库文件
allLibrariesFrom project(':some:project')
// 其他某个工程中的所有的互操作类型的库文件
allInteropLibrariesFrom project(':some:interop:project')
// 根据名字查找的.klib库文件
klib 'foo'
klib 'bar', 'baz'
}
// 需要链接的native库 (*.bc).
nativeLibrary project.file('path/to/native/library.bc')
nativeLibraries 'library1.bc', 'library2.bc'
noStdLib true // 不链接stdlib (true/false).
enableOptimizations true // 开启编译优化 (true/false).
enableAssertions true // 在生成二进制文件的时候开启断言 (true/false).
enableDebug true // 在生成二进制文件的时候开启debug (true/false).
noDefaultLibs true // 不链接默认库
// link参数.
linkerOpts 'Some linker option', 'More linker options'
// build时打印所有参数.
dumpParameters true
// 计算编译各阶段时间.
measureTime true
// 编译过程中依赖的其他任务.
dependsOn anotherTask
// 传递给编译器的额外命令行参数.
extraOpts '--time', '--verbose', 'linker'
// 额外编译Linux平台的.
target('linux') {
// 输出路径,默认为 /
destinationDir 'exact/output/path'
// 可以添加和上面类似的其他配置.
}
}
library('bar') {
// 其他参数的配置与上面一样
// 生成bar.klib文件,默认输出路径为 build/konan/libs
}
bitcode('baz') {
// 其他参数的配置与上面一样
// 生成baz.bc文件,默认输出路径为 build/konan/bitcode
}
dynamic('quux') {
// 其他参数的配置与上面一样
// 生成quux.dll和quux_api.h文件,默认输出路径为 is build/konan/bin
}
framework('quuux') {
// 其他参数的配置与上面一样
// Object-C framework文件,Windows下不支持,默认输出路径为 build/konan/bin
}
interop('qux') {
// native API的描述文件,默认路径为 src/main/c_interop/.def
defFile project.file("deffile.def")
// 头文件.
headers project.files('header1.h', 'header2.h')
// 其他属性配置同上
// 头文件目录.
includeDirs {
allHeaders 'path1', 'path2'
// 根据.def文件中定义的 'headerFilter' 筛选出来的头文件.
headerFilterOnly 'path1', 'path2'
}
// 目录下的所有头文件.
includeDirs "include/directory" "another/directory"
// 需要额外链接的文件.
link <files which will be linked with native stubs>
}
}
运行下面的命令或双击Intellij中的build选项进行编译
./gradlew build
编译完之后就可以在build/konan目录下发现生成的目标文件了。
因为是直接把kotlin代码直接编译成了机器代码,因此可以脱离虚拟机直接运行。
新建一个src/main/c目录用于放置c文件和.h头文件,用c语言编写一个函数给kotlin调用,代码如下:
//kotlinor.h
#ifndef KOTLINOR_H
#define KOTLINOR_H
int add(int a, int b);
#endif
//kotlinor.c
#include "kotlinor.h"
#include
int add(int a, int b){
return a + b;
}
//Main.kt
//导入的包名和下面konanArtifacts中配置的一致
import myPkg.*
fun main(args: Array) {
println(add(1, 3))
}
使用下面的命令通过c代码生成.bc(BitCode)文件供下面使用
clang -std=c99 -c kotliner.c(c文件) -o kotliner.bc(生成的bc文件) -emit-llvm
根据上面的介绍配置build.gradle,修改konanArtifacts中的内容
konanArtifacts {
// 这个名字下面会用到,必须保持一致
interop('myInterop') {
// kotlin代码中import的包名
packageName 'myPkg'
compilerOpts '-Isrc/c'
// null.def 中没有添加配置,可以按自己需求添加
defFile 'null.def'
headers "src/main/c/kotlinor.h"
includeDirs "src/main/c"
}
program('foo') {
srcFiles 'src/main/kotlin/Main.kt'
// 上一个步骤生成的bc文件
nativeLibraries 'src/main/c/kotlinor.bc'
libraries {
// interop的名字
artifact 'myInterop'
}
}
}
同样是使用./gradlew build命令编译,就可以在build目录下顺利生成目标文件了。
第一手最新资料请参考jetbrains的github
https://github.com/JetBrains/kotlin-native
因为Kotlin/Native编译器是将kotlin编译成机器码的编译器,而不是运行在JVM上的字节码,所以在这里的kotlin代码中不能使用Java sdk里的API。
生成的可执行文件,windows下后缀为exe、Linux下后缀为kexe。windows下可以用直接双击运行,如果程序运行时间很短的话只会看到一个黑框一闪而过。