Skip to content

Commit e498c10

Browse files
committed
Add support for relative file paths in debug symbols.
1 parent d893073 commit e498c10

File tree

13 files changed

+207
-10
lines changed

13 files changed

+207
-10
lines changed

SKIE/common/configuration/declaration/src/commonMain/kotlin/co/touchlab/skie/configuration/SkieConfigurationFlag.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ enum class SkieConfigurationFlag {
1616
Build_ParallelSkieCompilation,
1717
Build_ConcurrentSkieCompilation,
1818
Build_NoClangModuleBreadcrumbsInStaticFramework,
19+
Build_RelativeSourcePathsInDebugSymbols,
1920

2021
Migration_WildcardExport,
2122
Migration_AnyMethodsAsFunctions,

SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/swift/CompileSwiftPhase.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import co.touchlab.skie.sir.element.SirCompilableFile
88
import co.touchlab.skie.util.Command
99
import kotlin.io.path.absolutePathString
1010
import kotlin.io.path.nameWithoutExtension
11+
import kotlin.io.path.pathString
1112

1213
class CompileSwiftPhase(
1314
context: SirPhase.Context,
@@ -31,6 +32,7 @@ class CompileSwiftPhase(
3132
private val isConcurrentSkieCompilationEnabled = SkieConfigurationFlag.Build_ConcurrentSkieCompilation in globalConfiguration.enabledFlags
3233
private val noClangModuleBreadcrumbsInStaticFramework =
3334
SkieConfigurationFlag.Build_NoClangModuleBreadcrumbsInStaticFramework in globalConfiguration.enabledFlags
35+
private val isRelativeSourcePathsInDebugSymbolsEnabled = SkieConfigurationFlag.Build_RelativeSourcePathsInDebugSymbols in globalConfiguration.enabledFlags
3436

3537
context(SirPhase.Context)
3638
override suspend fun execute() {
@@ -48,7 +50,7 @@ class CompileSwiftPhase(
4850
}
4951

5052
private fun createSwiftFileList(compilableFiles: List<SirCompilableFile>) {
51-
val content = compilableFiles.joinToString("\n") { "'${it.absolutePath.absolutePathString()}'" }
53+
val content = compilableFiles.joinToString("\n") { "'${it.relativePath.pathString}'" }
5254

5355
swiftFileList.writeText(content)
5456
}
@@ -71,10 +73,10 @@ class CompileSwiftPhase(
7173
""".trimIndent()
7274

7375
val body = compilableFiles.joinToString(",\n") { compilableFile ->
74-
val sourceFileName = compilableFile.absolutePath.nameWithoutExtension
76+
val sourceFileName = compilableFile.relativePath.nameWithoutExtension
7577

7678
"""
77-
"${compilableFile.absolutePath}": {
79+
"${compilableFile.relativePath.pathString}": {
7880
"object": "${objectFileProvider.getOrCreate(compilableFile).absolutePath.absolutePathString()}",
7981
"dependencies": "${objectFiles.dependencies(sourceFileName).absolutePath}",
8082
"swift-dependencies": "${objectFiles.swiftDependencies(sourceFileName).absolutePath}",
@@ -142,21 +144,27 @@ class CompileSwiftPhase(
142144
}
143145
}
144146
+"-output-file-map"
145-
+outputFileMap.absolutePath
147+
+outputFileMap
146148
+"-g"
147149
+"-module-cache-path"
148-
+skieBuildDirectory.cache.swiftModules.directory.absolutePath
150+
+skieBuildDirectory.cache.swiftModules.directory
149151
+"-swift-version"
150152
+swiftCompilerConfiguration.swiftVersion
151153
+parallelizationArgument
152154
+"-sdk"
153155
+swiftCompilerConfiguration.absoluteTargetSysRootPath
154156
+"-target"
155157
+swiftCompilerConfiguration.targetTriple.withOsVersion(swiftCompilerConfiguration.osVersionMin).toString()
158+
159+
if (isRelativeSourcePathsInDebugSymbolsEnabled) {
160+
+"-file-compilation-dir"
161+
+"."
162+
}
163+
156164
+swiftCompilerConfiguration.freeCompilerArgs
157165
+"@${swiftFileList.absolutePath}"
158166

159-
workingDirectory = objectFiles.directory
167+
workingDirectory = skieBuildDirectory.swift.directory
160168

161169
execute(logFile = skieBuildDirectory.debug.logs.swiftc)
162170
}

SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/SirFileProvider.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,14 @@ class SirFileProvider(
5656

5757
absolutePath.writeTextIfDifferent(sourceFile.content)
5858

59-
return SirCompilableFile(sourceFile.module, absolutePath, sourceFile)
59+
val relativePath = skieBuildDirectory.swift.path.relativize(absolutePath)
60+
61+
return SirCompilableFile(
62+
module = sourceFile.module,
63+
absolutePath = absolutePath,
64+
relativePath = relativePath,
65+
originFile = sourceFile,
66+
)
6067
}
6168

6269
fun loadCompilableFile(path: Path): SirCompilableFile {
@@ -74,7 +81,14 @@ class SirFileProvider(
7481
"Custom source file must have the swift extension. Was: $absolutePath."
7582
}
7683

77-
return SirCompilableFile(skieModule, absolutePath, null)
84+
val relativePath = skieBuildDirectory.swift.path.relativize(absolutePath)
85+
86+
return SirCompilableFile(
87+
module = skieModule,
88+
absolutePath = absolutePath,
89+
relativePath = relativePath,
90+
originFile = null
91+
)
7892
}
7993

8094
private val Path.asCacheKey: String

SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/compilation/ObjectFileProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class ObjectFileProvider(
1919

2020
fun getOrCreate(compilableFile: SirCompilableFile): ObjectFile =
2121
compilableFilesCache.getOrPut(compilableFile) {
22-
val objectFilePath = skieBuildDirectory.swiftCompiler.objectFiles.objectFile(compilableFile.absolutePath.nameWithoutExtension).toPath()
22+
val objectFilePath = skieBuildDirectory.swiftCompiler.objectFiles.objectFile(compilableFile.relativePath.nameWithoutExtension).toPath()
2323

2424
ObjectFile(objectFilePath)
2525
}

SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirCompilableFile.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import java.nio.file.Path
66
class SirCompilableFile(
77
override val module: SirModule.Skie,
88
val absolutePath: Path,
9+
// Relative to the SKIE Swift build directory
10+
val relativePath: Path,
911
val originFile: SirSourceFile?,
1012
) : SirFile {
1113

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
@file:Suppress("invisible_reference", "invisible_member")
2+
3+
package co.touchlab.skie.entrypoint
4+
5+
import co.touchlab.skie.compilerinject.compilerplugin.mainSkieContext
6+
import co.touchlab.skie.compilerinject.interceptor.PhaseInterceptor
7+
import co.touchlab.skie.configuration.SkieConfigurationFlag
8+
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
9+
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
10+
import org.jetbrains.kotlin.backend.konan.driver.phases.CodegenInput
11+
import org.jetbrains.kotlin.backend.konan.driver.phases.CodegenPhase
12+
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
13+
14+
internal class CodegenPhaseInterceptor : PhaseInterceptor<NativeGenerationState, CodegenInput, Unit> {
15+
override fun getInterceptedPhase(): Any = CodegenPhase
16+
17+
override fun intercept(context: NativeGenerationState, input: CodegenInput, next: (NativeGenerationState, CodegenInput) -> Unit) {
18+
val mainSkieContext = context.config.configuration.mainSkieContext
19+
with(mainSkieContext) {
20+
if (SkieConfigurationFlag.Build_RelativeSourcePathsInDebugSymbols.isEnabled) {
21+
workaroundRelativeDebugPrefixMapBug(context)
22+
}
23+
}
24+
25+
next(context, input)
26+
}
27+
28+
private fun workaroundRelativeDebugPrefixMapBug(context: NativeGenerationState) {
29+
if (context.hasDebugInfo()) {
30+
context.context.messageCollector.report(
31+
severity = CompilerMessageSeverity.ERROR,
32+
message = "NativeGenerationState.debugInfo was initialized before debug-prefix-map workaround was applied! " +
33+
"Please disable the debug-prefix-map SKIE feature and report this issue to the SKIE GitHub at https://github.com/touchlab/SKIE",
34+
)
35+
} else {
36+
/*
37+
* This piece of code removes
38+
*/
39+
val existingMap = context.config.configuration.getMap(KonanConfigKeys.DEBUG_PREFIX_MAP)
40+
context.config.configuration.put(KonanConfigKeys.DEBUG_PREFIX_MAP, emptyMap())
41+
42+
// Touch the `debugInfo` to create it while the `DEBUG_PREFIX_MAP` is empty.
43+
@Suppress("UNUSED_VARIABLE")
44+
val debugInfo = context.debugInfo
45+
46+
// Set the `DEBUG_PREFIX_MAP` back to original value so the .kt source files can get remapped correctly.
47+
context.config.configuration.put(KonanConfigKeys.DEBUG_PREFIX_MAP, existingMap)
48+
}
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
co.touchlab.skie.entrypoint.CreateObjCExportCodeSpecPhaseInterceptor
22
co.touchlab.skie.entrypoint.LinkerPhaseInterceptor
33
co.touchlab.skie.entrypoint.ProduceObjCExportInterfacePhaseInterceptor
4+
co.touchlab.skie.entrypoint.CodegenPhaseInterceptor

SKIE/skie-gradle/plugin-api/src/main/kotlin/co/touchlab/skie/plugin/configuration/SkieBuildConfiguration.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ abstract class SkieBuildConfiguration @Inject constructor(objects: ObjectFactory
4242
val enableConcurrentSkieCompilation: Property<Boolean> = objects.property(Boolean::class.java).convention(true)
4343
val enableParallelSkieCompilation: Property<Boolean> = objects.property(Boolean::class.java).convention(true)
4444

45+
/**
46+
* SKIE can configure the Kotlin/Native compiler to make source file paths in the final binary relative.
47+
* When enabled,
48+
* SKIE will configure `-Xdebug-prefix-map` to replace the value of `rootProject.projectDir.absolutePath` with `.`,
49+
* and then workaround a bug in Kotlin/Native compiler that'd otherwise result in the binary missing links to these source files.
50+
*
51+
* Doing this enables debugging of Kotlin sources built on a different machine,
52+
* which compiles the Kotlin code from a different path.
53+
* With `xcode-kotlin` (https://github.com/touchlab/xcode-kotlin) you can debug Kotlin code
54+
* that's been compiled into a binary .framework on your CI and then distributed through SwiftPM or CocoaPods.
55+
*/
56+
val enableRelativeSourcePathsInDebugSymbols: Property<Boolean> = objects.property(Boolean::class.java).convention(false)
57+
4558
/**
4659
* Additional Swift compiler arguments that will be passed to the Swift compiler.
4760
*/
@@ -58,6 +71,7 @@ abstract class SkieBuildConfiguration @Inject constructor(objects: ObjectFactory
5871
fun produceDistributableFramework() {
5972
enableSwiftLibraryEvolution.set(true)
6073
noClangModuleBreadcrumbsInStaticFrameworks.set(true)
74+
enableRelativeSourcePathsInDebugSymbols.set(true)
6175
}
6276

6377
internal fun buildConfigurationFlags(): Set<SkieConfigurationFlag> =
@@ -67,6 +81,7 @@ abstract class SkieBuildConfiguration @Inject constructor(objects: ObjectFactory
6781
SkieConfigurationFlag.Build_ParallelSwiftCompilation takeIf enableParallelSwiftCompilation,
6882
SkieConfigurationFlag.Build_ConcurrentSkieCompilation takeIf enableConcurrentSkieCompilation,
6983
SkieConfigurationFlag.Build_ParallelSkieCompilation takeIf enableParallelSkieCompilation,
84+
SkieConfigurationFlag.Build_RelativeSourcePathsInDebugSymbols takeIf enableRelativeSourcePathsInDebugSymbols,
7085
)
7186

7287
internal fun buildItems(): Map<String, String?> = mapOf(

SKIE/skie-gradle/plugin-impl/src/main/kotlin/co/touchlab/skie/plugin/SkieGradlePluginApplier.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import co.touchlab.skie.plugin.defaultarguments.disableCachingIfNeeded
1212
import co.touchlab.skie.plugin.dependencies.SkieCompilerPluginDependencyProvider
1313
import co.touchlab.skie.plugin.directory.SkieDirectoriesManager
1414
import co.touchlab.skie.plugin.fatframework.FatFrameworkConfigurator
15+
import co.touchlab.skie.plugin.relativepaths.configureDebugPrefixMap
1516
import co.touchlab.skie.plugin.subplugin.SkieSubPluginManager
1617
import co.touchlab.skie.plugin.switflink.SwiftBundlingConfigurator
1718
import co.touchlab.skie.plugin.switflink.SwiftUnpackingConfigurator
@@ -65,6 +66,7 @@ object SkieGradlePluginApplier {
6566
GradleAnalyticsManager(project).configureAnalytics(this)
6667

6768
configureMinOsVersionIfNeeded()
69+
configureDebugPrefixMap()
6870

6971
CreateSkieConfigurationTask.registerTask(this)
7072

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package co.touchlab.skie.plugin.relativepaths
2+
3+
import co.touchlab.skie.plugin.SkieTarget
4+
5+
fun SkieTarget.configureDebugPrefixMap() {
6+
if (!project.isRelativeSourcePathsPreviewEnabled) {
7+
return
8+
}
9+
10+
addFreeCompilerArgs(
11+
"-Xdebug-prefix-map=${project.rootDir.absolutePath}=."
12+
)
13+
}

0 commit comments

Comments
 (0)