kapt in Kotlin Multiplatform - src dirs not recognized by gradle and IDE by default - kotlin

I have a Kotlin annotation processor library which generates some classes and writes them with
FileSpec.builder(...)
...
.build()
.writeTo(processingEnv.filer)
The generated files end up in build/generated/source/kapt/.... They are only recognized by gradle if I add kotlin.srcDir("${buildDir.absolutePath}/generated/source/kapt/") to my build.gradle.kts.
It works the same way if I use kapt.kotlin.generated option - the path changes to build/generated/source/kaptKotlin/... but I still need to explicitly add the path to sources dir for the gradle to use these files during build process. Otherwise it's not only unrecognized by gradle, but also by Intellij.
Important note: my processor works in a Kotlin Multiplatform module.
I don't see necessity to include the generated source dirs with codegen libraries like dagger or moshi - they seem to just write to processingEnv.filer and everything works automagically.
So there must either be some additional configuration which makes it possible to omit the explicit kotlin.srcDir... or there is some limitation of KMM project. Any idea what the fix might be?

Related

How does kotlin-gradle-plugin use 'kotlin.code.style' property?

The official Kotlin documentation states:
Add kotlin.code.style=official property to the gradle.properties file at the project root.
I'm trying to understand how kotlin-gradle-plugin handles this property.
Which gradle task uses it?
When running gradle build, I don't see my code being reformatted, even if I format my code badly on purpose.
I went through the Github source code of the plugin but couldn't properly get to understand it.
Thanks for your help.
Kotlin Gradle plugin doesn't use this property, as it's not responsible for reformatting the code. Instead, this property is used by Gradle importer of Kotlin plugin for IntelliJ IDEA.
This facade provides access to Gradle properties defined for the project:
https://github.com/JetBrains/kotlin/blob/v1.4.10/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradlePropertiesFileFacade.kt
It checks local.properties first in case user wants to override this value in the local configuration (this file is usually added to .gitignore for VCS to skip it during it's operations), then in usual gradle.properties.
Then the property gets consumed to configure the project here:
https://github.com/JetBrains/kotlin/blob/v1.4.10/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt#L158-L159
Same thing goes for Maven-based projects. These are the only two places the property is used throughout Kotlin repository apart from tests right now.

How to add dependencies to a kotlin library?

I am trying to build a kotlin library for discord bots, which can be found at https://github.com/TheDrone7/discord-kt , published to jcenter (bintray link - https://bintray.com/thedrone7/discordKt/discord-kt). The library has a few dependencies of it's own as well.
When I add my own library to my test app, the library's dependencies were not installed and I started getting some errors. Is there a way to specify the library's dependencies so that they get automatically installed when a user uses my library?
EDIT: -
So basically my test app's build.gradle.kts file's dependencies section is given below
dependencies {
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.theDrone:discordKt:0.0.1a")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
And my library is dependent on the following packages: -
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.0
org.java-websocket:Java-WebSocket:1.4.0
com.beust:klaxon:5.0.5
org.slf4j:slf4j-jdk14:1.7.26
now when I run my test app, it shows gives error that there is no class named WebSocketClient which is a part of the org.java-websocket:Java-WebSocket:1.4.0 package and is also the base of my entire library.
When I add the listed packages to my test app's dependencies, it works perfectly fine. So is there a way that I could define in my library that the apps using it will also automatically depend on the packages my library depends on?
You declared the Java-WebSocket library as a dependency of your library using the implementation configuration.
This configuration means: I need that for my code to work, but it's an implementation detail and it's thus not part of my public API, so users of my library won't have access to it in their compile classpath.
So Gradle, when it generates the pom.xml file for your library, adds Java-WebSocket as a runtime dependency, and not as a compile dependency.
Read the java-library plugin documentation, which explains all of that in details. Once you have understood it, use api instead of implementation in your library's build.gradle.kts file for the dependencies that are part of your API, and should thus be compile dependencies and not runtime dependencies:
api("org.java-websocket:Java-WebSocket:1.4.0")

Gradle project with no project classes but with some buildscript-accessible custom classes?

I am thinking to use Gradle to manipulate with mysql database. It will read some files from filesystem, analyse them and populate database accordingly.
Such project will not produce any project code, because all output will go to database tables. On the other hand, gradle script should access some custom java or groovy classes to facilitate working with source data.
Is this a possible Gradle usage? Where to put gradle-accessible classes then? I don't want to have separate project, producing JAR for this project. I wan't single project, so that Gradle first compiles classes and the utilizes them in the script.
Is this possible?
Gradle is extensible, so you can utilize buildSrc for such scenarios. It works in the following way:
along build.gradle in the project there is buildSrc dir with custom build.gradle
in buildSrc/build.gradle you can define the script dependencies itself, implement plugins and tasks
finally you can apply a plugin from buildSrc to build.gradle.
It's quite handy, since e.g. IntelliJ can import such project and provide code completion for instance.
Another way is to put all the necessary stuff in build.gradle itself.
Such buildSrc project can be compiled to a jar, published and provided as a plugin, or it can be a separate project on github to be downloaded and used to manipulate data. Also, there no need to implement Plugin, you can use static methods e.g. Have a look at the demo.

What is a Kotlin module?

In the Kotlin documentation they are mentioning some kind of module for instance in the documentation for the internal modifier.
However I couldn't find any definition of the term module itself. So what is meant by module?
A module is a set of Kotlin sources compiled together:
an IntelliJ IDEA module;
a Maven project;
a Gradle source set;
a set of files compiled with one invocation of the Ant task.
This is in the same docs article about visibility modifiers. :)
From the Kotlin's documentation, a module is a set of Kotlin files compiled together:
an IntelliJ IDEA module
a Maven project;
a Gradle source set
a set of files compiled with one invocation of the <kotlinc> Ant task.
That is #hotkey's, but I would like to complement this answer.
According to Andrey Breslav, the Lead Language Designer of Kotlin:
a Kotlin module maps one-to-one to IntelliJ's module (iml-file).
According to IntelliJ's documentation:
Modules allow you to combine several technologies and frameworks in one application. In IntelliJ IDEA, you can create several modules for a project and each of them can be responsible for its own framework.
When it comes to a Maven project or a command line compilation, Andrey states:
Each compiler run, by default, is a separate module: all the binary dependencies will be treated as being not in the module being compiled at the moment.
Also, a Gradle source set is a module, with the exception that the test source set can access the internal declarations of main.
This means that if you have different build flavors in your Gradle configuration resulting in different source sets, for production and debug versions for example, then an internal class from one source set would not be available to be used in another source set.
Per Kotlin language specification ยง10.2 Modules:
A module is a concept on the boundary between the code itself and the
resulting application, thus it depends on and influences both of them.
A Kotlin module is a set of Kotlin files which are considered to be
interdependent and must be handled together during compilation.
In a simple case, a module is a set of files compiled at the same time
in a given project.
A set of files being compiled with a single Kotlin compiler invocation
A Maven module
A Gradle project
In a more complicated case involving multi-platform projects, a module
may be distributed across several compilations, projects and/or platforms.
For the purposes of Kotlin/Core, modules are important for internal
visibility. How modules influence particular platforms is
described in their respective sections of this specification.
I think you might be referring to org.koin.core.module.Module
A Koin module is a "space" to gather Koin definition. It's declared with the module function.
val myModule = module {
// Your definitions ...
}
This documentation would be helpful in that case.

Idea not recognizing thrift types from another module in same gradle project

I have the following project structure
datatypes/
build.gradle
src/main/thrift/service.thrift
service/
build.gradle
/src/main/java/ServiceImpl.java
build.gradle
settings.gradle
I am using yodle/gradle as a gradle plugin to generate java sources from thrift and compiling those. The sources and jar files are being generated in datatypes as expected.
in service/build.gradle, I have a dependency defined as:
dependencies {
compile project(':datatypes')
}
Running gradle build works perfectly fine; my only issue is while working in idea. After importing this as gradle module, I can't get the types defined in thrift to be recognized in ServiceImpl.java.
How do I get idea to include the jar in datatypes/build/libs/ as dependency for service?
Thanks!
The issue really is that the default thrift generated java source path set by yodle/griddle plugin is inside the build/ folder. I just added the following in my datatypes/build.gradle
thriftGenDir = 'src/main'
and now the java code is generated in src/main/gen-java which is picked up as source for dataypes by idea, and uses it to define types for anyone who depends on datatypes.