scalasbtscala-3sbt-native-packagerjlink

Fix missing transnitive dependencies with jlink and scala3 `scala.quoted -> scala `


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

Solution

  • 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 contains dir/.* format and not dir/* 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