[Native] Enable real Android Native executables (#4624)
* Add AndroidProgramType binary option, override entry point, fix linker flags * Add Konan_main_standalone entry point to the Android runtime * Add compiler warning * Make standalone programs print to stdout * Fix warning message and readability
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
|
||||
|
||||
/**
|
||||
* For historical reasons, Android Native executables can be of two types:
|
||||
* - [Standalone] is a regular executable, in which the Konan entry point receives command line arguments as usual.
|
||||
* - [NativeActivity] is a shared library in which the Konan entry point matches Android NDK's NativeActivity
|
||||
* signature ( https://developer.android.com/ndk/reference/group/native-activity#anativeactivity_createfunc ).
|
||||
*/
|
||||
enum class AndroidProgramType(
|
||||
val konanMainOverride: String?,
|
||||
val linkerOutputKindOverride: LinkerOutputKind?,
|
||||
val consolePrintsToLogcat: Boolean
|
||||
) {
|
||||
|
||||
/** Regular executable. The runtime entry point name is not Konan_main for historical reasons. */
|
||||
Standalone("Konan_main_standalone", null, false),
|
||||
|
||||
/** Native activity "executable" - a shared library with a specific entry point. */
|
||||
NativeActivity(null, LinkerOutputKind.DYNAMIC_LIBRARY, true);
|
||||
|
||||
companion object {
|
||||
val Default = NativeActivity
|
||||
}
|
||||
}
|
||||
+2
@@ -21,6 +21,8 @@ object BinaryOptions : BinaryOptionRegistry() {
|
||||
val stripDebugInfoFromNativeLibs by booleanOption()
|
||||
|
||||
val sourceInfoType by option<SourceInfoType>()
|
||||
|
||||
val androidProgramType by option<AndroidProgramType>()
|
||||
}
|
||||
|
||||
open class BinaryOption<T : Any>(
|
||||
|
||||
+3
-2
@@ -85,8 +85,9 @@ private fun insertAliasToEntryPoint(context: Context) {
|
||||
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
|
||||
return
|
||||
val module = context.llvmModule
|
||||
val entryPoint = LLVMGetNamedFunction(module, "Konan_main")
|
||||
?: error("Module doesn't contain `Konan_main`")
|
||||
val entryPointName = context.config.entryPointName
|
||||
val entryPoint = LLVMGetNamedFunction(module, entryPointName)
|
||||
?: error("Module doesn't contain `$entryPointName`")
|
||||
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -275,6 +275,29 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
internal val propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION)!!
|
||||
|
||||
internal val lazyIrForCaches: Boolean get() = configuration.get(KonanConfigKeys.LAZY_IR_FOR_CACHES)!!
|
||||
|
||||
internal val entryPointName: String by lazy {
|
||||
if (target.family == Family.ANDROID) {
|
||||
val androidProgramTypeOrNull = configuration.get(BinaryOptions.androidProgramType)
|
||||
if (androidProgramTypeOrNull == null) {
|
||||
configuration.report(CompilerMessageSeverity.WARNING, """
|
||||
Android Native executables are currently built as shared libraries with NativeActivity support, but the default behavior is going to change in 1.7.0 to build regular executables instead.
|
||||
To keep using NativeActivity support, add binaryOptions["androidProgramType"] = "nativeActivity" to your androidNative executable configuration block in Gradle script:
|
||||
binaries {
|
||||
executable {
|
||||
binaryOptions["androidProgramType"] = "nativeActivity"
|
||||
}
|
||||
}
|
||||
See https://youtrack.jetbrains.com/issue/KT-49406 for more details.
|
||||
""".trimIndent())
|
||||
}
|
||||
val androidProgramType = androidProgramTypeOrNull ?: AndroidProgramType.Default
|
||||
if (androidProgramType.konanMainOverride != null) {
|
||||
return@lazy androidProgramType.konanMainOverride
|
||||
}
|
||||
}
|
||||
"Konan_main"
|
||||
}
|
||||
}
|
||||
|
||||
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
|
||||
|
||||
+10
-1
@@ -21,7 +21,16 @@ internal fun determineLinkerOutput(context: Context): LinkerOutputKind =
|
||||
CompilerOutputKind.DYNAMIC -> LinkerOutputKind.DYNAMIC_LIBRARY
|
||||
CompilerOutputKind.STATIC_CACHE,
|
||||
CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY
|
||||
CompilerOutputKind.PROGRAM -> LinkerOutputKind.EXECUTABLE
|
||||
CompilerOutputKind.PROGRAM -> run {
|
||||
if (context.config.target.family == Family.ANDROID) {
|
||||
val configuration = context.config.configuration
|
||||
val androidProgramType = configuration.get(BinaryOptions.androidProgramType) ?: AndroidProgramType.Default
|
||||
if (androidProgramType.linkerOutputKindOverride != null) {
|
||||
return@run androidProgramType.linkerOutputKindOverride
|
||||
}
|
||||
}
|
||||
LinkerOutputKind.EXECUTABLE
|
||||
}
|
||||
else -> TODO("${context.config.produce} should not reach native linker stage")
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -2745,6 +2745,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
functionType(int32Type, false, int8TypePtr, int8TypePtr, int32Type))
|
||||
overrideRuntimeGlobal("Kotlin_getSourceInfo_Function", constValue(getSourceInfoFunction!!))
|
||||
}
|
||||
if (context.config.target.family == Family.ANDROID && context.config.produce == CompilerOutputKind.PROGRAM) {
|
||||
val configuration = context.config.configuration
|
||||
val programType = configuration.get(BinaryOptions.androidProgramType) ?: AndroidProgramType.Default
|
||||
overrideRuntimeGlobal("Kotlin_printToAndroidLogcat", Int32(if (programType.consolePrintsToLogcat) 1 else 0))
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
Reference in New Issue
Block a user