Hello, I am trying to write test for an iOS targe...
# ios
t
Hello, I am trying to write test for an iOS target, but I am getting errors that I don't have when I compile my app. I use Kotlin 2.0.21 with XCode 16.1 on MacOS 15.1.1 And I am getting this error only when trying to run a test (being a simple hello world test)
Copy code
ld: warning: Could not find or use auto-linked library 'swiftCompatibility56': library 'swiftCompatibility56' not found
ld: warning: Could not find or use auto-linked library 'swiftCompatibilityConcurrency': library 'swiftCompatibilityConcurrency' not found
ld: warning: Could not find or use auto-linked library 'swiftCompatibilityPacks': library 'swiftCompatibilityPacks' not found
ld: warning: Could not find or use auto-linked framework 'CoreAudioTypes': framework 'CoreAudioTypes' not found
ld: warning: Could not find or use auto-linked framework 'UnitySwiftProtobuf': framework 'UnitySwiftProtobuf' not found
Undefined symbols for architecture arm64:
  "__swift_FORCE_LOAD_$_swiftCompatibility56", referenced from:
      __swift_FORCE_LOAD_$_swiftCompatibility56_$_UnityAds in UnityAds[arm64][2](UnityAds-arm64-master.o)
      __swift_FORCE_LOAD_$_swiftCompatibility56_$_UnitySwiftProtobuf in UnityAds[arm64][44](AnyMessageStorage.o)
  "__swift_FORCE_LOAD_$_swiftCompatibilityConcurrency", referenced from:
      __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_UnityAds in UnityAds[arm64][2](UnityAds-arm64-master.o)
      __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_UnitySwiftProtobuf in UnityAds[arm64][44](AnyMessageStorage.o)
ld: symbol(s) not found for architecture arm64
I use cocoapods with
Copy code
pod("UnityAds") {
            version = "~> 4.12.5"
            extraOpts += listOf("-compiler-option", "-fmodules") // because of clang
        }

        podfile = project.file("../iosTestApp/Podfile")

        framework {
            baseName = "SimpleGame"
            isStatic = true
        }
Do you think it could come from my configuration, or is it their framework that might have an issue?
f
Hi, can you the give the full cocoapods block of your gradle? Some tips : • Add the target version of in your pods config • try this pod in a clean xcode project, see if you can reproduce the issue
t
Hi. Most likely you have encountered KT-69793 and it is also suspicious that the linker reports:
Could not find or use auto-linked framework 'CoreAudioTypes'
Please make sure that you have the iOS simulator installed and do a clean build. As a workaround for missing Swift compatibility libraries during test linkage could you please try the following workaround:
Copy code
kotlin {
    abstract class IphoneSimulatorCompatibilityLinkagePath @Inject constructor(): ValueSource<List<String>, ValueSourceParameters.None> {
        @get:Inject
        abstract val execOperations: ExecOperations

        override fun obtain(): List<String> {
            val buffer = ByteArrayOutputStream()
            execOperations.exec {
                commandLine("xcode-select", "-p")
                standardOutput = buffer
            }.assertNormalExitValue()
            val iphoneSimulatorCompatibilityLibrariesPath = File(buffer.toString("UTF-8").dropLast(1))
                .resolve("Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator")
            return listOf(
                "-linker-option",
                "-L${iphoneSimulatorCompatibilityLibrariesPath.path}",
            )
        }
    }

    targets.withType<KotlinNativeTargetWithSimulatorTests> {
        testRuns.all {
            executionSource.binary.linkTaskProvider.configure {
                toolOptions.freeCompilerArgs.addAll(
                    providers.of(IphoneSimulatorCompatibilityLinkagePath::class.java) {}
                )
            }
        }
    }
}
In any case, could you please create an issue and attach a reproduction project?
t
Thanks! Sorry for the delay. I also got the same error without using Cocoapods
Copy code
val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())
    iosTargets.forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "Shared"
            isStatic = true
            binaryOption("bundleId", "com.tristan.game.shared")
        }

        val baseCinteropPath = "$projectDir/../vendor/UnityAds/UnityAds.xcframework"
        val unityAdsPath = when (iosTarget.name) {
            "iosSimulatorArm64", "iosX64" -> "${baseCinteropPath}/ios-arm64_x86_64-simulator/"
            else -> "${baseCinteropPath}/ios-arm64/"
        }
        iosTarget.compilations.getByName("main") {
            val UnityAds by cinterops.creating {
                definitionFile.set(
                    project.file("$projectDir/../vendor/UnityAds/UnityAds.def"),
                )
                compilerOpts(
                    "-fmodules",
                    "-F$unityAdsPath",
                    "-rpath", unityAdsPath,
                    "-framework", "UnityAds",
                )
            }
        }
        iosTarget.binaries.all {
            linkerOpts(
                "-F$unityAdsPath",
                "-rpath", unityAdsPath,
                "-framework", "UnityAds",
            )
        }
    }
Although it seems that your workaround worked 😮 I'll cleanup the sample and open a ticket as soon as possible.
t
I also got the same error without using Cocoapods
I am almost sure what is happening is that
UnityAds.xcframework
vendors a static library with some object files that were compiled from Swift code with a deployment target that requires the use of compatibility libraries. When the Kotlin framework builds against
UnityAds
with
isStatic = true
there is no linkage step in Gradle and the actual linkage happens in the iOS app that consumes both UnityAds and the Kotlin framework. This
-L
search path to compatibility libraries is going to be inserted by Xcode's build system, so the app linkage succeeds. However, when you run K/N tests from Gradle, we link a standalone executable, so we have to receive the compatibility libraries search path somehow. In CocoaPods integration we could likely infer this from build settings generated by CocoaPods, but with pure cinterops you will have to specify it manually. Another option for you could be to prelink
UnityAds
into a dynamic library and link the tests executable against the
UnityAds
dynamic library with an appropriate
rpath
. I see that in the second build script sample you specify `-rpath`; iiuc your build configuration, this is unlikely to be of use, because UnityAds is not a dynamic library.
thank you color 1
115 Views