Update builder to support building from a JDK9 host_javabase (#82)

* script to work with a bazel process from head

* adjust the script so that it can set the host_jb and the jb

* get build working under jdk9 host_javabase
diff --git a/Makefile b/Makefile
index 1d86e39..438e0b0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,11 @@
-test.smoke:
+test:
 	bazel test all_tests
 
+test.no_worker:
+	bazel clean
+	bazel shutdown
+	bazel test --strategy=KotlinCompile=local //:all_tests
+
 reformat:
 	buildifier -mode=fix -v kotlin/*.bzl
 	buildifier -mode=fix -v kotlin/internal/*.bzl
diff --git a/examples/dagger/BUILD b/examples/dagger/BUILD
index 36685f7..5c6ac7e 100644
--- a/examples/dagger/BUILD
+++ b/examples/dagger/BUILD
@@ -49,6 +49,7 @@
 }
 EOF
 external/local_jdk/bin/jar -cf $@ TeaPot.kt
+rm TeaPot.kt
 """,
     outs = ["donkey.srcjar"]
 )
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt
index 5b4baae..9e69452 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt
@@ -131,7 +131,7 @@
                 }
 
                 if (plugins.annotationProcessorsList.isNotEmpty()) {
-                    addAllEncodedPluginDescriptors(pluginEncoder.encode(root.outputs, root.info.plugins))
+                    addAllEncodedPluginDescriptors(pluginEncoder.encode(root))
                 }
 
                 label.split(":").also {
@@ -174,7 +174,5 @@
             }
         }
     }
-
-    private fun String?.supplyIfNullOrBlank(s: () -> String): String = this?.takeIf { it.isNotBlank() } ?: s()
 }
 
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchain.kt b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchain.kt
index 36be75f..8efabd0 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchain.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchain.kt
@@ -15,11 +15,10 @@
  */
 package io.bazel.kotlin.builder
 
+import com.google.common.collect.ImmutableSet
 import com.google.inject.*
 import com.google.inject.util.Modules
-import io.bazel.kotlin.builder.utils.executeAndAwait
 import io.bazel.kotlin.builder.utils.resolveVerified
-import io.bazel.kotlin.builder.utils.verifiedRelativeFiles
 import org.jetbrains.kotlin.preloading.ClassPreloadingUtils
 import org.jetbrains.kotlin.preloading.Preloader
 import java.io.File
@@ -27,44 +26,70 @@
 import java.io.PrintWriter
 import java.nio.file.Path
 import java.nio.file.Paths
+import javax.inject.Qualifier
 
-class KotlinToolchain constructor(
-    val kotlinLibraryDirectory: Path,
-    val kotlinStandardLibraries: Array<String> = arrayOf(
+class KotlinToolchain private constructor(
+    internal val javaHome: Path,
+    val kotlinHome: Path,
+    internal val classLoader: ClassLoader,
+    val kotlinStandardLibraries: ImmutableSet<String> = ImmutableSet.of(
         "kotlin-stdlib.jar",
         "kotlin-stdlib-jdk7.jar",
         "kotlin-stdlib-jdk8.jar"
     )
-) : AbstractModule() {
+) {
     companion object {
         internal val NO_ARGS = arrayOf<Any>()
 
+        private val isJdk9OrNewer = !System.getProperty("java.version").startsWith("1.")
+        private val javaRunfiles get() = Paths.get(System.getenv("JAVA_RUNFILES"))
+
+        private fun createClassLoader(javaHome: Path, kotlinHome: Path): ClassLoader {
+            val preloadJars = mutableListOf<File>().also {
+                it += kotlinHome.resolveVerified("lib", "kotlin-compiler.jar")
+                it +=  javaRunfiles.resolveVerified("io_bazel_rules_kotlin", "kotlin", "builder", "compiler_lib.jar")
+                if(!isJdk9OrNewer) {
+                    it += javaHome.resolveVerified("lib", "tools.jar")
+                }
+            }
+            return ClassPreloadingUtils.preloadClasses(
+                preloadJars,
+                Preloader.DEFAULT_CLASS_NUMBER_ESTIMATE,
+                ClassLoader.getSystemClassLoader(),
+                null
+            )
+        }
+
+        private fun createToolchain(): KotlinToolchain {
+            val kotlinHome = Paths.get("external", "com_github_jetbrains_kotlin")
+            val javaHome = Paths.get(System.getProperty("java.home")).let {
+                it.takeIf { !it.endsWith(Paths.get("jre")) } ?: it.parent
+            }
+            return KotlinToolchain(javaHome, kotlinHome, createClassLoader(javaHome, kotlinHome))
+        }
+
         /**
          * @param outputProvider A provider for the output stream to write to. A provider is used here as the System.err
          * gets rebound when the worker is executing.
          */
         @JvmStatic
-        fun createInjector(outputProvider: Provider<PrintStream>, overrides: Module? = null): Injector =
-            Guice.createInjector(
-                object : AbstractModule() {
-                    override fun configure() {
-                        val builderRunfiles=Paths.get(System.getenv("JAVA_RUNFILES"))
-                        bind(PrintStream::class.java).toProvider(outputProvider)
-                        install(
-                            KotlinToolchain.TCModule(
-                                javaHome = Paths.get("external", "local_jdk"),
-                                kotlinHome = Paths.get("external", "com_github_jetbrains_kotlin"),
-                                bazelKotlinCompilersJar = builderRunfiles.resolveVerified(
-                                    "io_bazel_rules_kotlin", "kotlin", "builder","compiler_lib.jar")
-                            )
-                        )
-                    }
-                }.let { module -> overrides?.let { Modules.override(module).with(it) } ?: module }
+        fun createInjector(outputProvider: Provider<PrintStream>, overrides: Module? = null): Injector {
+            val toolchain = createToolchain()
+            val module = object : AbstractModule() {
+                override fun configure() {
+                    bind(KotlinToolchain::class.java).toInstance(toolchain)
+                    bind(PrintStream::class.java).toProvider(outputProvider)
+                    install(KotlinToolchainModule)
+                }
+            }
+            return Guice.createInjector(
+                overrides?.let { Modules.override(module).with(it) } ?: module
             )
+        }
     }
 
     data class CompilerPlugin(val jarPath: String, val id: String) {
-        @BindingAnnotation
+        @Qualifier
         annotation class Kapt3
     }
 
@@ -86,86 +111,6 @@
     interface JarToolInvoker {
         fun invoke(args: List<String>, directory: File? = null)
     }
-
-    private class TCModule constructor(
-        javaHome: Path,
-        kotlinHome: Path,
-        bazelKotlinCompilersJar: File,
-        kotlinLibraryDirectory: Path = kotlinHome.resolveVerified("lib").toPath(),
-        kapt3Jar: File = kotlinLibraryDirectory.resolveVerified("kotlin-annotation-processing.jar"),
-        classloader: ClassLoader = ClassPreloadingUtils.preloadClasses(
-            mutableListOf<File>().let {
-                it.add(bazelKotlinCompilersJar)
-                it.addAll(kotlinLibraryDirectory.verifiedRelativeFiles(Paths.get("kotlin-compiler.jar")))
-                it.addAll(javaHome.verifiedRelativeFiles(Paths.get("lib", "tools.jar")))
-                it.toList()
-            },
-            Preloader.DEFAULT_CLASS_NUMBER_ESTIMATE,
-            Thread.currentThread().contextClassLoader,
-            null
-        )
-    ) : AbstractModule() {
-        private val toolchain = KotlinToolchain(kotlinHome)
-
-        private val kapt3 = CompilerPlugin(kapt3Jar.toString(), "org.jetbrains.kotlin.kapt3")
-
-        private val jarToolInvoker = object : JarToolInvoker {
-            val jarToolPath = javaHome.resolveVerified("bin", "jar").absolutePath.toString()
-            override fun invoke(args: List<String>, directory: File?) {
-                val command = mutableListOf(jarToolPath).also { it.addAll(args) }
-                executeAndAwait(10, directory, command).takeIf { it != 0 }?.also {
-                    throw CompilationStatusException("error running jar command ${command.joinToString(" ")}", it)
-                }
-            }
-        }
-
-        private val javacInvoker = object : JavacInvoker {
-            val c = classloader.loadClass("com.sun.tools.javac.Main")
-            val m = c.getMethod("compile", Array<String>::class.java)
-            val mPw = c.getMethod("compile", Array<String>::class.java, PrintWriter::class.java)
-            override fun compile(args: Array<String>) = m.invoke(c, args) as Int
-            override fun compile(args: Array<String>, out: PrintWriter) = mPw.invoke(c, args, out) as Int
-        }
-
-        private val jdepsInvoker = object : JDepsInvoker {
-            val clazz = classloader.loadClass("com.sun.tools.jdeps.Main")
-            val method = clazz.getMethod("run", Array<String>::class.java, PrintWriter::class.java)
-            override fun run(args: Array<String>, out: PrintWriter): Int = method.invoke(clazz, args, out) as Int
-        }
-
-        private val kotlincInvoker = object : KotlincInvoker {
-            val compilerClass = classloader.loadClass("io.bazel.kotlin.compiler.BazelK2JVMCompiler")
-            val exitCodeClass = classloader.loadClass("org.jetbrains.kotlin.cli.common.ExitCode")
-
-            val compiler = compilerClass.getConstructor().newInstance()
-            val execMethod = compilerClass.getMethod("exec", PrintStream::class.java, Array<String>::class.java)
-            val getCodeMethod = exitCodeClass.getMethod("getCode")
-
-
-            override fun compile(args: Array<String>, out: PrintStream): Int {
-                val exitCodeInstance = execMethod.invoke(compiler, out, args)
-                return getCodeMethod.invoke(exitCodeInstance, *NO_ARGS) as Int
-            }
-        }
-
-        override fun configure() {
-            bind(KotlinToolchain::class.java).toInstance(toolchain)
-            bind(JarToolInvoker::class.java).toInstance(jarToolInvoker)
-            bind(JavacInvoker::class.java).toInstance(javacInvoker)
-            bind(JDepsInvoker::class.java).toInstance(jdepsInvoker)
-            bind(KotlincInvoker::class.java).toInstance(kotlincInvoker)
-        }
-
-        @Provides
-        @CompilerPlugin.Kapt3
-        fun provideKapt3(): CompilerPlugin = kapt3
-
-        @Provides
-        fun provideBazelWorker(
-            kotlinBuilder: KotlinBuilder,
-            output: PrintStream
-        ): BazelWorker = BazelWorker(kotlinBuilder, output, "KotlinCompile")
-    }
 }
 
 
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchainModule.kt b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchainModule.kt
new file mode 100644
index 0000000..9ede01a
--- /dev/null
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinToolchainModule.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 The Bazel Authors. All rights reserved.
+ *
+ * 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 io.bazel.kotlin.builder
+
+import com.google.inject.AbstractModule
+import com.google.inject.Provides
+import io.bazel.kotlin.builder.KotlinToolchain.Companion.NO_ARGS
+import io.bazel.kotlin.builder.utils.executeAndAwait
+import io.bazel.kotlin.builder.utils.resolveVerified
+import io.bazel.kotlin.builder.utils.resolveVerifiedToAbsoluteString
+import java.io.File
+import java.io.PrintStream
+import java.io.PrintWriter
+
+internal object KotlinToolchainModule : AbstractModule() {
+    @Provides
+    fun jarToolInvoker(toolchain: KotlinToolchain): KotlinToolchain.JarToolInvoker =
+        object : KotlinToolchain.JarToolInvoker {
+            override fun invoke(args: List<String>, directory: File?) {
+                val jarTool = toolchain.javaHome.resolveVerifiedToAbsoluteString("bin", "jar")
+                val command = mutableListOf(jarTool).also { it.addAll(args) }
+                executeAndAwait(10, directory, command).takeIf { it != 0 }?.also {
+                    throw CompilationStatusException("error running jar command ${command.joinToString(" ")}", it)
+                }
+            }
+        }
+
+    @Provides
+    fun javacInvoker(toolchain: KotlinToolchain): KotlinToolchain.JavacInvoker = object : KotlinToolchain.JavacInvoker {
+        val c = toolchain.classLoader.loadClass("com.sun.tools.javac.Main")
+        val m = c.getMethod("compile", Array<String>::class.java)
+        val mPw = c.getMethod("compile", Array<String>::class.java, PrintWriter::class.java)
+        override fun compile(args: Array<String>) = m.invoke(c, args) as Int
+        override fun compile(args: Array<String>, out: PrintWriter) = mPw.invoke(c, args, out) as Int
+    }
+
+    @Provides
+    fun jdepsInvoker(toolchain: KotlinToolchain): KotlinToolchain.JDepsInvoker = object : KotlinToolchain.JDepsInvoker {
+        val clazz = toolchain.classLoader.loadClass("com.sun.tools.jdeps.Main")
+        val method = clazz.getMethod("run", Array<String>::class.java, PrintWriter::class.java)
+        override fun run(args: Array<String>, out: PrintWriter): Int = method.invoke(clazz, args, out) as Int
+    }
+
+    @Provides
+    fun kotlincInvoker(toolchain: KotlinToolchain): KotlinToolchain.KotlincInvoker =
+        object : KotlinToolchain.KotlincInvoker {
+            val compilerClass = toolchain.classLoader.loadClass("io.bazel.kotlin.compiler.BazelK2JVMCompiler")
+            val exitCodeClass = toolchain.classLoader.loadClass("org.jetbrains.kotlin.cli.common.ExitCode")
+
+            val compiler = compilerClass.getConstructor().newInstance()
+            val execMethod = compilerClass.getMethod("exec", PrintStream::class.java, Array<String>::class.java)
+            val getCodeMethod = exitCodeClass.getMethod("getCode")
+
+
+            override fun compile(args: Array<String>, out: PrintStream): Int {
+                val exitCodeInstance = execMethod.invoke(compiler, out, args)
+                return getCodeMethod.invoke(exitCodeInstance, *NO_ARGS) as Int
+            }
+        }
+
+    @Provides
+    @KotlinToolchain.CompilerPlugin.Kapt3
+    fun provideKapt3(toolchain: KotlinToolchain): KotlinToolchain.CompilerPlugin =
+        KotlinToolchain.CompilerPlugin(
+            toolchain.kotlinHome.resolveVerified("lib", "kotlin-annotation-processing.jar").absolutePath,
+            "org.jetbrains.kotlin.kapt3"
+        )
+
+    @Provides
+    fun provideBazelWorker(kotlinBuilder: KotlinBuilder, output: PrintStream): BazelWorker =
+        BazelWorker(kotlinBuilder, output, "KotlinCompile")
+}
\ No newline at end of file
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt
index 2c0db72..4c167a2 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt
@@ -22,6 +22,7 @@
 import io.bazel.kotlin.builder.CompilationStatusException
 import io.bazel.kotlin.builder.KotlinToolchain
 import io.bazel.kotlin.builder.mode.jvm.utils.JdepsParser
+import io.bazel.kotlin.builder.utils.resolveVerified
 import io.bazel.kotlin.builder.utils.rootCause
 import io.bazel.kotlin.model.KotlinModel
 import java.io.ByteArrayOutputStream
@@ -39,7 +40,8 @@
     toolchain: KotlinToolchain,
     val invoker: KotlinToolchain.JDepsInvoker
 ) : JDepsGenerator {
-    private val isKotlinImplicit = JdepsParser.pathSuffixMatchingPredicate(toolchain.kotlinLibraryDirectory, *toolchain.kotlinStandardLibraries)
+    private val isKotlinImplicit = JdepsParser.pathSuffixMatchingPredicate(
+        toolchain.kotlinHome.resolveVerified("lib").toPath(), *toolchain.kotlinStandardLibraries.toTypedArray())
     override fun generateJDeps(command: KotlinModel.BuilderCommand) {
         val jdepsContent =
             if (command.inputs.classpathList.isEmpty()) {
@@ -50,7 +52,11 @@
             } else {
                 ByteArrayOutputStream().use { out ->
                     PrintWriter(out).use { writer ->
-                        val res = invoker.run(arrayOf("-cp", command.inputs.joinedClasspath, command.outputs.output), writer)
+                        val res = invoker.run(
+                            arrayOf(
+                                "-cp", command.inputs.joinedClasspath,
+                                command.outputs.output),
+                            writer)
                         out.toByteArray().inputStream().bufferedReader().readLines().let {
                             if (res != 0) {
                                 throw CompilationStatusException("could not run jdeps tool", res, it)
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt
index acab09a..b88f440 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt
@@ -19,6 +19,7 @@
 import com.google.inject.Inject
 import io.bazel.kotlin.builder.CompilationStatusException
 import io.bazel.kotlin.builder.KotlinToolchain
+import io.bazel.kotlin.builder.utils.addAll
 import io.bazel.kotlin.model.KotlinModel.BuilderCommand
 
 @ImplementedBy(DefaultJavaCompiler::class)
@@ -37,8 +38,14 @@
                 "-cp", "${outputs.classDirectory}/:${outputs.tempDirectory}/:${inputs.joinedClasspath}",
                 "-d", outputs.classDirectory
             ).let {
-                // Kotlin takes care of annotation processing.
-                it.add("-proc:none")
+                it.addAll(
+                    // Kotlin takes care of annotation processing.
+                    "-proc:none",
+                    // Disable option linting, it will complain about the source.
+                    "-Xlint:-options",
+                    "-source", command.info.toolchainInfo.jvm.jvmTarget,
+                    "-target", command.info.toolchainInfo.jvm.jvmTarget
+                )
                 it.addAll(inputs.javaSourcesList)
                 it.addAll(inputs.generatedJavaSourcesList)
                 it.toTypedArray()
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt
index 16bd759..0eb34a3 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt
@@ -17,11 +17,12 @@
 
 package io.bazel.kotlin.builder.utils
 
-import java.io.*
+import java.io.BufferedReader
+import java.io.File
+import java.io.PrintStream
 import java.nio.file.Path
 import java.nio.file.Paths
 import java.util.*
-import java.util.concurrent.CompletableFuture
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
 
@@ -63,12 +64,11 @@
     lines().forEach(pw::println); close()
 }
 
-fun Path.resolveVerified(vararg parts: String): File = resolve(Paths.get(parts[0], *Arrays.copyOfRange(parts, 1, parts.size))).verified()
+fun Path.resolveVerified(vararg parts: String): File =
+    resolve(Paths.get(parts[0], *Arrays.copyOfRange(parts, 1, parts.size))).verified()
 
-/**
- * Return a stream of paths that are known to exists relative to this location.
- */
-fun Path.verifiedRelativeFiles(vararg paths: Path): List<File> = paths.map { relative -> resolve(relative).verified() }
+fun Path.resolveVerifiedToAbsoluteString(vararg parts: String): String =
+    resolveVerified(*parts).absolutePath.toString()
 
 fun Path.verified(): File = this.toFile().also { check(it.exists()) { "file did not exist: $this" } }
 
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
index 3d7c68b..716107d 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
@@ -26,17 +26,46 @@
 
 @ImplementedBy(DefaultKotlinCompilerPluginArgsEncoder::class)
 interface KotlinCompilerPluginArgsEncoder {
-    fun encode(
-        outputs: KotlinModel.BuilderCommand.Outputs,
-        plugins: KotlinModel.CompilerPlugins
-    ): List<String>
+    fun encode(command: KotlinModel.BuilderCommandOrBuilder): List<String>
 }
 
 class DefaultKotlinCompilerPluginArgsEncoder @Inject internal constructor(
     @CompilerPlugin.Kapt3
     private val kapt3: CompilerPlugin
 ) : KotlinCompilerPluginArgsEncoder {
+    companion object {
+        private fun encodeMap(options: Map<String, String>): String {
+            val os = ByteArrayOutputStream()
+            val oos = ObjectOutputStream(os)
 
+            oos.writeInt(options.size)
+            for ((key, value) in options.entries) {
+                oos.writeUTF(key)
+                oos.writeUTF(value)
+            }
+
+            oos.flush()
+            return Base64.getEncoder().encodeToString(os.toByteArray())
+        }
+
+        private fun encodeMultiMap(options: Map<String, List<String>>): String {
+            val os = ByteArrayOutputStream()
+            val oos = ObjectOutputStream(os)
+
+            oos.writeInt(options.size)
+            for ((key, values) in options.entries) {
+                oos.writeUTF(key)
+
+                oos.writeInt(values.size)
+                for (value in values) {
+                    oos.writeUTF(value)
+                }
+            }
+
+            oos.flush()
+            return Base64.getEncoder().encodeToString(os.toByteArray())
+        }
+    }
     /**
      * Plugin using the undocumented encoding format for kapt3
      */
@@ -57,42 +86,27 @@
         fun encode(): ImmutableList<String> =
             ImmutableList.of(
                 "-Xplugin=${kapt3.jarPath}",
-                "-P", "plugin:${kapt3.id}:configuration=${encodePluginOptions(tally)}"
+                "-P", "plugin:${kapt3.id}:configuration=${encodeMultiMap(tally)}"
             )
-
-        private fun encodePluginOptions(options: Map<String, List<String>>): String {
-            val os = ByteArrayOutputStream()
-            val oos = ObjectOutputStream(os)
-
-            oos.writeInt(options.size)
-            for ((key, values) in options.entries) {
-                oos.writeUTF(key)
-
-                oos.writeInt(values.size)
-                for (value in values) {
-                    oos.writeUTF(value)
-                }
-            }
-
-            oos.flush()
-            return Base64.getEncoder().encodeToString(os.toByteArray())
-        }
     }
 
     override fun encode(
-        outputs: KotlinModel.BuilderCommand.Outputs,
-        plugins: KotlinModel.CompilerPlugins
-    ): List<String> =
-        plugins.takeIf { it.annotationProcessorsList.isNotEmpty() }?.let { plugin ->
-            PluginArgs().let { arg ->
-                arg["sources"] = outputs.sourceGenDir.toString()
-                arg["classes"] = outputs.classDirectory.toString()
-                arg["stubs"] = outputs.tempDirectory.toString()
-                arg["incrementalData"] = outputs.tempDirectory.toString()
+        command: KotlinModel.BuilderCommandOrBuilder
+    ): List<String> {
+        val javacArgs = mutableMapOf<String, String>(
+            "-target" to command.info.toolchainInfo.jvm.jvmTarget
+        )
 
+        return command.info.plugins.takeIf { it.annotationProcessorsList.isNotEmpty() }?.let { plugin ->
+            PluginArgs().let { arg ->
+                arg["sources"] = command.outputs.sourceGenDir.toString()
+                arg["classes"] = command.outputs.classDirectory.toString()
+                arg["stubs"] = command.outputs.tempDirectory.toString()
+                arg["incrementalData"] = command.outputs.tempDirectory.toString()
+                arg["javacArguments"] = javacArgs.let(::encodeMap)
                 arg["aptMode"] = "stubsAndApt"
                 arg["correctErrorTypes"] = "true"
-//                  arg["verbose"] = "true"
+//                arg["verbose"] = "true"
 
                 arg["processors"] = plugin.annotationProcessorsList
                     .filter { it.processorClass.isNotEmpty() }
@@ -101,4 +115,5 @@
                 arg.encode()
             }
         }?.let { ImmutableList.copyOf(it) } ?: ImmutableList.of()
+    }
 }
\ No newline at end of file
diff --git a/scripts/bazel_from_source b/scripts/bazel_from_source
new file mode 100755
index 0000000..4cad042
--- /dev/null
+++ b/scripts/bazel_from_source
@@ -0,0 +1,70 @@
+# Copyright 2018 The Bazel Authors. All rights reserved.
+#
+# 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.
+#!/usr/bin/env bash
+# Note: Written on a mac please make it compatible with linux if needed.
+set -o errexit
+
+# The script assumes that the bazel source code is checked out in the GOPATH
+: ${BAZEL_SOURCE:=${GOPATH?GOPATH not set}/src/github.com/bazelbuild/bazel}
+# The version of the jdk to use target javabase. The path of the jdk is set as the JAVA_HOME
+: ${JAVA_BASE_VERSION:="1.8"}
+# The version of the jdk to use as the host_javabase. The path of the jdk is Passed as a startup flag.
+: ${HOST_JAVA_BASE_VERSION:="9"}
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+WORKSPACE_DIR=$(dirname ${SCRIPT_DIR})
+BAZEL_RC=${WORKSPACE_DIR}/.bazelrc
+
+function _exit { echo $1; exit 1; }
+function _jdk_path { /usr/libexec/java_home -v $1; }
+
+function _head_bazel {
+    local head_bazel=${BAZEL_SOURCE}/bazel-bin/src/bazel
+    if [ ! -f  ${head_bazel} ]; then _exit "bazel binary not found at ${head_bazel} run ${0} _build"; fi
+
+    local hjb="$(_jdk_path ${HOST_JAVA_BASE_VERSION})"
+    export JAVA_HOME="$(_jdk_path ${JAVA_BASE_VERSION})"
+
+    ${head_bazel}\
+        --host_javabase=${hjb}\
+        --bazelrc=${BAZEL_RC}\
+        --max_idle_secs=600\
+        ${1} $2
+}
+
+function _build_head_bazel {
+    pushd ${BAZEL_SOURCE}
+    bazel build //src:bazel
+    if [ $? -ne 0 ]; then _exit "could not build bazel"; fi
+    bazel shutdown
+}
+
+function _main {
+    if [ ! -d ${BAZEL_SOURCE} ]; then _exit "bazel source directory does not exist ${BAZEL_SOURCE}"; fi
+
+    local CMD=$1
+    shift 1
+
+    case ${CMD} in
+        # compile bazel from head
+        _build)
+            _build_head_bazel
+            ;;
+        *)
+            _head_bazel ${CMD} $@
+            ;;
+    esac
+}
+
+_main $@
\ No newline at end of file
diff --git a/third_party/regen_deps.sh b/scripts/regen_deps
similarity index 100%
rename from third_party/regen_deps.sh
rename to scripts/regen_deps
diff --git a/tests/integrationtests/jvm/BUILD b/tests/integrationtests/jvm/BUILD
index 67d50f6..70bd38a 100644
--- a/tests/integrationtests/jvm/BUILD
+++ b/tests/integrationtests/jvm/BUILD
@@ -25,7 +25,6 @@
     name = "kapt_tests",
     cases = "//tests/integrationtests/jvm/kapt:cases",
     test_class="io.bazel.kotlin.testing.jvm.KaptTests",
-    data = [  "//examples/dagger:coffee_app"]
 )
 
 kt_it_assertion_test(
diff --git a/third_party/dependencies.yaml b/third_party/dependencies.yaml
index 8132b15..c7d68ea 100644
--- a/third_party/dependencies.yaml
+++ b/third_party/dependencies.yaml
@@ -44,7 +44,7 @@
     dagger:
       modules: ["", "compiler", "producers"]
       lang: "java"
-      version: "2.9"
+      version: "2.16"
   org.jetbrains.kotlinx:
     kotlinx-coroutines:
       modules: ["core"]
diff --git a/third_party/jvm/com/google/dagger/BUILD b/third_party/jvm/com/google/dagger/BUILD
index b33e3b9..96c6e61 100644
--- a/third_party/jvm/com/google/dagger/BUILD
+++ b/third_party/jvm/com/google/dagger/BUILD
@@ -20,9 +20,14 @@
         "//external:jar/io_bazel_rules_kotlin_com/google/dagger/dagger_compiler"
     ],
     runtime_deps = [
+        "//third_party/jvm/com/google/googlejavaformat:google_java_format",
         "//third_party/jvm/com/google/guava:guava",
+        "//third_party/jvm/com/squareup:javapoet",
+        "//third_party/jvm/javax/annotation:jsr250_api",
+        "//third_party/jvm/javax/inject:javax_inject",
         ":dagger",
-        ":dagger_producers"
+        ":dagger_producers",
+        ":dagger_spi"
     ],
     visibility = [
         "//visibility:public"
@@ -38,6 +43,8 @@
     ],
     runtime_deps = [
         "//third_party/jvm/com/google/guava:guava",
+        "//third_party/jvm/javax/inject:javax_inject",
+        "//third_party/jvm/org/checkerframework:checker_compat_qual",
         ":dagger"
     ],
     visibility = [
@@ -46,3 +53,15 @@
 )
 
 
+
+java_library(
+    name = "dagger_spi",
+    exports = [
+        "//external:jar/io_bazel_rules_kotlin_com/google/dagger/dagger_spi"
+    ],
+    visibility = [
+        "//visibility:public"
+    ]
+)
+
+
diff --git a/third_party/jvm/com/google/errorprone/BUILD b/third_party/jvm/com/google/errorprone/BUILD
index 1d979a3..ef2e803 100644
--- a/third_party/jvm/com/google/errorprone/BUILD
+++ b/third_party/jvm/com/google/errorprone/BUILD
@@ -10,3 +10,15 @@
 )
 
 
+
+java_library(
+    name = "javac_shaded",
+    exports = [
+        "//external:jar/io_bazel_rules_kotlin_com/google/errorprone/javac_shaded"
+    ],
+    visibility = [
+        "//visibility:public"
+    ]
+)
+
+
diff --git a/third_party/jvm/com/google/googlejavaformat/BUILD b/third_party/jvm/com/google/googlejavaformat/BUILD
new file mode 100644
index 0000000..253e2d2
--- /dev/null
+++ b/third_party/jvm/com/google/googlejavaformat/BUILD
@@ -0,0 +1,15 @@
+licenses(["notice"])
+java_library(
+    name = "google_java_format",
+    exports = [
+        "//external:jar/io_bazel_rules_kotlin_com/google/googlejavaformat/google_java_format"
+    ],
+    runtime_deps = [
+        "//third_party/jvm/com/google/errorprone:javac_shaded"
+    ],
+    visibility = [
+        "//visibility:public"
+    ]
+)
+
+
diff --git a/third_party/jvm/com/squareup/BUILD b/third_party/jvm/com/squareup/BUILD
new file mode 100644
index 0000000..6086b33
--- /dev/null
+++ b/third_party/jvm/com/squareup/BUILD
@@ -0,0 +1,12 @@
+licenses(["notice"])
+java_library(
+    name = "javapoet",
+    exports = [
+        "//external:jar/io_bazel_rules_kotlin_com/squareup/javapoet"
+    ],
+    visibility = [
+        "//visibility:public"
+    ]
+)
+
+
diff --git a/third_party/jvm/javax/annotation/BUILD b/third_party/jvm/javax/annotation/BUILD
new file mode 100644
index 0000000..56a995c
--- /dev/null
+++ b/third_party/jvm/javax/annotation/BUILD
@@ -0,0 +1,12 @@
+licenses(["notice"])
+java_library(
+    name = "jsr250_api",
+    exports = [
+        "//external:jar/io_bazel_rules_kotlin_javax/annotation/jsr250_api"
+    ],
+    visibility = [
+        "//visibility:public"
+    ]
+)
+
+
diff --git a/third_party/jvm/workspace.bzl b/third_party/jvm/workspace.bzl
index fdcc1b6..dac3946 100644
--- a/third_party/jvm/workspace.bzl
+++ b/third_party/jvm/workspace.bzl
@@ -20,14 +20,17 @@
     {"artifact": "com.google.auto:auto-common:0.8", "lang": "java", "sha1": "c6f7af0e57b9d69d81b05434ef9f3c5610d498c4", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_auto_auto_common", "actual": "@io_bazel_rules_kotlin_com_google_auto_auto_common//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/auto_common"},
     {"artifact": "com.google.code.findbugs:jsr305:3.0.2", "lang": "java", "sha1": "25ea2e8b0c338a877313bd4672d3fe056ea78f0d", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_code_findbugs_jsr305", "actual": "@io_bazel_rules_kotlin_com_google_code_findbugs_jsr305//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305"},
     {"artifact": "com.google.code.gson:gson:2.8.4", "lang": "java", "sha1": "d0de1ca9b69e69d1d497ee3c6009d015f64dad57", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_code_gson_gson", "actual": "@io_bazel_rules_kotlin_com_google_code_gson_gson//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/gson/gson"},
-    {"artifact": "com.google.dagger:dagger-compiler:2.9", "lang": "java", "sha1": "276b9c7acc73acb449e1837a47623a7b94afd90b", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_compiler", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_compiler//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_compiler"},
-    {"artifact": "com.google.dagger:dagger-producers:2.9", "lang": "java", "sha1": "159090ee31e1752408dedda6fa92ede36a312834", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_producers", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_producers//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_producers"},
-    {"artifact": "com.google.dagger:dagger:2.9", "lang": "java", "sha1": "75a739e59d7ede2f7f425f369955bdd1c2ac122b", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger"},
+    {"artifact": "com.google.dagger:dagger-compiler:2.16", "lang": "java", "sha1": "203235b0c6875c39a0b5053dfc2f043acab04acf", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_compiler", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_compiler//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_compiler"},
+    {"artifact": "com.google.dagger:dagger-producers:2.16", "lang": "java", "sha1": "4e084a99b71a31e7079603c9675cb4994aff1344", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_producers", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_producers//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_producers"},
+    {"artifact": "com.google.dagger:dagger-spi:2.16", "lang": "java", "sha1": "26da9b6bf60185ca6f42da51bc20d93b2c825661", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_spi", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_spi//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_spi"},
+    {"artifact": "com.google.dagger:dagger:2.16", "lang": "java", "sha1": "a54ab49a739fd87e31be49c6179a0e9a135a7f39", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_dagger_dagger", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger"},
     {"artifact": "com.google.errorprone:error_prone_annotations:2.1.3", "lang": "java", "sha1": "39b109f2cd352b2d71b52a3b5a1a9850e1dc304b", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_errorprone_error_prone_annotations", "actual": "@io_bazel_rules_kotlin_com_google_errorprone_error_prone_annotations//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/errorprone/error_prone_annotations"},
+    {"artifact": "com.google.errorprone:javac-shaded:9-dev-r4023-3", "lang": "java", "sha1": "72b688efd290280a0afde5f9892b0fde6f362d1d", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_errorprone_javac_shaded", "actual": "@io_bazel_rules_kotlin_com_google_errorprone_javac_shaded//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/errorprone/javac_shaded"},
+    {"artifact": "com.google.googlejavaformat:google-java-format:1.4", "lang": "java", "sha1": "c2f8925850e17caa6da0ed1891a9e9de9414c062", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_googlejavaformat_google_java_format", "actual": "@io_bazel_rules_kotlin_com_google_googlejavaformat_google_java_format//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/googlejavaformat/google_java_format"},
 # duplicates in com.google.guava:guava fixed to 25.0-jre
 # - com.google.auto.service:auto-service:1.0-rc4 wanted version 23.5-jre
-# - com.google.dagger:dagger-compiler:2.9 wanted version 20.0-rc1
-# - com.google.dagger:dagger-producers:2.9 wanted version 20.0-rc1
+# - com.google.dagger:dagger-compiler:2.16 wanted version 23.3-jre
+# - com.google.dagger:dagger-producers:2.16 wanted version 23.3-jre
 # - com.google.inject:guice:4.2.0 wanted version 23.6-android
 # - com.google.protobuf:protobuf-java-util:3.5.1 wanted version 19.0
 # - com.google.truth:truth:0.40 wanted version 23.4-android
@@ -38,9 +41,14 @@
     {"artifact": "com.google.protobuf:protobuf-java:3.5.1", "lang": "java", "sha1": "8c3492f7662fa1cbf8ca76a0f5eb1146f7725acd", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_protobuf_protobuf_java", "actual": "@io_bazel_rules_kotlin_com_google_protobuf_protobuf_java//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/protobuf/protobuf_java"},
     {"artifact": "com.google.truth:truth:0.40", "lang": "java", "sha1": "0d74e716afec045cc4a178dbbfde2a8314ae5574", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_google_truth_truth", "actual": "@io_bazel_rules_kotlin_com_google_truth_truth//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/truth/truth"},
     {"artifact": "com.googlecode.java-diff-utils:diffutils:1.3.0", "lang": "java", "sha1": "7e060dd5b19431e6d198e91ff670644372f60fbd", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_googlecode_java_diff_utils_diffutils", "actual": "@io_bazel_rules_kotlin_com_googlecode_java_diff_utils_diffutils//jar", "bind": "jar/io_bazel_rules_kotlin_com/googlecode/java_diff_utils/diffutils"},
+    {"artifact": "com.squareup:javapoet:1.8.0", "lang": "java", "sha1": "e858dc62ef484048540d27d36f3ec2177a3fa9b1", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_com_squareup_javapoet", "actual": "@io_bazel_rules_kotlin_com_squareup_javapoet//jar", "bind": "jar/io_bazel_rules_kotlin_com/squareup/javapoet"},
+    {"artifact": "javax.annotation:jsr250-api:1.0", "lang": "java", "sha1": "5025422767732a1ab45d93abfea846513d742dcf", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_javax_annotation_jsr250_api", "actual": "@io_bazel_rules_kotlin_javax_annotation_jsr250_api//jar", "bind": "jar/io_bazel_rules_kotlin_javax/annotation/jsr250_api"},
     {"artifact": "javax.inject:javax.inject:1", "lang": "java", "sha1": "6975da39a7040257bd51d21a231b76c915872d38", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_javax_inject_javax_inject", "actual": "@io_bazel_rules_kotlin_javax_inject_javax_inject//jar", "bind": "jar/io_bazel_rules_kotlin_javax/inject/javax_inject"},
     {"artifact": "junit:junit:4.12", "lang": "java", "sha1": "2973d150c0dc1fefe998f834810d68f278ea58ec", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_junit_junit", "actual": "@io_bazel_rules_kotlin_junit_junit//jar", "bind": "jar/io_bazel_rules_kotlin_junit/junit"},
-    {"artifact": "org.checkerframework:checker-compat-qual:2.0.0", "lang": "java", "sha1": "fc89b03860d11d6213d0154a62bcd1c2f69b9efa", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_org_checkerframework_checker_compat_qual", "actual": "@io_bazel_rules_kotlin_org_checkerframework_checker_compat_qual//jar", "bind": "jar/io_bazel_rules_kotlin_org/checkerframework/checker_compat_qual"},
+# duplicates in org.checkerframework:checker-compat-qual promoted to 2.3.0
+# - com.google.dagger:dagger-producers:2.16 wanted version 2.3.0
+# - com.google.guava:guava:25.0-jre wanted version 2.0.0
+    {"artifact": "org.checkerframework:checker-compat-qual:2.3.0", "lang": "java", "sha1": "69cb4fea55a9d89b8827d107f17c985cc1a76052", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_org_checkerframework_checker_compat_qual", "actual": "@io_bazel_rules_kotlin_org_checkerframework_checker_compat_qual//jar", "bind": "jar/io_bazel_rules_kotlin_org/checkerframework/checker_compat_qual"},
     {"artifact": "org.codehaus.mojo:animal-sniffer-annotations:1.14", "lang": "java", "sha1": "775b7e22fb10026eed3f86e8dc556dfafe35f2d5", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_org_codehaus_mojo_animal_sniffer_annotations", "actual": "@io_bazel_rules_kotlin_org_codehaus_mojo_animal_sniffer_annotations//jar", "bind": "jar/io_bazel_rules_kotlin_org/codehaus/mojo/animal_sniffer_annotations"},
     {"artifact": "org.hamcrest:hamcrest-core:1.3", "lang": "java", "sha1": "42a25dc3219429f0e5d060061f71acb49bf010a0", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_org_hamcrest_hamcrest_core", "actual": "@io_bazel_rules_kotlin_org_hamcrest_hamcrest_core//jar", "bind": "jar/io_bazel_rules_kotlin_org/hamcrest/hamcrest_core"},
     {"artifact": "org.jetbrains.kotlin:kotlin-stdlib-common:1.2.41", "lang": "java", "sha1": "bf0bdac1048fd1c5c54362978dd7e06bd2230e78", "repository": "https://repo.maven.apache.org/maven2/", "name": "io_bazel_rules_kotlin_org_jetbrains_kotlin_kotlin_stdlib_common", "actual": "@io_bazel_rules_kotlin_org_jetbrains_kotlin_kotlin_stdlib_common//jar", "bind": "jar/io_bazel_rules_kotlin_org/jetbrains/kotlin/kotlin_stdlib_common"},