I'm trying to upgrade a scala library to scala3 and cannot seem to figure out how to get the scala3 language to work with jlink. It says I'm missing transitive dependencies on a jlink build. You can see the build failure here.
I can of course add these to the jlinkIgnore
settings but that seems to be a poor practice. What are the transitive dependencies at play here that I am missing?
Here is a direct link to a CI failure https://github.com/bitcoin-s/bitcoin-s/actions/runs/15227451712/job/42831225145?pr=5713#step:5:23602
[error] Dependee packages not found in classpath. You can use jlinkIgnoreMissingDependency to silence these.
[error] org.apache.pekko.http.scaladsl.model -> org.apache.pekko.http.javadsl.model
[error] org.apache.pekko.stream.serialization -> org.apache.pekko.stream
[error] scala.quoted -> scala
[error] scala.quoted.runtime -> scala
[error] stack trace is suppressed; run last appServer / jlinkModules for the full output
[error] (appServer / jlinkModules) Missing package dependencies
Current reproduction is
git clone https://github.com/Christewart/bitcoin-s-core.git
cd bitcoin-s-core
git checkout 2024-05-11-scala3-crossbuild
git clone https://github.com/bitcoin-s/secp256k1-zkp.git
sbt appServer/universal:packageBin
Your CI fails on sbt appServer/universal:packageBin
. Locally it produces the error
[info] Running: jdeps --multi-release 21 -R /media/data/Projects2/bitcoin-s-core/app/server/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/app/server-routes/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/app-commons/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/core/.jvm/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/crypto/.jvm/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/secp256k1jni/target/classes /media/data/Projects2/bitcoin-s-core/db-commons/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/key-manager/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/node/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/async-utils/.jvm/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/chain/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/bitcoind-rpc/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/tor/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/wallet/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/fee-provider/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/dlc-wallet/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/dlc-node/target/scala-3.7.0/classes /media/data/Projects2/bitcoin-s-core/zmq/target/scala-3.7.0/classes /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.0/scala3-library_3-3.7.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/upickle_3/4.0.2/upickle_3-4.0.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.5.18/logback-classic-1.5.18.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-actor_3/1.1.3/pekko-actor_3-1.1.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-http_3/1.2.0/pekko-http_3-1.2.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-stream_3/1.1.3/pekko-stream_3-1.1.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-slf4j_3/1.1.3/pekko-slf4j_3-1.1.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/codehaus/janino/janino/3.1.12/janino-3.1.12.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/google/guava/guava/33.4.8-jre/guava-33.4.8-jre.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/dropwizard/metrics/metrics-healthchecks/4.2.30/metrics-healthchecks-4.2.30.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/dropwizard/metrics/metrics-jvm/4.2.30/metrics-jvm-4.2.30.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/dropwizard/metrics5/metrics-core/5.0.0/metrics-core-5.0.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/net/java/dev/jna/jna/5.17.0/jna-5.17.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/github/waffle/waffle-jna/3.5.1/waffle-jna-3.5.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/osgi/osgi.core/8.0.0/osgi.core-8.0.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/osgi/org.osgi.service.jdbc/1.1.0/org.osgi.service.jdbc-1.1.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/osgi/org.osgi.framework/1.10.0/org.osgi.framework-1.10.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/avalon-framework/avalon-framework/20020627/avalon-framework-20020627.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/logkit/logkit/20020529/logkit-20020529.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/tukaani/xz/1.10/xz-1.10.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/javax/servlet/javax.servlet-api/4.0.1/javax.servlet-api-4.0.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/javax/mail/mail/1.4.7/mail-1.4.7.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/javax/jms/javax.jms-api/2.0.1/javax.jms-api-2.0.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/playframework/play-json_3/3.0.4/play-json_3-3.0.4.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/typesafe/config/1.4.3/config-1.4.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/typesafe/slick/slick_3/3.6.1/slick_3-3.6.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/typesafe/slick/slick-hikaricp_3/3.6.1/slick-hikaricp_3-3.6.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.49.1.0/sqlite-jdbc-3.49.1.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/ujson_3/4.0.2/ujson_3-4.0.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/zeromq/jeromq/0.5.4/jeromq-0.5.4.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/upack_3/4.0.2/upack_3-4.0.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/upickle-implicits_3/4.0.2/upickle-implicits_3-4.0.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/ch/qos/logback/logback-core/1.5.18/logback-core-1.5.18.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.17/slf4j-api-2.0.17.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-http-core_3/1.2.0/pekko-http-core_3-1.2.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-protobuf-v3_3/1.1.3/pekko-protobuf-v3_3-1.1.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/typesafe/ssl-config-core_3/0.6.1/ssl-config-core_3-0.6.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/codehaus/janino/commons-compiler/3.1.12/commons-compiler-3.1.12.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.38.0/error_prone_annotations-2.38.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.3/failureaccess-1.0.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/3.0.0/j2objc-annotations-3.0.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/dropwizard/metrics/metrics-core/4.2.30/metrics-core-4.2.30.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.16.0/jna-platform-5.16.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/2.0.16/jcl-over-slf4j-2.0.16.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/checkerframework/checker-qual/3.48.3/checker-qual-3.48.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.15.11/byte-buddy-1.15.11.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.15.11/byte-buddy-agent-1.15.11.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/osgi/osgi.annotation/8.1.0/osgi.annotation-8.1.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/javax/activation/activation/1.1/activation-1.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/flywaydb/flyway-core/11.8.0/flyway-core-11.8.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/flywaydb/flyway-database-postgresql/11.8.0/flyway-database-postgresql-11.8.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/postgresql/postgresql/42.7.5/postgresql-42.7.5.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.80/bcprov-jdk18on-1.80.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scodec/scodec-bits_3/1.2.1/scodec-bits_3-1.2.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/playframework/play-functional_3/3.0.4/play-functional_3-3.0.4.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.14.3/jackson-datatype-jdk8-2.14.3.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.15.2/jackson-datatype-jsr310-2.15.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/monix/monix-execution_3/3.4.1/monix-execution_3-3.4.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/zaxxer/HikariCP/6.3.0/HikariCP-6.3.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/upickle-core_3/4.0.2/upickle-core_3-4.0.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/eu/neilalexander/jnacl/1.0.0/jnacl-1.0.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/apache/pekko/pekko-parsing_3/1.2.0/pekko-parsing_3-1.2.0.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/parboiled/parboiled_3/2.5.1/parboiled_3-2.5.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-toml/2.15.2/jackson-dataformat-toml-2.15.2.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/monix/monix-internal-jctools_3/3.4.1/monix-internal-jctools_3-3.4.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/io/monix/implicitbox_3/0.3.4/implicitbox_3-0.3.4.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/geny_3/1.1.1/geny_3-1.1.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scijava/native-lib-loader/2.5.0/native-lib-loader-2.5.0.jar
^^^^^^^^ <-------------
...
[error] Dependee packages not found in classpath. You can use jlinkIgnoreMissingDependency to silence these.
[error] org.apache.pekko.http.scaladsl.model -> org.apache.pekko.http.javadsl.model
[error] org.apache.pekko.stream.serialization -> org.apache.pekko.stream
[error] scala.quoted -> scala
[error] scala.quoted.runtime -> scala
[error] stack trace is suppressed; run last appServer / jlinkModules for the full output
[error] (appServer / jlinkModules) Missing package dependencies
[IJ]last appServer / jlinkModules
...
[error] java.lang.RuntimeException: Missing package dependencies
[error] at scala.sys.package$.error(package.scala:30)
[error] at com.typesafe.sbt.packager.archetypes.jlink.JlinkPlugin$.$anonfun$projectSettings$9(JlinkPlugin.scala:108)
[error] at scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:63)
[error] at sbt.std.Transform$$anon$4.work(Transform.scala:69)
[error] at sbt.Execute.$anonfun$submit$2(Execute.scala:283)
[error] at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:24)
[error] at sbt.Execute.work(Execute.scala:292)
[error] at sbt.Execute.$anonfun$submit$1(Execute.scala:283)
[error] at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] at sbt.CompletionService$$anon$2.call(CompletionService.scala:65)
[error] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[error] at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
[error] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[error] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[error] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[error] at java.base/java.lang.Thread.run(Thread.java:1583)
[error] (appServer / jlinkModules) Missing package dependencies
Notice the command jdeps ...
above.
https://docs.oracle.com/en/java/javase/11/tools/jdeps.html
Simpler reproduction is the following.
myscalaproject/src/main/scala/module-info.java
module myscalaproject {
exports com.example;
}
myscalaproject/src/main/scala/com/example/App.scala
package com.example
object App {
def main(args: Array[String]): Unit = {
println("hi")
}
}
myscalaproject/project/build.properties
sbt.version = 1.11.0
myscalaproject/project/plugins.sbt
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.1")
myscalaproject/build.sbt
Global / onChangedBuildSource := ReloadOnSourceChanges
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "2.13.16"
lazy val root = (project in file("."))
.settings(
name := "myscalaproject",
compileOrder := CompileOrder.ScalaThenJava,
packageOptions += Package.ManifestAttributes(
"Class-Path" -> "/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar"
),
Compile / mainClass := Some("com.example.App"),
//https://stackoverflow.com/questions/21461798/how-to-disable-scaladoc-generation-in-dist-task-in-play-2-2-x-using-project-bui
Compile / packageDoc / publishArtifact := false,
packageDoc / publishArtifact := false,
Compile / doc / sources := Seq.empty
)
.enablePlugins(
JavaAppPackaging,
JlinkPlugin,
)
sbt package
produces myscalaproject_2.13-0.1.0-SNAPSHOT.jar
.
Then jdeps
works properly:
jdeps -s -R mydir/myscalaproject_2.13-0.1.0-SNAPSHOT.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
myscalaproject -> java.base
myscalaproject -> /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
scala-library-2.13.16.jar -> java.base
myscala3project/src/main/scala/module-info.java
myscala3project/src/main/scala/com/example/App.scala
myscalaproject/project/build.properties
myscala3project/project/plugins.sbt
The same.
myscala3project/build.sbt
Global / onChangedBuildSource := ReloadOnSourceChanges
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "3.7.0"
lazy val root = (project in file("."))
.settings(
name := "myscala3project",
compileOrder := CompileOrder.ScalaThenJava,
packageOptions += Package.ManifestAttributes(
"Class-Path" -> Seq(
"/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar",
"/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.0/scala3-library_3-3.7.0.jar",
).mkString(" ")
),
Compile / mainClass := Some("com.example.App"),
//https://stackoverflow.com/questions/21461798/how-to-disable-scaladoc-generation-in-dist-task-in-play-2-2-x-using-project-bui
Compile / packageDoc / publishArtifact := false,
packageDoc / publishArtifact := false,
Compile / doc / sources := Seq.empty
)
.enablePlugins(
JavaAppPackaging,
JlinkPlugin,
)
jdeps
fails:
jdeps -s -R mydir/myscala3project_3-0.1.0-SNAPSHOT.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.0/scala3-library_3-3.7.0.jar
myscala3project -> java.base
myscala3project -> /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
myscala3project -> /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.0/scala3-library_3-3.7.0.jar
scala-library-2.13.16.jar -> java.base
scala3-library_3-3.7.0.jar -> java.base
scala3-library_3-3.7.0.jar -> jdk.unsupported
scala3-library_3-3.7.0.jar -> not found <------------- !!!
scala3-library_3-3.7.0.jar -> /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
You will see more details if you remove the summary flag -s
...
scala.quoted -> scala scala-library-2.13.16.jar
scala.quoted -> scala not found <------------- ???
...
scala.quoted.runtime -> scala scala-library-2.13.16.jar
scala.quoted.runtime -> scala not found <------------- ???
...
It seems there is a bug in jdeps
:
A: https://stackoverflow.com/a/75430512/5249621 (Q: jdeps returns "not found")
You can see the actual Path parser checks if the
-cp
/-classpath
argument list containsdir/.*
format and notdir/*
format as advertised by the docs, examples and the API's javadoc.
// wildcard to parse all JAR files e.g. -classpath dir/*
int i = p.lastIndexOf(".*");
JDK 11 Adoptium JDK 17 Adoptium JDK 21 Adoptium JDK 24 Adoptium JDK 24 Corretto OpenJDK
So if you don't want to patch jdk and jdeps
then it seems you should add those lines to jlinkIgnore
, indeed.
Update. Actually, the situation is a little more complicated. I patched OpenJDK 25 fixing jdeps
. On contrary to .split
, .lastIndexOf
doesn't support regex. So I replaced
int i = p.lastIndexOf(".*");
if (i > 0) {
Path dir = Paths.get(p.substring(0, i));
...
with
int i = lastIndex(p, ".\\*");
if (i > 0) {
Path dir = Paths.get(p.substring(0, i));
...
private int lastIndex(String str, String regex) {
String splitted[] = (str + " ").split(regex);
if (splitted.length == 0 || splitted.length == 1) {
return -1;
}
return str.length() - 1 - splitted[splitted.length - 1].length();
}
https://github.com/DmytroMitin/jdk/commit/9e601728961170940aee1356855f075557bae613
https://stackoverflow.com/a/10619920/5249621 ( Find Last Index Of by Regex in Java )
or just
int i = p.lastIndexOf("*");
if (i > 0) {
Path dir = Paths.get(p.substring(0, i - 1));
...
https://github.com/DmytroMitin/jdk/commit/381ea799460e959eec5a8000d837934fcd29946f
But still jdeps -s -R ...
(-s
stands for "summary", -R
for "recursively" i.e. transitive dependencies) produces not found
in some places:
https://github.com/DmytroMitin/so79636833_jdeps_bug_demo/actions/runs/15419307905/job/43389831125
(https://github.com/DmytroMitin/so79636833_jdeps_bug_demo - creating a module via module-info.java
seems not significant
https://github.com/DmytroMitin/setup-java
https://github.com/DmytroMitin/jdk25
https://github.com/DmytroMitin/jdk/tree/so79636833_jdeps_bug)
Run JDK 25 jdeps
jdeps -s -R /home/runner/work/so79636833_jdeps_bug_demo/so79636833_jdeps_bug_demo/target/scala-3.7.1/so79636833_jdeps_bug_demo_3-0.1.0-SNAPSHOT.jar /home/runner/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.1/scala3-library_3-3.7.1.jar /home/runner/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
scala-library-2.13.16.jar -> java.base
scala3-library_3-3.7.1.jar -> java.base
scala3-library_3-3.7.1.jar -> jdk.unsupported
scala3-library_3-3.7.1.jar -> not found <------------
scala3-library_3-3.7.1.jar -> /home/runner/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
so79636833_jdeps_bug_demo_3-0.1.0-SNAPSHOT.jar -> java.base
so79636833_jdeps_bug_demo_3-0.1.0-SNAPSHOT.jar -> /home/runner/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
I found better flags -v
("verbose" i.e. even more verbose than if just to remove -s
) and especially --missing-deps
jdeps --missing-deps -R target/scala-3.7.1/so79636833_jdeps_bug_demo_3-0.1.0-SNAPSHOT.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.1/scala3-library_3-3.7.1.jar /home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar
scala3-library_3-3.7.1.jar -> not found
scala.quoted.Quotes$reflectModule$TypeReprModule -> scala.AnyKind not found
scala.quoted.Quotes$reflectModule$TypeTreeModule -> scala.AnyKind not found
scala.quoted.Type -> scala.AnyKind not found
scala.quoted.Type$ -> scala.AnyKind not found
scala.quoted.runtime.QuoteUnpickler -> scala.AnyKind not found
So what confuses jdeps
in Scala 3 is scala.AnyKind
. And this makes sense. In Scala there are types present in sources but not in bytecode, or even some types not present either in sources or bytecode (e.g. ContextFunctionN
Can't create an anonymous implementation of ContextFunction1 in Scala 3). But scala.AnyKind
is a class present in sources but not in bytecode
https://www.scala-lang.org/api/current/scala/AnyKind.html
https://github.com/scala/scala3/blob/main/library-aux/src/scala/AnyKind.scala
Scala 3. Kind polymorphism and AnyKind type - any code example?
package scala
final abstract class AnyKind
Class.forName("scala.AnyKind") //java.lang.ClassNotFoundException
So the answer to your question
Either this bug is in the jlink tool itself or is something weird about the new scala3 system that didn't exist with scala2
is that it's both a bug in jlink (actually, jdeps) and something specific to Scala 3.
Here is the output of jdeps --missing-deps -R ...
for https://github.com/bitcoin-s/bitcoin-s
https://gist.github.com/DmytroMitin/6b6d9338dc8abe38bd15113f1cd0d915