i spent a lot of time trying to understand gradle ...
# getting-started
r
i spent a lot of time trying to understand gradle a few months ago. now I come back, and I want to create a fresh kotlin project. I do
gradle init
. All good, except I dislike the default directory structure. I don't want src/main/kotlin/ whatever. I just want src/main.kt. I've forgotten how to do that. And I don't know how to quickly find the answer. This seems like a real problem with gradle, that it is so dependent on memory. I really wish kotlin had it's own build tool. like swift.
v
From the top of my head it should be something like
kotlin.sourceSets.main.kotlin.srcDir("src")
. What would you win with an own build tool? The Kotlin developers could not concentrate on Kotlin as they also had to maintain the build tool. It's development would any way be less active than Gradle`s, as there the build tool is the main product. Everyone starting with Kotlin would have to learn a new tool instead of using the existing knowledge. You would loose it split all the plugin development out there. I honestly only see drawbacks if Kotlin had it's own build tool.
r
it is just that gradle is very uncomfortable and complex
also related complaint
this is insane
6 levels of folder nesting for the starter hello world...
why does gradle assume I am going to be doing some crazy mulit-platofrm project where I am supporting multiple languages and have my own organization ?
im not in android studio making an android app. I am wanting to make a command line terminal application... in pure kotlin. this dir structure is complete overkill
h
You don’t need package folders in Kotlin, you can remove them. It’s even the official code style. But by default, Gradle applies the historically JVM sourceset (src/main/kotlin) structure. You can also change it, like Björn already mentioned.
r
why is build.gradle.kts inside of app/ instead of root, when settings.gradle.kts is in root?
Copy code
application {
    // Define the main class for the application.
    mainClass = "org.example.AppKt"
}
i dont understand main class. what if my main does not have a class?
h
Settings defines your whole project, each project can contains sub projects, like
app
. I guess, the init project is structured in this way to easily add more subprojects in the future. If you don’t need an app subproject, you could also use the root project.
The main class is the JVM entrypoint. If you want to execute your code, you need a main class.
And I don’t think another build tool would help, it’s just the init project generator that can be improved, just create an issue in the Gradle GitHub repository, cause dev UX is important for Gradle.
BTW regarding main class: If you want to write a top level main function in Kotlin, you need to specify the Kotlin file name in PascalCase and add a Kt suffix: like
MainKt
, because the Kotlin compiler creates an JVM class under the hood.
r
BTW regarding main class: If you want to write a top level main function in Kotlin, you need to specify the Kotlin file name in PascalCase and add a Kt suffix: like
MainKt
, because the Kotlin compiler creates an JVM class under the hood.
stuff like this is why gradle is so hard. Where and when would I have ever learned that?
implicit subtleties in the config file like that
h
stuff like this is why gradle is so hard.
That's unrelated to Gradle but to Kotlin. Yes, JetBrains could create another Gradle plugin:
kotlin-application
, but this adds another complexity 🙂
r
I am coming into kotlin as someone who has never done Java. And I do not want to change that; I would like to live the rest of my life, never have been a java developer
so the less amount of java-esque things that I am expected to know, the better.
i would like kotlin to be a standalone language that beginners can jump into without java experience
h
But you do want to target the JVM and use the Java stdlib? Without knowledge of the JVM/Java?
v
> it is just that gradle is very uncomfortable That's highly subjective though. I find it super comfortable with all the sane conventions but the flexibility to configure it exactly the way I need / want it. > this is insane > 6 levels of folder nesting for the starter hello world... > why does gradle assume I am going to be doing some crazy mulit-platofrm project where I am supporting multiple languages That's not insane, but a sane default that works in most situations and for most people and that is a convention most Maven and Gradle users are used to, so it is immediately familiar to most people seeing the codebase the first time. The only think I personally object is having the subproject in
app
instead of having the source directly in the root project. But also here, it just is a sane default where you then can easily add other subprojects without moving things around. > this dir structure is complete overkill I usually just use
init
to generate a
basic
project, so practically the wrapper files and nearly empty settings and build script in the root project and then just configure the build like I want or need it. > and have my own organization ? It's just best practice to use a namespace for own classes in each and every JVM code you write, be it Java or Kotlin. And common convention to use some Domainname you own and reverse it for the beginning of the package name, or similar
io.github.youusername....
assuming you do not change your username. > You don’t need package folders in Kotlin, you can remove them. It’s even the official code style. Which is insane imho. 😄 > why is build.gradle.kts inside of app/ instead of root, when settings.gradle.kts is in root? Like I said above. The
init
creates the
app
subproject that is then included in the settings script, so that you can easily add other subproject like one dedicated for docs, or for systemtests, or whatever else you need. If you don't like it, just change it. Just move all stuff from
app
up one level and remove the include from the settings script. > i dont understand main class. what if my main does not have a class? It always has. In the example the main function is directly top-level in
org/example/App.kt
which makes it part of the class
AppKt
after compilation. This is not about Kotlin class, but about JVM class where it ultimately ends so that you can start it when invoking the runtime. This is simply releated to the target environment for which you code the Kotlin which in your case is the JVM
r
But you do want to target the JVM and use the Java stdlib? Without knowledge of the JVM/Java?
no, not really. I picked Kotlin because it had a language feature set and syntax that I found very attractive. I have little interest in JVM compatibility and android development.
the language is just sexy and lets me do OOP easily
v
But you do use Kotlin/JVM, so you do target the JVM. You could also use Kotlin/JS or Kotlin/Native
But I don't think you will make your life easier with that 😄
r
@Vampire so I do grew init basic, and it generates an empty build file
Copy code
/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * To learn more about Gradle by exploring our Samples at <https://docs.gradle.org/8.6/samples>
 * This project uses @Incubating APIs which are subject to change.
 */
