Kotlin Native编程探索

Kotlin简介

Kotlin是JetBains开发一种基于JVM的新的编程语言。Kotlin可以编译成字节码运行在JVM上,与Java完美兼容,并在Java的基础上添加了很多好用的特性。也正因为kotlin的种种优点,Google将Kotlin选为Android开发的一级语言。

Kotlin Native利用LLVM来将Kotlin代码编译成本地机器代码,使得Kotlin可以脱离JVM运行。借助Kotlin Native,Kotlin也能被打包成lib、exe、dll等格式、运用于嵌入式或其他对性能要求较高的场景。

Kotlin编译器准备

这个编译器和Kotlin/JVM工程里的不一样,Kotlin/Native工程里是直接把代码编译成机器码而不是运行在虚拟机上的字节码。下载对应的编译器,或者直接从github上下载源码编译。直接下载release目录下的编译器可以略过下面的编译过程。

首先运行下面的命令下载依赖包。

./gradlew dependencies:update

然后运行下面的命令build编译器,因为编译整包的时间较长,所以建议使用下面的第二种方式或直接下载编译器。

./gradlew bundle     // 1.编译整包
./gradlew dist       // 2.只编译当前系统对应的包

将Kotlin编译成机器码

新建一个kotlin工程,选择使用gradle来构建。
Kotlin Native编程探索_第1张图片
在项目根目录下新建一个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

Kotlin Native编程探索_第2张图片
编译完之后就可以在build/konan目录下发现生成的目标文件了。
Kotlin Native编程探索_第3张图片
因为是直接把kotlin代码直接编译成了机器代码,因此可以脱离虚拟机直接运行。
这里写图片描述

使用Kotlin和C混合编程

新建一个src/main/c目录用于放置c文件和.h头文件,用c语言编写一个函数给kotlin调用,代码如下:
Kotlin Native编程探索_第4张图片

//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目录下顺利生成目标文件了。
Kotlin Native编程探索_第5张图片

这里写图片描述

PS

  • 第一手最新资料请参考jetbrains的github
    https://github.com/JetBrains/kotlin-native

  • 因为Kotlin/Native编译器是将kotlin编译成机器码的编译器,而不是运行在JVM上的字节码,所以在这里的kotlin代码中不能使用Java sdk里的API。

  • 生成的可执行文件,windows下后缀为exe、Linux下后缀为kexe。windows下可以用直接双击运行,如果程序运行时间很短的话只会看到一个黑框一闪而过。

你可能感兴趣的:(kotlin)