Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f4187ef
update arch folders and test
buenaflor Jan 30, 2025
6d6f6b2
update test
buenaflor Jan 30, 2025
03b12e8
update comment
buenaflor Jan 30, 2025
a8dd89f
refactor linking to own file
buenaflor Jan 31, 2025
b2ba00f
update
buenaflor Jan 31, 2025
6d90d3f
update
buenaflor Jan 31, 2025
4afae70
update comment
buenaflor Jan 31, 2025
e0f2e1b
update comment
buenaflor Jan 31, 2025
9c82a2a
update message
buenaflor Jan 31, 2025
a63d95e
draft commit
buenaflor Feb 4, 2025
40dbe8a
better logging
buenaflor Feb 4, 2025
2f5ea50
add docs per strategy
buenaflor Feb 4, 2025
38db872
docs
buenaflor Feb 4, 2025
3be1bcc
add FrameworkPathResolver test
buenaflor Feb 5, 2025
c58f714
update tests
buenaflor Feb 5, 2025
a74e90a
update tests
buenaflor Feb 5, 2025
ca5cacc
update tests
buenaflor Feb 5, 2025
c9bdd38
formatting
buenaflor Feb 5, 2025
ae0e0ac
update tests
buenaflor Feb 5, 2025
e551c09
fix test
buenaflor Feb 5, 2025
7beec81
add comment to test
buenaflor Feb 5, 2025
909fa95
dont throw if mac is not host
buenaflor Feb 5, 2025
0cf0e41
fix test
buenaflor Feb 5, 2025
90dd2c0
improve coverage
buenaflor Feb 6, 2025
af76fcb
detekt
buenaflor Feb 6, 2025
e7f3958
fix test
buenaflor Feb 6, 2025
4e73235
update
buenaflor Feb 6, 2025
e1f05cc
Update CHANGELOG
buenaflor Feb 6, 2025
abe48d9
update test
buenaflor Feb 6, 2025
524aef2
fix expected architectures
buenaflor Feb 6, 2025
3b4d218
add todo
buenaflor Feb 6, 2025
85a8b56
review feedback
buenaflor Feb 10, 2025
15f1eb7
update formatting
buenaflor Feb 10, 2025
c0fbf16
formatting
buenaflor Feb 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Fixes