its not clear to me what all the rules are that i need to put
do I just do this
Copy code
sourceSets {
    main {
        kotlin.srcDir("src/")
    }
}
a
v
I looked at it and really dislike it. But there is a parallel approach for "Declarative Gradle" that I dislike the same 😄 https://blog.gradle.org/declarative-gradle
r
amper looks good. but i am having a hard time figuring out how to get and use it without an ide..
a
yeah, that makes sense. Kotlin development basically requires IntelliJ.
v
And yes, with
basic
the build script of course is empty, you told it to create a basic Gradle build without any opinion. You can then follow the Kotlin documentation what to configure. Unless the issue for Gradle is resolved that custom init-task-templates can be used, you have to live with either minimal project or opinionated project that you don't like. If Kotlin would provide an own build tool it would be the same though. Conventions and defaults are never liked by all users.
r
the docs are not very clear
my specific questions are not answered
image.png
why is src/main/myKotlin in the java.srcDirs??
if its kotlin instead of java
a
btw, for configuring the source sets, I'd use something like this:
Copy code
sourceSets {
    main {
        kotlin.setSrcDirs(listOf("src"))
        resources.setSrcDirs(listOf("resources"))
        java.setSrcDirs(emptyList<String>())
    }
    test {
        kotlin.setSrcDirs(listOf("testSrc"))
        resources.setSrcDirs(listOf("testResources"))
        java.setSrcDirs(emptyList<String>())
    }
}
It's nicer to use
setSrcDirs
because it means that it will remove the default (e.g. src/main/kotlin). And if you don't have Java, then it's nice to remove the Java dirs by setting an empty list.
r
Copy code
Build file '/Users/ray/test/build.gradle.kts' line: 1
* What went wrong:
Script compilation errors:

  Line 1: sourceSets {
          ^ Unresolved reference: sourceSets
on ./gradlew run
a
Hm, weird. What Gradle plugins have you applied (what's in the
plugins {}
block)?
r
Copy code
plugins {
    kotlin("jvm") version "1.9.23"
}

sourceSets.main {
    java.srcDirs("src/main/myJava", "src/main/myKotlin")
}
h
This is the most simplified Gradle setup for your use-case (without resources/java src). And yes, it can be improved in many ways (but this adds more complexity too).
r
what am I doing wrong then?
yours has sourceSets but doesnt crash
a
what version of Gradle do you have Ray?
I can't think of any explanation why you'd get that error
r
Copy code
------------------------------------------------------------
Gradle 8.6
------------------------------------------------------------

Build time:   2024-02-02 16:47:16 UTC
Revision:     d55c486870a0dc6f6278f53d21381396d0741c6e

Kotlin:       1.9.20
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          21.0.2 (Homebrew 21.0.2)
OS:           Mac OS X 14.2.1 aarch64
a
image.png
r
its this actually
Copy code
plugins {
    kotlin("jvm") version "1.9.23"
}

sourceSets.main {
    java.srcDirs("src/main/myJava", "src/main/myKotlin")
}
now this
Copy code
plugins {
    kotlin("jvm") version "1.9.23"
}

sourceSets {
    main {
        java.srcDirs("src/main/myJava", "src/main/myKotlin")
    }
}
gives
Copy code
* What went wrong:
Task 'run' not found in root project 'test'.

* Try:
> Run gradlew tasks to get a list of available tasks.
a
I don't see any problems there, either
r
man gradle has stolen actual days of my life in raw hours
a
I know that feel
r
everytime I want to use kotlin i stop wanting to becuse of gradle
a
To use
gradle run
you need to add the application plugin, and specify a main class https://kotlinlang.org/docs/get-started-with-jvm-gradle-project.html#explore-the-build-script
r
whatdoes the application plugin do?
r
how is that different form kotlin jvm?
a
Copy code
plugins {
    kotlin("jvm") version "1.9.23"
    application
}

sourceSets.main {
    java.srcDirs("src/main/myJava", "src/main/myKotlin")
}

application {
    mainClass.set("my.package.MainKt") // The main class of the application
}
This assumes you have a file
src/main/myKotlin/main.kt
, with
package my.package
at the top, and a
fun main() {}
r
an app that runs on ktolin jvm
a
Kotlin JVM compiles
.kt
files into
.class
files, and packages them into a
.jar
r
also I still dont understand
java.srcDirs("src/main/myJava", "src/main/myKotlin")
why is this in java.srcDirs
when it includes a kotlin folder
a
can you share a link to the page where the
java.srcDirs()
example is? I agree, it's confusing without context.
Oh, here it is https://kotlinlang.org/docs/gradle-configure-project.html#kotlin-and-java-sources
Kotlin sources and Java sources can be stored in the same directory, or they can be placed in different directories.
So I think the point of the example is to demonstrate how the directory names don't have to be strict. It's not an example of best practice. But the example doesn't make that clear, so I'm not sure...
r
all the motivation and energy I had 3 hours ago is gone now. no interest in coding my project now
if i have to read manuals to understand your build tool then your build tool was poorly designed
a
I get that this is frustrating, I find Gradle really frustrating too, but you are not going to find a build tool that doesn't require reading confusing docs and has janky behaviour
r
didn't ever have to do this with typescript or python
rust seemed more sensible too
first of all, the config file just should have all of the settings. right there
a
I'm feeling bummed out that you have asked for help, and have had several people providing multiple types of help, and you haven't said 'thanks'
r
i should never have to open up google and search for a rule
and i cannot possibly remember all of them
sorry. it is hard to remember to say thanks when you are currently frustrated with the few hours of your day being totally wasted on a miscellaneous tedium
that you absolutely will forget and have to redo all over in 3 months
thank you for your help of course.
Copy code
* What went wrong:
Execution failed for task ':run'.
> Could not resolve all files for configuration ':runtimeClasspath'.
   > Cannot resolve external dependency org.jetbrains.kotlin:kotlin-stdlib:1.9.23 because no repositories are defined.
     Required by:
         project :
like obviously I need to put a repositories {}
but what inside? maven? maven()? mavenCentral()? the kotlin docs dont immediately show it. general gradle docs tell me to do mavenCentral() which fails
another thing where you just have to know it from memory
OK, found it in the kotlin docs.
apologies and thanks to everyone. logging off now
v
also I still dont understand
java.srcDirs("src/main/myJava", "src/main/myKotlin")
why is this in java.srcDirs
I guess this is meant for when you mix Java and Kotlin and want to also have them side-by-side, so putting your Java classes into
src/main/myKotlin
too. But that's something to complain to the Kotlin docs that they don't make clear for which situation that snippet is meant.