Anyone getting: ```exception: java.lang.ClassNotFo...
# scripting
p
Anyone getting:
Copy code
exception: java.lang.ClassNotFoundException: kotlin.script.experimental.dependencies.Repository
when compiling their main.kts files? I think it started since Kotlin 2.4.0
👌 1
i
Can you give some more details please? It works fine in tests for me.
p
sure, here's a log from GitHub Actions: https://github.com/typesafegithub/github-actions-typing-catalog/actions/runs/27461150997/job/81175122104 will try to come up with a minimal reproducer
i
Well, in your example you're compiling a main-kts script as a regular source without specifying main-kts jar as a dependency, so the annotation is not in the dependencies. You either need to add the jar to
-cp
or use
-script
. The latter "magically" adds definition jar into classpath. Have you seen it working before?
p
adding
-script
indeed fixed the issue, but still reporting it as some kind of a regression
e
Good to know 🙂
👍 1
i
Please tell me what was executed behind the
⁣Compiling ./.github/workflows/update-typings.main.kts
before, and what it is now. Adding
-script
is maybe not what you want, it is a command to execute the script, not to compile it. So if under this line, I assume, you're compiling the script, you need to use
-cp
variant.
v
I think it should indeed just verify that all committed
*.main.kts
files are compiling properly, but not execute them. So yes, specifying the classpath until Kotlin fixes it, is probably the better work-around. With 2.3.10 and a script that does just
println("FOO")
, running like shown in the issue just compiles the script, using
-script
executes it. Just that with 2.3.10 it just worked as the jar was automatically added to the classpath.
i
So yes, specifying the classpath until Kotlin fixes it, is probably the better work-around.
I do not think that we should fix it, tbh. I rather think that the old functionality is incorrect.
v
Really? Why? The main.kts is a built-in script definition and before it just handled it properly. With the new behavior you could not simply use
kotlinc
to compile the script, but have to look up where the jar is lying around to specify it on the classpath, or is there some magic
[kotlin installation]/lib/kotlin-main-kts.jar
you could specify?
i
Well, the fact that you need to use -X options to make it compile already should hint that you're using some non-standard stuff. For all other script definitions, the correct way to run/compile them is to either specify the definition via dedicated cli options or to use the discovery mechanism by placing the definitions jar to the classpath. The
main-kts
is a script supported by default but intended for running with the
-script
option. So the magic was added: if you're using
-script
with
main.kts
, you don't need anything else, no
-X
-es, no classpath, it all happens automatically. In all other scenarios (including compiling of the script that is not designed to be compiled along with other sources), you need to instruct the compiler with all details.
v
So then how would you correctly compile a
*.main.kts
script without executing it and without using
-X
-es?
i
You cannot do it without
-Xallow-any-scripts-in-source-roots
and
-cp
, but the compilation of scripts is a non-standard operation. A script definition is either designed for running, using the
-script
option, as in the
main-kts
case. Or a definition could be designed for compiling along with sources using the configuration property
isStandalone(false)
. In the latter case, as in the case when you're using
-Xallow-any-scripts-in-source-roots
, you need to be aware of the implementation details of the script compilation, namely what object will be generated from the script, and how you should consume it. It is quite an advanced case, and the result is not a public API/ABI, is not stable, and can be changing from release to release. So my assumption is that most likely you don't need to compile the main-kts script per se; you probably want to run it eventually.
v
Well, the check was - but @Piotr KrzemiƄski has to confirm - just to ensure they do compile without actually running them.
Otherwise he could also just have called the scripts like he does with some specific ones further below where the outcome also is verified.
i
If there is a good reason for it, please create an issue with the feature request for
-script-verify
or something. But I still believe that the original issue should not be fixed.
p
in this particular case, I agree that only compiling the scripts may be surplus, as running them has a simple side effect: just updates some YAML files locally. But as a generic case, I can imagine that running some script has some serious side effects so we run the script in well-defined moments, but we want to continuously check if it compiles fine, so I think the use case of just compiling is legit (if it's popular - TBD)
to ensure that 2.3.21 worked fine wrt. just compilation, I put this into the script:
Copy code
#!/usr/bin/env kotlin

println("Hello world! The script is executed. To show it, let's throw")
error("ERROR")
and called:
Copy code
% kotlinc -Xallow-any-scripts-in-source-roots -Xuse-fir-lt=false .github/workflows/test.main.kts
% kotlinc -script -Xallow-any-scripts-in-source-roots -Xuse-fir-lt=false .github/workflows/test.main.kts
Hello world! The script is executed. To show it, let's throw
java.lang.IllegalStateException: ERROR
	at Test_main.<init>(test.main.kts:4)
so we see that only after adding
-script
, the script was executed
v
Yes, hat's what I tried and said above already. 😉
i
but we want to continuously check if it compiles fine
This could be a valid justification for some "dry"/"verify" feature, so please file an issue with the feature request. Meanwhile, please use
-Xallow-any-scripts-in-source-roots
+
-cp
for the case.
BTW, you can also implement your own host app that combines a regular script compiler with the
BasicJvmScriptJarGenerator
as an evaluator, and the latter generates a runnable jar from the script, so the execution part will become much cheaper.
v
Sounds interesting, but not really applicable in this case 🙂
p
ok, so I want to do it the right/new way, and came up with this one-liner:
Copy code
kotlinc -cp $(dirname $(dirname $(which kotlin)))/lib/kotlin-main-kts.jar -Xallow-any-scripts-in-source-roots -Xuse-fir-lt=false .github/workflows/test.main.kts
results in:
Copy code
exception: java.lang.ClassNotFoundException: kotlin.script.experimental.dependencies.Repository
works this way both in 2.3.21 and 2.4.0.
$(dirname $(dirname $(which kotlin)))/lib/kotlin-main-kts.jar
alone resolves to the existing JAR correctly. Maybe the JAR is wrong? Tried other JARs from Kotlin's
lib/
dir, doesn't work
v
Run with
-verbose
and you see the classpath it uses
Or are there maybe spaces in the path that you need to escape or quote?
p
from the invocation with
-script
and `-verbose`:
Copy code
logging: configure scripting: Added template org.jetbrains.kotlin.mainKts.MainKtsScript from [/Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-main-kts.jar, /Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-reflect.jar, /Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-script-runtime.jar, /Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-stdlib.jar]
so calling the compiler to compile:
Copy code
kotlinc -cp "$(dirname $(dirname $(which kotlin)))/lib/kotlin-main-kts.jar:$(dirname $(dirname $(which kotlin)))/lib/kotlin-reflect.jar:$(dirname $(dirname $(which kotlin)))/lib/kotlin-script-runtime.jar:$(dirname $(dirname $(which kotlin)))/lib/kotlin-stdlib.jar" -Xallow-any-scripts-in-source-roots -Xuse-fir-lt=false .github/workflows/test.main.kts
still fails with
Copy code
exception: java.lang.ClassNotFoundException: kotlin.script.experimental.dependencies.Repository
looks like
kotlinc
(the compiler) is better at running the scripts than in compiling them đŸ€” I'd expect the invocation of
kotlinc
to be as simple as possible to just compile because that's why I call this specific binary: kotlin*c*
v
Just to make sure, what does it output if you prefix it with
echo
?
p
Copy code
echo "$(dirname $(dirname $(which kotlin)))/lib/kotlin-main-kts.jar:$(dirname $(dirname $(which kotlin)))/lib/kotlin-reflect.jar:$(dirname $(dirname $(which kotlin)))/lib/kotlin-script-runtime.jar:$(dirname $(dirname $(which kotlin)))/lib/kotlin-stdlib.jar"
/Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-main-kts.jar:/Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-reflect.jar:/Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-script-runtime.jar:/Users/piotr/.sdkman/candidates/kotlin/2.4.0/lib/kotlin-stdlib.jar
did you mean this?
👌 1
i
Can you try adding
kotlin-stdlib
and
kotlin-reflect
to the classpath?
p
they are there, please see above
i
What is the output of
Copy code
jar tf "$(dirname $(dirname $(which kotlin)))/lib/kotlin-main-kts.jar" | grep dependencies/Repository.class
?
p
Copy code
kotlin/script/experimental/dependencies/Repository.class
looks sane
i
Please try without
-Xuse-fir-lt=false
You don't need stdlib/reflect too
p
got a bunch of compilation errors related to the lack of classes from libraries added by
@file:DependsOn(...)
, which is a step forward, but how do I attach them to the classpath - where are they downloaded? is it a deterministic location?
i
Is it on 2.4?
p
yes:
Copy code
kotlinc -version
info: kotlinc-jvm 2.4.0 (JRE 23.0.1+11-39)
đŸ€” 1
v
The location is the usual maven local repository / cache. But probably only if you actually execute the script if it does not just work once you got the script host to be used.
👍 1
Also, if KT-87047 per-se is not going to be "fixed", then it can maybe right away the
-verify-script
FR 🙂
👍 1