Compile the C Adaptor with clang and link it to the final binary.
This commit is contained in:
committed by
alexander-gorshenev
parent
5116d43f4f
commit
63aff3eded
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.exec.*
|
||||||
|
import org.jetbrains.kotlin.konan.target.*
|
||||||
|
import org.jetbrains.kotlin.konan.file.*
|
||||||
|
|
||||||
|
fun produceCAdapterBitcode(clang: TargetClang, headerFileName: String, cppFileName: String, bitcodeFileName: String) {
|
||||||
|
|
||||||
|
val headerDirName = File(headerFileName).absoluteFile.parent
|
||||||
|
|
||||||
|
val clangCommand = clang.clangCXX("-std=c++11", cppFileName, "-I", headerDirName, "-emit-llvm", "-c", "-o", bitcodeFileName)
|
||||||
|
|
||||||
|
runTool(clangCommand)
|
||||||
|
}
|
||||||
+9
-3
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.*
|
||||||
|
|
||||||
private enum class ScopeKind {
|
private enum class ScopeKind {
|
||||||
TOP,
|
TOP,
|
||||||
@@ -426,7 +426,10 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun makeGlobalStruct(top: ExportedElementScope) {
|
private fun makeGlobalStruct(top: ExportedElementScope) {
|
||||||
outputStreamWriter = PrintWriter(File(".", "${prefix}_api.h").outputStream())
|
outputStreamWriter = context.config.tempFiles
|
||||||
|
.cAdapterHeader
|
||||||
|
.printWriter()
|
||||||
|
|
||||||
output("#ifndef KONAN_${prefix.toUpperCase()}_H")
|
output("#ifndef KONAN_${prefix.toUpperCase()}_H")
|
||||||
output("#define KONAN_${prefix.toUpperCase()}_H")
|
output("#define KONAN_${prefix.toUpperCase()}_H")
|
||||||
// TODO: use namespace for C++ case?
|
// TODO: use namespace for C++ case?
|
||||||
@@ -472,7 +475,10 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
outputStreamWriter.close()
|
outputStreamWriter.close()
|
||||||
println("Produced dynamic library API in ${prefix}_api.h")
|
println("Produced dynamic library API in ${prefix}_api.h")
|
||||||
|
|
||||||
outputStreamWriter = PrintWriter(File(".", "${prefix}_api.cpp").outputStream())
|
outputStreamWriter = context.config.tempFiles
|
||||||
|
.cAdapterCpp
|
||||||
|
.printWriter()
|
||||||
|
|
||||||
output("#include \"${prefix}_api.h\"")
|
output("#include \"${prefix}_api.h\"")
|
||||||
output("""
|
output("""
|
||||||
|struct KObjHeader;
|
|struct KObjHeader;
|
||||||
|
|||||||
+16
-3
@@ -31,18 +31,31 @@ internal fun produceOutput(context: Context) {
|
|||||||
|
|
||||||
val llvmModule = context.llvmModule!!
|
val llvmModule = context.llvmModule!!
|
||||||
val config = context.config.configuration
|
val config = context.config.configuration
|
||||||
|
val tempFiles = context.config.tempFiles
|
||||||
|
val produce = config.get(KonanConfigKeys.PRODUCE)
|
||||||
|
|
||||||
when (config.get(KonanConfigKeys.PRODUCE)) {
|
when (produce) {
|
||||||
CompilerOutputKind.DYNAMIC,
|
CompilerOutputKind.DYNAMIC,
|
||||||
CompilerOutputKind.FRAMEWORK,
|
CompilerOutputKind.FRAMEWORK,
|
||||||
CompilerOutputKind.PROGRAM -> {
|
CompilerOutputKind.PROGRAM -> {
|
||||||
val program = context.config.outputName
|
val program = context.config.outputName
|
||||||
val output = "$program.kt.bc"
|
val output = tempFiles.nativeBinaryFileName
|
||||||
context.bitcodeFileName = output
|
context.bitcodeFileName = output
|
||||||
|
|
||||||
|
val generatedBitcodeFiles =
|
||||||
|
if (produce == CompilerOutputKind.DYNAMIC) {
|
||||||
|
produceCAdapterBitcode(
|
||||||
|
context.config.clang,
|
||||||
|
tempFiles.cAdapterHeaderName,
|
||||||
|
tempFiles.cAdapterCppName,
|
||||||
|
tempFiles.cAdapterBitcodeName)
|
||||||
|
listOf(tempFiles.cAdapterBitcodeName)
|
||||||
|
} else emptyList()
|
||||||
|
|
||||||
val nativeLibraries =
|
val nativeLibraries =
|
||||||
context.config.nativeLibraries +
|
context.config.nativeLibraries +
|
||||||
context.config.defaultNativeLibraries
|
context.config.defaultNativeLibraries +
|
||||||
|
generatedBitcodeFiles
|
||||||
|
|
||||||
PhaseManager(context).phase(KonanPhase.BITCODE_LINKER) {
|
PhaseManager(context).phase(KonanPhase.BITCODE_LINKER) {
|
||||||
for (library in nativeLibraries) {
|
for (library in nativeLibraries) {
|
||||||
|
|||||||
+5
-5
@@ -21,6 +21,11 @@ package org.jetbrains.kotlin.backend.konan
|
|||||||
*/
|
*/
|
||||||
open class KonanException(message: String = "", cause: Throwable? = null) : Exception(message, cause)
|
open class KonanException(message: String = "", cause: Throwable? = null) : Exception(message, cause)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error occured during external tool invocation. Such as non-zero exit code.
|
||||||
|
*/
|
||||||
|
class KonanExternalToolFailure(message: String = "", cause: Throwable? = null) : KonanException(message, cause)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a compilation error caused by mistakes in an input file, e.g. undefined reference.
|
* Represents a compilation error caused by mistakes in an input file, e.g. undefined reference.
|
||||||
*/
|
*/
|
||||||
@@ -31,8 +36,3 @@ class KonanCompilationException(message: String = "", cause: Throwable? = null)
|
|||||||
*/
|
*/
|
||||||
class KonanIrDeserializationException(message: String = "", cause: Throwable? = null) : KonanException(message, cause)
|
class KonanIrDeserializationException(message: String = "", cause: Throwable? = null) : KonanException(message, cause)
|
||||||
|
|
||||||
/**
|
|
||||||
* An error occured during external tool invocation. Such as non-zero exit code.
|
|
||||||
*/
|
|
||||||
class KonanExternalToolFailure(message: String = "", cause: Throwable? = null) : KonanException(message, cause)
|
|
||||||
|
|
||||||
|
|||||||
+15
-9
@@ -20,9 +20,7 @@ import com.intellij.openapi.project.Project
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.createForwardDeclarationsModule
|
import org.jetbrains.kotlin.backend.konan.descriptors.createForwardDeclarationsModule
|
||||||
import org.jetbrains.kotlin.backend.konan.library.*
|
import org.jetbrains.kotlin.backend.konan.library.*
|
||||||
import org.jetbrains.kotlin.backend.konan.library.impl.*
|
import org.jetbrains.kotlin.backend.konan.library.impl.*
|
||||||
import org.jetbrains.kotlin.backend.konan.util.profile
|
import org.jetbrains.kotlin.backend.konan.util.*
|
||||||
import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent
|
|
||||||
import org.jetbrains.kotlin.backend.konan.util.suffixIfNot
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
@@ -44,15 +42,16 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
internal val targetManager = TargetManager(
|
internal val targetManager = TargetManager(
|
||||||
configuration.get(KonanConfigKeys.TARGET))
|
configuration.get(KonanConfigKeys.TARGET))
|
||||||
|
|
||||||
val indirectBranchesAreAllowed = targetManager.target != KonanTarget.WASM32
|
private val target = targetManager.target
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val target = targetManager.target
|
|
||||||
if (!target.enabled) {
|
if (!target.enabled) {
|
||||||
error("Target $target is not available on the ${TargetManager.host} host")
|
error("Target $target is not available on the ${TargetManager.host} host")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val indirectBranchesAreAllowed = target != KonanTarget.WASM32
|
||||||
|
|
||||||
private fun Distribution.prepareDependencies(checkDependencies: Boolean) {
|
private fun Distribution.prepareDependencies(checkDependencies: Boolean) {
|
||||||
if (checkDependencies) {
|
if (checkDependencies) {
|
||||||
DependencyProcessor(java.io.File(dependenciesDir), targetProperties).run()
|
DependencyProcessor(java.io.File(dependenciesDir), targetProperties).run()
|
||||||
@@ -65,10 +64,17 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
prepareDependencies(configuration.getBoolean(KonanConfigKeys.CHECK_DEPENDENCIES))
|
prepareDependencies(configuration.getBoolean(KonanConfigKeys.CHECK_DEPENDENCIES))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val clang = TargetClang(distribution.properties, distribution.dependenciesDir, target)
|
||||||
|
|
||||||
internal val produce get() = configuration.get(KonanConfigKeys.PRODUCE)!!
|
internal val produce get() = configuration.get(KonanConfigKeys.PRODUCE)!!
|
||||||
private val suffix = produce.suffix(targetManager.target)
|
private val prefix = produce.prefix(target)
|
||||||
|
private val suffix = produce.suffix(target)
|
||||||
val outputName = configuration.get(KonanConfigKeys.OUTPUT)?.removeSuffixIfPresent(suffix) ?: produce.name.toLowerCase()
|
val outputName = configuration.get(KonanConfigKeys.OUTPUT)?.removeSuffixIfPresent(suffix) ?: produce.name.toLowerCase()
|
||||||
val outputFile = outputName.suffixIfNot(produce.suffix(targetManager.target))
|
val outputFile = outputName
|
||||||
|
.prefixIfNot(prefix)
|
||||||
|
.suffixIfNot(suffix)
|
||||||
|
|
||||||
|
val tempFiles = TempFiles(outputName)
|
||||||
|
|
||||||
val moduleId: String
|
val moduleId: String
|
||||||
get() = configuration.get(KonanConfigKeys.MODULE_NAME) ?: File(outputName).name
|
get() = configuration.get(KonanConfigKeys.MODULE_NAME) ?: File(outputName).name
|
||||||
@@ -85,13 +91,13 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
internal val immediateLibraries: List<LibraryReaderImpl> by lazy {
|
internal val immediateLibraries: List<LibraryReaderImpl> by lazy {
|
||||||
val result = resolver.resolveImmediateLibraries(
|
val result = resolver.resolveImmediateLibraries(
|
||||||
libraryNames,
|
libraryNames,
|
||||||
targetManager.target,
|
target,
|
||||||
currentAbiVersion,
|
currentAbiVersion,
|
||||||
configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
|
configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
|
||||||
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS),
|
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS),
|
||||||
{ msg -> configuration.report(STRONG_WARNING, msg) }
|
{ msg -> configuration.report(STRONG_WARNING, msg) }
|
||||||
)
|
)
|
||||||
resolver.resolveLibrariesRecursive(result, targetManager.target, currentAbiVersion)
|
resolver.resolveLibrariesRecursive(result, target, currentAbiVersion)
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
|
import org.jetbrains.kotlin.konan.file.*
|
||||||
|
|
||||||
|
class TempFiles(val outputName: String) {
|
||||||
|
val nativeBinaryFile by lazy { File("${outputName}.kt.bc") }
|
||||||
|
val cAdapterHeader by lazy { File("${outputName}_api.h") }
|
||||||
|
val cAdapterCpp by lazy { createTempFile("api", ".cpp").deleteOnExit() }
|
||||||
|
val cAdapterBitcode by lazy { createTempFile("api", ".bc").deleteOnExit() }
|
||||||
|
|
||||||
|
val nativeBinaryFileName get() = nativeBinaryFile.absolutePath
|
||||||
|
val cAdapterHeaderName get() = cAdapterHeader.absolutePath
|
||||||
|
val cAdapterCppName get() = cAdapterCpp.absolutePath
|
||||||
|
val cAdapterBitcodeName get() = cAdapterBitcode.absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
+4
-1
@@ -36,10 +36,13 @@ fun nTabs(amount: Int): String {
|
|||||||
return String.format("%1$-${(amount+1)*4}s", "")
|
return String.format("%1$-${(amount+1)*4}s", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.prefixIfNot(prefix: String) =
|
||||||
|
if (this.startsWith(prefix)) this else "$prefix$this"
|
||||||
|
|
||||||
fun String.suffixIfNot(suffix: String) =
|
fun String.suffixIfNot(suffix: String) =
|
||||||
if (this.endsWith(suffix)) this else "$this$suffix"
|
if (this.endsWith(suffix)) this else "$this$suffix"
|
||||||
|
|
||||||
fun String.removeSuffixIfPresent(suffix: String) =
|
fun String.removeSuffixIfPresent(suffix: String) =
|
||||||
if (this.endsWith(suffix)) this.dropLast(suffix.length) else this
|
if (this.endsWith(suffix)) this.dropLast(suffix.length) else this
|
||||||
|
|
||||||
fun <T> Lazy<T>.getValueOrNull(): T? = if (isInitialized()) value else null
|
fun <T> Lazy<T>.getValueOrNull(): T? = if (isInitialized()) value else null
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.kotlin.konan.exec
|
||||||
|
|
||||||
|
import java.lang.ProcessBuilder
|
||||||
|
import java.lang.ProcessBuilder.Redirect
|
||||||
|
|
||||||
|
fun executeCommand(command: List<String>) =
|
||||||
|
executeCommand(*command.toTypedArray())
|
||||||
|
|
||||||
|
fun executeCommand(vararg command: String): Int {
|
||||||
|
// TODO: need a verbose logger here.
|
||||||
|
|
||||||
|
val builder = ProcessBuilder(command.asList())
|
||||||
|
|
||||||
|
builder.redirectOutput(Redirect.INHERIT)
|
||||||
|
builder.redirectInput(Redirect.INHERIT)
|
||||||
|
builder.redirectError(Redirect.INHERIT)
|
||||||
|
|
||||||
|
val process = builder.start()
|
||||||
|
val exitCode = process.waitFor()
|
||||||
|
return exitCode
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runTool(command: List<String>) =
|
||||||
|
runTool(*command.toTypedArray())
|
||||||
|
|
||||||
|
fun runTool(vararg command: String) {
|
||||||
|
val code = executeCommand(*command)
|
||||||
|
if (code != 0) error("The ${command[0]} command returned non-zero exit code: $code.")
|
||||||
|
}
|
||||||
|
|
||||||
@@ -103,10 +103,11 @@ data class File constructor(internal val javaPath: Path) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
fun deleteOnExit() {
|
fun deleteOnExit(): File {
|
||||||
// Works only on the default file system,
|
// Works only on the default file system,
|
||||||
// but that's okay for now.
|
// but that's okay for now.
|
||||||
javaPath.toFile().deleteOnExit()
|
javaPath.toFile().deleteOnExit()
|
||||||
|
return this // Allow streaming.
|
||||||
}
|
}
|
||||||
fun readBytes() = Files.readAllBytes(javaPath)
|
fun readBytes() = Files.readAllBytes(javaPath)
|
||||||
fun writeBytes(bytes: ByteArray) = Files.write(javaPath, bytes)
|
fun writeBytes(bytes: ByteArray) = Files.write(javaPath, bytes)
|
||||||
@@ -136,6 +137,7 @@ data class File constructor(internal val javaPath: Path) {
|
|||||||
// TODO: Consider removeing these after konanazing java.util.Properties.
|
// TODO: Consider removeing these after konanazing java.util.Properties.
|
||||||
fun bufferedReader() = Files.newBufferedReader(javaPath)
|
fun bufferedReader() = Files.newBufferedReader(javaPath)
|
||||||
fun outputStream() = Files.newOutputStream(javaPath)
|
fun outputStream() = Files.newOutputStream(javaPath)
|
||||||
|
fun printWriter() = javaPath.toFile().printWriter()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val userDir
|
val userDir
|
||||||
|
|||||||
@@ -39,5 +39,21 @@ class ClangManager(val properties: Properties, val baseDir: String) {
|
|||||||
= (hostClang.commonClangArgs + targetClangArgs[target]!!.specificClangArgs).toTypedArray()
|
= (hostClang.commonClangArgs + targetClangArgs[target]!!.specificClangArgs).toTypedArray()
|
||||||
|
|
||||||
val hostCompilerArgsForJni = hostClang.hostCompilerArgsForJni.toTypedArray()
|
val hostCompilerArgsForJni = hostClang.hostCompilerArgsForJni.toTypedArray()
|
||||||
|
|
||||||
|
fun targetClangCmd(target: KonanTarget)
|
||||||
|
= listOf("${hostClang.llvmDir}/bin/clang") + targetClangArgs(target)
|
||||||
|
|
||||||
|
fun targetClangXXCmd(target: KonanTarget)
|
||||||
|
= listOf("${hostClang.llvmDir}/bin/clang++") + targetClangArgs(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TargetClang(private val clangManager: ClangManager, private val target: KonanTarget) {
|
||||||
|
constructor (properties: Properties, baseDir: String, target: KonanTarget)
|
||||||
|
: this (ClangManager(properties, baseDir), target)
|
||||||
|
|
||||||
|
fun clangC(vararg userArgs: String) = clangManager.targetClangCmd(target) + userArgs.asList()
|
||||||
|
|
||||||
|
fun clangCXX(vararg userArgs: String) = clangManager.targetClangXXCmd(target) + userArgs.asList()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.target
|
package org.jetbrains.kotlin.konan.target
|
||||||
|
|
||||||
enum class Family(name:String, val exeSuffix:String, val dynamicSuffix: String?) {
|
enum class Family(name:String, val exeSuffix:String, val dynamicPrefix: String, val dynamicSuffix: String) {
|
||||||
OSX("osx", "kexe", "dylib"),
|
OSX( "osx" , "kexe", "lib", "dylib"),
|
||||||
IOS("ios", "kexe", "dylib"),
|
IOS( "ios" , "kexe", "lib", "dylib"),
|
||||||
LINUX("linux", "kexe", "so"),
|
LINUX( "linux" , "kexe", "lib", "so" ),
|
||||||
WINDOWS("windows", "exe", "dll"),
|
WINDOWS("windows", "exe" , "" , "dll" ),
|
||||||
ANDROID("android", "so", "so"),
|
ANDROID("android", "so" , "lib", "so" ),
|
||||||
WASM("wasm", "wasm", "wasm")
|
WASM( "wasm" , "wasm", "" , "wasm" )
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Architecture(val bitness: Int) {
|
enum class Architecture(val bitness: Int) {
|
||||||
@@ -62,6 +62,7 @@ enum class CompilerOutputKind {
|
|||||||
},
|
},
|
||||||
DYNAMIC {
|
DYNAMIC {
|
||||||
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
|
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
|
||||||
|
override fun prefix(target: KonanTarget?) = ".${target!!.family.dynamicPrefix}"
|
||||||
},
|
},
|
||||||
FRAMEWORK {
|
FRAMEWORK {
|
||||||
override fun suffix(target: KonanTarget?): String = ".framework"
|
override fun suffix(target: KonanTarget?): String = ".framework"
|
||||||
@@ -74,6 +75,7 @@ enum class CompilerOutputKind {
|
|||||||
};
|
};
|
||||||
|
|
||||||
abstract fun suffix(target: KonanTarget? = null): String
|
abstract fun suffix(target: KonanTarget? = null): String
|
||||||
|
open fun prefix(target: KonanTarget? = null): String = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
class TargetManager(val userRequest: String? = null) {
|
class TargetManager(val userRequest: String? = null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user