Entry point selection.
$ kotlinc -entry foo.bar.qux ... selects `qux(args: Array<String>):Unit` in the package `foo.bar` as an entry point. The short flag is `-e`.
This commit is contained in:
committed by
alexander-gorshenev
parent
a2fa4938f3
commit
5192bd1313
@@ -122,6 +122,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
put(CommonConfigurationKeys.MODULE_NAME, output)
|
put(CommonConfigurationKeys.MODULE_NAME, output)
|
||||||
put(ABI_VERSION, 1)
|
put(ABI_VERSION, 1)
|
||||||
|
|
||||||
|
arguments.mainPackage ?.let{ put(ENTRY, it) }
|
||||||
arguments.runtimeFile ?.let{ put(RUNTIME_FILE, it) }
|
arguments.runtimeFile ?.let{ put(RUNTIME_FILE, it) }
|
||||||
arguments.propertyFile ?.let{ put(PROPERTY_FILE, it) }
|
arguments.propertyFile ?.let{ put(PROPERTY_FILE, it) }
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
@field:Argument(value = "-output", shortName = "-o", valueDescription = "<path>", description = "Output file path")
|
@field:Argument(value = "-output", shortName = "-o", valueDescription = "<path>", description = "Output file path")
|
||||||
@JvmField var outputFile: String? = null
|
@JvmField var outputFile: String? = null
|
||||||
|
|
||||||
|
@field:Argument(value = "-entry", shortName = "-e", valueDescription = "<name>", description = "Qualified entry point name")
|
||||||
|
@JvmField var mainPackage: String? = null
|
||||||
|
|
||||||
@field:Argument(value = "-produce", shortName = "-p", valueDescription = "{program|library|bitcode}", description = "Produce either .kexe, .klib or a .bc file.")
|
@field:Argument(value = "-produce", shortName = "-p", valueDescription = "{program|library|bitcode}", description = "Produce either .kexe, .klib or a .bc file.")
|
||||||
@JvmField var produce: String? = null
|
@JvmField var produce: String? = null
|
||||||
|
|
||||||
|
|||||||
+2
@@ -40,6 +40,8 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("list backend phases")
|
= CompilerConfigurationKey.create("list backend phases")
|
||||||
val LIST_TARGETS: CompilerConfigurationKey<Boolean>
|
val LIST_TARGETS: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("list available targets")
|
= CompilerConfigurationKey.create("list available targets")
|
||||||
|
val ENTRY: CompilerConfigurationKey<String?>
|
||||||
|
= CompilerConfigurationKey.create("fully qualified main() name")
|
||||||
val META_INFO: CompilerConfigurationKey<List<String>>
|
val META_INFO: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create("generate metadata")
|
= CompilerConfigurationKey.create("generate metadata")
|
||||||
val MODULE_KIND: CompilerConfigurationKey<ModuleKind>
|
val MODULE_KIND: CompilerConfigurationKey<ModuleKind>
|
||||||
|
|||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.llvm
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.konan.CompilerOutputKind
|
||||||
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
|
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.isArray
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
import org.jetbrains.kotlin.utils.alwaysTrue
|
||||||
|
|
||||||
|
internal fun findMainEntryPoint(context: Context): FunctionDescriptor? {
|
||||||
|
|
||||||
|
val config = context.config.configuration
|
||||||
|
if (config.get(KonanConfigKeys.PRODUCE) != CompilerOutputKind.PROGRAM) return null
|
||||||
|
|
||||||
|
val entryPoint = FqName(config.get(KonanConfigKeys.ENTRY) ?: defaultEntryName)
|
||||||
|
|
||||||
|
val entryName = entryPoint.shortName()
|
||||||
|
val packageName = entryPoint.parent()
|
||||||
|
|
||||||
|
val packageScope = context.builtIns.builtInsModule.getPackage(packageName).memberScope
|
||||||
|
|
||||||
|
val main = packageScope.getContributedFunctions(entryName,
|
||||||
|
NoLookupLocation.FROM_BACKEND).singleOrNull {
|
||||||
|
it.returnType?.isUnit() == true &&
|
||||||
|
it.hasSingleArrayOfStringParameter &&
|
||||||
|
it.typeParameters.isEmpty() &&
|
||||||
|
it.isExported()
|
||||||
|
}
|
||||||
|
return main
|
||||||
|
}
|
||||||
|
|
||||||
|
private val defaultEntryName = "main"
|
||||||
|
|
||||||
|
private val defaultEntryPackage = FqName.ROOT
|
||||||
|
|
||||||
|
private val KotlinType.filterClass: ClassDescriptor?
|
||||||
|
get() {
|
||||||
|
val constr = constructor.declarationDescriptor
|
||||||
|
return constr as? ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ClassDescriptor.isString
|
||||||
|
get() = fqNameSafe.asString() == "kotlin.String"
|
||||||
|
|
||||||
|
private val KotlinType.isString
|
||||||
|
get() = filterClass?.isString ?: false
|
||||||
|
|
||||||
|
private val KotlinType.isArrayOfString: Boolean
|
||||||
|
get() = (filterClass?.isArray ?: false) &&
|
||||||
|
(arguments.singleOrNull()?.type?.isString ?: false)
|
||||||
|
|
||||||
|
private val FunctionDescriptor.hasSingleArrayOfStringParameter: Boolean
|
||||||
|
get() = valueParameters.singleOrNull()?.type?.isArrayOfString ?: false
|
||||||
|
|
||||||
+39
@@ -334,6 +334,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
module.acceptChildrenVoid(this)
|
module.acceptChildrenVoid(this)
|
||||||
appendLlvmUsed(context.llvm.usedFunctions)
|
appendLlvmUsed(context.llvm.usedFunctions)
|
||||||
appendStaticInitializers(context.llvm.staticInitializers)
|
appendStaticInitializers(context.llvm.staticInitializers)
|
||||||
|
appendEntryPointSelector(findMainEntryPoint(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -2096,6 +2097,44 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun entryPointSelector(entryPoint: LLVMValueRef,
|
||||||
|
entryPointType: LLVMTypeRef, selectorName: String): LLVMValueRef {
|
||||||
|
|
||||||
|
assert(LLVMCountParams(entryPoint) == 1)
|
||||||
|
|
||||||
|
val selector = LLVMAddFunction(context.llvmModule, selectorName, entryPointType)!!
|
||||||
|
codegen.prologue(selector, voidType)
|
||||||
|
|
||||||
|
// Note, that 'parameter' is an object reference, and as such, shall
|
||||||
|
// be accounted for in the rootset. However, current object management
|
||||||
|
// scheme for arguments guarantees, that reference is being held in C++
|
||||||
|
// launcher, so we could optimize out creating slot for 'parameter' in
|
||||||
|
// this function.
|
||||||
|
val parameter = LLVMGetParam(selector, 0)!!
|
||||||
|
codegen.callAtFunctionScope(entryPoint, listOf(parameter), Lifetime.IRRELEVANT)
|
||||||
|
|
||||||
|
codegen.ret(null)
|
||||||
|
codegen.epilogue()
|
||||||
|
return selector
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun appendEntryPointSelector(descriptor: FunctionDescriptor?) {
|
||||||
|
if (descriptor == null) return
|
||||||
|
|
||||||
|
val entryPoint = codegen.llvmFunction(descriptor)
|
||||||
|
val selectorName = "EntryPointSelector"
|
||||||
|
val entryPointType = getFunctionType(entryPoint)!!
|
||||||
|
|
||||||
|
val selector = entryPointSelector(entryPoint, entryPointType, selectorName)
|
||||||
|
|
||||||
|
LLVMSetLinkage(selector, LLVMLinkage.LLVMExternalLinkage)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
// Create type { i32, void ()*, i8* }
|
// Create type { i32, void ()*, i8* }
|
||||||
|
|
||||||
|
|||||||
@@ -371,6 +371,25 @@ task hello4(type: RunKonanTest) {
|
|||||||
source = "runtime/basic/hello4.kt"
|
source = "runtime/basic/hello4.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task entry0(type: RunKonanTest) {
|
||||||
|
goldValue = "Hello.\n"
|
||||||
|
source = "runtime/basic/entry0.kt"
|
||||||
|
flags = ["-entry", "koko.lala.main"]
|
||||||
|
}
|
||||||
|
|
||||||
|
task entry1(type: RunKonanTest) {
|
||||||
|
goldValue = "Hello.\n"
|
||||||
|
source = "runtime/basic/entry1.kt"
|
||||||
|
flags = ["-entry", "foo"]
|
||||||
|
}
|
||||||
|
|
||||||
|
task entry2(type: LinkKonanTest) {
|
||||||
|
goldValue = "Hello.\n"
|
||||||
|
source = "runtime/basic/entry2.kt"
|
||||||
|
lib = "runtime/basic/libentry2.kt"
|
||||||
|
flags = ["-entry", "foo"]
|
||||||
|
}
|
||||||
|
|
||||||
task tostring0(type: RunKonanTest) {
|
task tostring0(type: RunKonanTest) {
|
||||||
goldValue = "127\n-1\n239\nA\nЁ\nト\n1122334455\n112233445566778899\n3.14159265358\n1.0E27\n1.0E-300\ntrue\nfalse\n"
|
goldValue = "127\n-1\n239\nA\nЁ\nト\n1122334455\n112233445566778899\n3.14159265358\n1.0E27\n1.0E-300\ntrue\nfalse\n"
|
||||||
source = "runtime/basic/tostring0.kt"
|
source = "runtime/basic/tostring0.kt"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package koko.lala
|
||||||
|
|
||||||
|
fun fail() {
|
||||||
|
println("Test failed, this is a wrong main() function.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> main(args: Array<String>) {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<Int>) {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>, second_arg: Int) {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
println("Hello.")
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
fun fail() {
|
||||||
|
println("Test failed, this is a wrong main() function.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(args: Array<String>) {
|
||||||
|
println("Hello.")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun main(args: Array<String>) {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun fail() {
|
||||||
|
println("Test failed, this is a wrong main() function.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(args: Array<String>) {
|
||||||
|
println("Hello.")
|
||||||
|
}
|
||||||
|
|
||||||
@@ -16,14 +16,18 @@
|
|||||||
|
|
||||||
import konan.internal.ExportForCppRuntime
|
import konan.internal.ExportForCppRuntime
|
||||||
|
|
||||||
external fun main(args: Array<String>)
|
// This function is produced by the code generator given
|
||||||
|
// the '-entry foo.bar.main' flag.
|
||||||
|
// It calls the requested entry point.
|
||||||
|
// The default is main(Array<String>):Unit in the root package.
|
||||||
|
@ExportForCppRuntime
|
||||||
|
external fun EntryPointSelector(args: Array<String>)
|
||||||
|
|
||||||
@ExportForCppRuntime
|
@ExportForCppRuntime
|
||||||
private fun Konan_start(args: Array<String>): Int {
|
private fun Konan_start(args: Array<String>): Int {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// This is kotlin program main entry point
|
EntryPointSelector(args)
|
||||||
main(args)
|
|
||||||
|
|
||||||
// Successfully finished:
|
// Successfully finished:
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user