All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fizzed.blaze.kotlin.KotlinCompiler Maven / Gradle / Ivy

/*
 * Copyright 2016 Fizzed, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.fizzed.blaze.kotlin;

import com.fizzed.blaze.core.CompilationException;
import com.fizzed.blaze.internal.ClassLoaderHelper;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler;
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
import org.jetbrains.kotlin.com.intellij.openapi.Disposable;
import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer;
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.utils.PathUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;

/**
 * Compiles .kt files to .class files that are saved on the filesystem
 * for later re-use.  Based loosely on:
 * 
 *   https://github.com/JetBrains/kotlin/blob/d89e907f00e7a93a715d540255d98bbe8da57b3e/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.java
 *   https://github.com/JetBrains/kotlin/blob/9a762e0fa282deac1ca48ee15e548325b1e7ab2b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/ExecuteKotlinScriptMojo.java
 * 
 * @author joelauer
 */
public class KotlinCompiler {
    static private final Logger log = LoggerFactory.getLogger(KotlinCompiler.class);

    private final ClassLoader classLoader;
    
    public KotlinCompiler(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void compile(Path file, Path classesDir, boolean isScript) throws CompilationException {
        // collect and log errors and warnings as compilation occurs
        CountingSLF4JMessageCollector messageCollector = new CountingSLF4JMessageCollector(log);

        // build kotline compiler configuration
        CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
        compilerConfiguration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector);
        //compilerConfiguration.put(JVMConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME);

        /*List jdkClassesRootsFromCurrentJre = ;
        System.out.println("jdkClassesRootsFromCurrentJre: " + jdkClassesRootsFromCurrentJre);

        List jvmClassPath = ClassLoaderHelper.buildJvmClassPath();
        System.out.println("jvmClassPath: " + jvmClassPath);*/

        /*List modFiles;
        try {
            modFiles = Files.list(Paths.get("/usr/lib/jvm/current/jmods/"))
                .map(v -> v.toFile())
                .collect(Collectors.toList());
            System.out.println("modFiles: " + modFiles);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
        JvmContentRootsKt.addJvmClasspathRoots(compilerConfiguration, modFiles);*/

        // java 8 requires this for its .jars to compile kotlin, for anything else only the "JDK_HOME" set below was key
        JvmContentRootsKt.addJvmClasspathRoots(compilerConfiguration, PathUtil.getJdkClassesRootsFromCurrentJre());
        JvmContentRootsKt.addJvmClasspathRoots(compilerConfiguration, ClassLoaderHelper.buildClassPathAsFiles(classLoader));
        JvmContentRootsKt.addJvmClasspathRoots(compilerConfiguration, ClassLoaderHelper.buildJvmClassPath());
        ContentRootsKt.addKotlinSourceRoot(compilerConfiguration, file.toAbsolutePath().toString());
        // NOTE: Kotlin v1.0.2+ moved this config key around and will break
        // when we bump up the version down the road. Kotlin is a moving target
        // with changing how its compiler internally is called
        //compilerConfiguration.add(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY, StandardScriptDefinition.INSTANCE);

        //List classRoots = PathUtil.getJdkClassesRootsFromCurrentJre().stream().map(v -> v.toString()).collect(Collectors.toList());

        compilerConfiguration.put(JVMConfigurationKeys.FRIEND_PATHS, new ArrayList<>());
        compilerConfiguration.put(CommonConfigurationKeys.MODULE_NAME, "blaze");
        compilerConfiguration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, classesDir.toFile());
//        compilerConfiguration.put(JVMConfigurationKeys.JDK_HOME, Paths.get("/usr/lib/jvm/current").toFile());
        // java 9, 11+ this is apparently needed for a "modular" jdk
        compilerConfiguration.put(JVMConfigurationKeys.JDK_HOME, Paths.get(System.getProperty("java.home")).toFile());

        Disposable disposable = Disposer.newDisposable();
        try {
            KotlinCoreEnvironment env = KotlinCoreEnvironment.createForProduction(
                disposable, compilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES);

            env.addKotlinSourceRoots(Collections.singletonList(file.toAbsolutePath().toFile()));
            
            boolean compiled = 
                KotlinToJVMBytecodeCompiler.INSTANCE.compileBunchOfSources(env);

            if (!compiled) {
                throw new CompilationException("Unable to cleanly compile " + file
                    + " (" + messageCollector.getErrors() + " errors, "
                    + messageCollector.getWarnings() + " warnings)");
            }
        } finally {
            Disposer.dispose(disposable);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy