diff --git a/buildSrc/src/main/kotlin/HmppConfigure.kt b/buildSrc/src/main/kotlin/HmppConfigure.kt
index 87e64ecc8..5d98d0565 100644
--- a/buildSrc/src/main/kotlin/HmppConfigure.kt
+++ b/buildSrc/src/main/kotlin/HmppConfigure.kt
@@ -16,6 +16,9 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPI
 import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
 import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
 import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
+import java.io.File
 
 /*
  * Copyright 2019-2022 Mamoe Technologies and contributors.
@@ -60,16 +63,18 @@ fun Project.configureHMPPJvm() {
 
         val nativeMainSets = mutableListOf<KotlinSourceSet>()
         val nativeTestSets = mutableListOf<KotlinSourceSet>()
+        val nativeTargets = mutableListOf<KotlinNativeTarget>()
 
         if (ideaActive) {
-            when {
+            val target = when {
                 Os.isFamily(Os.FAMILY_MAC) -> if (Os.isArch("aarch64")) macosArm64("native") else macosX64("native")
                 Os.isFamily(Os.FAMILY_WINDOWS) -> mingwX64("native")
                 else -> linuxX64("native")
             }
+            nativeTargets.add(target)
         } else {
             // 1.6.0
-            val nativeTargets: List<String> = arrayOf(
+            val nativeTargetNames: List<String> = arrayOf(
                 // serialization doesn't support those commented targets
 //                "androidNativeArm32, androidNativeArm64, androidNativeX86, androidNativeX64",
                 "iosArm32, iosArm64, iosX64, iosSimulatorArm64",
@@ -80,11 +85,12 @@ fun Project.configureHMPPJvm() {
                 "mingwX64",
 //                "wasm32" // linuxArm32Hfp, mingwX86
             ).flatMap { it.split(",") }.map { it.trim() }
-            presets.filter { it.name in nativeTargets }
+            presets.filter { it.name in nativeTargetNames }
                 .forEach { preset ->
-                    val target = targetFromPreset(preset, preset.name)
+                    val target = targetFromPreset(preset, preset.name) as KotlinNativeTarget
                     nativeMainSets.add(target.compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.first())
                     nativeTestSets.add(target.compilations[TEST_COMPILATION_NAME].kotlinSourceSets.first())
+                    nativeTargets.add(target)
                 }
 
             if (!ideaActive) {
@@ -98,31 +104,8 @@ fun Project.configureHMPPJvm() {
             }
         }
 
-//        nativeTarget.apply {
-//            val myrust by compilations.getByName("main").cinterops.creating {
-//                headers(project.projectDir.resolve("untitled/myrust.h"))
-//            }
-//
-//            binaries {
-//                sharedLib {
-//                    linkerOpts("-v")
-//                    linkerOpts("-L${project.projectDir.resolve("untitled/target/debug/").absolutePath}")
-////                    linkerOpts("-lmyrust")
-//                    linkerOpts("-Wl,-undefined,dynamic_lookup") // resolve symbols in runtime
-//                    baseName = "mykotlin"
-//                }
-//
-//                executable {
-//
-//                    linkerOpts("-v")
-//                    linkerOpts("-L${project.projectDir.resolve("untitled/target/debug/").absolutePath}")
-////                    linkerOpts("-lmyrust")
-//                    linkerOpts("-Wl,-undefined,dynamic_lookup") // resolve symbols in runtime
-//                    baseName = "KotlinExecutable"
-//                    entryPoint = "main.main"
-//                }
-//            }
-//        }
+        configureNativeInterop("main", projectDir.resolve("src/nativeMainInterop"), nativeTargets)
+        configureNativeInterop("test", projectDir.resolve("src/nativeTestInterop"), nativeTargets)
 
 
         val sourceSets = kotlinSourceSets.orEmpty()
@@ -151,4 +134,107 @@ fun Project.configureHMPPJvm() {
         nativeMain.dependsOn(commonMain)
         nativeTest.dependsOn(commonTest)
     }
+}
+
+private fun Project.configureNativeInterop(
+    compilationName: String,
+    nativeInteropDir: File,
+    nativeTargets: MutableList<KotlinNativeTarget>
+) {
+    if (nativeInteropDir.exists() && nativeInteropDir.isDirectory && nativeInteropDir.resolve("build.rs").exists()) {
+        val crateName = project.name.replace("-", "_")
+
+        val headerName = "$crateName.h"
+        val rustLibDir = nativeInteropDir.resolve("target/debug/")
+
+        configure(nativeTargets) {
+            compilations.getByName(compilationName).cinterops.create(compilationName) {
+                val headerFile = nativeInteropDir.resolve(headerName)
+                if (headerFile.exists()) headers(headerFile)
+                defFile(nativeInteropDir.resolve("interop.def"))
+            }
+
+            binaries {
+                sharedLib {
+                    linkerOpts("-v")
+                    linkerOpts("-L${rustLibDir.absolutePath.replace("\\", "/")}")
+//                    linkerOpts("-lmyrust")
+                    linkerOpts("-Wl,-undefined,dynamic_lookup") // resolve symbols in runtime
+                    baseName = project.name
+                }
+            }
+        }
+
+        val cbindgen = tasks.register("cbindgen${compilationName.titlecase()}") {
+            group = "mirai"
+            inputs.files(nativeInteropDir.resolve("src"))
+            outputs.file(nativeInteropDir.resolve(headerName))
+            doLast {
+                exec {
+                    workingDir(nativeInteropDir)
+                    commandLine(
+                        "cbindgen",
+                        "--config", "cbindgen.toml",
+                        "--crate", crateName,
+                        "--output", headerName
+                    )
+                }
+            }
+        }
+
+        val bindgen = tasks.register("bindgen${compilationName.titlecase()}") {
+            group = "mirai"
+            val bindingsPath = nativeInteropDir.resolve("src/bindings.rs")
+            inputs.files(nativeInteropDir.resolve("src"))
+            outputs.file(bindingsPath)
+            doLast {
+                exec {
+                    workingDir(nativeInteropDir)
+                    // bindgen input.h -o bindings.rs
+                    commandLine(
+                        "bindgen",
+                        buildDir.resolve("bin/native/debugShared/lib${crateName}_api.h"),
+                        "-o", bindingsPath,
+                    )
+                }
+            }
+        }
+
+        var targetCompilation: KotlinNativeCompilation? = null
+        configure(nativeTargets) {
+            val compilations = compilations.filter { nativeInteropDir.name.contains(it.name, ignoreCase = true) }
+            check(compilations.isNotEmpty()) { "Should be at lease one corresponding native compilation, but found 0" }
+            targetCompilation = compilations.single()
+            targetCompilation!!.compileKotlinTask.dependsOn(cbindgen)
+//            tasks.getByName("cinteropNative$name").dependsOn(cbindgen)
+        }
+        targetCompilation!!
+
+        val compileRust = tasks.register("compileRust${compilationName.titlecase()}") {
+            group = "mirai"
+            inputs.files(nativeInteropDir.resolve("src"))
+            outputs.file(rustLibDir.resolve("lib$crateName.dynlib"))
+            dependsOn(targetCompilation!!.compileKotlinTask)
+            dependsOn(bindgen)
+            dependsOn(tasks.findByName("linkDebugSharedNative"))
+            doLast {
+                exec {
+                    workingDir(nativeInteropDir)
+                    commandLine(
+                        "cargo",
+                        "build",
+                        "--all"
+                    )
+                }
+            }
+        }
+
+        tasks.getByName("assemble").dependsOn(compileRust)
+    }
+}
+
+fun String.titlecase(): String {
+    if (this.isEmpty()) return this
+    val c = get(0)
+    return replaceFirst(c, Character.toTitleCase(c))
 }
\ No newline at end of file
diff --git a/install.sh b/install.sh
new file mode 100644
index 000000000..17edd0362
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,11 @@
+#
+# Copyright 2019-2022 Mamoe Technologies and contributors.
+#
+# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+#
+# https://github.com/mamoe/mirai/blob/dev/LICENSE
+#
+
+cargo install --force cbindgen
+cargo install bindgen
\ No newline at end of file
diff --git a/mirai-core/src/nativeMainInterop/.gitignore b/mirai-core/src/nativeMainInterop/.gitignore
new file mode 100644
index 000000000..683119ebf
--- /dev/null
+++ b/mirai-core/src/nativeMainInterop/.gitignore
@@ -0,0 +1,8 @@
+/target
+Cargo.lock
+myrust.h
+
+*.iml
+
+src/bindings.rs
+/*.h
\ No newline at end of file
diff --git a/mirai-core/src/nativeMainInterop/Cargo.toml b/mirai-core/src/nativeMainInterop/Cargo.toml
new file mode 100644
index 000000000..6864969ca
--- /dev/null
+++ b/mirai-core/src/nativeMainInterop/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "mirai_core"
+version = "0.1.0"
+
+[dependencies]
+
+[lib]
+name = "mirai_core"
+crate-type = ["cdylib"]      # Creates dynamic lib
+# crate-type = ["staticlib"] # Creates static lib
+
+[build-dependencies]
+bindgen = "0.53.1"
+cbindgen = "0.20.0"
\ No newline at end of file
diff --git a/mirai-core/src/nativeMainInterop/build.rs b/mirai-core/src/nativeMainInterop/build.rs
new file mode 100644
index 000000000..af3ef6335
--- /dev/null
+++ b/mirai-core/src/nativeMainInterop/build.rs
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+extern crate bindgen;
+extern crate cbindgen;
+
+use std::env;
+use std::path::PathBuf;
+
+use cbindgen::Config;
+use cbindgen::Language::C;
+
+fn main() {
+    // let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+
+    // cbindgen::Builder::new()
+    //     .with_crate(crate_dir)
+    //     .with_language(C)
+    //     .generate()
+    //     .expect("Unable to generate bindings")
+    //     .write_to_file("nativeInterop.h");
+
+
+    println!("cargo:rustc-link-search=../../build/bin/native/debugShared");
+    println!("cargo:rustc-link-lib=mirai_core");
+}
\ No newline at end of file
diff --git a/mirai-core/src/nativeMainInterop/cbindgen.toml b/mirai-core/src/nativeMainInterop/cbindgen.toml
new file mode 100644
index 000000000..4aa4b4903
--- /dev/null
+++ b/mirai-core/src/nativeMainInterop/cbindgen.toml
@@ -0,0 +1,10 @@
+# This is a template cbindgen.toml file with all of the default values.
+# Some values are commented out because their absence is the real default.
+#
+# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml
+# for detailed documentation of every option here.
+
+
+
+language = "C"
+
diff --git a/mirai-core/src/nativeMainInterop/interop.def b/mirai-core/src/nativeMainInterop/interop.def
new file mode 100644
index 000000000..e69de29bb
diff --git a/mirai-core/src/nativeMainInterop/src/lib.rs b/mirai-core/src/nativeMainInterop/src/lib.rs
new file mode 100644
index 000000000..4572df655
--- /dev/null
+++ b/mirai-core/src/nativeMainInterop/src/lib.rs
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+/// cbindgen:ignore
+mod bindings;