Доступ к C / C ++ lib из мультиплатформенного kotlin проекта - PullRequest
1 голос
/ 15 марта 2020

Впервые я использую Android Studio для создания мультиплатформенного проекта. Я создал Android модуль приложения, который использует многоплатформенную библиотеку на Android. Я также использовал XCode для создания приложения iOS, которое использует многоплатформенную библиотеку на iOS. Все отлично работает, и я могу использовать expect fun, который реализован различными actual fun для Android и iOS.

Я также создал библиотеку на C ++, которая предоставляет C interface.

#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

Я использую 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

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

Как я могу использовать библиотеку, созданную cinterop в моем kotlin -мультиплатформенном проекте?

Я нашел разные способы его импорта, но я не нашел полного описания того, как это сделать. Здесь говорят, что я могу использовать что-то вроде:

    implementation files("ping.klib")

Я сделал это для проекта iOS, но я до сих пор не знаю, как получить доступ к классам kotlin. на Android ни на iOS.

Это мой 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

РЕДАКТИРОВАТЬ Я изменил вопрос, потому что изначально я думал, что cinterop не создавал библиотеку klib, но это была просто ошибка: я искал в папке ping-build, но файл находится вне этой папки. Таким образом, я решил половину вопроса.

EDIT2 Я добавил build.script

1 Ответ

1 голос
/ 23 марта 2020

Я рад видеть, что с KLIB все в порядке, теперь об использовании библиотеки.
Прежде всего, я должен отметить, что эта библиотека может использоваться только компилятором Kotlin / Native, то есть она будет доступна для некоторых целей (см. Список здесь ). Затем, если вы собираетесь включить использование библиотеки C в проект MPP, всегда лучше создавать привязки через скрипт Gradle. Это можно сделать внутри цели, см., Например, this do c. Для вашей цели 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")
            }
        }
    }
}

Этот фрагмент кода добавит задачу cinterop в ваш Gradle и предоставит модуль для включения как import c.ping.* в соответствующие файлы Kotlin.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...