Added option to specify the Kotlin compiler (kotlinc) path directly

This commit is contained in:
Erik C. Thauvin 2024-07-12 04:18:17 -07:00
parent 53681aa2ba
commit 7f3fc6ff95
Signed by: erik
GPG key ID: 776702A6A2DA330E
5 changed files with 118 additions and 64 deletions

View file

@ -8,7 +8,8 @@
[![Snapshot](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/snapshots/com/uwyn/rife2/bld-kotlin/maven-metadata.xml?label=snapshot)](https://repo.rife2.com/#/snapshots/com/uwyn/rife2/bld-kotlin) [![Snapshot](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/snapshots/com/uwyn/rife2/bld-kotlin/maven-metadata.xml?label=snapshot)](https://repo.rife2.com/#/snapshots/com/uwyn/rife2/bld-kotlin)
[![GitHub CI](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml) [![GitHub CI](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld-kotlin/actions/workflows/bld.yml)
To install, please refer to the [extensions](https://github.com/rife2/bld/wiki/Extensions) and [support](https://github.com/rife2/bld/wiki/Kotlin-Support) To install, please refer to the [extensions](https://github.com/rife2/bld/wiki/Extensions)
and [support](https://github.com/rife2/bld/wiki/Kotlin-Support)
documentation. documentation.
## Compile Kotlin Source Code ## Compile Kotlin Source Code
@ -16,6 +17,7 @@ documentation.
To compile the source code located in `src/main/kotlin` and `src/test/kotlin` from the current project: To compile the source code located in `src/main/kotlin` and `src/test/kotlin` from the current project:
```java ```java
@BuildCommand(summary = "Compiles the Kotlin project") @BuildCommand(summary = "Compiles the Kotlin project")
public void compile() throws Exception { public void compile() throws Exception {
new CompileKotlinOperation() new CompileKotlinOperation()
@ -30,16 +32,18 @@ public void compile() throws Exception {
- [View Examples Project](https://github.com/rife2/bld-kotlin/tree/main/examples/) - [View Examples Project](https://github.com/rife2/bld-kotlin/tree/main/examples/)
Please check the [Compile Operation documentation](https://rife2.github.io/bld-kotlin/rife/bld/extension/CompileKotlinOperation.html#method-summary) Please check
the [Compile Operation documentation](https://rife2.github.io/bld-kotlin/rife/bld/extension/CompileKotlinOperation.html#method-summary)
for all available configuration options. for all available configuration options.
## Kotlin Compiler Requirement ## Kotlin Compiler Requirement
Please make sure Kotlin is installed and that the `KOTLIN_HOME` environment variable is set. Please make sure the Kotlin compiler is [installed](https://kotlinlang.org/docs/command-line.html#install-the-compiler).
You can also manually configure the Kotlin home location as follows: You can also manually configure the Kotlin home location as follows:
```java ```java
@BuildCommand(summary = "Compiles the Kotlin project") @BuildCommand(summary = "Compiles the Kotlin project")
public void compile() throws Exception { public void compile() throws Exception {
new CompileKotlinOperation() new CompileKotlinOperation()
@ -49,8 +53,23 @@ public void compile() throws Exception {
} }
``` ```
While older version of Kotlin are likely working with the extension, only version 1.9.24 or higher are officially supported. The Kotlin compiler executable can also be specified directly:
```java
@BuildCommand(summary = "Compiles the Kotlin project")
public void compile() throws Exception {
new CompileKotlinOperation()
.fromProject(this)
.kotlinc("/usr/bin/kotlinc")
.execute();
}
```
While older version of Kotlin are likely working with the extension, only version 1.9.24 or higher are officially
supported.
## Template Project ## Template Project
There is also a [Template Project](https://github.com/rife2/kotlin-bld-example) with support for the [Dokka](https://github.com/rife2/bld-dokka) and [Detekt](https://github.com/rife2/bld-detekt) extensions. There is also a [Template Project](https://github.com/rife2/kotlin-bld-example) with support for
the [Dokka](https://github.com/rife2/bld-dokka) and [Detekt](https://github.com/rife2/bld-detekt) extensions.

View file

@ -18,5 +18,4 @@
## Requirements ## Requirements
- Kotlin installed - A Kotlin compiler must be [installed](https://kotlinlang.org/docs/command-line.html#install-the-compiler).
- `KOTLIN_HOME` environment variable set

View file

@ -5,7 +5,6 @@ import rife.bld.Project;
import rife.bld.extension.CompileKotlinOperation; import rife.bld.extension.CompileKotlinOperation;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.logging.ConsoleHandler; import java.util.logging.ConsoleHandler;
import java.util.logging.Level; import java.util.logging.Level;
@ -43,14 +42,14 @@ public class ExampleBuild extends Project {
public static void main(String[] args) { public static void main(String[] args) {
// Enable detailed logging for the Kotlin extension // Enable detailed logging for the Kotlin extension
var level = Level.ALL; var level = Level.ALL;
var logger = Logger.getLogger("rife.bld.extension"); var logger = Logger.getLogger("rife.bld.extension");
var consoleHandler = new ConsoleHandler(); var consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(level); consoleHandler.setLevel(level);
logger.addHandler(consoleHandler); logger.addHandler(consoleHandler);
logger.setLevel(level); logger.setLevel(level);
logger.setUseParentHandlers(false); logger.setUseParentHandlers(false);
new ExampleBuild().start(args); new ExampleBuild().start(args);
} }
@ -61,6 +60,8 @@ public class ExampleBuild extends Project {
// The source code located in src/main/kotlin and src/test/kotlin will be compiled // The source code located in src/main/kotlin and src/test/kotlin will be compiled
new CompileKotlinOperation() new CompileKotlinOperation()
.fromProject(this) .fromProject(this)
// .kotlinHome("path/to/kotlin")
// .kotlinc("path/to/kotlinc")
.execute(); .execute();
// var op = new CompileKotlinOperation().fromProject(this); // var op = new CompileKotlinOperation().fromProject(this);

View file

@ -52,6 +52,7 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
private File buildTestDirectory_; private File buildTestDirectory_;
private CompileOptions compileOptions_ = new CompileOptions(); private CompileOptions compileOptions_ = new CompileOptions();
private File kotlinHome_; private File kotlinHome_;
private File kotlinc_;
private BaseProject project_; private BaseProject project_;
private File workDir_; private File workDir_;
@ -205,13 +206,6 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE); throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
} }
if (kotlinHome_ == null) {
if (LOGGER.isLoggable(Level.SEVERE) && !silent()) {
LOGGER.severe("The KOTLIN_HOME environment variable is not set.");
}
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
}
executeCreateBuildDirectories(); executeCreateBuildDirectories();
executeBuildMainSources(); executeBuildMainSources();
executeBuildTestSources(); executeBuildTestSources();
@ -227,7 +221,7 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
* @throws ExitStatusException if an error occurs * @throws ExitStatusException if an error occurs
*/ */
@SuppressWarnings("PMD.SystemPrintln") @SuppressWarnings("PMD.SystemPrintln")
protected void executeBuildMainSources() throws ExitStatusException, IOException, InterruptedException { protected void executeBuildMainSources() throws ExitStatusException {
if (!silent()) { if (!silent()) {
System.out.println("Compiling Kotlin main sources."); System.out.println("Compiling Kotlin main sources.");
} }
@ -248,62 +242,61 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
* @param friendPaths the output directory for friendly modules * @param friendPaths the output directory for friendly modules
* @throws ExitStatusException if an error occurs * @throws ExitStatusException if an error occurs
*/ */
@SuppressWarnings("PMD.PreserveStackTrace")
protected void executeBuildSources(Collection<String> classpath, Collection<File> sources, File destination, protected void executeBuildSources(Collection<String> classpath, Collection<File> sources, File destination,
File friendPaths) File friendPaths)
throws ExitStatusException, InterruptedException, IOException { throws ExitStatusException {
if (sources.isEmpty() || destination == null) { if (sources.isEmpty() || destination == null) {
return; return;
} }
var kotlinc = Path.of(kotlinHome_.getAbsolutePath(), "bin", "kotlinc").toFile(); var args = new ArrayList<String>();
if (kotlinc.exists() && kotlinc.canExecute()) { // kotlinc
var args = new ArrayList<String>(); args.add(kotlinCompiler());
// kotlinc // classpath
args.add(kotlinc.getAbsolutePath()); args.add("-cp");
args.add(FileUtils.joinPaths(classpath.stream().toList()));
// classpath // destination
args.add("-cp"); args.add("-d");
args.add(FileUtils.joinPaths(classpath.stream().toList())); args.add(destination.getAbsolutePath());
// destination // friend-path
args.add("-d"); if (friendPaths != null && friendPaths.exists()) {
args.add(destination.getAbsolutePath()); args.add("-Xfriend-paths=" + friendPaths.getAbsolutePath());
}
// friend-path // options
if (friendPaths != null && friendPaths.exists()) { if (compileOptions_ != null) {
args.add("-Xfriend-paths=" + friendPaths.getAbsolutePath()); args.addAll(compileOptions_.args());
} }
// options // plugins
if (compileOptions_ != null) { if (!plugins_.isEmpty()) {
args.addAll(compileOptions_.args()); plugins_.forEach(p -> args.add("-Xplugin=" + p));
} }
// plugins // sources
if (!plugins_.isEmpty()) { sources.forEach(f -> args.add(f.getAbsolutePath()));
plugins_.forEach(p -> args.add("-Xplugin=" + p));
}
// sources if (LOGGER.isLoggable(Level.FINE) && !silent()) {
sources.forEach(f -> args.add(f.getAbsolutePath())); LOGGER.fine(String.join(" ", args));
}
if (LOGGER.isLoggable(Level.FINE) && !silent()) { var pb = new ProcessBuilder();
LOGGER.fine(String.join(" ", args)); pb.inheritIO();
} pb.command(args);
pb.directory(workDir_);
var pb = new ProcessBuilder();
pb.inheritIO();
pb.command(args);
pb.directory(workDir_);
try {
var proc = pb.start(); var proc = pb.start();
proc.waitFor(); proc.waitFor();
ExitStatusException.throwOnFailure(proc.exitValue()); ExitStatusException.throwOnFailure(proc.exitValue());
} else { } catch (IOException | InterruptedException e) {
if (LOGGER.isLoggable(Level.SEVERE) && !silent()) { if (LOGGER.isLoggable(Level.SEVERE) && !silent()) {
LOGGER.severe("The Kotlin compiler could not be found or executed: " + kotlinc.getAbsolutePath()); LOGGER.severe(e.getLocalizedMessage());
} }
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE); throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
} }
@ -315,7 +308,7 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
* @throws ExitStatusException if an error occurs * @throws ExitStatusException if an error occurs
*/ */
@SuppressWarnings("PMD.SystemPrintln") @SuppressWarnings("PMD.SystemPrintln")
protected void executeBuildTestSources() throws ExitStatusException, IOException, InterruptedException { protected void executeBuildTestSources() throws ExitStatusException {
if (!silent()) { if (!silent()) {
System.out.println("Compiling Kotlin test sources."); System.out.println("Compiling Kotlin test sources.");
} }
@ -386,6 +379,18 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
return op; return op;
} }
private String kotlinCompiler() {
if (kotlinc_ != null) {
return kotlinc_.getAbsolutePath();
} else if (kotlinHome_ != null) {
var kotlinc = Path.of(kotlinHome_.getAbsolutePath(), "bin", "kotlinc").toFile();
if (kotlinc.exists() && kotlinc.canExecute()) {
return kotlinc.getAbsolutePath();
}
}
return "kotlinc";
}
/** /**
* Provides the Kotlin home directory, if it differs from the default {@code KOTLIN_HOME}. * Provides the Kotlin home directory, if it differs from the default {@code KOTLIN_HOME}.
* *
@ -416,6 +421,36 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
return kotlinHome_; return kotlinHome_;
} }
/**
* Retrieves the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @return the executable path
*/
public File kotlinc() {
return kotlinc_;
}
/**
* Provides the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @param executable the executable path
* @return this operation instance
*/
public CompileKotlinOperation kotlinc(File executable) {
kotlinc_ = executable;
return this;
}
/**
* Provides the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @param executable the executable path
* @return this operation instance
*/
public CompileKotlinOperation kotlinc(String executable) {
return kotlinc(new File(executable));
}
/** /**
* Provides main source directories that should be compiled. * Provides main source directories that should be compiled.
* *
@ -546,9 +581,7 @@ public class CompileKotlinOperation extends AbstractOperation<CompileKotlinOpera
} }
/** /**
* Provides compiler plugins. * Provides compiler plugins located in the {@link #kotlinHome()} lib directory.
* <p>
* The {@link #kotlinHome()} should be set first.
* *
* @param plugins one or more plugins * @param plugins one or more plugins
* @return this class instance * @return this class instance

View file

@ -54,6 +54,7 @@ class CompileKotlinOperationTest {
var op = new CompileKotlinOperation() var op = new CompileKotlinOperation()
.fromProject(new Project()) .fromProject(new Project())
.kotlinHome("/kotlin_home") .kotlinHome("/kotlin_home")
.kotlinc("kotlinc")
.workDir("work_dir") .workDir("work_dir")
.compileMainClasspath("path1", "path2") .compileMainClasspath("path1", "path2")
.compileOptions(new CompileOptions().jdkRelease("17").verbose(true)) .compileOptions(new CompileOptions().jdkRelease("17").verbose(true))
@ -75,6 +76,7 @@ class CompileKotlinOperationTest {
CompilerPlugin.ALL_OPEN, CompilerPlugin.SAM_WITH_RECEIVER); CompilerPlugin.ALL_OPEN, CompilerPlugin.SAM_WITH_RECEIVER);
assertThat(op.kotlinHome().getName()).as("kotlin_home").isEqualTo("kotlin_home"); assertThat(op.kotlinHome().getName()).as("kotlin_home").isEqualTo("kotlin_home");
assertThat(op.kotlinc().getName()).as("kotlinc").isEqualTo("kotlinc");
assertThat(op.workDir().getName()).as("work_dir").isEqualTo("work_dir"); assertThat(op.workDir().getName()).as("work_dir").isEqualTo("work_dir");
assertThat(op.compileMainClasspath()).as("compileMainClassPath") assertThat(op.compileMainClasspath()).as("compileMainClassPath")