[Gradle, JS] Migrate onto destinationDirectory and outputName

This commit is contained in:
Ilya Goncharov
2022-07-27 21:03:05 +02:00
committed by teamcity
parent cd5b9d6356
commit 642fae1a5b
10 changed files with 150 additions and 80 deletions
@@ -28,6 +28,12 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-output", valueDescription = "<filepath>", description = "Destination *.js file for the compilation result")
var outputFile: String? by NullableStringFreezableVar(null)
@Argument(value = "-Xir-output-dir", valueDescription = "<directory>", description = "Destination for generated files")
var outputDir: String? by NullableStringFreezableVar(null)
@Argument(value = "-Xir-output-name", description = "Base name of generated files")
var outputName: String? by NullableStringFreezableVar(null)
@GradleOption(
value = DefaultValues.BooleanTrueDefault::class,
gradleInputType = GradleInputTypes.INPUT
@@ -238,9 +238,15 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
if (!checkKotlinPackageUsage(environmentForJS.configuration, sourcesFiles)) return ExitCode.COMPILATION_ERROR
val outputFilePath = arguments.outputFile
if (outputFilePath == null) {
messageCollector.report(ERROR, "IR: Specify output file via -output", null)
val outputDirPath = arguments.outputDir
val outputName = arguments.outputName
if (outputDirPath == null) {
messageCollector.report(ERROR, "IR: Specify output dir via -Xir-output-dir", null)
return ExitCode.COMPILATION_ERROR
}
if (outputName == null) {
messageCollector.report(ERROR, "IR: Specify output name via -Xir-output-name", null)
return ExitCode.COMPILATION_ERROR
}
@@ -257,12 +263,11 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
reportCompiledSourcesList(messageCollector, sourcesFiles)
}
val outputFile = File(outputFilePath)
val moduleName = arguments.irModuleName ?: FileUtil.getNameWithoutExtension(outputFile)
val moduleName = arguments.irModuleName ?: outputName
configurationJs.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
val outputDir: File = outputFile.parentFile ?: outputFile.absoluteFile.parentFile!!
val outputDir = File(outputDirPath)
try {
configurationJs.put(JSConfigurationKeys.OUTPUT_DIR, outputDir.canonicalFile)
} catch (e: IOException) {
@@ -279,7 +284,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
val icCaches = if (!arguments.wasm && cacheDirectories.isNotEmpty()) {
messageCollector.report(INFO, "")
messageCollector.report(INFO, "Building cache:")
messageCollector.report(INFO, "to: ${outputFilePath}")
messageCollector.report(INFO, "to: ${outputDir}")
messageCollector.report(INFO, arguments.cacheDirectories ?: "")
messageCollector.report(INFO, libraries.toString())
@@ -347,21 +352,21 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
}
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
if (arguments.irProduceKlibFile) {
require(outputFile.extension == KLIB_FILE_EXTENSION) { "Please set up .klib file as output" }
}
generateKLib(
sourceModule,
irFactory = IrFactoryImpl,
outputKlibPath = outputFile.path,
outputKlibPath = if (arguments.irProduceKlibFile)
outputDir.resolve("$outputName.klib").normalize().absolutePath
else
outputDirPath,
nopack = arguments.irProduceKlibDir,
jsOutputName = arguments.irPerModuleOutputName,
)
}
if (arguments.irProduceJs) {
messageCollector.report(INFO, "Produce executable: $outputFilePath")
messageCollector.report(INFO, "Produce executable: $outputDirPath")
messageCollector.report(INFO, arguments.cacheDirectories ?: "")
if (icCaches.isNotEmpty()) {
@@ -383,10 +388,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
}
)
outputFile.write(outputs)
outputs.dependencies.forEach { (name, content) ->
outputFile.resolveSibling("$name.js").write(content)
}
outputs.write(outputDir, outputName)
messageCollector.report(INFO, "Executable production duration (IC): ${System.currentTimeMillis() - beforeIc2Js}ms")
@@ -416,6 +418,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
if (arguments.wasm) {
val outputFile = File(arguments.outputFile)
val (allModules, backendContext) = compileToLoweredIr(
depsDescriptors = module,
phaseConfig = PhaseConfig(wasmPhases),
@@ -455,10 +458,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms")
outputFile.write(outputs)
outputs.dependencies.forEach { (name, content) ->
outputFile.resolveSibling("$name.js").write(content)
}
outputs.write(outputDir, outputName)
if (arguments.generateDts) {
val dtsFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "d.ts")!!
dtsFile.writeText(tsDefinitions)
@@ -481,6 +482,18 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
return OK
}
private fun CompilationOutputs.write(outputDir: File, outputName: String) {
val outputFile = outputDir.resolve("$outputName.js")
outputFile.parentFile.mkdirs()
outputFile.write(this)
dependencies.forEach { (name, content) ->
outputDir.resolve("$name.js").let {
it.parentFile.mkdirs()
it.write(content)
}
}
}
private fun File.write(outputs: CompilationOutputs) {
writeText(outputs.jsCode)
outputs.writeSourceMapIfPresent(this)
+2
View File
@@ -38,6 +38,8 @@ where advanced options include:
Enable runtime diagnostics when access safely to boolean in external declarations
-Xlegacy-deprecated-no-warn Disable warnings of deprecation of legacy compiler
-Xmetadata-only Generate *.meta.js and *.kjsm files only
-Xir-output-dir=<directory> Destination for generated files
-Xir-output-name Base name of generated files
-Xpartial-linkage Allow unlinked symbols
-Xrepositories=<path> Paths to additional places where libraries could be found
-Xstrict-implicit-export-types Generate strict types for implicitly exported entities inside d.ts files. Available in IR backend only.
@@ -120,10 +120,8 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
) { task ->
task.dependsOn(binary.linkSyncTask)
val entryFileProvider = binary.linkSyncTask.flatMap { syncTask ->
binary.linkTask.flatMap { linkTask ->
linkTask.outputFileProperty.map {
syncTask.destinationDir.resolve(it.name)
}
binary.linkTask.map {
syncTask.destinationDir.resolve(it.outputFileProperty.get().name)
}
}
@@ -207,13 +205,9 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
),
listOf(compilation)
) { task ->
task.dependsOn(binary.linkSyncTask)
val entryFileProvider = binary.linkSyncTask.flatMap { linkSyncTask ->
binary.linkTask.flatMap { linkTask ->
linkTask.outputFileProperty.map {
linkSyncTask.destinationDir.resolve(it.name)
}
}
val entryFileProvider = binary.linkSyncTask.map {
it.destinationDir
.resolve(binary.linkTask.get().outputName.get() + ".js")
}
task.description = "build webpack ${mode.name.toLowerCase()} bundle"
@@ -10,18 +10,21 @@ import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.work.NormalizeLineEndings
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.gradle.dsl.CompilerJsOptionsDefault
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.toHexString
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
@@ -34,6 +37,7 @@ import javax.inject.Inject
abstract class KotlinJsIrLink @Inject constructor(
objectFactory: ObjectFactory,
workerExecutor: WorkerExecutor,
private val projectLayout: ProjectLayout
) : Kotlin2JsCompile(
objectFactory.newInstance(CompilerJsOptionsDefault::class.java),
objectFactory,
@@ -56,6 +60,10 @@ abstract class KotlinJsIrLink @Inject constructor(
@get:Internal
internal lateinit var compilation: KotlinCompilationData<*>
private val platformType by project.provider {
compilation.platformType
}
@Transient
@get:Internal
internal val propertiesProvider = PropertiesProvider(project)
@@ -86,13 +94,6 @@ abstract class KotlinJsIrLink @Inject constructor(
@get:PathSensitive(PathSensitivity.RELATIVE)
internal abstract val entryModule: DirectoryProperty
@Deprecated(
message = "Replace with destinationDirectory",
replaceWith = ReplaceWith("destinationDirectory")
)
@get:Internal
val normalizedDestinationDirectory: DirectoryProperty get() = destinationDirectory
@get:Internal
val rootCacheDirectory by lazy {
buildDir.resolve("klib/cache")
@@ -144,4 +145,53 @@ abstract class KotlinJsIrLink @Inject constructor(
.toTypedArray()
.filterNot { it.isEmpty() }
}
override fun setupCompilerArgs(args: K2JSCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) {
when (mode) {
PRODUCTION -> {
kotlinOptions.configureOptions(ENABLE_DCE, GENERATE_D_TS, MINIMIZED_MEMBER_NAMES)
}
DEVELOPMENT -> {
kotlinOptions.configureOptions(GENERATE_D_TS)
}
}
val alreadyDefinedOutputMode = kotlinOptions.freeCompilerArgs
.any { it.startsWith(PER_MODULE) }
if (!alreadyDefinedOutputMode) {
kotlinOptions.freeCompilerArgs += outputGranularity.toCompilerArgument()
}
super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors)
}
private fun KotlinJsOptions.configureOptions(vararg additionalCompilerArgs: String) {
freeCompilerArgs += (additionalCompilerArgs.toList() + PRODUCE_JS + "$ENTRY_IR_MODULE=${entryModule.get().asFile.canonicalPath}")
.mapNotNull { arg ->
if (kotlinOptions.freeCompilerArgs
.any { it.startsWith(arg) }
) null else arg
}
if (platformType == KotlinPlatformType.wasm) {
freeCompilerArgs += WASM_BACKEND
}
}
@get:Input
override val filteredArgumentsMap: Map<String, String>
get() {
val superFiltered = super.filteredArgumentsMap
return superFiltered.mapValues { (key, value) ->
if (key != K2JSCompilerArguments::freeArgs.name) {
value
} else {
value
.removePrefix("[")
.removeSuffix("]")
.split(", ")
.filter { !it.contains(ENTRY_IR_MODULE) }
.joinToString()
}
}
}
}
@@ -121,15 +121,13 @@ abstract class KotlinJsIrSubTarget(
KotlinJsBinaryMode.DEVELOPMENT
).single()
testJs.dependsOn(binary.linkSyncTask)
testJs.inputFileProperty.fileProvider(
binary.linkSyncTask.flatMap { linkSyncTask ->
binary.linkTask.flatMap { linkTask ->
linkTask.outputFileProperty.map {
linkSyncTask.destinationDir.resolve(it.name)
}
testJs.inputFileProperty.set(
project.layout.file(
binary.linkSyncTask.map {
it.destinationDir
.resolve(binary.linkTask.get().outputName.get() + ".js")
}
}
)
)
configureTestDependencies(testJs)
@@ -11,6 +11,7 @@ import org.gradle.api.Task
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator.Companion.runTaskNameSuffix
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.binaryen.BinaryenExec
import org.jetbrains.kotlin.gradle.targets.js.dsl.*
import org.jetbrains.kotlin.gradle.targets.js.internal.RewriteSourceMapFilterReader
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.targets.js.typescript.TypeScriptValidationTask
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
@@ -120,13 +122,15 @@ constructor(
val tsValidationTask = registerTypeScriptCheckTask(binary)
binary.linkTask.configure {
it.kotlinOptions.outputFile = project.buildDir
.resolve(COMPILE_SYNC)
.resolve(if (compilation.platformType == KotlinPlatformType.wasm) "wasm" else "js")
.resolve(compilation.name)
.resolve(binary.name)
.resolve(npmProject.main)
.canonicalPath
it.destinationDirectory.set(
project.buildDir
.resolve(COMPILE_SYNC)
.resolve(if (compilation.platformType == KotlinPlatformType.wasm) "wasm" else "js")
.resolve(compilation.name)
.resolve(binary.name)
.resolve(NpmProject.DIST_FOLDER)
)
(it.kotlinOptions as KotlinJsOptionsImpl).outputName = npmProject.name
it.finalizedBy(syncTask)
@@ -145,7 +149,11 @@ constructor(
return project.registerTask<Copy>(
binary.linkSyncTaskName
) { task ->
task.from(binary.linkTask.flatMap { it.normalizedDestinationDirectory })
task.from(
binary.linkTask.flatMap { linkTask ->
linkTask.destinationDirectory.map { it.asFile }
}
)
task.from(project.tasks.named(compilation.processResourcesTaskName))
@@ -173,7 +181,7 @@ constructor(
null
} else {
project.registerTask(binary.validateGeneratedTsTaskName, listOf(compilation)) {
it.inputDir.set(linkTask.flatMap { it.normalizedDestinationDirectory })
it.inputDir.set(linkTask.destinationDirectory.map { it.asFile })
it.validationStrategy.set(
when (binary.mode) {
KotlinJsBinaryMode.DEVELOPMENT -> propertiesProvider.jsIrGeneratedTypeScriptValidationDevStrategy
@@ -184,12 +192,6 @@ constructor(
}
}
// private val TaskProvider<KotlinJsIrLink>.normalizedDestinationDirectory
// get() =
// flatMap { linkTask ->
// linkTask.normalizedDestinationDirectory.map { it.asFile }
// }
//Binaryen
private val applyBinaryenHandlers = mutableListOf<(BinaryenExec.() -> Unit) -> Unit>()
@@ -980,18 +980,12 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:Internal
internal abstract val defaultDestinationDirectory: DirectoryProperty
// This can be file or directory
@Deprecated("Use destinationDirectory and moduleName instead")
@get:Internal
abstract val outputFileProperty: Property<File>
@Deprecated("Please use outputFileProperty, this is kept for backwards compatibility.", replaceWith = ReplaceWith("outputFileProperty"))
@get:Internal
val outputFile: File
get() = outputFileProperty.get()
@get:OutputFile
@get:Optional
abstract val optionalOutputFile: RegularFileProperty
@get:Input
abstract val outputName: Property<String>
// Workaround to add additional compiler args based on the exising one
// Currently there is a logic to add additional compiler arguments based on already existing one.
@@ -1018,15 +1012,18 @@ abstract class Kotlin2JsCompile @Inject constructor(
(compilerOptions as CompilerJsOptionsDefault).fillDefaultValues(args)
super.setupCompilerArgs(args, defaultsOnly = defaultsOnly, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors)
try {
outputFileProperty.get().canonicalPath
} catch (ex: Throwable) {
logger.warn("IO EXCEPTION: outputFile: ${outputFileProperty.get().path}")
throw ex
if (kotlinOptions.isIrBackendEnabled()) {
if (kotlinOptions.outputFile != null) {
args.outputDir = (kotlinOptions as KotlinJsOptionsImpl).destDir
kotlinOptions.outputFile?.let { args.outputName = File(it).nameWithoutExtension }
} else {
args.outputDir = destinationDirectory.get().asFile.normalize().absolutePath
args.outputName = outputName.get()
}
} else {
args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath
}
args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath
if (defaultsOnly) return
(compilerOptions as CompilerJsOptionsDefault).fillCompilerArguments(args)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData
@@ -73,6 +74,10 @@ internal open class BaseKotlin2JsCompileConfig<TASK : Kotlin2JsCompile>(
)
.disallowChanges()
task.outputName.value(task.project.provider {
(task.kotlinOptions as KotlinJsOptionsImpl).outputName ?: compilation.ownModuleName
}).disallowChanges()
task.optionalOutputFile.fileProvider(
task.outputFileProperty.flatMap { outputFile ->
task.enhancedFreeCompilerArgs.flatMap { freeArgs ->
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink
import java.io.File
import org.gradle.api.InvalidUserDataException
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData