Adam Vastopa
07/15/2023, 9:58 AMiOSLibs
directory. The klib for the module successfully compiles and I'm able to reference and use the framework in my iOS specific kotlin classes but the build breaks down during the linkDebugTestIos
step in the iosTest
gradle build task. When I try to specify the framework and framework path in the linkerOpts
in my .def
file, I get a linking error saying the StripeTerminal
framework cannot be found (even though I'm certain it's there - tested by using the absolute path locally for the framework paths).
I've tried specifying the implementation fileTree(dir: <dir>, include: <binary>)
in the iosTest { dependencies { ... } }
with no luck. Not sure how I can properly link the framework to the test test.
Am I missing something with regards to linking a native iOS framework for use in a KMM module? Any suggestions/ideas are greatly appreciatedJeff Lockhart
07/15/2023, 4:48 PMKotlinNativeTarget
binary.linkerOpts
, to be able to get the absolute path relative to projectDir
.Adam Vastopa
07/16/2023, 8:08 PMbuild.gradle
looks like the following:
kotlin {
def iosTarget = kotlin.targets.ios
def iosDevice = findProperty("kn.ios.platform") == "iphoneos" ?: false
def target = iosDevice ? "ios-arm64" : "ios-arm64_x86_64-simulator"
iosTarget.compilations.getByName("main").cinterops.create("StripeTerminal")
iosTarget.binaries {
framework("StripeWrapper") {
linkerOpts += ["-F${projectDir}/iOSLibs/StripeTerminal.xcframework/$target/StripeTerminal.framework"]
linkerOpts += ["-framework", "StripeTerminal"]
}
}
sourceSets {
iosTest {
dependencies {}
}
I get the error:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_SCPPaymentMethod", referenced from:
objc-class-ref in result.o
ld: symbol(s) not found for architecture arm64
Execution failed for task ':PointOfSale-StripeWrapper:linkDebugTestIos'.
> Compilation finished with errors
When I add a filepath declaration in the iosTest
dependencies like the following:
kotlin {
def iosTarget = kotlin.targets.ios
def iosDevice = findProperty("kn.ios.platform") == "iphoneos" ?: false
def target = iosDevice ? "ios-arm64" : "ios-arm64_x86_64-simulator"
iosTarget.compilations.getByName("main").cinterops.create("StripeTerminal")
iosTarget.binaries {
framework("StripeWrapper") {
linkerOpts += ["-F${projectDir}/iOSLibs/StripeTerminal.xcframework/$target/StripeTerminal.framework"]
linkerOpts += ["-framework", "StripeTerminal"]
}
}
sourceSets {
iosTest {
dependencies {
implementation files("${projectDir}/iOSLibs/StripeTerminal.xcframework/$target/StripeTerminal.framework")
}
}
I get the error (I verified in my filesystem that the framework is at that exact path):
e: Could not find "/Users/vastopa/src/github.com/Shopify/pos-next-react-native/multiplatform/PointOfSale-StripeWrapper/iOSLibs/StripeTerminal.xcframework/ios-arm64_x86_64-simulator/StripeTerminal.framework" in [/Users/vastopa/src/github.com/Shopify/pos-next-react-native/android, /Users/vastopa/.konan/klib, /Users/vastopa/.konan/kotlin-native-prebuilt-macos-aarch64-1.7.10/klib/common, /Users/vastopa/.konan/kotlin-native-prebuilt-macos-aarch64-1.7.10/klib/platform/ios_simulator_arm64]
Execution failed for task ':PointOfSale-StripeWrapper:compileTestKotlinIos'.
> Compilation finished with errors
Adam Vastopa
07/16/2023, 8:11 PMJeff Lockhart
07/16/2023, 8:57 PM-rpath
linker option for the runtime path for the dynamic framework.Adam Vastopa
07/17/2023, 4:11 AMStripeTerminal.def
as linkerOpts = -rpath @loader_path/Frameworks
, as well as in
framework("StripeWrapper") {
linkerOpts += ["-rpath", "@loader_path/Frameworks"]
linkerOpts += ["-F${projectDir}/iOSLibs/StripeTerminal.xcframework/$target/StripeTerminal.framework"]
linkerOpts += ["-framework", "StripeTerminal"]
}
Still no luck. Do I need to do something like this comment (although having a hardtime to determine how exactly to fill in the blanks there). One other thing I'm noticing is I can't seem to locate the framework output for StripeWrapper
. It should be in build/bin/ios
path but I guess it's not there because the linking step fails?Jeff Lockhart
07/17/2023, 5:07 AM-F
option for -rpath
.Adam Vastopa
07/17/2023, 8:00 AMlinkerOpts
should look as follows?
iosTarget.binaries {
framework("StripeWrapper") {
linkerOpts += ["-rpath", "${projectDir}/iOSLibs/StripeTerminal.xcframework/$target/StripeTerminal.framework"]
linkerOpts += ["-F${projectDir}/iOSLibs/StripeTerminal.xcframework/$target/StripeTerminal.framework"]
linkerOpts += ["-framework", "StripeTerminal"]
}
}
If so, unfortunately, still seeing the error
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_SCPPaymentMethod", referenced from:
objc-class-ref in result.o
ld: symbol(s) not found for architecture arm64
Execution failed for task ':PointOfSale-StripeWrapper:linkDebugTestIos'.
> Compilation finished with errors
PS - the reason it's that particular class in the error is because I've set up a test to reference the StripeTerminal SDK to test the linking. Without the reference to SCPPaymentMethod
, the build/linking passes:
package com.shopify.pos.stripewrapper
import StripeTerminal.SCPPaymentMethod
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertEquals
class StripePaymentModelsTest {
@Test
fun `fake test to testing fixing linking`() = runBlocking {
val paymentMethod = SCPPaymentMethod()
assertEquals(paymentMethod, paymentMethod)
}
}
Jeff Lockhart
07/18/2023, 2:32 PM/StripeTerminal.framework
from the end of both paths.Adam Vastopa
07/20/2023, 11:28 AMStripeWrapper.framework
output in my build products or does the iosTest
task only create a .kexe
(all I'm seeing is the latter)Jeff Lockhart
07/20/2023, 3:55 PMbinaries {
getTest(DEBUG).linkerOpts(...)
}
Adam Vastopa
07/20/2023, 8:34 PMJeff Lockhart
07/20/2023, 8:44 PMAdam Vastopa
07/20/2023, 9:18 PMStripeTerminal.framework
, the getTest
, and the -rpath
all combined which I wasn't getting all right in all my testing. happy to be getting more familiar with the intricacies of gradle!Jeff Lockhart
07/20/2023, 9:58 PM-rpath
linker option in the framework build you're distributing, since that path won't exist for consumers of the framework. But it works well for tests.Adam Vastopa
07/21/2023, 10:05 AMprojectDir
, and yea, I only had to add linkerOpts to the test target. thanks for the tip!