Sam
11/27/2018, 9:01 AMlanguage = Objective-C
headers = Keychain.h KeychainQuery.h KeychainWrapper.h
compilerOpts = -framework keychainwrapper
linkerOpts = -F/path/ -framework keychainwrapper
excludeDependentModules = true
build.gradle cinterop dependency declaration:
dependencies {
cinterop("KeychainWrapper"){
packageName "com.company.keychainWrapper"
includeDirs {
allHeaders "./KeychainWrapper.framework/Headers"
}
linkerOpts "-F${projectDir}"
compilerOpts "-F${projectDir}"
}
}
Problem:
After linking Objective-C framework generated for both architectures (x86_64 and arm64) cinterop is letting us to use only the first linked one, so if the x86_64 is the first listed in the build settings - it will work only for that architecture.
Effect:
I can use the framework on simulator only when using it in my iOS project. The project doesn’t build for the real device
Do you have an idea how this can be fixed? (xcode log in comment)Sam
11/27/2018, 9:02 AMld: warning: ignoring file /Project/ios/keychainwrapper.framework/keychainwrapper, file was built for x86_64 which is not the architecture being linked (arm64): /Project/ios/keychainwrapper.framework/keychainwrapper
ld: warning: ignoring file /Project/sampleapp/app/build/xcode-frameworks/app.framework/app, file was built for x86_64 which is not the architecture being linked (arm64): /Project/sampleapp/app/build/xcode-frameworks/app.framework/app
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_AppMainPresenter", referenced from:
objc-class-ref in ViewController.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
svyatoslav.scherbina
11/27/2018, 9:32 AMfile /Project/ios/keychainwrapper.framework/keychainwrapper
How do you compile Kotlin/Native to x86_64 and arm64?Sam
11/27/2018, 9:41 AMapply plugin: 'org.jetbrains.kotlin.platform.native'
sourceSets.main {
kotlin.srcDirs += 'src/main/kotlin'
}
components.main {
targets = ['ios_arm64', 'ios_x64']
outputKinds = [KLIBRARY]
baseName = "kotlinmultiplatformstorage-ios"
dependencies {
cinterop("KeychainWrapper"){
packageName "com.netguru.keychainWrapper"
includeDirs {
allHeaders "./KeychainWrapper.framework/Headers"
}
linkerOpts "-F${projectDir}"
compilerOpts "-F${projectDir}"
}
}
}
dependencies {
expectedBy project(':common')
}
file command returns the following metadata: ./ios/keychainwrapper.framework/keychainwrapper: Mach-O 64-bit dynamically linked shared library arm64
Sam
11/27/2018, 9:44 AMsvyatoslav.scherbina
11/27/2018, 9:51 AMld: warning: ignoring file /Project/sampleapp/app/build/xcode-frameworks/app.framework/app, file was built for x86_64 which is not the architecture being linked (arm64)may be caused by incorrect configuration too: Xcode refers the framework built for x86_64.
Sam
11/27/2018, 5:20 PMkeychainwrapper.framework
in xcode. Now it targets both architectures and the build is successful. 💪
However, I’m experiencing a further problem.
I Have a sample app project which uses kotlin-multiplatform
plugin where I’m adding the successfully built .klib dependency. The sample app project is generating an iOS .framework
library which I’m linking in xcode to the iOS project.
Here’s how I obtain the iOS target in the gradle build script:
kotlin {
targets {
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") ? presets.iosArm64 : presets.iosX64
println(System.getenv('SDK_NAME'))
fromPreset(presets.android, 'android')
fromPreset(iOSTarget, 'ios') {
compilations.main.outputKinds('FRAMEWORK')
}
}
The xCode is configured to run the packForXCode
task which invokes build
task first when building the iOS app. However, the problem is the SDK_NAME
environment variable doesn’t exist.
Do you have any clue what can be a problem? I have no clue what can I be missing (probably something blocks xcode from setting this variable)Sam
11/27/2018, 5:24 PMSDK_NAME
being null I’m not able to run the sample app on the real device (it works well on emulator)Sam
11/27/2018, 8:09 PMsvyatoslav.scherbina
11/28/2018, 9:15 AMSam
11/28/2018, 1:16 PMSDK_NAME
is set correctly when gradle build command is invoked by xcode. (It was null when build was run on terminal). Another issue was that I needed to force gradle to rebuild the project for the correct target by calling ./gradlew clean
right before packForXCode
(in xcode). Otherwise gradle doesn’t detect any source code change and doesn’t want to regenerate the app.framework
when I’m trying to switch between iphone simulator and iphone device targets.Sam
11/28/2018, 1:18 PM./gradlew clean
forces gradle building for the correct target. However, it slows down the building process significantly. I need to wait 5min each time I’m building the iOS app even if I’m not changing the compilation target.Sam
11/28/2018, 1:19 PM./gradlew clean
each time but only when the SDK_NAME
variable value change is detected but I don’t find it possible.Sam
11/28/2018, 1:20 PMSam
11/28/2018, 1:22 PMsvyatoslav.scherbina
11/28/2018, 1:27 PMOtherwise gradle doesn’t detect any source code change and doesn’t want to regenerate the@ilya.matveev do you have any ideas?when I’m trying to switch between iphone simulator and iphone device targets.app.framework
ilya.matveev
12/03/2018, 9:16 AMSDK_NAME
) may not be passed to a Gradle script executed by the Gradle daemon. This bug is observed on Java 9+ and fixed in Gradle 4.10.
So the solution is to use Gradle 4.10 or later. If for some reason it's impossible (e.g. if you use kotlinx libraries with Gradle metadata enabled), this issue can be fixed by disabling Gradle daemon. Just pass the --no-daemon
flag to Gradle when you run the packForXcode
task:
./gradlew :packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION} -i --no-daemon
As for not rebuilding after changing sources, it looks strange. I didn't manage to reproduce this issue with a playground project based on this tutorial: https://kotlinlang.org/docs/tutorials/native/mpp-ios-android.html. Could you please provide a link to your project?