[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))
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "launcher.h"
|
||||
#include "androidLauncher.h"
|
||||
|
||||
#include <android/log.h>
|
||||
@@ -44,8 +45,6 @@
|
||||
#endif
|
||||
|
||||
//--- main --------------------------------------------------------------------//
|
||||
extern "C" KInt Konan_start(const ObjHeader*);
|
||||
|
||||
namespace {
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "Types.h"
|
||||
#include "Worker.h"
|
||||
|
||||
#ifndef KONAN_ANDROID
|
||||
#include "launcher.h"
|
||||
|
||||
//--- Setup args --------------------------------------------------------------//
|
||||
|
||||
@@ -38,8 +38,6 @@ OBJ_GETTER(setupArgs, int argc, const char** argv) {
|
||||
}
|
||||
|
||||
//--- main --------------------------------------------------------------------//
|
||||
extern "C" KInt Konan_start(const ObjHeader*);
|
||||
|
||||
extern "C" KInt Konan_run_start(int argc, const char** argv) {
|
||||
ObjHolder args;
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef KONAN_ANDROID
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
#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_freezingEnabled = 1;
|
||||
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 {
|
||||
return static_cast<compiler::DestroyRuntimeMode>(Kotlin_destroyRuntimeMode);
|
||||
@@ -32,3 +35,9 @@ ALWAYS_INLINE compiler::WorkerExceptionHandling compiler::workerExceptionHandlin
|
||||
ALWAYS_INLINE bool compiler::freezingEnabled() noexcept {
|
||||
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 kotlin
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "Porting.h"
|
||||
#include "Types.h"
|
||||
#include "Exceptions.h"
|
||||
#ifdef KONAN_ANDROID
|
||||
#include "CompilerConstants.hpp"
|
||||
#endif
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
@@ -46,8 +49,12 @@ void Kotlin_io_Console_print(KString message) {
|
||||
void Kotlin_io_Console_println(KString message) {
|
||||
Kotlin_io_Console_print(message);
|
||||
#ifndef KONAN_ANDROID
|
||||
// On Android single print produces logcat entry, so no need in linefeed.
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,12 @@ void consoleInit() {
|
||||
|
||||
void consoleWriteUtf8(const char* utf8, uint32_t sizeBytes) {
|
||||
#ifdef KONAN_ANDROID
|
||||
// TODO: use sizeBytes!
|
||||
__android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
|
||||
if (kotlin::compiler::printToAndroidLogcat()) {
|
||||
// TODO: use sizeBytes!
|
||||
__android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
|
||||
} else {
|
||||
::write(STDOUT_FILENO, utf8, sizeBytes);
|
||||
}
|
||||
#else
|
||||
::write(STDOUT_FILENO, utf8, sizeBytes);
|
||||
#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) {
|
||||
#ifdef KONAN_ANDROID
|
||||
// TODO: use sizeBytes!
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
|
||||
if (kotlin::compiler::printToAndroidLogcat()) {
|
||||
// TODO: use sizeBytes!
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
|
||||
} else {
|
||||
::write(STDERR_FILENO, utf8, sizeBytes);
|
||||
}
|
||||
#else
|
||||
::write(STDERR_FILENO, utf8, sizeBytes);
|
||||
#endif
|
||||
|
||||
@@ -145,8 +145,11 @@ class AndroidLinker(targetProperties: AndroidConfigurables)
|
||||
return listOf(Command(clang).apply {
|
||||
+"-o"
|
||||
+executable
|
||||
+"-fPIC"
|
||||
+"-shared"
|
||||
when (kind) {
|
||||
LinkerOutputKind.EXECUTABLE -> +listOf("-fPIE", "-pie")
|
||||
LinkerOutputKind.DYNAMIC_LIBRARY -> +listOf("-fPIC", "-shared")
|
||||
LinkerOutputKind.STATIC_LIBRARY -> {}
|
||||
}
|
||||
+"-target"
|
||||
+clangTarget
|
||||
+libDirs
|
||||
|
||||
Reference in New Issue
Block a user