- [Gradle Plugin]: Architecture folder name missmatch when using SPM and framework path searching ([#320](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/320))

### Dependencies

- Bump Java SDK from v7.16.0 to v7.18.1 ([#295](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/295), [#299](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/299))
Expand Down
2 changes: 2 additions & 0 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ style:
UnusedPrivateMember:
excludes:
- "**/Attachment.kt"
ReturnCount:
active: false
naming:
MatchingDeclarationName:
active: false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package io.sentry.kotlin.multiplatform.gradle

import org.gradle.api.GradleException
import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget

/**
* Configures Sentry Cocoa framework linking for Apple targets in Kotlin Multiplatform projects.
*
* Resolves framework paths and applies necessary linker options to both test and framework binaries.
*/
class CocoaFrameworkLinker(
private val logger: Logger,
private val pathResolver: FrameworkPathResolver,
private val binaryLinker: FrameworkLinker
) {
fun configure(appleTargets: List<KotlinNativeTarget>) {
appleTargets.forEach { target ->
try {
logger.info(
"Start resolving Sentry Cocoa framework paths for target: ${target.name}"
)
processTarget(target)
logger.lifecycle("Successfully configured Sentry Cocoa framework linking for target: ${target.name}")
} catch (e: FrameworkLinkingException) {
throw FrameworkLinkingException("Failed to configure ${target.name}: ${e.message}", e)

Check warning on line 27 in sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/CocoaFrameworkLinker.kt

View check run for this annotation

Codecov / codecov/patch

sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/CocoaFrameworkLinker.kt#L26-L27

Added lines #L26 - L27 were not covered by tests
}
}
}

private fun processTarget(target: KotlinNativeTarget) {
val architectures =
target.toSentryFrameworkArchitecture().takeIf { it.isNotEmpty() } ?: run {
logger.warn("Skipping target ${target.name}: Unsupported architecture")

Check warning on line 35 in sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/CocoaFrameworkLinker.kt

View check run for this annotation

Codecov / codecov/patch

sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/CocoaFrameworkLinker.kt#L35

Added line #L35 was not covered by tests
return
}
val paths: FrameworkPaths = pathResolver.resolvePaths(architectures)
binaryLinker.configureBinaries(target.binaries, paths.dynamic, paths.static)
}
}

internal class FrameworkLinkingException(
message: String,
cause: Throwable? = null
) : GradleException(message, cause)

/**
* Transforms a Kotlin Multiplatform target name to possible architecture names found inside
* Sentry's framework directory.
*
* Returns a set of possible architecture names because Sentry Cocoa SDK has changed folder naming
* across different versions. For example:
* - iosArm64 -> [SentryCocoaFrameworkArchitectures.IOS_ARM64]
* - macosArm64 -> [SentryCocoaFrameworkArchitectures.MACOS_ARM64_AND_X64]
* @return Set of possible architecture folder names for the given target.
* Returns empty set if target is not supported.
*/
internal fun KotlinNativeTarget.toSentryFrameworkArchitecture(): Set<String> = buildSet {
when (name) {
"iosSimulatorArm64", "iosX64" -> addAll(SentryCocoaFrameworkArchitectures.IOS_SIMULATOR_AND_X64)
"iosArm64" -> addAll(SentryCocoaFrameworkArchitectures.IOS_ARM64)
"macosArm64", "macosX64" -> addAll(SentryCocoaFrameworkArchitectures.MACOS_ARM64_AND_X64)
"tvosSimulatorArm64", "tvosX64" -> addAll(SentryCocoaFrameworkArchitectures.TVOS_SIMULATOR_AND_X64)
"tvosArm64" -> addAll(SentryCocoaFrameworkArchitectures.TVOS_ARM64)
"watchosArm32", "watchosArm64" -> addAll(SentryCocoaFrameworkArchitectures.WATCHOS_ARM)
"watchosSimulatorArm64", "watchosX64" -> addAll(SentryCocoaFrameworkArchitectures.WATCHOS_SIMULATOR_AND_X64)
}
}

internal object SentryCocoaFrameworkArchitectures {
val IOS_SIMULATOR_AND_X64 = setOf("ios-arm64_x86_64-simulator")
val IOS_ARM64 = setOf("ios-arm64", "ios-arm64_arm64e")
val MACOS_ARM64_AND_X64 = setOf("macos-arm64_x86_64", "macos-arm64_arm64e_x86_64")
val TVOS_SIMULATOR_AND_X64 = setOf("tvos-arm64_x86_64-simulator")
val TVOS_ARM64 = setOf("tvos-arm64", "tvos-arm64_arm64e")
val WATCHOS_ARM = setOf("watchos-arm64_arm64_32_armv7k", "watchos-arm64_arm64_32_arm64e_armv7k")
val WATCHOS_SIMULATOR_AND_X64 = setOf("watchos-arm64_i386_x86_64-simulator")

// Used for tests
val all = setOf(
IOS_SIMULATOR_AND_X64,
IOS_ARM64,
MACOS_ARM64_AND_X64,
TVOS_SIMULATOR_AND_X64,
TVOS_ARM64,
WATCHOS_ARM,
WATCHOS_SIMULATOR_AND_X64
)
}

internal fun KotlinMultiplatformExtension.appleTargets() =
targets.withType(KotlinNativeTarget::class.java).matching {
it.konanTarget.family.isAppleFamily
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.sentry.kotlin.multiplatform.gradle

import org.gradle.api.GradleException
import org.gradle.api.provider.Property
import org.gradle.api.provider.ValueSource
import org.gradle.api.provider.ValueSourceParameters
Expand All @@ -9,8 +8,13 @@ import org.gradle.process.ExecOperations
import java.io.ByteArrayOutputStream
import javax.inject.Inject

internal abstract class DerivedDataPathValueSource :
ValueSource<String, DerivedDataPathValueSource.Parameters> {
/**
* Provides the derived data path for an Xcode project using the xcodebuild command.
*
* e.g /Users/theusername/Library/Developer/Xcode/DerivedData/iosApp-ddefikekigqzzgcnpfkkdallksmlfpln/
*/
abstract class DerivedDataPathValueSource :
ValueSource<String?, DerivedDataPathValueSource.Parameters> {
interface Parameters : ValueSourceParameters {
@get:Input
val xcodeprojPath: Property<String>
Expand All @@ -23,7 +27,7 @@ internal abstract class DerivedDataPathValueSource :
private val buildDirRegex = Regex("BUILD_DIR = (.+)")
}

override fun obtain(): String {
override fun obtain(): String? {
val buildDirOutput = ByteArrayOutputStream()
execOperations.exec {
it.commandLine = listOf(
Expand All @@ -37,7 +41,9 @@ internal abstract class DerivedDataPathValueSource :
val buildSettings = buildDirOutput.toString("UTF-8")
val buildDirMatch = buildDirRegex.find(buildSettings)
val buildDir = buildDirMatch?.groupValues?.get(1)
?: throw GradleException("BUILD_DIR not found in xcodebuild output")
if (buildDir == null || buildDir.contains("DerivedData").not()) {
return null
}
return buildDir.replace("/Build/Products", "")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.sentry.kotlin.multiplatform.gradle

import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable

/**
* Responsible for executing the linking.
* This involves configuring and linking binaries to the Sentry Cocoa framework.
*/
class FrameworkLinker(
private val logger: Logger
) {
fun configureBinaries(
binaries: KotlinNativeBinaryContainer,
dynamicPath: String?,
staticPath: String?
) {
binaries.all { binary ->
when (binary) {
is TestExecutable -> linkTestBinary(binary, chooseTestPath(dynamicPath, staticPath))
is Framework -> linkFrameworkBinary(binary, dynamicPath, staticPath)
else -> logger.info("Ignoring binary type: ${binary::class.java.simpleName}")

Check warning on line 24 in sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/FrameworkLinker.kt

View check run for this annotation

Codecov / codecov/patch

sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/FrameworkLinker.kt#L24

Added line #L24 was not covered by tests
}
}
}

private fun chooseTestPath(dynamic: String?, static: String?) = when {
dynamic != null -> dynamic
static != null -> static
else -> throw FrameworkLinkingException("No valid framework path found for tests")

Check warning on line 32 in sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/FrameworkLinker.kt

View check run for this annotation

Codecov / codecov/patch

sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/FrameworkLinker.kt#L32

Added line #L32 was not covered by tests
}

private fun linkTestBinary(binary: TestExecutable, path: String) {
// Linking in test binaries works with both dynamic and static framework
binary.linkerOpts("-rpath", path, "-F$path")
logger.info("Linked Sentry Cocoa framework to test binary ${binary.name}")
}

private fun linkFrameworkBinary(binary: Framework, dynamicPath: String?, staticPath: String?) {
val (path, type) = when {
binary.isStatic && staticPath != null -> staticPath to "static"
!binary.isStatic && dynamicPath != null -> dynamicPath to "dynamic"
else -> throw FrameworkLinkingException(
"Framework mismatch for ${binary.name}. " +

Check warning on line 46 in sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/FrameworkLinker.kt

View check run for this annotation

Codecov / codecov/patch

sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/FrameworkLinker.kt#L45-L46

Added lines #L45 - L46 were not covered by tests
"Required ${if (binary.isStatic) "static" else "dynamic"} Sentry Cocoa framework not found."
)
}

binary.linkerOpts("-F$path")
logger.info("Linked $type Sentry Cocoa framework to ${binary.name}")
}
}
Loading
Loading