[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 stripDebugInfoFromNativeLibs by booleanOption()
|
||||||
|
|
||||||
val sourceInfoType by option<SourceInfoType>()
|
val sourceInfoType by option<SourceInfoType>()
|
||||||
|
|
||||||
|
val androidProgramType by option<AndroidProgramType>()
|
||||||
}
|
}
|
||||||
|
|
||||||
open class BinaryOption<T : Any>(
|
open class BinaryOption<T : Any>(
|
||||||
|
|||||||
+3
-2
@@ -85,8 +85,9 @@ private fun insertAliasToEntryPoint(context: Context) {
|
|||||||
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
|
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
|
||||||
return
|
return
|
||||||
val module = context.llvmModule
|
val module = context.llvmModule
|
||||||
val entryPoint = LLVMGetNamedFunction(module, "Konan_main")
|
val entryPointName = context.config.entryPointName
|
||||||
?: error("Module doesn't contain `Konan_main`")
|
val entryPoint = LLVMGetNamedFunction(module, entryPointName)
|
||||||
|
?: error("Module doesn't contain `$entryPointName`")
|
||||||
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
|
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 propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION)!!
|
||||||
|
|
||||||
internal val lazyIrForCaches: Boolean get() = configuration.get(KonanConfigKeys.LAZY_IR_FOR_CACHES)!!
|
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)
|
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.DYNAMIC -> LinkerOutputKind.DYNAMIC_LIBRARY
|
||||||
CompilerOutputKind.STATIC_CACHE,
|
CompilerOutputKind.STATIC_CACHE,
|
||||||
CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY
|
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")
|
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))
|
functionType(int32Type, false, int8TypePtr, int8TypePtr, int32Type))
|
||||||
overrideRuntimeGlobal("Kotlin_getSourceInfo_Function", constValue(getSourceInfoFunction!!))
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "launcher.h"
|
||||||
#include "androidLauncher.h"
|
#include "androidLauncher.h"
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
@@ -44,8 +45,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--- main --------------------------------------------------------------------//
|
//--- main --------------------------------------------------------------------//
|
||||||
extern "C" KInt Konan_start(const ObjHeader*);
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Worker.h"
|
#include "Worker.h"
|
||||||
|
|
||||||
#ifndef KONAN_ANDROID
|
#include "launcher.h"
|
||||||
|
|
||||||
//--- Setup args --------------------------------------------------------------//
|
//--- Setup args --------------------------------------------------------------//
|
||||||
|
|
||||||
@@ -38,8 +38,6 @@ OBJ_GETTER(setupArgs, int argc, const char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--- main --------------------------------------------------------------------//
|
//--- main --------------------------------------------------------------------//
|
||||||
extern "C" KInt Konan_start(const ObjHeader*);
|
|
||||||
|
|
||||||
extern "C" KInt Konan_run_start(int argc, const char** argv) {
|
extern "C" KInt Konan_run_start(int argc, const char** argv) {
|
||||||
ObjHolder args;
|
ObjHolder args;
|
||||||
setupArgs(argc, argv, args.slot());
|
setupArgs(argc, argv, args.slot());
|
||||||
@@ -64,7 +62,11 @@ extern "C" RUNTIME_USED int Init_and_run_start(int argc, const char** argv, int
|
|||||||
return exitStatus;
|
return exitStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef KONAN_ANDROID
|
||||||
extern "C" RUNTIME_USED int Konan_main(int argc, const char** argv) {
|
extern "C" RUNTIME_USED int Konan_main(int argc, const char** argv) {
|
||||||
|
#else
|
||||||
|
extern "C" RUNTIME_USED int Konan_main_standalone(int argc, const char** argv) {
|
||||||
|
#endif
|
||||||
return Init_and_run_start(argc, argv, 1);
|
return Init_and_run_start(argc, argv, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +85,4 @@ extern "C" RUNTIME_USED int Konan_js_main(int argc, int memoryDeInit) {
|
|||||||
return Init_and_run_start(argc, (const char**)argv, memoryDeInit);
|
return Init_and_run_start(argc, (const char**)argv, memoryDeInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LAUNCHER_H
|
||||||
|
#define LAUNCHER_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
KInt Konan_start(const ObjHeader*);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // LAUNCHER_H
|
||||||
@@ -16,6 +16,9 @@ RUNTIME_WEAK int32_t Kotlin_gcAggressive = 0;
|
|||||||
RUNTIME_WEAK int32_t Kotlin_workerExceptionHandling = 0;
|
RUNTIME_WEAK int32_t Kotlin_workerExceptionHandling = 0;
|
||||||
RUNTIME_WEAK int32_t Kotlin_freezingEnabled = 1;
|
RUNTIME_WEAK int32_t Kotlin_freezingEnabled = 1;
|
||||||
RUNTIME_WEAK const Kotlin_getSourceInfo_FunctionType Kotlin_getSourceInfo_Function = nullptr;
|
RUNTIME_WEAK const Kotlin_getSourceInfo_FunctionType Kotlin_getSourceInfo_Function = nullptr;
|
||||||
|
#ifdef KONAN_ANDROID
|
||||||
|
RUNTIME_WEAK int32_t Kotlin_printToAndroidLogcat = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
ALWAYS_INLINE compiler::DestroyRuntimeMode compiler::destroyRuntimeMode() noexcept {
|
ALWAYS_INLINE compiler::DestroyRuntimeMode compiler::destroyRuntimeMode() noexcept {
|
||||||
return static_cast<compiler::DestroyRuntimeMode>(Kotlin_destroyRuntimeMode);
|
return static_cast<compiler::DestroyRuntimeMode>(Kotlin_destroyRuntimeMode);
|
||||||
@@ -32,3 +35,9 @@ ALWAYS_INLINE compiler::WorkerExceptionHandling compiler::workerExceptionHandlin
|
|||||||
ALWAYS_INLINE bool compiler::freezingEnabled() noexcept {
|
ALWAYS_INLINE bool compiler::freezingEnabled() noexcept {
|
||||||
return Kotlin_freezingEnabled != 0;
|
return Kotlin_freezingEnabled != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef KONAN_ANDROID
|
||||||
|
ALWAYS_INLINE bool compiler::printToAndroidLogcat() noexcept {
|
||||||
|
return Kotlin_printToAndroidLogcat != 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ ALWAYS_INLINE inline int getSourceInfo(void* addr, SourceInfo *result, int resul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef KONAN_ANDROID
|
||||||
|
bool printToAndroidLogcat() noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
#include "Porting.h"
|
#include "Porting.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Exceptions.h"
|
#include "Exceptions.h"
|
||||||
|
#ifdef KONAN_ANDROID
|
||||||
|
#include "CompilerConstants.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
|
||||||
@@ -46,8 +49,12 @@ void Kotlin_io_Console_print(KString message) {
|
|||||||
void Kotlin_io_Console_println(KString message) {
|
void Kotlin_io_Console_println(KString message) {
|
||||||
Kotlin_io_Console_print(message);
|
Kotlin_io_Console_print(message);
|
||||||
#ifndef KONAN_ANDROID
|
#ifndef KONAN_ANDROID
|
||||||
// On Android single print produces logcat entry, so no need in linefeed.
|
|
||||||
Kotlin_io_Console_println0();
|
Kotlin_io_Console_println0();
|
||||||
|
#else
|
||||||
|
// On Android single print produces logcat entry, so no need in linefeed.
|
||||||
|
if (!kotlin::compiler::printToAndroidLogcat()) {
|
||||||
|
Kotlin_io_Console_println0();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,12 @@ void consoleInit() {
|
|||||||
|
|
||||||
void consoleWriteUtf8(const char* utf8, uint32_t sizeBytes) {
|
void consoleWriteUtf8(const char* utf8, uint32_t sizeBytes) {
|
||||||
#ifdef KONAN_ANDROID
|
#ifdef KONAN_ANDROID
|
||||||
// TODO: use sizeBytes!
|
if (kotlin::compiler::printToAndroidLogcat()) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
|
// TODO: use sizeBytes!
|
||||||
|
__android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
|
||||||
|
} else {
|
||||||
|
::write(STDOUT_FILENO, utf8, sizeBytes);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
::write(STDOUT_FILENO, utf8, sizeBytes);
|
::write(STDOUT_FILENO, utf8, sizeBytes);
|
||||||
#endif
|
#endif
|
||||||
@@ -71,8 +75,12 @@ void consoleWriteUtf8(const char* utf8, uint32_t sizeBytes) {
|
|||||||
|
|
||||||
NO_EXTERNAL_CALLS_CHECK void consoleErrorUtf8(const char* utf8, uint32_t sizeBytes) {
|
NO_EXTERNAL_CALLS_CHECK void consoleErrorUtf8(const char* utf8, uint32_t sizeBytes) {
|
||||||
#ifdef KONAN_ANDROID
|
#ifdef KONAN_ANDROID
|
||||||
// TODO: use sizeBytes!
|
if (kotlin::compiler::printToAndroidLogcat()) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
|
// TODO: use sizeBytes!
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
|
||||||
|
} else {
|
||||||
|
::write(STDERR_FILENO, utf8, sizeBytes);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
::write(STDERR_FILENO, utf8, sizeBytes);
|
::write(STDERR_FILENO, utf8, sizeBytes);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -145,8 +145,11 @@ class AndroidLinker(targetProperties: AndroidConfigurables)
|
|||||||
return listOf(Command(clang).apply {
|
return listOf(Command(clang).apply {
|
||||||
+"-o"
|
+"-o"
|
||||||
+executable
|
+executable
|
||||||
+"-fPIC"
|
when (kind) {
|
||||||
+"-shared"
|
LinkerOutputKind.EXECUTABLE -> +listOf("-fPIE", "-pie")
|
||||||
|
LinkerOutputKind.DYNAMIC_LIBRARY -> +listOf("-fPIC", "-shared")
|
||||||
|
LinkerOutputKind.STATIC_LIBRARY -> {}
|
||||||
|
}
|
||||||
+"-target"
|
+"-target"
|
||||||
+clangTarget
|
+clangTarget
|
||||||
+libDirs
|
+libDirs
|
||||||
|
|||||||
Reference in New Issue
Block a user