Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Automatically add -release option when needed #2172

Merged
merged 3 commits into from
Oct 13, 2023

Conversation

tgodzik
Copy link
Contributor

@tgodzik tgodzik commented Oct 10, 2023

Previously, if we compiled with a Bloop running an newer JDK we would not see any errors even when using methods belonging to a newer JDK. Now, we automatically add -release flag, which makes sure that we will fail any compilation that should not pass with an older JDK (if specified in configuration)

This is needed for incorporating the forks.

Previously, if we compiled with a Bloop running an newer JDK we would not see any errors even when using methods belonging to a newer JDK. Now, we automatically add -release flag, which makes sure that we will fail any compilation that should not pass with an older JDK (if specified in configuration)
@tgodzik tgodzik marked this pull request as ready for review October 10, 2023 17:09
@tgodzik tgodzik requested review from adpi2 and ckipp01 October 10, 2023 17:10
inputs.scalacOptions ++ List("-release", numVer.toString())
} else {
logger.warn(
s"Bloop is run with ${JavaRuntime.version} but your code requires $version to compile, " +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
s"Bloop is run with ${JavaRuntime.version} but your code requires $version to compile, " +
s"Bloop is running with ${JavaRuntime.version} but your code requires $version to compile, " +

Should we maybe change it to running to hint at the fact that it needs to stop and be restarted with that version if necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines 294 to 298
def existsReleaseSetting = inputs.scalacOptions.exists(opt =>
opt.startsWith("-release") ||
opt.startsWith("--release") ||
opt.startsWith("-java-output-version")
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd extract getCompilationOptions to standalone function, not nested one. Compile is already too long and complicated without your changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, extracted!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting that method helped me realize one thing, the main complexity of getCompilationOptions is connected with adjusting scalac options with release flag if needed. That is why I think it's worth to extract another function, which I hope makes getCompilationOptions even easier and allows to explain why there is need for adding release flag in the first place. I put some scaladoc based on your replies, but it definitely needs to be improved. I'm leaving this as a suggestion, it's up to you to decide whether extract another function or not.

adjustScalacOptions
  /**
   * Bloop runs Scala compilation in the same process as the main server,
   * so the compilation process will use the same JDK that Bloop is using.
   * That's why we must ensure that produce class files will be compliant with expected JDK version.
   */
  private def adjustScalacOptions(
      scalacOptions: Array[String],
      javacBin: Option[AbsolutePath],
      logger: Logger
  ): Array[String] = {
    def existsReleaseSetting = scalacOptions.exists(opt =>
      opt.startsWith("-release") ||
        opt.startsWith("--release") ||
        opt.startsWith("-java-output-version")
    )
    def sameHome = javacBin match {
      case Some(bin) => bin.getParent.getParent == JavaRuntime.home
      case None => false
    }

    javacBin.flatMap(binary =>
      // <JAVA_HOME>/bin/java
      JavaRuntime.getJavaVersionFromJavaHome(binary.getParent.getParent)
    ) match {
      case None => scalacOptions
      case Some(_) if existsReleaseSetting || sameHome => scalacOptions
      case Some(version) =>
        try {
          val numVer = if (version.startsWith("1.8")) 8 else version.takeWhile(_.isDigit).toInt
          val bloopNumVer = JavaRuntime.version.takeWhile(_.isDigit).toInt
          if (bloopNumVer > numVer) {
            scalacOptions ++ List("-release", numVer.toString())
          } else {
            logger.warn(
              s"Bloop is runing with ${JavaRuntime.version} but your code requires $version to compile, " +
                "this might cause some compilation issues when using JDK API unsupported by the Bloop's current JVM version"
            )
            scalacOptions
          }
        } catch {
          case NonFatal(_) =>
            scalacOptions
        }
    }
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done!

Comment on lines 305 to 306
// <JAVA_HOME>/bin/java
JavaRuntime.getJavaVersionFromJavaHome(binary.getParent.getParent)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is checking java home relevant? I thought that what's important is checking current java version of the bloop process?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the java version of Java we are compiling with, not the Java version Bloop is using. The latter is below in line 313 val bloopNumVer = JavaRuntime.version.takeWhile(_.isDigit).toInt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also in case this wasn't clear. Bloop runs Scala compilation in the same process as the main server, so the compilation process will use the JDK from Bloop unless we specify the release flag.

@tgodzik tgodzik requested a review from kpodsiad October 11, 2023 15:22
backend/src/main/scala/bloop/Compiler.scala Outdated Show resolved Hide resolved
Comment on lines 294 to 298
def existsReleaseSetting = inputs.scalacOptions.exists(opt =>
opt.startsWith("-release") ||
opt.startsWith("--release") ||
opt.startsWith("-java-output-version")
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting that method helped me realize one thing, the main complexity of getCompilationOptions is connected with adjusting scalac options with release flag if needed. That is why I think it's worth to extract another function, which I hope makes getCompilationOptions even easier and allows to explain why there is need for adding release flag in the first place. I put some scaladoc based on your replies, but it definitely needs to be improved. I'm leaving this as a suggestion, it's up to you to decide whether extract another function or not.

adjustScalacOptions
  /**
   * Bloop runs Scala compilation in the same process as the main server,
   * so the compilation process will use the same JDK that Bloop is using.
   * That's why we must ensure that produce class files will be compliant with expected JDK version.
   */
  private def adjustScalacOptions(
      scalacOptions: Array[String],
      javacBin: Option[AbsolutePath],
      logger: Logger
  ): Array[String] = {
    def existsReleaseSetting = scalacOptions.exists(opt =>
      opt.startsWith("-release") ||
        opt.startsWith("--release") ||
        opt.startsWith("-java-output-version")
    )
    def sameHome = javacBin match {
      case Some(bin) => bin.getParent.getParent == JavaRuntime.home
      case None => false
    }

    javacBin.flatMap(binary =>
      // <JAVA_HOME>/bin/java
      JavaRuntime.getJavaVersionFromJavaHome(binary.getParent.getParent)
    ) match {
      case None => scalacOptions
      case Some(_) if existsReleaseSetting || sameHome => scalacOptions
      case Some(version) =>
        try {
          val numVer = if (version.startsWith("1.8")) 8 else version.takeWhile(_.isDigit).toInt
          val bloopNumVer = JavaRuntime.version.takeWhile(_.isDigit).toInt
          if (bloopNumVer > numVer) {
            scalacOptions ++ List("-release", numVer.toString())
          } else {
            logger.warn(
              s"Bloop is runing with ${JavaRuntime.version} but your code requires $version to compile, " +
                "this might cause some compilation issues when using JDK API unsupported by the Bloop's current JVM version"
            )
            scalacOptions
          }
        } catch {
          case NonFatal(_) =>
            scalacOptions
        }
    }
  }

@tgodzik tgodzik requested a review from kpodsiad October 12, 2023 10:26
Copy link
Collaborator

@kpodsiad kpodsiad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@tgodzik tgodzik force-pushed the release-version branch 4 times, most recently from 13b7606 to a677ec4 Compare October 12, 2023 15:31
@tgodzik tgodzik merged commit d6b7fa6 into scalacenter:main Oct 13, 2023
17 checks passed
@tgodzik tgodzik deleted the release-version branch October 13, 2023 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants