从多平台 kotlin 项目访问 C/C++ lib

kin*_*ton 8 c++ android kotlin kotlin-native kotlin-multiplatform

我第一次使用 Android Studio 构建多平台项目。我创建了一个 Android 应用程序模块,该模块使用 Android 上的多平台库。我还使用 XCode 构建了一个 iOS 应用程序,该应用程序使用 iOS 上的多平台库。一切工作正常,我能够使用由不同的Android 和 iOSexpect fun实现的。actual fun

我还用 C++ 创建了一个公开 C 接口的库。

#ifndef PINGLIB_LIBRARY_H
#define PINGLIB_LIBRARY_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    long long elapsed;
} PingInfo;

typedef void (*PingCallback)(PingInfo pingInfo);
typedef struct
{
    PingCallback pingUpdate;
} PingObserver;

void* ping(const char * url, const PingCallback *pingCallback);
void subscribe(void* pingOperation);
void unsubscribe(void* pingOperation);

#ifdef __cplusplus
}
#endif

#endif //PINGLIB_LIBRARY_H
Run Code Online (Sandbox Code Playgroud)

我使用 CLion 构建 C++ 代码。我创建了一个.def文件,用于使用cinterop.

package = com.exercise.pinglib
headers = PingLibrary.h
linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu
compilerOpts = -std=c99 -I/Users/username/myproject/ping/ping/header
staticLibraries = libping.a
libraryPaths = /opt/local/lib /Users/username/myproject/ping/cmake-build-debug
Run Code Online (Sandbox Code Playgroud)

libping.a是构建 C++ 代码而创建的库。它是在文件夹中创建的/Users/username/myproject/ping/cmake-build-debug

当我运行该命令时cinterop -def ping.def -o ping,它会创建 klib 文件和一个包含manifest.properties文件的文件夹,一个natives包含文件的子文件夹cstubs.bc和一个kotlin包含文件的子文件夹.kt

ping.klib
-ping-build
    manifest.properties
    -natives
        cstubs.bc
    -kotlin
        -com
            -exercise
                -pinglib
                    pinglib.kt
Run Code Online (Sandbox Code Playgroud)

如何cinterop在我的 kotlin-multiplatform 项目中使用创建的库?

我找到了不同的导入方法,但没有找到有关如何导入的完整描述。 他们说我可以使用类似的东西:

    implementation files("ping.klib")
Run Code Online (Sandbox Code Playgroud)

我为 iOS 项目做到了这一点,但我仍然不知道如何在 Android 和 iOS 上访问 kotlin 类。

这是我的build.gradle

apply plugin: 'com.android.library'
apply plugin: 'kotlin-multiplatform'

android {
    compileSdkVersion 28
    defaultConfig {
        minSdkVersion 15
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
kotlin {
    targets {
        final def iOSTarget = System.getenv('SDK_NAME')?.startsWith('iphoneos') ? presets.iosArm64 : presets.iosX64
        fromPreset(iOSTarget, 'ios') {
            binaries {
                framework('shared')
            }
        }
        fromPreset(presets.android, 'android')
    }
    sourceSets {
        // for common code
        commonMain.dependencies {
            api 'org.jetbrains.kotlin:kotlin-stdlib-common'
        }
        androidMain.dependencies {
            api 'org.jetbrains.kotlin:kotlin-stdlib'
        }
        iosMain.dependencies {
            implementation files("ping.klib")
        }
    }
}
configurations {
    compileClasspath
}

task packForXCode(type: Sync) {
    final File frameworkDir = new File(buildDir, "xcode-frameworks")
    final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
    final def framework = kotlin.targets.ios.binaries.getFramework("shared", mode)
    inputs.property "mode", mode
    dependsOn framework.linkTask
    from { framework.outputFile.parentFile }
    into frameworkDir
    doLast {
        new File(frameworkDir, 'gradlew').with {
            text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
            setExecutable(true)
        }
    }
}
tasks.build.dependsOn packForXCode
Run Code Online (Sandbox Code Playgroud)

编辑 我改变了问题,因为最初,我认为这cinterop不是创建 klib 库,但这只是一个错误:我正在文件ping-build夹中查找,但文件位于该文件夹之外。这样我就解决了一半的问题。

EDIT2 我添加了build.script

Art*_*rev 2

我很高兴看到 KLIB 一切都很好,现在是关于图书馆的使用。
首先,我必须提到这个库只能由 Kotlin/Native 编译器使用,这意味着它将可用于某些目标(请参阅此处的列表)。然后,如果您要将 C 库的使用包含到 MPP 项目中,那么最好通过 Gradle 脚本生成绑定。它可以在目标内部完成,例如请参阅此文档。对于你的 iOS 目标,它应该是这样的:

kotlin {
    iosX64 {  // Replace with a target you need.
        compilations.getByName("main") {
            val ping by cinterops.creating {
                defFile(project.file("ping.def"))
                packageName("c.ping")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码片段会将 cinterop 任务添加到您的 Gradle,并提供模块以包含import c.ping.*在相应的 Kotlin 文件中。