core
Packages
-
-
+
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/navigation.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/navigation.html
index bd6d8f71e2..30200edd94 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/navigation.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/navigation.html
@@ -1,28 +1,28 @@
-
+
Link copied to clipboard
-
common
+ android
-
+
-
+
-
+
-
+
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/-menu-item.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/-menu-item.html
index aa77c63349..7906ef7c2d 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/-menu-item.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/-menu-item.html
@@ -45,7 +45,7 @@
-
+
@@ -90,12 +90,12 @@
-
@@ -56,9 +56,9 @@
-
+
Menu
-
+
MenuItem
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/image-vector.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/image-vector.html
index 7ef178ac0c..8f6fa24b89 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/image-vector.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/image-vector.html
@@ -45,7 +45,7 @@
-
+
@@ -90,12 +90,12 @@
-
@@ -56,9 +56,9 @@
-
+
image
-
+
imageVector
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/index.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/index.html
index 010b722e89..dcff2a3c24 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/index.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/index.html
@@ -45,7 +45,7 @@
-
+
@@ -90,28 +90,28 @@
-
@@ -56,9 +56,9 @@
-
+
Menu
-
MenuItem
-
+
Constructors
-
-
+
+
@@ -120,62 +120,62 @@
-
+
Link copied to clipboard
-
+
Constructors
Properties
-
-
+
+
-
-
-
+
Link copied to clipboard
-
+
+
+
-
-
-
+
Link copied to clipboard
-
+
+
+
-
-
+
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/is-important.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/is-important.html
index db16080cee..3d8e384942 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/is-important.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/is-important.html
@@ -45,7 +45,7 @@
-
+
@@ -90,12 +90,12 @@
-
@@ -56,9 +56,9 @@
-
+
is
-
+
isImportant
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/label.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/label.html
index a654d7ec3c..91e71e9693 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/label.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/label.html
@@ -45,7 +45,7 @@
-
+
@@ -90,12 +90,12 @@
-
@@ -56,9 +56,9 @@
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/on-click.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/on-click.html
index 67adb9bf92..52bcff0a13 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/on-click.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/-menu-item/on-click.html
@@ -45,7 +45,7 @@
-
+
@@ -90,12 +90,12 @@
-
@@ -56,9 +56,9 @@
-
+
on
-
+
onClick
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/index.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/index.html
index 5b3f93c758..193aedc7a9 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/index.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/core/org.dokka.it.android.kmp.core/index.html
@@ -45,7 +45,7 @@
-
+
@@ -90,7 +90,7 @@
-
@@ -56,9 +56,9 @@
-
+
Package-level declaratio
Package-level declarations
@@ -100,17 +100,17 @@Package-level declaratio
Types
-
-
+
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html
index 1dd9f85f4f..49da92df32 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html
@@ -45,7 +45,7 @@
-
+
@@ -56,9 +56,9 @@
@@ -90,24 +90,24 @@
-
+
material3
Packages
-
-
+
+
-
+
Link copied to clipboard
- common
+ android
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html
index bd6d8f71e2..30200edd94 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html
@@ -1,28 +1,28 @@
-
+
-
+
-
+
-
+
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html
index a150b3080c..910f59d63b 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html
@@ -45,7 +45,7 @@
-
+
@@ -56,9 +56,9 @@
@@ -90,12 +90,12 @@
-
+
TopAppBarAction
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html
index ee309d0f46..d295e6ade0 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html
@@ -45,7 +45,7 @@
-
+
@@ -56,9 +56,9 @@
@@ -90,7 +90,7 @@
-
+
Package-level declarations
@@ -100,17 +100,17 @@ Package-level declaratio
Functions
-
-
+
+
-
+
Link copied to clipboard
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
index 2ffb90a607..b163ff71db 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
@@ -1,28 +1,28 @@
-
+
-
+
-
+
-
+
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/material3/src/commonMain/kotlin/TopAppBarAction.kt b/dokka-integration-tests/gradle/projects/it-android-compose/material3/src/androidMain/kotlin/TopAppBarAction.kt
similarity index 100%
rename from dokka-integration-tests/gradle/projects/it-android-compose/material3/src/commonMain/kotlin/TopAppBarAction.kt
rename to dokka-integration-tests/gradle/projects/it-android-compose/material3/src/androidMain/kotlin/TopAppBarAction.kt
diff --git a/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt b/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
index 5caf8ddb79..ae046bbbd5 100644
--- a/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
+++ b/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
@@ -74,7 +74,7 @@ class AndroidComposeIT {
val expectedFileTree = expectedHtml.toTreeString()
val actualFileTree = actualHtmlDir.toTreeString()
withClue((actualFileTree to expectedFileTree).sideBySide()) {
- expectedFileTree shouldBe actualFileTree
+ actualFileTree shouldBe expectedFileTree
actualHtmlDir shouldBeADirectoryWithSameContentAs expectedHtml
}
diff --git a/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt b/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
index 584e1cfcf3..57ad85da03 100644
--- a/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
+++ b/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
@@ -75,7 +75,7 @@ class AndroidProjectIT {
val expectedFileTree = expectedHtml.toTreeString()
val actualFileTree = actualHtmlDir.toTreeString()
withClue((actualFileTree to expectedFileTree).sideBySide()) {
- expectedFileTree shouldBe actualFileTree
+ actualFileTree shouldBe expectedFileTree
actualHtmlDir shouldBeADirectoryWithSameContentAs expectedHtml
}
diff --git a/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt b/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
index fe36d458be..94b1fdb76d 100644
--- a/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
+++ b/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
@@ -5,14 +5,18 @@ package org.jetbrains.dokka.it.gradle.examples
import io.kotest.assertions.asClue
import io.kotest.assertions.withClue
+import io.kotest.inspectors.shouldForAll
import io.kotest.matchers.paths.shouldBeADirectory
+import io.kotest.matchers.sequences.shouldNotBeEmpty
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
+import io.kotest.matchers.string.shouldNotContain
import org.gradle.testkit.runner.GradleRunner
-import org.gradle.testkit.runner.TaskOutcome.FROM_CACHE
-import org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE
+import org.gradle.testkit.runner.TaskOutcome.*
import org.jetbrains.dokka.gradle.utils.*
import org.jetbrains.dokka.it.gradle.loadConfigurationCacheReportData
+import org.jetbrains.dokka.it.gradle.shouldHaveOutcome
+import org.jetbrains.dokka.it.gradle.shouldHaveTask
import org.jetbrains.dokka.it.systemProperty
import org.junit.jupiter.api.Assumptions.assumeTrue
import org.junit.jupiter.api.Named.named
@@ -118,6 +122,28 @@ class ExampleProjectsTest {
ExampleProject.CompositeBuild -> ":build"
else -> ":dokkaGenerate"
}
+
+ init {
+ updateGradleProperties()
+ }
+
+ private fun updateGradleProperties() {
+ when (exampleProjectName) {
+ ExampleProject.KotlinMultiplatform -> {
+ project.gradleProperties {
+ // kotlin.native.enableKlibsCrossCompilation must be set to `true`
+ // otherwise Kotlin can't generate a Klib for Coroutines in macosMain
+ // when generating on Linux machines, resulting in 'Error class: unknown class'
+ // for CoroutineScope appearing in the generated docs.
+ kotlin.native.enableKlibsCrossCompilation = true
+ }
+ }
+
+ else -> {}
+ }
+
+ project.runner.writeGradleProperties(project.gradleProperties)
+ }
}
/**
@@ -165,6 +191,10 @@ class ExampleProjectsTest {
testCase = testCase,
format = "html",
)
+
+ verifyNoUnknownClassErrorsInHtml(
+ dokkaOutputDir = testCase.dokkaOutputDir.resolve("html")
+ )
}
@ParameterizedTest
@@ -183,7 +213,7 @@ class ExampleProjectsTest {
format: String,
) {
val expectedDataDir = testCase.expectedDataDir.resolve(format)
- val dokkaOutputDir = testCase.dokkaOutputDir.resolve(format)
+ val actualHtmlDir = testCase.dokkaOutputDir.resolve(format)
assert(expectedDataDir.isDirectory()) {
"Missing expectedDataDir: ${expectedDataDir.toUri()}"
@@ -195,27 +225,47 @@ class ExampleProjectsTest {
"--stacktrace",
)
.build {
- dokkaOutputDir.shouldBeADirectory()
+ actualHtmlDir.shouldBeADirectory()
- withClue({
+ withClue(
"""
- expectedDataDir: ${expectedDataDir.toUri()}
- actualOutputDir: ${dokkaOutputDir.toUri()}
- """.trimIndent()
- }) {
+ |expectedDataDir: ${expectedDataDir.toUri()}
+ |actualHtmlDir: ${actualHtmlDir.toUri()}
+ """.trimMargin()
+ ) {
withClue("expect file trees are the same") {
val expectedFileTree = expectedDataDir.toTreeString()
- val actualFileTree = dokkaOutputDir.toTreeString()
- expectedFileTree shouldBe actualFileTree
+ val actualFileTree = actualHtmlDir.toTreeString()
+ actualFileTree shouldBe expectedFileTree
}
withClue("expect directories are the same") {
- dokkaOutputDir shouldBeADirectoryWithSameContentAs expectedDataDir
+ actualHtmlDir shouldBeADirectoryWithSameContentAs expectedDataDir
}
}
}
}
+ private fun verifyNoUnknownClassErrorsInHtml(
+ dokkaOutputDir: Path,
+ ) {
+ withClue("expect no 'unknown class' message in output files") {
+ val htmlFiles = dokkaOutputDir.walk()
+ .filter { it.isRegularFile() && it.extension == "html" }
+
+ htmlFiles.shouldNotBeEmpty()
+
+ htmlFiles.forEach { file ->
+ val relativePath = file.relativeTo(dokkaOutputDir)
+ withClue("$relativePath should not contain Error class: unknown class") {
+ file.useLines { lines ->
+ lines.shouldForAll { line -> line.shouldNotContain("Error class: unknown class") }
+ }
+ }
+ }
+ }
+ }
+
@ParameterizedTest
@ArgumentsSource(TestCaseProvider::class)
@@ -330,9 +380,10 @@ class ExampleProjectsTest {
"--configuration-cache",
)
- //first build should store the configuration cache
+ // first build should store the configuration cache
configCacheRunner.build {
- output shouldContain "BUILD SUCCESSFUL"
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
+
output shouldContain "Configuration cache entry stored"
loadConfigurationCacheReportData(projectDir = testCase.project.projectDir)
@@ -341,9 +392,15 @@ class ExampleProjectsTest {
}
}
+ withClue("KT-66423 KGP needs another build to finish setting up kotlin-native") {
+ configCacheRunner.build {
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
+ }
+ }
+
// second build should reuse the configuration cache
configCacheRunner.build {
- output shouldContain "BUILD SUCCESSFUL"
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
output shouldContain "Configuration cache entry reused"
}
}
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
index 409dc00522..7d786b2c1d 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
@@ -167,7 +167,7 @@ abstract class KotlinAdapter @Inject constructor(
projectPath: String,
details: KotlinSourceSetDetails,
): Provider {
- return details.compilations.map { compilations: List ->
+ return details.allCompilations.map { compilations: List ->
val allPlatforms = compilations
// Exclude metadata compilations: they are always KotlinPlatform.Common, which isn't relevant here.
// Dokka only cares about the compilable KMP targets of a KotlinSourceSet.
@@ -193,7 +193,7 @@ abstract class KotlinAdapter @Inject constructor(
private fun determineClasspath(
details: KotlinSourceSetDetails
): Provider {
- return details.compilations.map { compilations: List ->
+ return details.primaryCompilations.map { compilations: List ->
val classpath = objects.fileCollection()
if (compilations.isNotEmpty()) {
@@ -254,11 +254,19 @@ abstract class KotlinAdapter @Inject constructor(
private data class KotlinCompilationDetails(
/** [KotlinCompilation.target] name. */
val target: String,
+
/** `true` if the compilation is 'metadata'. See [KotlinMetadataTarget]. */
val isMetadata: Boolean,
+
/** [KotlinCompilation.platformType] name. */
val kotlinPlatform: KotlinPlatform,
- val allKotlinSourceSetsNames: Set,
+
+ /** The names of [KotlinCompilation.kotlinSourceSets]. */
+ val primarySourceSetNames: Set,
+
+ /** The names of [KotlinCompilation.allKotlinSourceSets]. */
+ val allSourceSetNames: Set,
+
/**
* Whether the compilation is published or not.
*
@@ -267,9 +275,12 @@ private data class KotlinCompilationDetails(
* (E.g. 'main' compilations are published, 'test' compilations are not.)
*/
val publishedCompilation: Boolean,
- /** [KotlinCompilation.defaultSourceSet] → [KotlinSourceSet.dependsOn] names. */
+
+ /** [KotlinCompilation.kotlinSourceSets] → [KotlinSourceSet.dependsOn] names. */
val dependentSourceSetNames: Set,
+
val compilationClasspath: FileCollection,
+
/** [KotlinCompilation.defaultSourceSet] name. */
val defaultSourceSetName: String,
)
@@ -305,11 +316,10 @@ private class KotlinCompilationDetailsBuilder(
private fun createCompilationDetails(
compilation: KotlinCompilation<*>,
): KotlinCompilationDetails {
- val allKotlinSourceSetsNames =
- compilation.allKotlinSourceSets.map { it.name } + compilation.defaultSourceSet.name
- val dependentSourceSetNames =
- compilation.defaultSourceSet.dependsOn.map { it.name }
+ val primarySourceSetNames = compilation.kotlinSourceSets.map { it.name }
+ val allSourceSetNames = compilation.allKotlinSourceSets.map { it.name }
+ val dependentSourceSetNames = compilation.kotlinSourceSets.flatMap { it.dependsOn }.map { it.name }
val compilationClasspath: FileCollection =
collectKotlinCompilationClasspath(compilation = compilation)
@@ -317,7 +327,8 @@ private class KotlinCompilationDetailsBuilder(
return KotlinCompilationDetails(
target = compilation.target.name,
kotlinPlatform = KotlinPlatform.fromString(compilation.platformType.name),
- allKotlinSourceSetsNames = allKotlinSourceSetsNames.toSet(),
+ primarySourceSetNames = primarySourceSetNames.toSet(),
+ allSourceSetNames = allSourceSetNames.toSet(),
publishedCompilation = compilation.isPublished(),
dependentSourceSetNames = dependentSourceSetNames.toSet(),
compilationClasspath = compilationClasspath,
@@ -475,12 +486,28 @@ private abstract class KotlinSourceSetDetails @Inject constructor(
/** _All_ source directories from any (recursively) dependant source set. */
abstract val sourceDirectoriesOfDependents: ConfigurableFileCollection
- /** The specific compilations used to build this source set. */
- abstract val compilations: ListProperty
+ /**
+ * The specific compilations used to build this source set.
+ *
+ * (Typically there will only be one, but KGP permits manually registering more.)
+ */
+ abstract val primaryCompilations: ListProperty
- /** Estimate if this Kotlin source set contains 'published' sources. */
+ /**
+ * Associated compilations that this [KotlinSourceSet] participates in.
+ *
+ * For example, the compilation for `commonMain` will also participate in compiling
+ * the leaf `linuxX64`, as well as the intermediate compilations of `nativeMain`, `linuxMain`, etc.
+ */
+ abstract val allCompilations: ListProperty
+
+ /**
+ * Estimate if this Kotlin source set contains 'published' (non-test) sources.
+ *
+ * @see KotlinCompilationDetails.publishedCompilation
+ */
fun isPublishedSourceSet(): Provider =
- compilations.map { values ->
+ allCompilations.map { values ->
values.any { it.publishedCompilation }
}
@@ -518,6 +545,7 @@ private class KotlinSourceSetDetailsBuilder(
return sourceSetDetails
}
+ /** Register a [DokkaSourceSetSpec]. */
private fun NamedDomainObjectContainer.register(
kotlinSourceSet: KotlinSourceSet,
allKotlinCompilationDetails: ListProperty,
@@ -530,9 +558,15 @@ private class KotlinSourceSetDetailsBuilder(
kotlinSourceSet.kotlin.sourceDirectories.filter { it.exists() }
}
- val compilations = allKotlinCompilationDetails.map { allCompilations ->
+ val primaryCompilations = allKotlinCompilationDetails.map { primaryCompilations ->
+ primaryCompilations.filter { compilation ->
+ kotlinSourceSet.name in compilation.primarySourceSetNames
+ }
+ }
+
+ val allCompilations = allKotlinCompilationDetails.map { allCompilations ->
allCompilations.filter { compilation ->
- kotlinSourceSet.name in compilation.allKotlinSourceSetsNames
+ kotlinSourceSet.name in compilation.allSourceSetNames
}
}
@@ -565,7 +599,8 @@ private class KotlinSourceSetDetailsBuilder(
this.dependentSourceSetIds.addAll(dependentSourceSetIds)
this.sourceDirectories.from(extantSourceDirectories)
this.sourceDirectoriesOfDependents.from(sourceDirectoriesOfDependents)
- this.compilations.addAll(compilations)
+ this.primaryCompilations.addAll(primaryCompilations)
+ this.allCompilations.addAll(allCompilations)
}
}
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
index 0657666714..530a897dd2 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
@@ -138,7 +138,7 @@ internal class DokkaParametersBuilder(
// across all modules (otherwise they'd be generated into the same directory), and even
// though it's a file - it's a _relative_ file, so the ordering should be stable across
// machines (which is important for relocatable Build Cache).
- .sortedBy { it.relativePathToOutputDirectory }
+ .sortedBy { it.relativePathToOutputDirectory.invariantSeparatorsPath }
}
private fun build(spec: DokkaPluginParametersBaseSpec): PluginConfigurationImpl {
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
index 64f2137ec9..5f02fa25a8 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
@@ -101,7 +101,8 @@ constructor(
* To disable this behaviour set this property to `null`.
*/
@InternalDokkaGradlePluginApi
- @get:Internal
+ @get:Optional
+ @get:OutputFile
abstract val dokkaConfigurationJsonFile: RegularFileProperty
/**
diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
index 5c57cb9afe..ec18f48b28 100644
--- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
@@ -57,7 +57,13 @@ data class GradlePropertiesBuilder(
/** Kotlin specific options. */
data class KotlinArgs(
var mppStabilityWarning: Boolean? = true,
- )
+ val native: NativeArgs = NativeArgs(),
+ ) {
+
+ data class NativeArgs(
+ var enableKlibsCrossCompilation: Boolean? = null
+ )
+ }
/** Dokka specific options. */
data class DokkaArgs(
@@ -105,6 +111,7 @@ data class GradlePropertiesBuilder(
with(kotlin) {
putNotNull("kotlin.mpp.stability.nowarn", mppStabilityWarning?.let { !it })
+ putNotNull("kotlin.native.enableKlibsCrossCompilation", native.enableKlibsCrossCompilation)
}
with(gradle) {
diff --git a/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts b/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
index e6fac67c31..0be6b4713a 100644
--- a/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
+++ b/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
@@ -1,5 +1,5 @@
plugins {
- kotlin("multiplatform") version "1.9.25"
+ kotlin("multiplatform") version "2.1.0"
id("org.jetbrains.dokka") version "2.0.20-SNAPSHOT"
}
diff --git a/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties b/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
index 1ff33cc762..4c7f17b212 100644
--- a/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
+++ b/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
@@ -5,3 +5,9 @@ org.gradle.parallel=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
+
+# kotlin.native.enableKlibsCrossCompilation could be set to `true`
+# to be able to generate documentation via Dokka for macosMain on Linux machines
+# Otherwise, Dokka will produce 'Error class: unknown class'
+# for CoroutineScope appearing in the generated docs because of absent klibs
+kotlin.native.enableKlibsCrossCompilation=false
Types
-
-
+
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html
index 1dd9f85f4f..49da92df32 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/index.html
@@ -45,7 +45,7 @@
-
+
@@ -90,24 +90,24 @@
-
@@ -56,9 +56,9 @@
-
+
material3
Packages
-
-
+
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html
index bd6d8f71e2..30200edd94 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/navigation.html
@@ -1,28 +1,28 @@
-
+
Link copied to clipboard
-
common
+ android
-
+
-
+
-
+
-
+
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html
index a150b3080c..910f59d63b 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/-top-app-bar-action.html
@@ -45,7 +45,7 @@
-
+
@@ -90,12 +90,12 @@
-
@@ -56,9 +56,9 @@
-
+
Top
-
+
TopAppBarAction
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html
index ee309d0f46..d295e6ade0 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/material3/org.dokka.it.android.kmp.material3/index.html
@@ -45,7 +45,7 @@
-
+
@@ -90,7 +90,7 @@
-
@@ -56,9 +56,9 @@
-
+
Package-level declaratio
Package-level declarations
@@ -100,17 +100,17 @@Package-level declaratio
Functions
-
-
+
+
-
+
Link copied to clipboard
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
index 2ffb90a607..b163ff71db 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
@@ -1,28 +1,28 @@
-
+
-
+
-
+
-
+
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/material3/src/commonMain/kotlin/TopAppBarAction.kt b/dokka-integration-tests/gradle/projects/it-android-compose/material3/src/androidMain/kotlin/TopAppBarAction.kt
similarity index 100%
rename from dokka-integration-tests/gradle/projects/it-android-compose/material3/src/commonMain/kotlin/TopAppBarAction.kt
rename to dokka-integration-tests/gradle/projects/it-android-compose/material3/src/androidMain/kotlin/TopAppBarAction.kt
diff --git a/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt b/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
index 5caf8ddb79..ae046bbbd5 100644
--- a/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
+++ b/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
@@ -74,7 +74,7 @@ class AndroidComposeIT {
val expectedFileTree = expectedHtml.toTreeString()
val actualFileTree = actualHtmlDir.toTreeString()
withClue((actualFileTree to expectedFileTree).sideBySide()) {
- expectedFileTree shouldBe actualFileTree
+ actualFileTree shouldBe expectedFileTree
actualHtmlDir shouldBeADirectoryWithSameContentAs expectedHtml
}
diff --git a/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt b/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
index 584e1cfcf3..57ad85da03 100644
--- a/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
+++ b/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
@@ -75,7 +75,7 @@ class AndroidProjectIT {
val expectedFileTree = expectedHtml.toTreeString()
val actualFileTree = actualHtmlDir.toTreeString()
withClue((actualFileTree to expectedFileTree).sideBySide()) {
- expectedFileTree shouldBe actualFileTree
+ actualFileTree shouldBe expectedFileTree
actualHtmlDir shouldBeADirectoryWithSameContentAs expectedHtml
}
diff --git a/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt b/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
index fe36d458be..94b1fdb76d 100644
--- a/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
+++ b/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
@@ -5,14 +5,18 @@ package org.jetbrains.dokka.it.gradle.examples
import io.kotest.assertions.asClue
import io.kotest.assertions.withClue
+import io.kotest.inspectors.shouldForAll
import io.kotest.matchers.paths.shouldBeADirectory
+import io.kotest.matchers.sequences.shouldNotBeEmpty
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
+import io.kotest.matchers.string.shouldNotContain
import org.gradle.testkit.runner.GradleRunner
-import org.gradle.testkit.runner.TaskOutcome.FROM_CACHE
-import org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE
+import org.gradle.testkit.runner.TaskOutcome.*
import org.jetbrains.dokka.gradle.utils.*
import org.jetbrains.dokka.it.gradle.loadConfigurationCacheReportData
+import org.jetbrains.dokka.it.gradle.shouldHaveOutcome
+import org.jetbrains.dokka.it.gradle.shouldHaveTask
import org.jetbrains.dokka.it.systemProperty
import org.junit.jupiter.api.Assumptions.assumeTrue
import org.junit.jupiter.api.Named.named
@@ -118,6 +122,28 @@ class ExampleProjectsTest {
ExampleProject.CompositeBuild -> ":build"
else -> ":dokkaGenerate"
}
+
+ init {
+ updateGradleProperties()
+ }
+
+ private fun updateGradleProperties() {
+ when (exampleProjectName) {
+ ExampleProject.KotlinMultiplatform -> {
+ project.gradleProperties {
+ // kotlin.native.enableKlibsCrossCompilation must be set to `true`
+ // otherwise Kotlin can't generate a Klib for Coroutines in macosMain
+ // when generating on Linux machines, resulting in 'Error class: unknown class'
+ // for CoroutineScope appearing in the generated docs.
+ kotlin.native.enableKlibsCrossCompilation = true
+ }
+ }
+
+ else -> {}
+ }
+
+ project.runner.writeGradleProperties(project.gradleProperties)
+ }
}
/**
@@ -165,6 +191,10 @@ class ExampleProjectsTest {
testCase = testCase,
format = "html",
)
+
+ verifyNoUnknownClassErrorsInHtml(
+ dokkaOutputDir = testCase.dokkaOutputDir.resolve("html")
+ )
}
@ParameterizedTest
@@ -183,7 +213,7 @@ class ExampleProjectsTest {
format: String,
) {
val expectedDataDir = testCase.expectedDataDir.resolve(format)
- val dokkaOutputDir = testCase.dokkaOutputDir.resolve(format)
+ val actualHtmlDir = testCase.dokkaOutputDir.resolve(format)
assert(expectedDataDir.isDirectory()) {
"Missing expectedDataDir: ${expectedDataDir.toUri()}"
@@ -195,27 +225,47 @@ class ExampleProjectsTest {
"--stacktrace",
)
.build {
- dokkaOutputDir.shouldBeADirectory()
+ actualHtmlDir.shouldBeADirectory()
- withClue({
+ withClue(
"""
- expectedDataDir: ${expectedDataDir.toUri()}
- actualOutputDir: ${dokkaOutputDir.toUri()}
- """.trimIndent()
- }) {
+ |expectedDataDir: ${expectedDataDir.toUri()}
+ |actualHtmlDir: ${actualHtmlDir.toUri()}
+ """.trimMargin()
+ ) {
withClue("expect file trees are the same") {
val expectedFileTree = expectedDataDir.toTreeString()
- val actualFileTree = dokkaOutputDir.toTreeString()
- expectedFileTree shouldBe actualFileTree
+ val actualFileTree = actualHtmlDir.toTreeString()
+ actualFileTree shouldBe expectedFileTree
}
withClue("expect directories are the same") {
- dokkaOutputDir shouldBeADirectoryWithSameContentAs expectedDataDir
+ actualHtmlDir shouldBeADirectoryWithSameContentAs expectedDataDir
}
}
}
}
+ private fun verifyNoUnknownClassErrorsInHtml(
+ dokkaOutputDir: Path,
+ ) {
+ withClue("expect no 'unknown class' message in output files") {
+ val htmlFiles = dokkaOutputDir.walk()
+ .filter { it.isRegularFile() && it.extension == "html" }
+
+ htmlFiles.shouldNotBeEmpty()
+
+ htmlFiles.forEach { file ->
+ val relativePath = file.relativeTo(dokkaOutputDir)
+ withClue("$relativePath should not contain Error class: unknown class") {
+ file.useLines { lines ->
+ lines.shouldForAll { line -> line.shouldNotContain("Error class: unknown class") }
+ }
+ }
+ }
+ }
+ }
+
@ParameterizedTest
@ArgumentsSource(TestCaseProvider::class)
@@ -330,9 +380,10 @@ class ExampleProjectsTest {
"--configuration-cache",
)
- //first build should store the configuration cache
+ // first build should store the configuration cache
configCacheRunner.build {
- output shouldContain "BUILD SUCCESSFUL"
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
+
output shouldContain "Configuration cache entry stored"
loadConfigurationCacheReportData(projectDir = testCase.project.projectDir)
@@ -341,9 +392,15 @@ class ExampleProjectsTest {
}
}
+ withClue("KT-66423 KGP needs another build to finish setting up kotlin-native") {
+ configCacheRunner.build {
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
+ }
+ }
+
// second build should reuse the configuration cache
configCacheRunner.build {
- output shouldContain "BUILD SUCCESSFUL"
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
output shouldContain "Configuration cache entry reused"
}
}
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
index 409dc00522..7d786b2c1d 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
@@ -167,7 +167,7 @@ abstract class KotlinAdapter @Inject constructor(
projectPath: String,
details: KotlinSourceSetDetails,
): Provider {
- return details.compilations.map { compilations: List ->
+ return details.allCompilations.map { compilations: List ->
val allPlatforms = compilations
// Exclude metadata compilations: they are always KotlinPlatform.Common, which isn't relevant here.
// Dokka only cares about the compilable KMP targets of a KotlinSourceSet.
@@ -193,7 +193,7 @@ abstract class KotlinAdapter @Inject constructor(
private fun determineClasspath(
details: KotlinSourceSetDetails
): Provider {
- return details.compilations.map { compilations: List ->
+ return details.primaryCompilations.map { compilations: List ->
val classpath = objects.fileCollection()
if (compilations.isNotEmpty()) {
@@ -254,11 +254,19 @@ abstract class KotlinAdapter @Inject constructor(
private data class KotlinCompilationDetails(
/** [KotlinCompilation.target] name. */
val target: String,
+
/** `true` if the compilation is 'metadata'. See [KotlinMetadataTarget]. */
val isMetadata: Boolean,
+
/** [KotlinCompilation.platformType] name. */
val kotlinPlatform: KotlinPlatform,
- val allKotlinSourceSetsNames: Set,
+
+ /** The names of [KotlinCompilation.kotlinSourceSets]. */
+ val primarySourceSetNames: Set,
+
+ /** The names of [KotlinCompilation.allKotlinSourceSets]. */
+ val allSourceSetNames: Set,
+
/**
* Whether the compilation is published or not.
*
@@ -267,9 +275,12 @@ private data class KotlinCompilationDetails(
* (E.g. 'main' compilations are published, 'test' compilations are not.)
*/
val publishedCompilation: Boolean,
- /** [KotlinCompilation.defaultSourceSet] → [KotlinSourceSet.dependsOn] names. */
+
+ /** [KotlinCompilation.kotlinSourceSets] → [KotlinSourceSet.dependsOn] names. */
val dependentSourceSetNames: Set,
+
val compilationClasspath: FileCollection,
+
/** [KotlinCompilation.defaultSourceSet] name. */
val defaultSourceSetName: String,
)
@@ -305,11 +316,10 @@ private class KotlinCompilationDetailsBuilder(
private fun createCompilationDetails(
compilation: KotlinCompilation<*>,
): KotlinCompilationDetails {
- val allKotlinSourceSetsNames =
- compilation.allKotlinSourceSets.map { it.name } + compilation.defaultSourceSet.name
- val dependentSourceSetNames =
- compilation.defaultSourceSet.dependsOn.map { it.name }
+ val primarySourceSetNames = compilation.kotlinSourceSets.map { it.name }
+ val allSourceSetNames = compilation.allKotlinSourceSets.map { it.name }
+ val dependentSourceSetNames = compilation.kotlinSourceSets.flatMap { it.dependsOn }.map { it.name }
val compilationClasspath: FileCollection =
collectKotlinCompilationClasspath(compilation = compilation)
@@ -317,7 +327,8 @@ private class KotlinCompilationDetailsBuilder(
return KotlinCompilationDetails(
target = compilation.target.name,
kotlinPlatform = KotlinPlatform.fromString(compilation.platformType.name),
- allKotlinSourceSetsNames = allKotlinSourceSetsNames.toSet(),
+ primarySourceSetNames = primarySourceSetNames.toSet(),
+ allSourceSetNames = allSourceSetNames.toSet(),
publishedCompilation = compilation.isPublished(),
dependentSourceSetNames = dependentSourceSetNames.toSet(),
compilationClasspath = compilationClasspath,
@@ -475,12 +486,28 @@ private abstract class KotlinSourceSetDetails @Inject constructor(
/** _All_ source directories from any (recursively) dependant source set. */
abstract val sourceDirectoriesOfDependents: ConfigurableFileCollection
- /** The specific compilations used to build this source set. */
- abstract val compilations: ListProperty
+ /**
+ * The specific compilations used to build this source set.
+ *
+ * (Typically there will only be one, but KGP permits manually registering more.)
+ */
+ abstract val primaryCompilations: ListProperty
- /** Estimate if this Kotlin source set contains 'published' sources. */
+ /**
+ * Associated compilations that this [KotlinSourceSet] participates in.
+ *
+ * For example, the compilation for `commonMain` will also participate in compiling
+ * the leaf `linuxX64`, as well as the intermediate compilations of `nativeMain`, `linuxMain`, etc.
+ */
+ abstract val allCompilations: ListProperty
+
+ /**
+ * Estimate if this Kotlin source set contains 'published' (non-test) sources.
+ *
+ * @see KotlinCompilationDetails.publishedCompilation
+ */
fun isPublishedSourceSet(): Provider =
- compilations.map { values ->
+ allCompilations.map { values ->
values.any { it.publishedCompilation }
}
@@ -518,6 +545,7 @@ private class KotlinSourceSetDetailsBuilder(
return sourceSetDetails
}
+ /** Register a [DokkaSourceSetSpec]. */
private fun NamedDomainObjectContainer.register(
kotlinSourceSet: KotlinSourceSet,
allKotlinCompilationDetails: ListProperty,
@@ -530,9 +558,15 @@ private class KotlinSourceSetDetailsBuilder(
kotlinSourceSet.kotlin.sourceDirectories.filter { it.exists() }
}
- val compilations = allKotlinCompilationDetails.map { allCompilations ->
+ val primaryCompilations = allKotlinCompilationDetails.map { primaryCompilations ->
+ primaryCompilations.filter { compilation ->
+ kotlinSourceSet.name in compilation.primarySourceSetNames
+ }
+ }
+
+ val allCompilations = allKotlinCompilationDetails.map { allCompilations ->
allCompilations.filter { compilation ->
- kotlinSourceSet.name in compilation.allKotlinSourceSetsNames
+ kotlinSourceSet.name in compilation.allSourceSetNames
}
}
@@ -565,7 +599,8 @@ private class KotlinSourceSetDetailsBuilder(
this.dependentSourceSetIds.addAll(dependentSourceSetIds)
this.sourceDirectories.from(extantSourceDirectories)
this.sourceDirectoriesOfDependents.from(sourceDirectoriesOfDependents)
- this.compilations.addAll(compilations)
+ this.primaryCompilations.addAll(primaryCompilations)
+ this.allCompilations.addAll(allCompilations)
}
}
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
index 0657666714..530a897dd2 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
@@ -138,7 +138,7 @@ internal class DokkaParametersBuilder(
// across all modules (otherwise they'd be generated into the same directory), and even
// though it's a file - it's a _relative_ file, so the ordering should be stable across
// machines (which is important for relocatable Build Cache).
- .sortedBy { it.relativePathToOutputDirectory }
+ .sortedBy { it.relativePathToOutputDirectory.invariantSeparatorsPath }
}
private fun build(spec: DokkaPluginParametersBaseSpec): PluginConfigurationImpl {
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
index 64f2137ec9..5f02fa25a8 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
@@ -101,7 +101,8 @@ constructor(
* To disable this behaviour set this property to `null`.
*/
@InternalDokkaGradlePluginApi
- @get:Internal
+ @get:Optional
+ @get:OutputFile
abstract val dokkaConfigurationJsonFile: RegularFileProperty
/**
diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
index 5c57cb9afe..ec18f48b28 100644
--- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
@@ -57,7 +57,13 @@ data class GradlePropertiesBuilder(
/** Kotlin specific options. */
data class KotlinArgs(
var mppStabilityWarning: Boolean? = true,
- )
+ val native: NativeArgs = NativeArgs(),
+ ) {
+
+ data class NativeArgs(
+ var enableKlibsCrossCompilation: Boolean? = null
+ )
+ }
/** Dokka specific options. */
data class DokkaArgs(
@@ -105,6 +111,7 @@ data class GradlePropertiesBuilder(
with(kotlin) {
putNotNull("kotlin.mpp.stability.nowarn", mppStabilityWarning?.let { !it })
+ putNotNull("kotlin.native.enableKlibsCrossCompilation", native.enableKlibsCrossCompilation)
}
with(gradle) {
diff --git a/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts b/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
index e6fac67c31..0be6b4713a 100644
--- a/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
+++ b/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
@@ -1,5 +1,5 @@
plugins {
- kotlin("multiplatform") version "1.9.25"
+ kotlin("multiplatform") version "2.1.0"
id("org.jetbrains.dokka") version "2.0.20-SNAPSHOT"
}
diff --git a/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties b/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
index 1ff33cc762..4c7f17b212 100644
--- a/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
+++ b/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
@@ -5,3 +5,9 @@ org.gradle.parallel=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
+
+# kotlin.native.enableKlibsCrossCompilation could be set to `true`
+# to be able to generate documentation via Dokka for macosMain on Linux machines
+# Otherwise, Dokka will produce 'Error class: unknown class'
+# for CoroutineScope appearing in the generated docs because of absent klibs
+kotlin.native.enableKlibsCrossCompilation=false
Functions
-
-
+
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
index 2ffb90a607..b163ff71db 100644
--- a/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
+++ b/dokka-integration-tests/gradle/projects/it-android-compose/expectedData/html/navigation.html
@@ -1,28 +1,28 @@
-
+
Link copied to clipboard
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-compose/material3/src/commonMain/kotlin/TopAppBarAction.kt b/dokka-integration-tests/gradle/projects/it-android-compose/material3/src/androidMain/kotlin/TopAppBarAction.kt
similarity index 100%
rename from dokka-integration-tests/gradle/projects/it-android-compose/material3/src/commonMain/kotlin/TopAppBarAction.kt
rename to dokka-integration-tests/gradle/projects/it-android-compose/material3/src/androidMain/kotlin/TopAppBarAction.kt
diff --git a/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt b/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
index 5caf8ddb79..ae046bbbd5 100644
--- a/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
+++ b/dokka-integration-tests/gradle/src/test/kotlin/AndroidComposeIT.kt
@@ -74,7 +74,7 @@ class AndroidComposeIT {
val expectedFileTree = expectedHtml.toTreeString()
val actualFileTree = actualHtmlDir.toTreeString()
withClue((actualFileTree to expectedFileTree).sideBySide()) {
- expectedFileTree shouldBe actualFileTree
+ actualFileTree shouldBe expectedFileTree
actualHtmlDir shouldBeADirectoryWithSameContentAs expectedHtml
}
diff --git a/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt b/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
index 584e1cfcf3..57ad85da03 100644
--- a/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
+++ b/dokka-integration-tests/gradle/src/test/kotlin/AndroidProjectIT.kt
@@ -75,7 +75,7 @@ class AndroidProjectIT {
val expectedFileTree = expectedHtml.toTreeString()
val actualFileTree = actualHtmlDir.toTreeString()
withClue((actualFileTree to expectedFileTree).sideBySide()) {
- expectedFileTree shouldBe actualFileTree
+ actualFileTree shouldBe expectedFileTree
actualHtmlDir shouldBeADirectoryWithSameContentAs expectedHtml
}
diff --git a/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt b/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
index fe36d458be..94b1fdb76d 100644
--- a/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
+++ b/dokka-integration-tests/gradle/src/testExampleProjects/kotlin/ExampleProjectsTest.kt
@@ -5,14 +5,18 @@ package org.jetbrains.dokka.it.gradle.examples
import io.kotest.assertions.asClue
import io.kotest.assertions.withClue
+import io.kotest.inspectors.shouldForAll
import io.kotest.matchers.paths.shouldBeADirectory
+import io.kotest.matchers.sequences.shouldNotBeEmpty
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
+import io.kotest.matchers.string.shouldNotContain
import org.gradle.testkit.runner.GradleRunner
-import org.gradle.testkit.runner.TaskOutcome.FROM_CACHE
-import org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE
+import org.gradle.testkit.runner.TaskOutcome.*
import org.jetbrains.dokka.gradle.utils.*
import org.jetbrains.dokka.it.gradle.loadConfigurationCacheReportData
+import org.jetbrains.dokka.it.gradle.shouldHaveOutcome
+import org.jetbrains.dokka.it.gradle.shouldHaveTask
import org.jetbrains.dokka.it.systemProperty
import org.junit.jupiter.api.Assumptions.assumeTrue
import org.junit.jupiter.api.Named.named
@@ -118,6 +122,28 @@ class ExampleProjectsTest {
ExampleProject.CompositeBuild -> ":build"
else -> ":dokkaGenerate"
}
+
+ init {
+ updateGradleProperties()
+ }
+
+ private fun updateGradleProperties() {
+ when (exampleProjectName) {
+ ExampleProject.KotlinMultiplatform -> {
+ project.gradleProperties {
+ // kotlin.native.enableKlibsCrossCompilation must be set to `true`
+ // otherwise Kotlin can't generate a Klib for Coroutines in macosMain
+ // when generating on Linux machines, resulting in 'Error class: unknown class'
+ // for CoroutineScope appearing in the generated docs.
+ kotlin.native.enableKlibsCrossCompilation = true
+ }
+ }
+
+ else -> {}
+ }
+
+ project.runner.writeGradleProperties(project.gradleProperties)
+ }
}
/**
@@ -165,6 +191,10 @@ class ExampleProjectsTest {
testCase = testCase,
format = "html",
)
+
+ verifyNoUnknownClassErrorsInHtml(
+ dokkaOutputDir = testCase.dokkaOutputDir.resolve("html")
+ )
}
@ParameterizedTest
@@ -183,7 +213,7 @@ class ExampleProjectsTest {
format: String,
) {
val expectedDataDir = testCase.expectedDataDir.resolve(format)
- val dokkaOutputDir = testCase.dokkaOutputDir.resolve(format)
+ val actualHtmlDir = testCase.dokkaOutputDir.resolve(format)
assert(expectedDataDir.isDirectory()) {
"Missing expectedDataDir: ${expectedDataDir.toUri()}"
@@ -195,27 +225,47 @@ class ExampleProjectsTest {
"--stacktrace",
)
.build {
- dokkaOutputDir.shouldBeADirectory()
+ actualHtmlDir.shouldBeADirectory()
- withClue({
+ withClue(
"""
- expectedDataDir: ${expectedDataDir.toUri()}
- actualOutputDir: ${dokkaOutputDir.toUri()}
- """.trimIndent()
- }) {
+ |expectedDataDir: ${expectedDataDir.toUri()}
+ |actualHtmlDir: ${actualHtmlDir.toUri()}
+ """.trimMargin()
+ ) {
withClue("expect file trees are the same") {
val expectedFileTree = expectedDataDir.toTreeString()
- val actualFileTree = dokkaOutputDir.toTreeString()
- expectedFileTree shouldBe actualFileTree
+ val actualFileTree = actualHtmlDir.toTreeString()
+ actualFileTree shouldBe expectedFileTree
}
withClue("expect directories are the same") {
- dokkaOutputDir shouldBeADirectoryWithSameContentAs expectedDataDir
+ actualHtmlDir shouldBeADirectoryWithSameContentAs expectedDataDir
}
}
}
}
+ private fun verifyNoUnknownClassErrorsInHtml(
+ dokkaOutputDir: Path,
+ ) {
+ withClue("expect no 'unknown class' message in output files") {
+ val htmlFiles = dokkaOutputDir.walk()
+ .filter { it.isRegularFile() && it.extension == "html" }
+
+ htmlFiles.shouldNotBeEmpty()
+
+ htmlFiles.forEach { file ->
+ val relativePath = file.relativeTo(dokkaOutputDir)
+ withClue("$relativePath should not contain Error class: unknown class") {
+ file.useLines { lines ->
+ lines.shouldForAll { line -> line.shouldNotContain("Error class: unknown class") }
+ }
+ }
+ }
+ }
+ }
+
@ParameterizedTest
@ArgumentsSource(TestCaseProvider::class)
@@ -330,9 +380,10 @@ class ExampleProjectsTest {
"--configuration-cache",
)
- //first build should store the configuration cache
+ // first build should store the configuration cache
configCacheRunner.build {
- output shouldContain "BUILD SUCCESSFUL"
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
+
output shouldContain "Configuration cache entry stored"
loadConfigurationCacheReportData(projectDir = testCase.project.projectDir)
@@ -341,9 +392,15 @@ class ExampleProjectsTest {
}
}
+ withClue("KT-66423 KGP needs another build to finish setting up kotlin-native") {
+ configCacheRunner.build {
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
+ }
+ }
+
// second build should reuse the configuration cache
configCacheRunner.build {
- output shouldContain "BUILD SUCCESSFUL"
+ shouldHaveTask(testCase.dokkaGenerateTask).shouldHaveOutcome(UP_TO_DATE, SUCCESS)
output shouldContain "Configuration cache entry reused"
}
}
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
index 409dc00522..7d786b2c1d 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/adapters/KotlinAdapter.kt
@@ -167,7 +167,7 @@ abstract class KotlinAdapter @Inject constructor(
projectPath: String,
details: KotlinSourceSetDetails,
): Provider {
- return details.compilations.map { compilations: List ->
+ return details.allCompilations.map { compilations: List ->
val allPlatforms = compilations
// Exclude metadata compilations: they are always KotlinPlatform.Common, which isn't relevant here.
// Dokka only cares about the compilable KMP targets of a KotlinSourceSet.
@@ -193,7 +193,7 @@ abstract class KotlinAdapter @Inject constructor(
private fun determineClasspath(
details: KotlinSourceSetDetails
): Provider {
- return details.compilations.map { compilations: List ->
+ return details.primaryCompilations.map { compilations: List ->
val classpath = objects.fileCollection()
if (compilations.isNotEmpty()) {
@@ -254,11 +254,19 @@ abstract class KotlinAdapter @Inject constructor(
private data class KotlinCompilationDetails(
/** [KotlinCompilation.target] name. */
val target: String,
+
/** `true` if the compilation is 'metadata'. See [KotlinMetadataTarget]. */
val isMetadata: Boolean,
+
/** [KotlinCompilation.platformType] name. */
val kotlinPlatform: KotlinPlatform,
- val allKotlinSourceSetsNames: Set,
+
+ /** The names of [KotlinCompilation.kotlinSourceSets]. */
+ val primarySourceSetNames: Set,
+
+ /** The names of [KotlinCompilation.allKotlinSourceSets]. */
+ val allSourceSetNames: Set,
+
/**
* Whether the compilation is published or not.
*
@@ -267,9 +275,12 @@ private data class KotlinCompilationDetails(
* (E.g. 'main' compilations are published, 'test' compilations are not.)
*/
val publishedCompilation: Boolean,
- /** [KotlinCompilation.defaultSourceSet] → [KotlinSourceSet.dependsOn] names. */
+
+ /** [KotlinCompilation.kotlinSourceSets] → [KotlinSourceSet.dependsOn] names. */
val dependentSourceSetNames: Set,
+
val compilationClasspath: FileCollection,
+
/** [KotlinCompilation.defaultSourceSet] name. */
val defaultSourceSetName: String,
)
@@ -305,11 +316,10 @@ private class KotlinCompilationDetailsBuilder(
private fun createCompilationDetails(
compilation: KotlinCompilation<*>,
): KotlinCompilationDetails {
- val allKotlinSourceSetsNames =
- compilation.allKotlinSourceSets.map { it.name } + compilation.defaultSourceSet.name
- val dependentSourceSetNames =
- compilation.defaultSourceSet.dependsOn.map { it.name }
+ val primarySourceSetNames = compilation.kotlinSourceSets.map { it.name }
+ val allSourceSetNames = compilation.allKotlinSourceSets.map { it.name }
+ val dependentSourceSetNames = compilation.kotlinSourceSets.flatMap { it.dependsOn }.map { it.name }
val compilationClasspath: FileCollection =
collectKotlinCompilationClasspath(compilation = compilation)
@@ -317,7 +327,8 @@ private class KotlinCompilationDetailsBuilder(
return KotlinCompilationDetails(
target = compilation.target.name,
kotlinPlatform = KotlinPlatform.fromString(compilation.platformType.name),
- allKotlinSourceSetsNames = allKotlinSourceSetsNames.toSet(),
+ primarySourceSetNames = primarySourceSetNames.toSet(),
+ allSourceSetNames = allSourceSetNames.toSet(),
publishedCompilation = compilation.isPublished(),
dependentSourceSetNames = dependentSourceSetNames.toSet(),
compilationClasspath = compilationClasspath,
@@ -475,12 +486,28 @@ private abstract class KotlinSourceSetDetails @Inject constructor(
/** _All_ source directories from any (recursively) dependant source set. */
abstract val sourceDirectoriesOfDependents: ConfigurableFileCollection
- /** The specific compilations used to build this source set. */
- abstract val compilations: ListProperty
+ /**
+ * The specific compilations used to build this source set.
+ *
+ * (Typically there will only be one, but KGP permits manually registering more.)
+ */
+ abstract val primaryCompilations: ListProperty
- /** Estimate if this Kotlin source set contains 'published' sources. */
+ /**
+ * Associated compilations that this [KotlinSourceSet] participates in.
+ *
+ * For example, the compilation for `commonMain` will also participate in compiling
+ * the leaf `linuxX64`, as well as the intermediate compilations of `nativeMain`, `linuxMain`, etc.
+ */
+ abstract val allCompilations: ListProperty
+
+ /**
+ * Estimate if this Kotlin source set contains 'published' (non-test) sources.
+ *
+ * @see KotlinCompilationDetails.publishedCompilation
+ */
fun isPublishedSourceSet(): Provider =
- compilations.map { values ->
+ allCompilations.map { values ->
values.any { it.publishedCompilation }
}
@@ -518,6 +545,7 @@ private class KotlinSourceSetDetailsBuilder(
return sourceSetDetails
}
+ /** Register a [DokkaSourceSetSpec]. */
private fun NamedDomainObjectContainer.register(
kotlinSourceSet: KotlinSourceSet,
allKotlinCompilationDetails: ListProperty,
@@ -530,9 +558,15 @@ private class KotlinSourceSetDetailsBuilder(
kotlinSourceSet.kotlin.sourceDirectories.filter { it.exists() }
}
- val compilations = allKotlinCompilationDetails.map { allCompilations ->
+ val primaryCompilations = allKotlinCompilationDetails.map { primaryCompilations ->
+ primaryCompilations.filter { compilation ->
+ kotlinSourceSet.name in compilation.primarySourceSetNames
+ }
+ }
+
+ val allCompilations = allKotlinCompilationDetails.map { allCompilations ->
allCompilations.filter { compilation ->
- kotlinSourceSet.name in compilation.allKotlinSourceSetsNames
+ kotlinSourceSet.name in compilation.allSourceSetNames
}
}
@@ -565,7 +599,8 @@ private class KotlinSourceSetDetailsBuilder(
this.dependentSourceSetIds.addAll(dependentSourceSetIds)
this.sourceDirectories.from(extantSourceDirectories)
this.sourceDirectoriesOfDependents.from(sourceDirectoriesOfDependents)
- this.compilations.addAll(compilations)
+ this.primaryCompilations.addAll(primaryCompilations)
+ this.allCompilations.addAll(allCompilations)
}
}
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
index 0657666714..530a897dd2 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/engine/parameters/builders/DokkaParametersBuilder.kt
@@ -138,7 +138,7 @@ internal class DokkaParametersBuilder(
// across all modules (otherwise they'd be generated into the same directory), and even
// though it's a file - it's a _relative_ file, so the ordering should be stable across
// machines (which is important for relocatable Build Cache).
- .sortedBy { it.relativePathToOutputDirectory }
+ .sortedBy { it.relativePathToOutputDirectory.invariantSeparatorsPath }
}
private fun build(spec: DokkaPluginParametersBaseSpec): PluginConfigurationImpl {
diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
index 64f2137ec9..5f02fa25a8 100644
--- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/tasks/DokkaGenerateTask.kt
@@ -101,7 +101,8 @@ constructor(
* To disable this behaviour set this property to `null`.
*/
@InternalDokkaGradlePluginApi
- @get:Internal
+ @get:Optional
+ @get:OutputFile
abstract val dokkaConfigurationJsonFile: RegularFileProperty
/**
diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
index 5c57cb9afe..ec18f48b28 100644
--- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
+++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt
@@ -57,7 +57,13 @@ data class GradlePropertiesBuilder(
/** Kotlin specific options. */
data class KotlinArgs(
var mppStabilityWarning: Boolean? = true,
- )
+ val native: NativeArgs = NativeArgs(),
+ ) {
+
+ data class NativeArgs(
+ var enableKlibsCrossCompilation: Boolean? = null
+ )
+ }
/** Dokka specific options. */
data class DokkaArgs(
@@ -105,6 +111,7 @@ data class GradlePropertiesBuilder(
with(kotlin) {
putNotNull("kotlin.mpp.stability.nowarn", mppStabilityWarning?.let { !it })
+ putNotNull("kotlin.native.enableKlibsCrossCompilation", native.enableKlibsCrossCompilation)
}
with(gradle) {
diff --git a/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts b/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
index e6fac67c31..0be6b4713a 100644
--- a/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
+++ b/examples/gradle-v2/kotlin-multiplatform-example/build.gradle.kts
@@ -1,5 +1,5 @@
plugins {
- kotlin("multiplatform") version "1.9.25"
+ kotlin("multiplatform") version "2.1.0"
id("org.jetbrains.dokka") version "2.0.20-SNAPSHOT"
}
diff --git a/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties b/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
index 1ff33cc762..4c7f17b212 100644
--- a/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
+++ b/examples/gradle-v2/kotlin-multiplatform-example/gradle.properties
@@ -5,3 +5,9 @@ org.gradle.parallel=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
+
+# kotlin.native.enableKlibsCrossCompilation could be set to `true`
+# to be able to generate documentation via Dokka for macosMain on Linux machines
+# Otherwise, Dokka will produce 'Error class: unknown class'
+# for CoroutineScope appearing in the generated docs because of absent klibs
+kotlin.native.enableKlibsCrossCompilation=false