@@ -26,48 +26,102 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
2626import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
2727import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
2828import org.jetbrains.kotlin.config.Services
29+ import java.io.FileOutputStream
2930import java.io.ObjectOutputStream
3031import java.io.PrintStream
3132import java.net.URLClassLoader
3233import java.net.URLDecoder
34+ import java.util.zip.ZipEntry
35+ import java.util.zip.ZipOutputStream
3336
34- private fun findJavaHome (): File {
37+ internal fun findJavaHome (): File {
3538 val path = System .getProperty(" java.home" )
3639 ? : throw IllegalStateException (" no java home found" )
3740
3841 return File (path).also { check(it.isDirectory) }
3942}
4043
41- private fun findToolsJar (javaHome : File ): File
42- = File (javaHome.absolutePath + " /../lib/tools.jar" ).also { check(it.isFile) }
43-
44+ internal fun findToolsJar (jdkHome : File ): File
45+ = File (jdkHome.absolutePath + " /../lib/tools.jar" ).also { check(it.isFile) }
4446
47+ @Suppress(" unused" , " MemberVisibilityCanBePrivate" )
4548class KotlinCompilation (
46- val dir : File ,
49+ /* * Working directory for the compilation */
50+ val workingDir : File ,
51+ /* * Arbitrary arguments to be passed to kotlinc */
4752 val args : List <String > = emptyList(),
53+ /* * Arbitrary arguments to be passed to kapt */
4854 val kaptArgs : Map <String , String > = emptyMap(),
49- classpaths : List <String > = emptyList(),
55+ /* *
56+ * Paths to directories or .jar files that contain classes
57+ * to be made available in the compilation (i.e. added to
58+ * the classpath)
59+ */
60+ classpaths : List <File > = emptyList(),
61+ /* * Source files to be compiled */
5062 val sources : List <SourceFile > = emptyList(),
51- private val jdkHome : File = findJavaHome(),
52- toolsJar : File = findToolsJar(jdkHome),
63+ /* * Services to be passed to kapt */
64+ val services : List <Service <* ,* >> = emptyList(),
65+ /* *
66+ * Path to the JDK to be used
67+ *
68+ * null if no JDK is to be used (option -no-jdk)
69+ * */
70+ val jdkHome : File ? = findJavaHome(),
71+ /* * Search path for Kotlin runtime libraries */
72+ val kotlinHome : File ? = null ,
73+ /* *
74+ * Don't look for kotlin-stdlib.jar, kotlin-script-runtime.jar
75+ * and kotlin-reflect.jar in the [kotlinHome] directory. They
76+ * need to be provided by [classpaths] or will be unavailable.
77+ * */
78+ val noStdLib : Boolean = kotlinHome == null ,
79+ /* *
80+ * Don't look for kotlin-reflect.jar in the [kotlinHome] directory.
81+ * It has to be provided by [classpaths] or will be unavailable.
82+ *
83+ * Setting it to false has no effect when [noStdLib] is true.
84+ */
85+ val noReflect : Boolean = noStdLib,
86+ /* * Path to the tools.jar file needed for kapt */
87+ toolsJar : File = findToolsJar(findJavaHome()),
88+ /* * Inherit classpath from calling process */
5389 inheritClassPath : Boolean = false ,
5490 correctErrorTypes : Boolean = false ,
55- private val skipRuntimeVersionCheck : Boolean = false
91+ val skipRuntimeVersionCheck : Boolean = false ,
92+ val verbose : Boolean = false ,
93+ val suppressWarnings : Boolean = false ,
94+ val allWarningsAsErrors : Boolean = false ,
95+ val reportOutputFiles : Boolean = false
5696) {
57- val sourcesDir = File (dir , " sources" )
58- val classesDir = File (dir , " classes" )
97+ val sourcesDir = File (workingDir , " sources" )
98+ val classesDir = File (workingDir , " classes" )
5999
60- private val services = Services .Builder ()
100+ /* *
101+ * Generate a .jar file that holds ServiceManager registrations. Necessary because AutoService's
102+ * results might not be visible to this test.
103+ */
104+ val servicesJar = File (workingDir, " services.jar" ).apply {
105+ val servicesGroupedByClass = services.groupBy({ it.serviceClass }, { it.implementationClass })
61106
62- fun <T : Any > addService (serviceClass : KClass <T >, implementation : T ) {
63- services.register(serviceClass.java, implementation)
64- }
107+ ZipOutputStream (FileOutputStream (this )).use { zipOutputStream ->
108+ for (serviceEntry in servicesGroupedByClass) {
109+ zipOutputStream.putNextEntry(
110+ ZipEntry (" META-INF/services/${serviceEntry.key.qualifiedName} " )
111+ )
112+ val serviceFile = zipOutputStream.sink().buffer()
113+ for (implementation in serviceEntry.value) {
114+ serviceFile.writeUtf8(implementation.qualifiedName!! )
115+ serviceFile.writeUtf8(" \n " )
116+ }
117+ serviceFile.emit() // Don't close the entry; that closes the file.
118+ zipOutputStream.closeEntry()
119+ }
120+ }
121+ }
65122
66- // private val servicesGroupedByClass = services.groupBy({ it.serviceClass }, { it.implementation })
67123
68- /* *
69- * A Kotlin source file to be compiled
70- */
124+ /* * A Kotlin source file to be compiled */
71125 data class SourceFile (val path : String , val contents : String ) {
72126 /* *
73127 * Writes the source file to the location and returns the
@@ -82,31 +136,36 @@ class KotlinCompilation(
82136 }
83137 }
84138
139+ /* * Result of the compilation */
85140 data class Result (val messages : String , val exitCode : ExitCode )
86141
142+ /* * A service that will be passed to kapt */
143+ data class Service <S : Any , T : S >(val serviceClass : KClass <S >, val implementationClass : KClass <T >)
144+
87145 val allClasspaths: List <String > = mutableListOf<String >().apply {
88- addAll(classpaths)
146+ addAll(classpaths.map(File ::getAbsolutePath))
147+
148+ add(servicesJar.absolutePath)
89149
90150 if (inheritClassPath)
91151 addAll(getHostProcessClasspathFiles().map(File ::getAbsolutePath))
92152 }
93153
94154 /* * Returns arguments necessary to enable and configure kapt3. */
95155 private val annotationProcessorArgs = object {
96- private val kaptSourceDir = File (dir , " kapt/sources" )
97- private val kaptStubsDir = File (dir , " kapt/stubs" )
156+ private val kaptSourceDir = File (workingDir , " kapt/sources" )
157+ private val kaptStubsDir = File (workingDir , " kapt/stubs" )
98158
99159 val pluginClassPaths = arrayOf(getKapt3Jar().absolutePath, toolsJar.absolutePath)
100160 val pluginOptions = arrayOf(
101161 " plugin:org.jetbrains.kotlin.kapt3:sources=$kaptSourceDir " ,
102162 " plugin:org.jetbrains.kotlin.kapt3:classes=$classesDir " ,
103163 " plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptStubsDir " ,
104- " plugin:org.jetbrains.kotlin.kapt3:apclasspath=$sourcesDir " ,
164+ " plugin:org.jetbrains.kotlin.kapt3:apclasspath=$servicesJar " ,
105165 " plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=$correctErrorTypes " ,
106166 // Don't forget aptMode! Without it, the compiler will crash with an obscure error about
107167 // write unsafe context
108168 " plugin:org.jetbrains.kotlin.kapt3:aptMode=stubsAndApt" ,
109- " plugin:org.jetbrains.kotlin.kapt3:processors=com.tschuchort.kotlinelements.TestProcessor" ,
110169 * if (kaptArgs.isNotEmpty())
111170 arrayOf(" plugin:org.jetbrains.kotlin.kapt3:apoptions=${encodeOptions(kaptArgs)} " )
112171 else
@@ -120,26 +179,44 @@ class KotlinCompilation(
120179 }
121180
122181 val k2jvmArgs = K2JVMCompilerArguments ().apply {
123- freeArgs = sourcesDir.listFiles().map { it.absolutePath }
182+ freeArgs = sourcesDir.listFiles().map { it.absolutePath } + args
124183 pluginOptions = annotationProcessorArgs.pluginOptions
125184 pluginClasspaths = annotationProcessorArgs.pluginClassPaths
126185 loadBuiltInsFromDependencies = true
127186 destination = classesDir.absolutePath
128187 classpath = allClasspaths.joinToString(separator = File .pathSeparator)
129- noStdlib = true
130- noReflect = true
188+ // noStdlib = true
189+ // noReflect = true
131190 skipRuntimeVersionCheck = this @KotlinCompilation.skipRuntimeVersionCheck
132191 reportPerf = false
133192 reportOutputFiles = true
134- jdkHome = this @KotlinCompilation.jdkHome.absolutePath
193+
194+ if (this @KotlinCompilation.jdkHome != null ) {
195+ jdkHome = this @KotlinCompilation.jdkHome.absolutePath
196+ }
197+ else {
198+ noJdk = true
199+ }
200+
201+ noStdlib = this @KotlinCompilation.noStdLib
202+ noReflect = this @KotlinCompilation.noReflect
203+
204+ this @KotlinCompilation.kotlinHome?.let {
205+ kotlinHome = it.absolutePath
206+ }
207+
208+ verbose = this @KotlinCompilation.verbose
209+ suppressWarnings = this @KotlinCompilation.suppressWarnings
210+ allWarningsAsErrors = this @KotlinCompilation.allWarningsAsErrors
211+ reportOutputFiles = this @KotlinCompilation.reportOutputFiles
135212 }
136213
137214 val compilerOutputbuffer = Buffer ()
138215
139216 val exitCode = K2JVMCompiler ().execImpl(
140217 PrintingMessageCollector (PrintStream (compilerOutputbuffer.outputStream()),
141218 MessageRenderer .WITHOUT_PATHS , true ),
142- Services .EMPTY ,// services.build(),
219+ Services .EMPTY ,
143220 k2jvmArgs
144221 )
145222
0 commit comments