Kotlin-native C-interop 与 leptonica 问题
Kotlin-native C-interop with leptonica issue
我正在尝试使用来自 Kotlin-native 的 leptonica
库。
我已经成功创建了 klib 并且基本代码正在运行。
我的问题是:
- 我用
pixRead()
加载图像 --> OK,
- 使用图片 --> OK,
- 我无法对该图像调用
pixDestroy()
--> 失败。
如果没有 pixDestroy()
调用,程序将按预期工作,只是它会泄漏内存。
基本上我想这样获取指针的地址(source):
pixt1 = pixRead("/tmp/lept/dewmod/0020.png");
pixWrite("/tmp/lept/dewtest/006.png", pixt1, IFF_PNG);
pixDestroy(&pixt1);
我的代码如下:
import leptonica.*
import kotlinx.cinterop.*
fun doSomethingWithPix(pix: PIX) {
// bla
println(pix.xres)
}
fun usePix(filename: String) {
val pix = pixRead(filename) ?: throw NullPointerException("Pix is null")
doSomethingWithPix(pix.pointed)
pixDestroy(pix ???) // Expect a CValuesRef<CPointerVar<PIX>> how to create/cast that ?
}
fun main() {
usePix("test.png") }
}
这里记录的是我的 leptonica.def 文件。
headers = leptonica/allheaders.h
headerFilter = leptonica/allheaders.h
package = leptonica
compilerOpts.osx = -I/usr/local/opt/include
linkerOpts.osx = -L/usr/local/opt/lib -llept
build.gradle
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.41'
}
repositories {
mavenCentral()
}
kotlin {
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
macosX64("macos") {
compilations.main.cinterops {
png
tesseract
leptonica
}
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'sample.main'
// Specify command-line arguments, if necessary:
runTask?.args('')
}
}
}
// iosArm64("ios64") {
// compilations.main.cinterops {
// png
// }
//
// binaries {
// executable {
// // Change to specify fully qualified name of your application's entry point:
// entryPoint = 'sample.main'
// // Specify command-line arguments, if necessary:
// runTask?.args('')
// }
// }
// }
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
macosMain {
}
macosTest {
}
}
}
// Use the following Gradle tasks to run your application:
// :runReleaseExecutableMacos - without debug symbols
// :runDebugExecutableMacos - with debug symbols
编辑:参见@ArtyomDegtyarev 的回答。
如果有人遇到同样的问题,请回答我自己的问题。
诀窍是创建一个所需大小的指针数组(此处为 1)并将返回的指针分配给数组的正确元素(此处为
0).
然后在数组上调用 toCValues()
以获得 &pointer C 等价物。
fun usePix(filename: String) {
memScoped {
val ppix = arrayOfNulls<CPointer<PIX>?>(1)
val pix = pixRead(filename) ?: throw NullPointerException("Pix is null")
ppix[0] = pix
doSomethingWithPix(pix.pointed)
pixDestroy(ppix.toCValues())
}
}
我不确定 memScoped
块在这里是否有用,它写在我发现的 source 中。
编辑:我希望有更自然的方法来做到这一点。 Kotlin-Native 应该有办法获取任何变量的地址吗?我认同。它是语言的限制,还是一项正在进行的工作?如果有人知道答案,我会很高兴听到。
您可以像这样转换您的变量:
fun usePix(filename: String) {
val pix = pixRead(filename) ?: throw NullPointerException("Pix is null")
doSomethingWithPix(pix.pointed)
pixDestroy(cValuesOf(pix))
}
我在文档中找到了这个解决方案,可以找到here
我正在尝试使用来自 Kotlin-native 的 leptonica
库。
我已经成功创建了 klib 并且基本代码正在运行。
我的问题是:
- 我用
pixRead()
加载图像 --> OK, - 使用图片 --> OK,
- 我无法对该图像调用
pixDestroy()
--> 失败。
如果没有 pixDestroy()
调用,程序将按预期工作,只是它会泄漏内存。
基本上我想这样获取指针的地址(source):
pixt1 = pixRead("/tmp/lept/dewmod/0020.png");
pixWrite("/tmp/lept/dewtest/006.png", pixt1, IFF_PNG);
pixDestroy(&pixt1);
我的代码如下:
import leptonica.*
import kotlinx.cinterop.*
fun doSomethingWithPix(pix: PIX) {
// bla
println(pix.xres)
}
fun usePix(filename: String) {
val pix = pixRead(filename) ?: throw NullPointerException("Pix is null")
doSomethingWithPix(pix.pointed)
pixDestroy(pix ???) // Expect a CValuesRef<CPointerVar<PIX>> how to create/cast that ?
}
fun main() {
usePix("test.png") }
}
这里记录的是我的 leptonica.def 文件。
headers = leptonica/allheaders.h
headerFilter = leptonica/allheaders.h
package = leptonica
compilerOpts.osx = -I/usr/local/opt/include
linkerOpts.osx = -L/usr/local/opt/lib -llept
build.gradle
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.41'
}
repositories {
mavenCentral()
}
kotlin {
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
macosX64("macos") {
compilations.main.cinterops {
png
tesseract
leptonica
}
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'sample.main'
// Specify command-line arguments, if necessary:
runTask?.args('')
}
}
}
// iosArm64("ios64") {
// compilations.main.cinterops {
// png
// }
//
// binaries {
// executable {
// // Change to specify fully qualified name of your application's entry point:
// entryPoint = 'sample.main'
// // Specify command-line arguments, if necessary:
// runTask?.args('')
// }
// }
// }
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
macosMain {
}
macosTest {
}
}
}
// Use the following Gradle tasks to run your application:
// :runReleaseExecutableMacos - without debug symbols
// :runDebugExecutableMacos - with debug symbols
编辑:参见@ArtyomDegtyarev 的回答。
如果有人遇到同样的问题,请回答我自己的问题。
诀窍是创建一个所需大小的指针数组(此处为 1)并将返回的指针分配给数组的正确元素(此处为 0).
然后在数组上调用 toCValues()
以获得 &pointer C 等价物。
fun usePix(filename: String) {
memScoped {
val ppix = arrayOfNulls<CPointer<PIX>?>(1)
val pix = pixRead(filename) ?: throw NullPointerException("Pix is null")
ppix[0] = pix
doSomethingWithPix(pix.pointed)
pixDestroy(ppix.toCValues())
}
}
我不确定 memScoped
块在这里是否有用,它写在我发现的 source 中。
编辑:我希望有更自然的方法来做到这一点。 Kotlin-Native 应该有办法获取任何变量的地址吗?我认同。它是语言的限制,还是一项正在进行的工作?如果有人知道答案,我会很高兴听到。
您可以像这样转换您的变量:
fun usePix(filename: String) {
val pix = pixRead(filename) ?: throw NullPointerException("Pix is null")
doSomethingWithPix(pix.pointed)
pixDestroy(cValuesOf(pix))
}
我在文档中找到了这个解决方案,可以找到here