[Commonizer] Move source code to the folder that corresponds package name
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
public fun CliCommonizer(classpath: Iterable<File>): CliCommonizer {
|
||||
return CliCommonizer(URLClassLoader(classpath.map { it.absoluteFile.toURI().toURL() }.toTypedArray()))
|
||||
}
|
||||
|
||||
public fun CliCommonizer(classLoader: ClassLoader): CliCommonizer {
|
||||
return CliCommonizer(CommonizerClassLoaderExecutor(classLoader))
|
||||
}
|
||||
|
||||
public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||
|
||||
public fun interface Executor {
|
||||
public operator fun invoke(arguments: List<String>)
|
||||
}
|
||||
|
||||
override fun commonizeLibraries(
|
||||
konanHome: File,
|
||||
inputLibraries: Set<File>,
|
||||
dependencyLibraries: Set<File>,
|
||||
outputCommonizerTarget: SharedCommonizerTarget,
|
||||
outputDirectory: File
|
||||
) {
|
||||
if (inputLibraries.isEmpty()) return
|
||||
val arguments = mutableListOf<String>().apply {
|
||||
add("native-klib-commonize")
|
||||
add("-distribution-path"); add(konanHome.absolutePath)
|
||||
add("-input-libraries"); add(inputLibraries.joinToString(";") { it.absolutePath })
|
||||
add("-output-commonizer-target"); add(outputCommonizerTarget.identityString)
|
||||
add("-output-path"); add(outputDirectory.absolutePath)
|
||||
if (dependencyLibraries.isNotEmpty()) {
|
||||
add("-dependency-libraries"); add(dependencyLibraries.joinToString(";") { it.absolutePath })
|
||||
}
|
||||
}
|
||||
executor(arguments)
|
||||
}
|
||||
}
|
||||
|
||||
private class CommonizerClassLoaderExecutor(private val commonizerClassLoader: ClassLoader) : CliCommonizer.Executor {
|
||||
companion object {
|
||||
private const val commonizerMainClass = "org.jetbrains.kotlin.commonizer.cli.CommonizerCLI"
|
||||
private const val commonizerMainFunction = "main"
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
override fun invoke(arguments: List<String>) {
|
||||
val commonizerMainClass = commonizerClassLoader.loadClass(commonizerMainClass)
|
||||
val commonizerMainMethod = commonizerMainClass.methods.singleOrNull { it.name == commonizerMainFunction }
|
||||
?: throw IllegalArgumentException(
|
||||
"Missing or conflicting $commonizerMainFunction function in " +
|
||||
"Class ${commonizerMainClass.name} from ClassLoader $commonizerClassLoader"
|
||||
)
|
||||
commonizerMainMethod.invoke(null, arguments.toTypedArray())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
public interface Commonizer : Serializable {
|
||||
@Throws(Throwable::class)
|
||||
public fun commonizeLibraries(
|
||||
konanHome: File,
|
||||
inputLibraries: Set<File>,
|
||||
dependencyLibraries: Set<File>,
|
||||
outputCommonizerTarget: SharedCommonizerTarget,
|
||||
outputDirectory: File
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName")
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.Serializable
|
||||
|
||||
// N.B. TargetPlatform/SimplePlatform are non exhaustive enough to address both target platforms such as
|
||||
// JVM, JS and concrete Kotlin/Native targets, e.g. macos_x64, ios_x64, linux_x64.
|
||||
public sealed class CommonizerTarget : Serializable {
|
||||
final override fun toString(): String = prettyName
|
||||
}
|
||||
|
||||
public data class LeafCommonizerTarget public constructor(val name: String) : CommonizerTarget() {
|
||||
public constructor(konanTarget: KonanTarget) : this(konanTarget.name)
|
||||
|
||||
public val konanTargetOrNull: KonanTarget? = KonanTarget.predefinedTargets[name]
|
||||
|
||||
public val konanTarget: KonanTarget get() = konanTargetOrNull ?: error("Unknown KonanTarget: $name")
|
||||
}
|
||||
|
||||
public data class SharedCommonizerTarget(val targets: Set<CommonizerTarget>) : CommonizerTarget() {
|
||||
public constructor(vararg targets: CommonizerTarget) : this(targets.toSet())
|
||||
public constructor(vararg targets: KonanTarget) : this(targets.toSet())
|
||||
public constructor(targets: Iterable<KonanTarget>) : this(targets.map(::LeafCommonizerTarget).toSet())
|
||||
|
||||
public companion object {
|
||||
public fun ifNotEmpty(targets: Set<CommonizerTarget>): SharedCommonizerTarget? {
|
||||
return if (targets.isNotEmpty()) SharedCommonizerTarget(targets) else null
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
require(targets.isNotEmpty()) { "Empty 'SharedCommonizerTarget': Expected at least one target" }
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommonizerTarget(konanTargets: Iterable<KonanTarget>): CommonizerTarget {
|
||||
val konanTargetsSet = konanTargets.toSet()
|
||||
require(konanTargetsSet.isNotEmpty()) { "Empty set of of konanTargets" }
|
||||
val leafTargets = konanTargetsSet.map(::LeafCommonizerTarget)
|
||||
return leafTargets.singleOrNull() ?: SharedCommonizerTarget(leafTargets.toSet())
|
||||
}
|
||||
|
||||
public fun CommonizerTarget(konanTarget: KonanTarget): LeafCommonizerTarget {
|
||||
return LeafCommonizerTarget(konanTarget)
|
||||
}
|
||||
|
||||
public fun CommonizerTarget(konanTarget: KonanTarget, vararg konanTargets: KonanTarget): SharedCommonizerTarget {
|
||||
val targets = ArrayList<KonanTarget>(konanTargets.size + 1).apply {
|
||||
add(konanTarget)
|
||||
addAll(konanTargets)
|
||||
}
|
||||
return SharedCommonizerTarget(targets.map(::LeafCommonizerTarget).toSet())
|
||||
}
|
||||
|
||||
public val CommonizerTarget.identityString: String
|
||||
get() = when (this) {
|
||||
is LeafCommonizerTarget -> name
|
||||
is SharedCommonizerTarget -> identityString
|
||||
}
|
||||
|
||||
private val SharedCommonizerTarget.identityString: String
|
||||
get() {
|
||||
val segments = targets.map(CommonizerTarget::identityString).sorted()
|
||||
return segments.joinToString(
|
||||
separator = ", ", prefix = "(", postfix = ")"
|
||||
)
|
||||
}
|
||||
|
||||
public val CommonizerTarget.prettyName: String
|
||||
get() = when (this) {
|
||||
is LeafCommonizerTarget -> "[$name]"
|
||||
is SharedCommonizerTarget -> prettyName(null)
|
||||
}
|
||||
|
||||
public fun SharedCommonizerTarget.prettyName(highlightedChild: CommonizerTarget?): String {
|
||||
return targets
|
||||
.sortedWith(compareBy<CommonizerTarget> { it.level }.thenBy { it.identityString }).joinToString(", ", "[", "]") { child ->
|
||||
when (child) {
|
||||
is LeafCommonizerTarget -> child.name
|
||||
is SharedCommonizerTarget -> child.prettyName(highlightedChild)
|
||||
} + if (child == highlightedChild) "(*)" else ""
|
||||
}
|
||||
}
|
||||
|
||||
public val CommonizerTarget.konanTargets: Set<KonanTarget>
|
||||
get() {
|
||||
return when (this) {
|
||||
is LeafCommonizerTarget -> setOf(konanTarget)
|
||||
is SharedCommonizerTarget -> targets.flatMap { it.konanTargets }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
public val CommonizerTarget.level: Int
|
||||
get() {
|
||||
return when (this) {
|
||||
is LeafCommonizerTarget -> return 0
|
||||
is SharedCommonizerTarget -> targets.maxOf { it.level } + 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
|
||||
import java.io.File
|
||||
|
||||
|
||||
public fun interface CommonizerOutputLayout {
|
||||
public fun getTargetDirectory(root: File, target: CommonizerTarget): File
|
||||
}
|
||||
|
||||
public object NativeDistributionCommonizerOutputLayout : CommonizerOutputLayout {
|
||||
override fun getTargetDirectory(root: File, target: CommonizerTarget): File {
|
||||
return when (target) {
|
||||
is LeafCommonizerTarget -> root.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.name)
|
||||
is SharedCommonizerTarget -> root.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object HierarchicalCommonizerOutputLayout : CommonizerOutputLayout {
|
||||
override fun getTargetDirectory(root: File, target: CommonizerTarget): File {
|
||||
return root.resolve(target.identityString)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.IdentityStringSyntaxNode.LeafTargetSyntaxNode
|
||||
import org.jetbrains.kotlin.commonizer.IdentityStringSyntaxNode.SharedTargetSyntaxNode
|
||||
import org.jetbrains.kotlin.commonizer.IdentityStringToken.*
|
||||
|
||||
public fun parseCommonizerTarget(identityString: String): CommonizerTarget {
|
||||
try {
|
||||
val tokens = tokenizeIdentityString(identityString)
|
||||
val syntaxTree = parser(tokens) ?: error("Failed building syntax tree. $identityString")
|
||||
check(syntaxTree.remaining.isEmpty()) { "Failed building syntax tree. Unexpected remaining tokens ${syntaxTree.remaining}" }
|
||||
return buildCommonizerTarget(syntaxTree.value)
|
||||
} catch (e: Throwable) {
|
||||
throw IllegalArgumentException("Failed parsing CommonizerTarget from \"$identityString\"", e)
|
||||
}
|
||||
}
|
||||
|
||||
//region Tokens
|
||||
|
||||
private fun tokenizeIdentityString(identityString: String): List<IdentityStringToken> {
|
||||
var remainingString = identityString
|
||||
val tokenizer = sharedTargetStartTokenizer + sharedTargetEndTokenizer + separatorTokenizer + wordTokenizer
|
||||
return mutableListOf<IdentityStringToken>().apply {
|
||||
while (remainingString.isNotEmpty()) {
|
||||
val generatedToken = tokenizer.nextToken(remainingString)
|
||||
?: error("Unexpected token at $remainingString")
|
||||
|
||||
remainingString = generatedToken.remaining
|
||||
add(generatedToken.token)
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private sealed class IdentityStringToken {
|
||||
data class Word(val value: String) : IdentityStringToken()
|
||||
object Separator : IdentityStringToken()
|
||||
object SharedTargetStart : IdentityStringToken()
|
||||
object SharedTargetEnd : IdentityStringToken()
|
||||
|
||||
final override fun toString(): String {
|
||||
return when (this) {
|
||||
is Word -> value
|
||||
is Separator -> ", "
|
||||
is SharedTargetStart -> "["
|
||||
is SharedTargetEnd -> "]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class GeneratedToken(val token: IdentityStringToken, val remaining: String)
|
||||
|
||||
private interface IdentityStringTokenizer {
|
||||
fun nextToken(value: String): GeneratedToken?
|
||||
}
|
||||
|
||||
private operator fun IdentityStringTokenizer.plus(other: IdentityStringTokenizer): IdentityStringTokenizer {
|
||||
return CompositeIdentityStringTokenizer(this, other)
|
||||
}
|
||||
|
||||
private data class CompositeIdentityStringTokenizer(
|
||||
val first: IdentityStringTokenizer,
|
||||
val second: IdentityStringTokenizer
|
||||
) : IdentityStringTokenizer {
|
||||
override fun nextToken(value: String): GeneratedToken? {
|
||||
return first.nextToken(value) ?: second.nextToken(value)
|
||||
}
|
||||
}
|
||||
|
||||
private data class RegexIdentityStringTokenizer(
|
||||
val regex: Regex,
|
||||
val token: (String) -> IdentityStringToken
|
||||
) : IdentityStringTokenizer {
|
||||
override fun nextToken(value: String): GeneratedToken? {
|
||||
val firstMatchResult = regex.findAll(value, 0).firstOrNull() ?: return null
|
||||
val range = firstMatchResult.range
|
||||
if (range.first != 0) return null
|
||||
return GeneratedToken(token(firstMatchResult.value), value.drop(firstMatchResult.value.length))
|
||||
}
|
||||
}
|
||||
|
||||
private val sharedTargetStartTokenizer =
|
||||
RegexIdentityStringTokenizer(Regex.fromLiteral("(")) { SharedTargetStart }
|
||||
|
||||
private val sharedTargetEndTokenizer =
|
||||
RegexIdentityStringTokenizer(Regex.fromLiteral(")")) { SharedTargetEnd }
|
||||
|
||||
private val separatorTokenizer =
|
||||
RegexIdentityStringTokenizer(Regex("""\s*,\s*""")) { Separator }
|
||||
|
||||
private val wordTokenizer =
|
||||
RegexIdentityStringTokenizer(Regex("\\w+"), IdentityStringToken::Word)
|
||||
|
||||
//endregion
|
||||
|
||||
//region Syntax Tree
|
||||
|
||||
private val parser = anyOf(SharedTargetParser, LeafTargetParser)
|
||||
|
||||
private data class ParserOutput<out T : Any>(val value: T, val remaining: List<IdentityStringToken>)
|
||||
|
||||
private interface Parser<out T : Any> {
|
||||
operator fun invoke(tokens: List<IdentityStringToken>): ParserOutput<T>?
|
||||
}
|
||||
|
||||
|
||||
private fun <T : Any> anyOf(vararg parser: Parser<T>): Parser<T> {
|
||||
return AnyOfParser(parser.toList())
|
||||
}
|
||||
|
||||
private data class AnyOfParser<T : Any>(val parsers: List<Parser<T>>) : Parser<T> {
|
||||
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<T>? {
|
||||
return parsers.mapNotNull { parser -> parser(tokens) }.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> Parser<T>.oneOrMore(): Parser<List<T>> {
|
||||
return OneOrMoreParser(this)
|
||||
}
|
||||
|
||||
private data class OneOrMoreParser<T : Any>(val parser: Parser<T>) : Parser<List<T>> {
|
||||
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<List<T>>? {
|
||||
val outputs = mutableListOf<T>()
|
||||
var remainingTokens = tokens
|
||||
while (true) {
|
||||
val output = parser(remainingTokens) ?: break
|
||||
if (output.remaining == remainingTokens) break
|
||||
outputs.add(output.value)
|
||||
remainingTokens = output.remaining
|
||||
}
|
||||
if (outputs.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
return ParserOutput(outputs.toList(), remainingTokens)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> Parser<T>.ignore(token: IdentityStringToken): Parser<T> {
|
||||
return IgnoreTokensParser(this, token)
|
||||
}
|
||||
|
||||
private data class IgnoreTokensParser<T : Any>(val parser: Parser<T>, val ignoredToken: IdentityStringToken) : Parser<T> {
|
||||
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<T>? {
|
||||
return parser(
|
||||
if (tokens.firstOrNull() == ignoredToken) tokens.drop(1) else tokens
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private object LeafTargetParser : Parser<LeafTargetSyntaxNode> {
|
||||
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<LeafTargetSyntaxNode>? {
|
||||
val nextToken = tokens.firstOrNull() as? Word ?: return null
|
||||
return ParserOutput(LeafTargetSyntaxNode(nextToken), tokens.drop(1))
|
||||
}
|
||||
}
|
||||
|
||||
private object SharedTargetParser : Parser<SharedTargetSyntaxNode> {
|
||||
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<SharedTargetSyntaxNode>? {
|
||||
if (tokens.firstOrNull() !is SharedTargetStart) return null
|
||||
|
||||
val innerParser = anyOf(LeafTargetParser, SharedTargetParser).ignore(Separator).oneOrMore()
|
||||
val innerParserOutput = innerParser(tokens.drop(1)) ?: return null
|
||||
|
||||
val closingToken = innerParserOutput.remaining.firstOrNull()
|
||||
if (closingToken != SharedTargetEnd) {
|
||||
error("Missing ']' at ${tokens.joinToString("")}")
|
||||
}
|
||||
|
||||
return ParserOutput(SharedTargetSyntaxNode(innerParserOutput.value), innerParserOutput.remaining.drop(1))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private sealed class IdentityStringSyntaxNode {
|
||||
data class LeafTargetSyntaxNode(val token: Word) : IdentityStringSyntaxNode()
|
||||
data class SharedTargetSyntaxNode(val children: List<IdentityStringSyntaxNode>) : IdentityStringSyntaxNode()
|
||||
}
|
||||
|
||||
//endregion Tree
|
||||
|
||||
//region Build CommonizerTarget
|
||||
|
||||
private fun buildCommonizerTarget(node: IdentityStringSyntaxNode): CommonizerTarget {
|
||||
return when (node) {
|
||||
is LeafTargetSyntaxNode -> LeafCommonizerTarget(node.token.value)
|
||||
is SharedTargetSyntaxNode -> SharedCommonizerTarget(
|
||||
node.children.map { child -> buildCommonizerTarget(child) }.toSet()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
Reference in New Issue
Block a user