Depend on kotlin-native-shared from a separate repo

Kotlin-native-shared was copied in a separate repository.
This patch removes this subproject from the K/N repo and
adds a dependency on an artifact built from this separate repo.
This commit is contained in:
Ilya Matveev
2018-10-10 21:12:29 +03:00
committed by Ilya Matveev
parent 575cbf48c3
commit a2370920db
79 changed files with 168 additions and 4156 deletions
+1 -1
View File
@@ -18,10 +18,10 @@ buildscript {
ext.rootBuildDirectory = file('../..')
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
apply from: "$rootBuildDirectory/gradle/kotlinNativeShared.gradle"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
}
}
apply plugin: 'kotlin'
+1 -1
View File
@@ -21,10 +21,10 @@ buildscript {
ext.rootBuildDirectory = file('../..')
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
apply from: "$rootBuildDirectory/gradle/kotlinNativeShared.gradle"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
}
}
import org.jetbrains.kotlin.konan.target.ClangArgs
+1 -1
View File
@@ -34,7 +34,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-compiler:$buildKotlinVersion"
compile project(':Interop:Indexer')
compile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
compile kotlinNativeSharedModule
}
compileKotlin {
+5 -3
View File
@@ -111,6 +111,7 @@ configurations {
kotlin_stdlib_jar
kotlin_reflect_jar
kotlin_script_runtime_jar
kotlin_native_shared_jar
kotlin_common_stdlib_src
kotlin_test_common_src
kotlin_test_annotations_common_src
@@ -132,6 +133,7 @@ dependencies {
kotlin_stdlib_jar "$kotlinStdLibModule@jar"
kotlin_reflect_jar "$kotlinReflectModule@jar"
kotlin_script_runtime_jar "$kotlinScriptRuntimeModule@jar"
kotlin_native_shared_jar "$kotlinNativeSharedModule@jar"
kotlin_common_stdlib_src kotlinCommonStdlibModule
kotlin_test_common_src kotlinTestCommonModule
kotlin_test_annotations_common_src kotlinTestAnnotationsCommonModule
@@ -141,11 +143,11 @@ dependencies {
compilerCompile kotlinCompilerModule
compilerCompile kotlinNativeInterop['llvm'].configuration
compilerCompile kotlinNativeInterop['hash'].configuration
compilerCompile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
compilerCompile kotlinNativeSharedModule
compilerCompile "org.jetbrains.kotlin:konan.serializer:$konanVersion"
cli_bcCompile kotlinCompilerModule
cli_bcCompile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
cli_bcCompile kotlinNativeSharedModule
cli_bcCompile sourceSets.compiler.output
cli_bcCompile "org.jetbrains.kotlin:konan.serializer:$konanVersion"
@@ -268,7 +270,7 @@ jar {
dependsOn ':runtime:hostRuntime', 'external_jars'
}
def externalJars = ['compiler', 'stdlib', 'reflect', 'script_runtime']
def externalJars = ['compiler', 'stdlib', 'reflect', 'script_runtime', 'native_shared']
task trove4jCopy(type: Copy) {
from configurations.getByName("trove4j_jar") {
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan
import llvm.*
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
@@ -13,18 +13,15 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_W
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.*
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.library.libraryResolver
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.resolver.TopologicalLibraryOrder
import org.jetbrains.kotlin.konan.library.toUnresolvedLibraries
import org.jetbrains.kotlin.konan.parseKonanVersion
class KonanConfig(val project: Project, val configuration: CompilerConfiguration) {
@@ -89,8 +86,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
libraryNames.filter { it.contains(File.separator) },
target,
distribution,
::resolverLogger,
compatibleCompilerVersions = compatibleCompilerVersions
compatibleCompilerVersions + KonanVersion.CURRENT,
::resolverLogger
).libraryResolver()
internal val resolvedLibraries by lazy {
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.types.KotlinType
+1 -1
View File
@@ -4,7 +4,7 @@ apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile project(path: ':backend.native', configuration: 'cli_bc')
compile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
compile kotlinNativeSharedModule
compile 'junit:junit:4.12'
}
+14 -8
View File
@@ -18,14 +18,16 @@ import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.properties.*
import org.jetbrains.kotlin.konan.util.*
import org.jetbrains.kotlin.CopySamples
import org.jetbrains.kotlin.konan.*
buildscript {
apply from: "gradle/kotlinGradlePlugin.gradle"
apply from: "gradle/kotlinNativeShared.gradle"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
classpath "org.jetbrains.kotlin:kotlin-native-version:$konanVersion"
}
}
import org.jetbrains.kotlin.konan.*
// Allows generating wrappers for the root build and all the samples during execution of the default 'wrapper' task.
// Run './gradlew wrapper --gradle-version <version>' to update all the wrappers.
@@ -52,13 +54,14 @@ ext {
kotlinTestAnnotationsCommonModule="org.jetbrains.kotlin:kotlin-test-annotations-common:${kotlinVersion}:sources"
kotlinReflectModule="org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}"
kotlinScriptRuntimeModule="org.jetbrains.kotlin:kotlin-script-runtime:${kotlinVersion}"
kotlinNativeSharedModule="org.jetbrains.kotlin:kotlin-native-shared:$sharedVersion"
konanVersionFull = KonanVersion.Companion.CURRENT
konanVersionFull = KonanVersionGeneratedKt.getCurrentKonanVersion()
if (konanVersionFull.meta == MetaVersion.RELEASE) {
gradlePluginVersion = kotlinVersion
} else {
gradlePluginVersion = "$kotlinVersion-native-${KonanVersion.Companion.CURRENT.toString()}"
gradlePluginVersion = "$kotlinVersion-native-${konanVersionFull.toString()}"
}
}
@@ -74,6 +77,9 @@ allprojects {
maven {
url kotlinCompilerRepo
}
maven {
url sharedRepo
}
}
setupHostAndTarget()
@@ -189,8 +195,8 @@ class PlatformInfo {
}
}
task sharedJar {
dependsOn gradle.includedBuild('kotlin-native-shared').task(':jar')
task versionJar {
dependsOn gradle.includedBuild('kotlin-native-version').task(':jar')
}
task gradlePluginJar {
@@ -221,7 +227,7 @@ task distCompiler(type: Copy) {
dependsOn ':backend.native:jar'
dependsOn ':utilities:jar'
dependsOn ':klib:jar'
dependsOn ':sharedJar'
dependsOn ':versionJar'
destinationDir distDir
@@ -281,7 +287,7 @@ task distCompiler(type: Copy) {
into('konan/lib')
}
from(file("${gradle.includedBuild('kotlin-native-shared').projectDir}/build/libs")) {
from(file("${gradle.includedBuild('kotlin-native-version').projectDir}/build/libs")) {
into('konan/lib')
}
+10 -1
View File
@@ -29,6 +29,15 @@ allprojects {
url 'https://cache-redirector.jetbrains.com/maven-central'
}
maven { url "https://kotlin.bintray.com/kotlinx" }
maven {
url "https://kotlin.bintray.com/kotlinx"
}
maven {
url sharedRepo
}
}
}
dependencies {
runtime project(':plugins')
}
+2 -3
View File
@@ -15,6 +15,7 @@
*/
apply plugin: 'groovy'
apply plugin: 'kotlin'
buildscript {
ext.rootBuildDirectory = "$rootDir/.."
@@ -37,9 +38,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-reflect:$buildKotlinVersion"
compile group: 'com.ullink.slack', name: 'simpleslackapi', version: '0.6.0'
// An artifact from the included build 'shared' cannot be used here due to https://github.com/gradle/gradle/issues/3768
// TODO: Remove this hack when the bug is fixed
compile project(':shared')
compile "org.jetbrains.kotlin:kotlin-native-shared:$sharedVersion"
compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.10.0"
}
-1
View File
@@ -14,5 +14,4 @@
* limitations under the License.
*/
include 'shared'
include 'plugins'
-45
View File
@@ -1,45 +0,0 @@
/*
* 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.
*/
buildscript {
ext {
gradleProperties = new Properties()
gradleProperties.load(new FileInputStream("$projectDir/../../gradle.properties"))
buildKotlinVersion = gradleProperties."buildKotlinVersion"
buildKotlinCompilerRepo = gradleProperties."buildKotlinCompilerRepo"
}
apply from: '../../gradle/kotlinGradlePlugin.gradle'
}
apply plugin: 'kotlin'
// We reuse the source code from the Project in buildSrc.
sourceSets.main.kotlin.srcDirs = ["$projectDir/../../shared/src/main/kotlin"]
repositories {
maven {
url buildKotlinCompilerRepo
}
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
}
rootProject.dependencies {
runtime project(path)
}
+3 -2
View File
@@ -85,13 +85,14 @@ KOTLIN_SCRIPT_RUNTIME_JAR="${KONAN_HOME}/konan/lib/kotlin-script-runtime.jar"
STUB_GENERATOR_JAR="${KONAN_HOME}/konan/lib/StubGenerator.jar"
INTEROP_INDEXER_JAR="${KONAN_HOME}/konan/lib/Indexer.jar"
INTEROP_JAR="${KONAN_HOME}/konan/lib/Runtime.jar"
SHARED_JAR="${KONAN_HOME}/konan/lib/shared.jar"
SHARED_JAR="${KONAN_HOME}/konan/lib/kotlin-native-shared.jar"
EXTRACTED_METADATA_JAR="${KONAN_HOME}/konan/lib/konan.metadata.jar"
EXTRACTED_SERIALIZER_JAR="${KONAN_HOME}/konan/lib/konan.serializer.jar"
KLIB_JAR="${KONAN_HOME}/konan/lib/klib.jar"
UTILITIES_JAR="${KONAN_HOME}/konan/lib/utilities.jar"
TROVE_JAR="${KONAN_HOME}/konan/lib/trove4j.jar"
KONAN_CLASSPATH="$KOTLIN_JAR:$KOTLIN_STDLIB_JAR:$KOTLIN_REFLECT_JAR:$KOTLIN_SCRIPT_RUNTIME_JAR:$INTEROP_JAR:$STUB_GENERATOR_JAR:$INTEROP_INDEXER_JAR:$KONAN_JAR:$KLIB_JAR:$UTILITIES_JAR:$SHARED_JAR:$EXTRACTED_METADATA_JAR:$EXTRACTED_SERIALIZER_JAR:$TROVE_JAR"
VERSION_JAR="${KONAN_HOME}/konan/lib/version.jar"
KONAN_CLASSPATH="$KOTLIN_JAR:$KOTLIN_STDLIB_JAR:$KOTLIN_REFLECT_JAR:$KOTLIN_SCRIPT_RUNTIME_JAR:$INTEROP_JAR:$STUB_GENERATOR_JAR:$INTEROP_INDEXER_JAR:$KONAN_JAR:$KLIB_JAR:$UTILITIES_JAR:$SHARED_JAR:$EXTRACTED_METADATA_JAR:$EXTRACTED_SERIALIZER_JAR:$TROVE_JAR:$VERSION_JAR"
TOOL_CLASS=org.jetbrains.kotlin.cli.utilities.MainKt
LIBCLANG_DISABLE_CRASH_RECOVERY=1 \
+3 -2
View File
@@ -54,7 +54,7 @@ if not "!ARG!" == "" (
set "NATIVE_LIB=%_KONAN_HOME%\konan\nativelib"
set "KONAN_LIB=%_KONAN_HOME%\konan\lib"
set "SHARED_JAR=%KONAN_LIB%\shared.jar"
set "SHARED_JAR=%KONAN_LIB%\kotlin-native-shared.jar"
set "EXTRACTED_METADATA_JAR=%KONAN_LIB%\konan.metadata.jar"
set "EXTRACTED_SERIALIZER_JAR=%KONAN_LIB%\konan.serializer.jar"
set "INTEROP_INDEXER_JAR=%KONAN_LIB%\Indexer.jar"
@@ -68,8 +68,9 @@ set "KOTLIN_SCRIPT_RUNTIME_JAR=%KONAN_LIB%\kotlin-script-runtime.jar"
set "STUB_GENERATOR_JAR=%KONAN_LIB%\StubGenerator.jar"
set "UTILITIES_JAR=%KONAN_LIB%\utilities.jar"
set TROVE_JAR="%KONAN_LIB%\lib\trove4j.jar"
set "VERSION_JAR=%KONAN_LIB%\version.jar"
set "KONAN_CLASSPATH=%KOTLIN_JAR%;%KOTLIN_STDLIB_JAR%;%KOTLIN_REFLECT_JAR%;%KOTLIN_SCRIPT_RUNTIME_JAR%;%INTEROP_RUNTIME_JAR%;%KONAN_JAR%;%STUB_GENERATOR_JAR%;%INTEROP_INDEXER_JAR%;%SHARED_JAR%;%EXTRACTED_METADATA_JAR%;%EXTRACTED_SERIALIZER_JAR%;%KLIB_JAR%;%UTILITIES_JAR%;%TROVE_JAR%"
set "KONAN_CLASSPATH=%KOTLIN_JAR%;%KOTLIN_STDLIB_JAR%;%KOTLIN_REFLECT_JAR%;%KOTLIN_SCRIPT_RUNTIME_JAR%;%INTEROP_RUNTIME_JAR%;%KONAN_JAR%;%STUB_GENERATOR_JAR%;%INTEROP_INDEXER_JAR%;%SHARED_JAR%;%EXTRACTED_METADATA_JAR%;%EXTRACTED_SERIALIZER_JAR%;%KLIB_JAR%;%UTILITIES_JAR%;%TROVE_JAR%;%VERSION_JAR%"
set JAVA_OPTS=-ea ^
-Xmx3G ^
+5 -1
View File
@@ -33,11 +33,15 @@ repositories {
maven {
url buildKotlinCompilerRepo
}
maven {
url sharedRepo
}
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
compile "org.jetbrains.kotlin:kotlin-native-shared:$sharedVersion"
compile "org.jetbrains.kotlin:kotlin-native-version"
compile "org.jetbrains.kotlin:kotlin-compiler:$kotlinVersion"
compile "org.jetbrains.kotlin:konan.metadata:$konanVersion"
}
+2
View File
@@ -21,6 +21,8 @@ remoteRoot=konan_tests
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_CompilerAllPlugins),number:1.3.40-dev-392,branch:default:true,pinned:true/artifacts/content/maven
kotlinVersion=1.3.40-dev-392
testKotlinVersion=1.3.40-dev-392
sharedRepo=https://teamcity.jetbrains.com/guestAuth/repository/download/Kotlin_KotlinNativeShared_BuildAndTest/2051827:id/maven
sharedVersion=1.2.0
konanVersion=1.3.0
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.workers.max=4
+19
View File
@@ -0,0 +1,19 @@
if (!hasProperty('sharedVersion')) {
throw new GradleException('Please ensure the "sharedVersion" property is defined before applying this script.')
}
if (!hasProperty('sharedRepo')) {
throw new GradleException('Please ensure the "sharedRepo" property is defined before applying this script.')
}
project.buildscript {
repositories {
maven { url sharedRepo }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-native-shared:$sharedVersion"
// An included build with generated Kotlin/Native version.
classpath "org.jetbrains.kotlin:kotlin-native-version"
}
}
+1 -1
View File
@@ -20,10 +20,10 @@ buildscript {
ext.rootBuildDirectory = file('..')
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
apply from: "$rootBuildDirectory/gradle/kotlinNativeShared.gradle"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
}
}
import org.jetbrains.kotlin.konan.target.ClangArgs
+1 -9
View File
@@ -17,16 +17,8 @@
apply plugin: "cpp"
apply plugin: "c"
buildscript {
ext.rootBuildDirectory = file('..')
apply from: "${rootProject.projectDir}/gradle/kotlinGradlePlugin.gradle"
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
}
}
import org.jetbrains.kotlin.konan.target.ClangArgs
model {
+1 -1
View File
@@ -21,10 +21,10 @@ buildscript {
ext.rootBuildDirectory = file('..')
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
apply from: "$rootBuildDirectory/gradle/kotlinNativeShared.gradle"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
}
}
import org.jetbrains.kotlin.konan.target.ClangArgs
+1 -1
View File
@@ -33,7 +33,7 @@ include ':utilities'
//include ':tools:benchmarksAnalyzer'
include ':platformLibs'
includeBuild 'shared'
includeBuild 'version'
includeBuild 'extracted/konan.metadata'
includeBuild 'extracted/konan.serializer'
includeBuild 'tools/kotlin-native-gradle-plugin'
@@ -1,115 +0,0 @@
package org.jetbrains.kotlin
import groovy.lang.Closure
import org.gradle.api.DefaultTask
import org.gradle.api.Task
import org.gradle.api.tasks.*
import java.io.File
open class VersionGenerator: DefaultTask() {
@OutputDirectory
val versionSourceDirectory = project.file("build/generated")
@OutputFile
val versionFile:File = project.file("${versionSourceDirectory.path}/org/jetbrains/kotlin/konan/KonanVersion.kt")
val konanVersion: String
@Input get() = project.properties["konanVersion"].toString()
val buildNumber: String?
// TeamCity passes all configuration parameters into a build script as project properties.
// Thus we can use them here instead of environment variables.
@Optional @Input get() = project.findProperty("build.number")?.toString()
val meta: String
@Input get() = project.properties["konanMetaVersion"]?.let {
"MetaVersion.${it.toString().toUpperCase()}"
} ?: "MetaVersion.DEV"
override fun configure(closure: Closure<*>): Task {
val result = super.configure(closure)
doFirst {
val content = buildString {
operator fun String.unaryPlus() = this@buildString.append(this)
val version = konanVersion.split(".")
val major = version[0].toInt()
val minor = version[1].toInt()
val maintenance = if (version.size > 2) version[2].toInt() else 0
project.logger.info("BUILD_NUMBER: $buildNumber")
val build = buildNumber?.let {
it.split("-")[2].toInt() //7-dev-buildcount
}?: -1
+ """
|package org.jetbrains.kotlin.konan
|
|import java.io.Serializable
|
|interface KonanVersion : Serializable {
| val meta: MetaVersion
| val major: Int
| val minor: Int
| val maintenance: Int
| val build: Int
|
| fun toString(showMeta: Boolean, showBuild: Boolean): String
|
| companion object {
| val CURRENT = KonanVersionImpl($meta, $major, $minor, $maintenance, $build)
| }
|}
|
|data class KonanVersionImpl(
| override val meta: MetaVersion = MetaVersion.DEV,
| override val major: Int,
| override val minor: Int,
| override val maintenance: Int,
| override val build: Int
|) : KonanVersion {
|
| override fun toString(showMeta: Boolean, showBuild: Boolean) = buildString {
| append(major)
| append('.')
| append(minor)
| if (maintenance != 0) {
| append('.')
| append(maintenance)
| }
| if (showMeta) {
| append('-')
| append(meta.metaString)
| }
| if (showBuild && build != -1) {
| append('-')
| append(build)
| }
| }
|
| private val isRelease: Boolean
| get() = meta == MetaVersion.RELEASE
|
| private val versionString by lazy { toString(!isRelease, !isRelease) }
|
| override fun toString() = versionString
|}
|fun String.parseKonanVersion(): KonanVersion {
| val (major, minor, maintenance, meta, build) =
| Regex(""${'"'}([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-(\p{Alpha}\p{Alnum}*))?(?:-([0-9]+))?""${'"'})
| .matchEntire(this)!!.destructured
| return KonanVersionImpl(
| MetaVersion.findAppropriate(meta),
| major.toInt(),
| minor.toInt(),
| maintenance.toIntOrNull() ?: 0,
| build.toIntOrNull() ?: -1)
|}
""".trimMargin()
}
versionFile.printWriter().use {
it.println(content)
}
}
return result
}
}
-1
View File
@@ -1 +0,0 @@
rootProject.name = "kotlin-native-shared"
@@ -1,73 +0,0 @@
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.propertyList
const val KLIB_PROPERTY_ABI_VERSION = "abi_version"
const val KLIB_PROPERTY_COMPILER_VERSION = "compiler_version"
const val KLIB_PROPERTY_DEPENDENCY_VERSION = "dependency_version"
const val KLIB_PROPERTY_LIBRARY_VERSION = "library_version"
const val KLIB_PROPERTY_UNIQUE_NAME = "unique_name"
const val KLIB_PROPERTY_LINKED_OPTS = "linkerOpts"
const val KLIB_PROPERTY_DEPENDS = "depends"
const val KLIB_PROPERTY_INTEROP = "interop"
const val KLIB_PROPERTY_PACKAGE = "package"
const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
const val KLIB_PROPERTY_INCLUDED_HEADERS = "includedHeaders"
/**
* An abstraction for getting access to the information stored inside of Kotlin/Native library.
*/
interface KonanLibrary {
val libraryName: String
val libraryFile: File
// Whether this library is default (provided by Kotlin/Native distribution)?
val isDefault: Boolean
// Properties:
val manifestProperties: Properties
val linkerOpts: List<String>
// Paths:
val bitcodePaths: List<String>
val includedPaths: List<String>
val targetList: List<String>
val versions: KonanLibraryVersioning
val dataFlowGraph: ByteArray?
val moduleHeaderData: ByteArray
fun packageMetadataParts(fqName: String): Set<String>
fun packageMetadata(fqName: String, partName: String): ByteArray
val irHeader: ByteArray?
fun irDeclaration(index: Long, isLocal: Boolean): ByteArray
}
val KonanLibrary.uniqueName
get() = manifestProperties.getProperty(KLIB_PROPERTY_UNIQUE_NAME)!!
val KonanLibrary.unresolvedDependencies: List<UnresolvedLibrary>
get() = manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS)
.map {
UnresolvedLibrary(it, manifestProperties.getProperty("dependency_version_$it"))
}
val KonanLibrary.isInterop
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
val KonanLibrary.packageFqName
get() = manifestProperties.getProperty(KLIB_PROPERTY_PACKAGE)
val KonanLibrary.exportForwardDeclarations
get() = manifestProperties.getProperty(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS)
.split(' ').asSequence()
.map { it.trim() }
.filter { it.isNotEmpty() }
.toList()
val KonanLibrary.includedHeaders
get() = manifestProperties.getProperty(KLIB_PROPERTY_INCLUDED_HEADERS).split(' ')
@@ -1,72 +0,0 @@
/**
* Copyright 2010-2019 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.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.KonanTarget
/**
* This scheme describes the Kotlin/Native Library (KLIB) layout.
*/
interface KonanLibraryLayout {
val libraryName: String
val libDir: File
val target: KonanTarget?
// This is a default implementation. Can't make it an assignment.
get() = null
val manifestFile
get() = File(libDir, "manifest")
val resourcesDir
get() = File(libDir, "resources")
val targetsDir
get() = File(libDir, "targets")
val targetDir
get() = File(targetsDir, target!!.visibleName)
val kotlinDir
get() = File(targetDir, "kotlin")
val nativeDir
get() = File(targetDir, "native")
val includedDir
get() = File(targetDir, "included")
val linkdataDir
get() = File(libDir, "linkdata")
val moduleHeaderFile
get() = File(linkdataDir, "module")
val dataFlowGraphFile
get() = File(linkdataDir, "module_data_flow_graph")
fun packageFragmentsDir(packageName: String)
= File(linkdataDir, if (packageName == "") "root_package" else "package_$packageName")
fun packageFragmentFile(packageFqName: String, partName: String) =
File(packageFragmentsDir(packageFqName), "$partName$KLIB_METADATA_FILE_EXTENSION_WITH_DOT")
val irDir
get() = File(libDir, "ir")
val irFile
get() = File(irDir, "irCombined.knd")
val irHeader
get() = File(irDir, "irHeaders.kni")
val irIndex: File
get() = File(irDir, "uniqIdTableDump.txt")
}
@@ -1,49 +0,0 @@
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.file
import org.jetbrains.kotlin.konan.file.withMutableZipFileSystem
import org.jetbrains.kotlin.konan.library.impl.DefaultMetadataReaderImpl
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
import org.jetbrains.kotlin.konan.library.impl.zippedKonanLibraryChecks
import org.jetbrains.kotlin.konan.target.KonanTarget
const val KLIB_FILE_EXTENSION = "klib"
const val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
const val KLIB_METADATA_FILE_EXTENSION = "knm"
const val KLIB_METADATA_FILE_EXTENSION_WITH_DOT = ".$KLIB_METADATA_FILE_EXTENSION"
fun File.unpackZippedKonanLibraryTo(newDir: File) {
// First, run validity checks for the given KLIB file.
zippedKonanLibraryChecks(this)
if (newDir.exists) {
if (newDir.isDirectory)
newDir.deleteRecursively()
else
newDir.delete()
}
this.withMutableZipFileSystem {
it.file("/").recursiveCopyTo(newDir)
}
check(newDir.exists) { "Could not unpack $this as $newDir." }
}
val List<String>.toUnresolvedLibraries
get() = this.map {
val version = it.substringAfterLast('@', "")
.let { if (it.isEmpty()) null else it}
val name = it.substringBeforeLast('@')
UnresolvedLibrary(name, version)
}
fun createKonanLibrary(
libraryFile: File,
target: KonanTarget? = null,
isDefault: Boolean = false,
metadataReader: MetadataReader = DefaultMetadataReaderImpl
): KonanLibrary = KonanLibraryImpl(libraryFile, target, isDefault, metadataReader)
@@ -1,28 +0,0 @@
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.parseKonanVersion
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.parseKonanAbiVersion
data class KonanLibraryVersioning(
val libraryVersion: String?,
val compilerVersion: KonanVersion?,
val abiVersion: KonanAbiVersion?
)
fun Properties.writeKonanLibraryVersioning(versions: KonanLibraryVersioning) {
versions.abiVersion ?. let { this.setProperty(KLIB_PROPERTY_ABI_VERSION, it.toString()) }
versions.libraryVersion ?. let { this.setProperty(KLIB_PROPERTY_LIBRARY_VERSION, it) }
versions.compilerVersion ?. let { this.setProperty(KLIB_PROPERTY_COMPILER_VERSION, "${versions.compilerVersion.toString(true, true)}") }
}
fun Properties.readKonanLibraryVersioning(): KonanLibraryVersioning {
val abiVersion = this.getProperty(KLIB_PROPERTY_ABI_VERSION)?.parseKonanAbiVersion()
val libraryVersion = this.getProperty(KLIB_PROPERTY_LIBRARY_VERSION)
val compilerVersion = this.getProperty(KLIB_PROPERTY_COMPILER_VERSION)?.parseKonanVersion()
return KonanLibraryVersioning(abiVersion = abiVersion, libraryVersion = libraryVersion, compilerVersion = compilerVersion)
}
@@ -1,6 +0,0 @@
package org.jetbrains.kotlin.konan.library
interface MetadataReader {
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray
}
@@ -1,244 +0,0 @@
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.*
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the constants below:
const val KONAN_STDLIB_NAME = "stdlib"
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
interface SearchPathResolver : WithLogger {
val searchRoots: List<File>
fun resolutionSequence(givenPath: String): Sequence<File>
fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean = false): KonanLibraryImpl
fun resolve(givenPath: String): KonanLibraryImpl
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<KonanLibraryImpl>
}
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
interface SearchPathResolverWithTarget: SearchPathResolver {
val target: KonanTarget
val knownAbiVersions: List<KonanAbiVersion>?
val knownCompilerVersions: List<KonanVersion>?
}
fun defaultResolver(
repositories: List<String>,
target: KonanTarget,
distribution: Distribution = Distribution()
): SearchPathResolverWithTarget = defaultResolver(repositories, emptyList(), target, distribution)
fun defaultResolver(
repositories: List<String>,
directLibs: List<String>,
target: KonanTarget,
distribution: Distribution,
logger: Logger = ::dummyLogger,
skipCurrentDir: Boolean = false,
compatibleCompilerVersions: List<KonanVersion> = emptyList()
): SearchPathResolverWithTarget = KonanLibraryProperResolver(
repositories,
directLibs,
target,
listOf(KonanAbiVersion.CURRENT),
listOf(KonanVersion.CURRENT) + compatibleCompilerVersions,
distribution.klib,
distribution.localKonanDir.absolutePath,
skipCurrentDir,
logger)
fun resolverByName(
repositories: List<String>,
directLibs: List<String> = emptyList(),
distributionKlib: String? = null,
localKonanDir: String? = null,
skipCurrentDir: Boolean = false
): SearchPathResolver = KonanLibrarySearchPathResolver(repositories, directLibs, distributionKlib, localKonanDir, skipCurrentDir)
internal open class KonanLibrarySearchPathResolver(
repositories: List<String>,
directLibs: List<String>,
val distributionKlib: String?,
val localKonanDir: String?,
val skipCurrentDir: Boolean,
override val logger:Logger = ::dummyLogger
) : SearchPathResolver {
val localHead: File?
get() = localKonanDir?.File()?.klib
val distHead: File?
get() = distributionKlib?.File()?.child("common")
open val distPlatformHead: File? = null
val currentDirHead: File?
get() = if (!skipCurrentDir) File.userDir else null
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
private val directLibraries: List<KonanLibrary> by lazy {
directLibs.mapNotNull { found(File(it)) }.map { createKonanLibrary(it, null) }
}
// This is the place where we specify the order of library search.
override val searchRoots: List<File> by lazy {
(listOf(currentDirHead) + repoRoots + listOf(localHead, distHead, distPlatformHead)).filterNotNull()
}
private fun found(candidate: File): File? {
fun check(file: File): Boolean =
file.exists && (file.isFile || File(file, "manifest").exists)
val noSuffix = File(candidate.path.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT))
val withSuffix = File(candidate.path.suffixIfNot(KLIB_FILE_EXTENSION_WITH_DOT))
return when {
check(withSuffix) -> withSuffix
check(noSuffix) -> noSuffix
else -> null
}
}
override fun resolutionSequence(givenPath: String): Sequence<File> {
val given = File(givenPath)
val sequence = if (given.isAbsolute) {
sequenceOf(found(given))
} else {
// Search among user-provided libraries by unique name.
// It's a workaround for maven publication. When a library is published without Gradle metadata,
// it has a complex file name (e.g. foo-macos_x64-1.0.klib). But a dependency on this lib in manifests
// of other libs uses its unique name written in the manifest (i.e just 'foo'). So we cannot resolve this
// library by its filename. But we have this library's file (we've downloaded it using maven dependency
// resolution) so we can pass it to the compiler directly. This code takes this into account and looks for
// a library dependencies also in libs passed to the compiler as files (passed to the resolver as the
// 'directLibraries' property).
val directLibs = directLibraries.asSequence().filter {
it.uniqueName == givenPath
}.map {
it.libraryFile
}
// Search among libraries in repositoreis by library filename.
val repoLibs = searchRoots.asSequence().map {
found(File(it, givenPath))
}
directLibs + repoLibs
}
return sequence.filterNotNull()
}
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): KonanLibraryImpl {
val givenPath = unresolved.path
return resolutionSequence(givenPath).firstOrNull() ?. let {
createKonanLibrary(it, null, isDefaultLink) as KonanLibraryImpl
} ?: error("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
}
override fun resolve(givenPath: String) = resolve(UnresolvedLibrary(givenPath, null), false)
private val File.klib
get() = File(this, "klib")
// The libraries from the default root are linked automatically.
val defaultRoots: List<File>
get() = listOfNotNull(distHead, distPlatformHead).filter { it.exists }
override fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<KonanLibraryImpl> {
val result = mutableListOf<KonanLibraryImpl>()
if (!noStdLib) {
result.add(resolve(UnresolvedLibrary(KONAN_STDLIB_NAME, null), true))
}
if (!noDefaultLibs) {
val defaultLibs = defaultRoots.flatMap { it.listFiles }
.filterNot { it.name.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT) == KONAN_STDLIB_NAME }
.map { UnresolvedLibrary(it.absolutePath, null) }
.map {resolve(it, isDefaultLink = true) }
result.addAll(defaultLibs)
}
return result
}
}
internal class KonanLibraryProperResolver(
repositories: List<String>,
directLibs: List<String>,
override val target: KonanTarget,
override val knownAbiVersions: List<KonanAbiVersion>?,
override val knownCompilerVersions: List<KonanVersion>?,
distributionKlib: String?,
localKonanDir: String?,
skipCurrentDir: Boolean,
override val logger: Logger = ::dummyLogger
) : KonanLibrarySearchPathResolver(repositories, directLibs, distributionKlib, localKonanDir, skipCurrentDir, logger),
SearchPathResolverWithTarget
{
override val distPlatformHead: File?
get() = distributionKlib?.File()?.child("platform")?.child(target.visibleName)
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): KonanLibraryImpl {
val givenPath = unresolved.path
val fileSequence = resolutionSequence(givenPath)
val matching = fileSequence.map { createKonanLibrary(it, target, isDefaultLink) as KonanLibraryImpl }
.map { it.takeIf { libraryMatch(it, unresolved) } }
.filterNotNull()
return matching.firstOrNull() ?: error("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
}
}
internal fun SearchPathResolverWithTarget.libraryMatch(candidate: KonanLibraryImpl, unresolved: UnresolvedLibrary): Boolean {
val resolverTarget = this.target
val candidatePath = candidate.libraryFile.absolutePath
val candidateCompilerVersion = candidate.versions.compilerVersion
val candidateAbiVersion = candidate.versions.abiVersion
val candidateLibraryVersion = candidate.versions.libraryVersion
if (!candidate.targetList.contains(resolverTarget.visibleName)) {
logger("skipping $candidatePath. The target doesn't match. Expected '$resolverTarget', found ${candidate.targetList}")
return false
}
val abiVersionMatch = candidateAbiVersion != null &&
knownAbiVersions != null &&
knownAbiVersions!!.contains(candidateAbiVersion)
val compilerVersionMatch = candidateCompilerVersion != null &&
knownCompilerVersions != null &&
knownCompilerVersions!!.any { it.compatible(candidateCompilerVersion) }
if (!abiVersionMatch && !compilerVersionMatch) {
logger("skipping $candidatePath. The abi versions don't match. Expected '${knownAbiVersions}', found '${candidateAbiVersion}'")
if (knownCompilerVersions != null) {
val expected = knownCompilerVersions?.map { it.toString(false, false) }
val found = candidateCompilerVersion?.toString(true, true)
logger("The compiler versions don't match either. Expected '${expected}', found '${found}'")
}
return false
}
if (candidateLibraryVersion != unresolved.libraryVersion &&
candidateLibraryVersion != null &&
unresolved.libraryVersion != null) {
logger("skipping $candidatePath. The library versions don't match. Expected '${unresolved.libraryVersion}', found '${candidateLibraryVersion}'")
return false
}
return true
}
private fun KonanVersion.compatible(other: KonanVersion) =
this.major == other.major
&& this.minor == other.minor
&& this.maintenance == other.maintenance
@@ -1,10 +0,0 @@
package org.jetbrains.kotlin.konan.library
data class UnresolvedLibrary(
val path: String,
val libraryVersion: String?) {
fun substitutePath(newPath: String): UnresolvedLibrary {
return UnresolvedLibrary(newPath, libraryVersion)
}
}
@@ -1,94 +0,0 @@
/**
* Copyright 2010-2019 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.library.impl
import org.jetbrains.kotlin.konan.file.File
import java.io.RandomAccessFile
import java.nio.channels.FileChannel
data class DeclarationId(val id: Long, val isLocal: Boolean)
class CombinedIrFileReader(file: File) {
private val buffer = file.map(FileChannel.MapMode.READ_ONLY)
private val declarationToOffsetSize = mutableMapOf<DeclarationId, Pair<Int, Int>>()
init {
val declarationsCount = buffer.int
for (i in 0 until declarationsCount) {
val id = buffer.long
val isLocal = buffer.int != 0
val offset = buffer.int
val size = buffer.int
declarationToOffsetSize[DeclarationId(id, isLocal)] = offset to size
}
}
fun declarationBytes(id: DeclarationId): ByteArray {
val offsetSize = declarationToOffsetSize[id] ?: throw Error("No declaration with $id here")
val result = ByteArray(offsetSize.second)
buffer.position(offsetSize.first)
buffer.get(result, 0, offsetSize.second)
return result
}
}
private const val SINGLE_INDEX_RECORD_SIZE = 20 // sizeof(Long) + 3 * sizeof(Int).
private const val INDEX_HEADER_SIZE = 4 // sizeof(Int).
class CombinedIrFileWriter(val declarationCount: Int) {
private var currentDeclaration = 0
private var currentPosition = 0
private val file = org.jetbrains.kotlin.konan.file.createTempFile("ir").deleteOnExit()
private val randomAccessFile = RandomAccessFile(file.path, "rw")
init {
randomAccessFile.writeInt(declarationCount)
assert(randomAccessFile.filePointer.toInt() == INDEX_HEADER_SIZE)
for (i in 0 until declarationCount) {
randomAccessFile.writeLong(-1) // id
randomAccessFile.writeInt(-1) // isLocal
randomAccessFile.writeInt(-1) // offset
randomAccessFile.writeInt(-1) // size
}
currentPosition = randomAccessFile.filePointer.toInt()
assert(currentPosition == INDEX_HEADER_SIZE + SINGLE_INDEX_RECORD_SIZE * declarationCount)
}
fun skipDeclaration() {
currentDeclaration++
}
fun addDeclaration(id: DeclarationId, bytes: ByteArray) {
randomAccessFile.seek((currentDeclaration * SINGLE_INDEX_RECORD_SIZE + INDEX_HEADER_SIZE).toLong())
randomAccessFile.writeLong(id.id)
randomAccessFile.writeInt(if (id.isLocal) 1 else 0)
randomAccessFile.writeInt(currentPosition)
randomAccessFile.writeInt(bytes.size)
randomAccessFile.seek(currentPosition.toLong())
randomAccessFile.write(bytes)
assert(randomAccessFile.filePointer < Int.MAX_VALUE.toLong())
currentPosition = randomAccessFile.filePointer.toInt()
currentDeclaration++
}
fun finishWriting(): File {
assert(currentDeclaration == declarationCount)
randomAccessFile.close()
return file
}
}
@@ -1,14 +0,0 @@
package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
import org.jetbrains.kotlin.konan.library.MetadataReader
internal object DefaultMetadataReaderImpl : MetadataReader {
override fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray =
libraryLayout.moduleHeaderFile.readBytes()
override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray =
libraryLayout.packageFragmentFile(fqName, partName).readBytes()
}
@@ -1,105 +0,0 @@
/*
* Copyright 2010-2018 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.library.impl
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
import org.jetbrains.kotlin.konan.util.substitute
class KonanLibraryImpl(
override val libraryFile: File,
internal val target: KonanTarget?,
override val isDefault: Boolean,
private val metadataReader: MetadataReader
) : KonanLibrary {
// For the zipped libraries inPlace gives files from zip file system
// whereas realFiles extracts them to /tmp.
// For unzipped libraries inPlace and realFiles are the same
// providing files in the library directory.
private val layout = createKonanLibraryLayout(libraryFile, target)
override val libraryName: String by lazy { layout.inPlace { it.libraryName } }
override val manifestProperties: Properties by lazy {
val properties = layout.inPlace { it.manifestFile.loadProperties() }
if (target != null) substitute(properties, defaultTargetSubstitutions(target))
properties
}
override val versions: KonanLibraryVersioning
get() = manifestProperties.readKonanLibraryVersioning()
override val linkerOpts: List<String>
get() = manifestProperties.propertyList(KLIB_PROPERTY_LINKED_OPTS)
override val bitcodePaths: List<String>
get() = layout.realFiles { (it.kotlinDir.listFilesOrEmpty + it.nativeDir.listFilesOrEmpty).map { it.absolutePath } }
override val includedPaths: List<String>
get() = layout.realFiles { it.includedDir.listFilesOrEmpty.map { it.absolutePath } }
override val targetList by lazy { layout.inPlace { it.targetsDir.listFiles.map { it.name } } }
override val dataFlowGraph by lazy { layout.inPlace { it.dataFlowGraphFile.let { if (it.exists) it.readBytes() else null } } }
override val moduleHeaderData: ByteArray by lazy { layout.inPlace { metadataReader.loadSerializedModule(it) } }
override fun packageMetadata(packageFqName: String, partName: String) =
layout.inPlace { metadataReader.loadSerializedPackageFragment(it, packageFqName, partName) }
override fun packageMetadataParts(fqName: String): Set<String> =
layout.inPlace { inPlaceLayout ->
val fileList =
inPlaceLayout.packageFragmentsDir(fqName)
.listFiles
.mapNotNull {
it.name
.substringBeforeLast(KLIB_METADATA_FILE_EXTENSION_WITH_DOT, missingDelimiterValue = "")
.takeIf { it.isNotEmpty() }
}
fileList.toSortedSet().also {
require(it.size == fileList.size) { "Duplicated names: ${fileList.groupingBy { it }.eachCount().filter { (_, count) -> count > 1 }}" }
}
}
override val irHeader: ByteArray? by lazy { layout.inPlace { library -> library.irHeader.let {
if (it.exists) loadIrHeader() else null }
}}
override fun irDeclaration(index: Long, isLocal: Boolean) = loadIrDeclaraton(index, isLocal)
override fun toString() = "$libraryName[default=$isDefault]"
private val combinedDeclarations: CombinedIrFileReader by lazy {
CombinedIrFileReader(layout.realFiles {
it.irFile
})
}
private fun loadIrHeader(): ByteArray =
layout.inPlace { it.irHeader.readBytes() }
private fun loadIrDeclaraton(index: Long, isLocal: Boolean) =
combinedDeclarations.declarationBytes(DeclarationId(index, isLocal))
}
@@ -1,91 +0,0 @@
package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION_WITH_DOT
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
import java.nio.file.FileSystem
interface KonanLibraryLayoutImpl: KonanLibraryLayout {
fun <T> inPlace(action: (KonanLibraryLayout) -> T): T
fun <T> realFiles (action: (KonanLibraryLayout) -> T): T
}
private class ZippedKonanLibraryLayout(val klibFile: File, override val target: KonanTarget?): KonanLibraryLayoutImpl {
init { zippedKonanLibraryChecks(klibFile) }
override val libraryName = klibFile.path.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT)
override val libDir = File("/")
override fun <T> realFiles(action: (KonanLibraryLayout) -> T): T {
return action(FileExtractor(this))!!
}
override fun <T> inPlace(action: (KonanLibraryLayout) -> T): T {
return klibFile.withZipFileSystem { zipFileSystem ->
action(DirectFromZip(this, zipFileSystem))
}
}
}
internal fun zippedKonanLibraryChecks(klibFile: File) {
check(klibFile.exists) { "Could not find $klibFile." }
check(klibFile.isFile) { "Expected $klibFile to be a regular file." }
val extension = klibFile.extension
check(extension.isEmpty() || extension == KLIB_FILE_EXTENSION) { "Unexpected file extension: $extension" }
}
private class UnzippedKonanLibraryLayout(override val libDir: File, override val target: KonanTarget?): KonanLibraryLayoutImpl {
override val libraryName = libDir.path
override fun <T> inPlace(action: (KonanLibraryLayout) -> T): T = action(this)
override fun <T> realFiles (action: (KonanLibraryLayout) -> T): T = inPlace(action)
}
private class DirectFromZip(zippedLayout: ZippedKonanLibraryLayout, val zipFileSystem: FileSystem): KonanLibraryLayout {
override val libraryName = zippedLayout.libraryName
override val libDir = zipFileSystem.file(zippedLayout.libDir)
}
/**
* This class automatically extracts pieces of the library on first access. Use it if you need
* to pass extracted files to an external tool. Otherwise, stick to [DirectFromZip].
*/
private class FileExtractor(val zippedLibraryLayout: ZippedKonanLibraryLayout): KonanLibraryLayout by zippedLibraryLayout {
override val manifestFile: File by lazy { extract(super.manifestFile) }
override val resourcesDir: File by lazy { extractDir(super.resourcesDir) }
override val includedDir: File by lazy { extractDir(super.includedDir) }
override val kotlinDir: File by lazy { extractDir(super.kotlinDir) }
override val nativeDir: File by lazy { extractDir(super.nativeDir) }
override val linkdataDir: File by lazy { extractDir(super.linkdataDir) }
override val irFile: File by lazy { extract(super.irFile) }
fun extract(file: File): File = zippedLibraryLayout.klibFile.withZipFileSystem { zipFileSystem ->
val temporary = createTempFile(file.name)
zipFileSystem.file(file).copyTo(temporary)
temporary.deleteOnExit()
temporary
}
fun extractDir(directory: File): File = zippedLibraryLayout.klibFile.withZipFileSystem { zipFileSystem ->
val temporary = createTempDir(directory.name)
zipFileSystem.file(directory).recursiveCopyTo(temporary)
temporary.deleteOnExitRecursively()
temporary
}
}
internal fun createKonanLibraryLayout(klib: File, target: KonanTarget? = null) =
if (klib.isFile) ZippedKonanLibraryLayout(klib, target) else UnzippedKonanLibraryLayout(klib, target)
@@ -1,28 +0,0 @@
/*
* 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
/**
* This is a common ancestor of all Kotlin/Native exceptions.
*/
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, val toolName: String, cause: Throwable? = null) : KonanException(message, cause)
@@ -1,28 +0,0 @@
/**
* Copyright 2010-2019 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
fun String.parseKonanAbiVersion(): KonanAbiVersion {
return KonanAbiVersion(this.toInt())
}
data class KonanAbiVersion(val version: Int) {
companion object {
val CURRENT = KonanAbiVersion(8)
}
override fun toString() = "$version"
}
@@ -1,42 +0,0 @@
/*
* 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
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
/**
* https://en.wikipedia.org/wiki/Software_versioning
* scheme major.minor[.build[.revision]].
*/
enum class MetaVersion(val metaString: String) {
DEV("dev"),
EAP("eap"),
ALPHA("alpha"),
BETA("beta"),
RC1("rc1"),
RC2("rc2"),
RELEASE("release");
companion object {
fun findAppropriate(metaString: String): MetaVersion {
return MetaVersion.values().find { it.metaString.equals(metaString, ignoreCase = true) }
?: if (metaString.isBlank()) RELEASE else error("Unknown meta version: $metaString")
}
}
}
@@ -1,58 +0,0 @@
/*
* Copyright 2010-2018 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
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.*
/**
* Creates and stores temporary compiler outputs
* If pathToTemporaryDir is given and is not empty then temporary outputs will be preserved
*/
class TempFiles(outputPath: String, pathToTemporaryDir: String? = null) {
private val outputName = File(outputPath).name
val nativeBinaryFile by lazy { File(dir,"${outputName}.kt.bc") }
val cAdapterCpp by lazy { File(dir, "api.cpp") }
val cAdapterBitcode by lazy { File(dir, "api.bc") }
val nativeBinaryFileName get() = nativeBinaryFile.absolutePath
val cAdapterCppName get() = cAdapterCpp.absolutePath
val cAdapterBitcodeName get() = cAdapterBitcode.absolutePath
private val dir by lazy { if (pathToTemporaryDir == null || pathToTemporaryDir.isEmpty()) {
createTempDir("konan_temp").deleteOnExit()
} else {
createDirForTemporaryFiles(pathToTemporaryDir)
}
}
private fun createDirForTemporaryFiles(path: String): File {
if (File(path).isFile) {
throw IllegalArgumentException("Given file is not a directory: $path")
}
return File(path).apply {
if (!exists) { mkdirs() }
}
}
/**
* Create file named {name}{suffix} inside temporary dir
*/
fun create(prefix: String, suffix: String = ""): File =
File(dir, "$prefix$suffix")
}
@@ -1,25 +0,0 @@
/*
* 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.util
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
val <T : Enum<T>> T.visibleName get() = name.toLowerCase()
interface Named {
val name: String
val visibleName get() = name
}
@@ -1,111 +0,0 @@
/*
* 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
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
open class Command(initialCommand: List<String>) {
constructor(tool: String) : this(listOf(tool))
constructor(vararg command: String) : this(command.toList<String>())
protected val command = initialCommand.toMutableList()
val args: List<String>
get() = command.drop(1)
operator fun String.unaryPlus(): Command {
command += this
return this@Command
}
operator fun List<String>.unaryPlus(): Command {
command.addAll(this)
return this@Command
}
var logger: ((() -> String)->Unit)? = null
fun logWith(newLogger: ((() -> String)->Unit)): Command {
logger = newLogger
return this
}
open fun runProcess(): Int {
val builder = ProcessBuilder(command)
builder.redirectOutput(Redirect.INHERIT)
builder.redirectInput(Redirect.INHERIT)
builder.redirectError(Redirect.INHERIT)
val process = builder.start()
val exitCode = process.waitFor()
return exitCode
}
open fun execute() {
log()
val code = runProcess()
handleExitCode(code)
}
/**
* If withErrors is true then output from error stream will be added
*/
fun getOutputLines(withErrors: Boolean = false): List<String> =
getResult(withErrors, handleError = true).outputLines
fun getResult(withErrors: Boolean, handleError: Boolean = false): Result {
log()
val outputFile = createTempFile()
outputFile.deleteOnExit()
try {
val builder = ProcessBuilder(command)
builder.redirectInput(Redirect.INHERIT)
builder.redirectError(Redirect.INHERIT)
builder.redirectOutput(Redirect.to(outputFile))
.redirectErrorStream(withErrors)
// Note: getting process output could be done without redirecting to temporary file,
// however this would require managing a thread to read `process.inputStream` because
// it may have limited capacity.
val process = builder.start()
val code = process.waitFor()
if (handleError) handleExitCode(code)
return Result(code, outputFile.readLines())
} finally {
outputFile.delete()
}
}
class Result(val exitCode: Int, val outputLines: List<String>)
private fun handleExitCode(code: Int) {
if (code != 0) throw KonanExternalToolFailure("The ${command[0]} command returned non-zero exit code: $code.", command[0])
}
private fun log() {
if (logger != null) logger!! { command.joinToString(" ") }
}
}
@@ -1,233 +0,0 @@
/*
* 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.file
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.RandomAccessFile
import java.net.URI
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
data class File constructor(internal val javaPath: Path) {
constructor(parent: Path, child: String): this(parent.resolve(child))
constructor(parent: File, child: String): this(parent.javaPath.resolve(child))
constructor(path: String): this(Paths.get(path))
constructor(parent: String, child: String): this(Paths.get(parent, child))
val path: String
get() = javaPath.toString()
val absolutePath: String
get() = javaPath.toAbsolutePath().toString()
val absoluteFile: File
get() = File(absolutePath)
val name: String
get() = javaPath.fileName.toString().removeSuffixIfPresent("/") // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8153248
val extension: String
get() = name.substringAfterLast('.', "")
val parent: String
get() = javaPath.parent.toString()
val parentFile: File
get() = File(javaPath.parent)
val exists
get() = Files.exists(javaPath)
val isDirectory
get() = Files.isDirectory(javaPath)
val isFile
get() = Files.isRegularFile(javaPath)
val isAbsolute
get() = javaPath.isAbsolute()
val listFiles: List<File>
get() = Files.newDirectoryStream(javaPath).use { stream -> stream.map { File(it) } }
val listFilesOrEmpty: List<File>
get() = if (exists) listFiles else emptyList()
fun child(name: String) = File(this, name)
fun copyTo(destination: File) {
Files.copy(javaPath, destination.javaPath, StandardCopyOption.REPLACE_EXISTING)
}
fun recursiveCopyTo(destination: File) {
val sourcePath = javaPath
val destPath = destination.javaPath
sourcePath.recursiveCopyTo(destPath)
}
fun mkdirs() = Files.createDirectories(javaPath)
fun delete() = Files.deleteIfExists(javaPath)
fun deleteRecursively() = postorder{Files.delete(it)}
fun deleteOnExitRecursively() = preorder{File(it).deleteOnExit()}
fun preorder(task: (Path) -> Unit) {
if (!this.exists) return
Files.walkFileTree(javaPath, object: SimpleFileVisitor<Path>() {
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(file!!)
return FileVisitResult.CONTINUE
}
override fun preVisitDirectory(dir: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(dir!!)
return FileVisitResult.CONTINUE
}
})
}
fun postorder(task: (Path) -> Unit) {
if (!this.exists) return
Files.walkFileTree(javaPath, object: SimpleFileVisitor<Path>() {
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(file!!)
return FileVisitResult.CONTINUE
}
override fun postVisitDirectory(dir: Path?, exc: java.io.IOException?): FileVisitResult {
task(dir!!)
return FileVisitResult.CONTINUE
}
})
}
fun map(mode: FileChannel.MapMode = FileChannel.MapMode.READ_ONLY,
start: Long = 0, size: Long = -1): MappedByteBuffer {
val file = RandomAccessFile(path,
if (mode == FileChannel.MapMode.READ_ONLY) "r" else "rw")
val fileSize = if (mode == FileChannel.MapMode.READ_ONLY)
file.length() else size.also { assert(size != -1L) }
return file.channel.map(mode, start, fileSize) // Shall we .also { file.close() }?
}
fun deleteOnExit(): File {
// Works only on the default file system,
// but that's okay for now.
javaPath.toFile().deleteOnExit()
return this // Allow streaming.
}
fun readBytes() = Files.readAllBytes(javaPath)
fun writeBytes(bytes: ByteArray) = Files.write(javaPath, bytes)
fun appendBytes(bytes: ByteArray)
= Files.write(javaPath, bytes, StandardOpenOption.APPEND)
fun writeLines(lines: Iterable<String>) {
Files.write(javaPath, lines)
}
fun writeText(text: String): Unit = writeLines(listOf(text))
fun forEachLine(action: (String) -> Unit) {
Files.lines(javaPath).use { lines ->
lines.forEach { action(it) }
}
}
fun createAsSymlink(target: String) {
val targetPath = Paths.get(target)
if (Files.isSymbolicLink(this.javaPath) && Files.readSymbolicLink(javaPath) == targetPath) {
return
}
Files.createSymbolicLink(this.javaPath, targetPath)
}
override fun toString() = path
// TODO: Consider removeing these after konanazing java.util.Properties.
fun bufferedReader() = Files.newBufferedReader(javaPath)
fun outputStream() = Files.newOutputStream(javaPath)
fun printWriter() = javaPath.toFile().printWriter()
companion object {
val userDir
get() = File(System.getProperty("user.dir"))
val userHome
get() = File(System.getProperty("user.home"))
val javaHome
get() = File(System.getProperty("java.home"))
val pathSeparator = java.io.File.pathSeparator
val separator = java.io.File.separator
}
fun readStrings() = mutableListOf<String>().also { list -> forEachLine{list.add(it)}}
override fun equals(other: Any?): Boolean {
val otherFile = other as? File ?: return false
return otherFile.javaPath.toAbsolutePath() == javaPath.toAbsolutePath()
}
override fun hashCode() = javaPath.toAbsolutePath().hashCode()
}
fun String.File(): File = File(this)
fun Path.File(): File = File(this)
fun createTempFile(name: String, suffix: String? = null)
= Files.createTempFile(name, suffix).File()
fun createTempDir(name: String): File
= Files.createTempDirectory(name).File()
fun Path.recursiveCopyTo(destPath: Path) {
val sourcePath = this
Files.walk(sourcePath).forEach next@ { oldPath ->
val relative = sourcePath.relativize(oldPath)
val destFs = destPath.getFileSystem()
// We are copying files between file systems,
// so pass the relative path through the String.
val newPath = destFs.getPath(destPath.toString(), relative.toString())
// File systems don't allow replacing an existing root.
if (newPath == newPath.getRoot()) return@next
if (Files.isDirectory(newPath)) {
Files.createDirectories(newPath)
} else {
Files.copy(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING)
}
}
}
fun bufferedReader(errorStream: InputStream?) = BufferedReader(InputStreamReader(errorStream))
// stdlib `use` function adapted for AutoCloseable.
inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this?.close()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this?.close()
}
}
}
@@ -1,29 +0,0 @@
/*
* 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.file
val String.isJavaScript
get() = this.endsWith(".js")
val String.isUnixStaticLib
get() = this.endsWith(".a")
val String.isWindowsStaticLib
get() = this.endsWith(".lib")
val String.isBitcode
get() = this.endsWith(".bc")
@@ -1,52 +0,0 @@
package org.jetbrains.kotlin.konan.file
import java.net.URI
import java.nio.file.*
private val File.zipUri: URI
get() = URI.create("jar:${this.toPath().toUri()}")
fun File.zipFileSystem(mutable: Boolean = false): FileSystem {
val zipUri = this.zipUri
val attributes = hashMapOf("create" to mutable.toString())
return try {
FileSystems.newFileSystem(zipUri, attributes, null)
} catch (e: FileSystemAlreadyExistsException) {
FileSystems.getFileSystem(zipUri)
}
}
fun FileSystem.file(file: File) = File(this.getPath(file.path))
fun FileSystem.file(path: String) = File(this.getPath(path))
private fun File.toPath() = Paths.get(this.path)
fun File.zipDirAs(unixFile: File) {
unixFile.withMutableZipFileSystem() {
this.recursiveCopyTo(it.file("/"))
}
}
fun Path.unzipTo(directory: Path) {
val zipUri = URI.create("jar:" + this.toUri())
FileSystems.newFileSystem(zipUri, emptyMap<String, Any?>(), null).use { zipfs ->
val zipPath = zipfs.getPath("/")
zipPath.recursiveCopyTo(directory)
}
}
fun <T> File.withZipFileSystem(mutable: Boolean = false, action: (FileSystem) -> T): T {
val zipFileSystem = this.zipFileSystem(mutable)
return try {
action(zipFileSystem)
} finally {
zipFileSystem.close()
}
}
fun <T> File.withZipFileSystem(action: (FileSystem) -> T): T
= this.withZipFileSystem(false, action)
fun <T> File.withMutableZipFileSystem(action: (FileSystem) -> T): T
= this.withZipFileSystem(true, action)
@@ -1,73 +0,0 @@
/*
* Copyright 2010-2018 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 -> 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.target
import org.jetbrains.kotlin.konan.properties.KonanPropertiesLoader
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.util.InternalServer
class AppleConfigurablesImpl(
target: KonanTarget,
properties: Properties,
baseDir: String?
) : AppleConfigurables, KonanPropertiesLoader(target, properties, baseDir) {
private val sdkDependency = this.targetSysRoot!!
private val toolchainDependency = this.targetToolchain!!
override val absoluteTargetSysRoot: String get() = when (xcodePartsProvider) {
is XcodePartsProvider.Local -> when (target) {
KonanTarget.MACOS_X64 -> xcodePartsProvider.xcode.macosxSdk
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> xcodePartsProvider.xcode.iphoneosSdk
KonanTarget.IOS_X64 -> xcodePartsProvider.xcode.iphonesimulatorSdk
else -> error(target)
}
XcodePartsProvider.InternalServer -> absolute(sdkDependency)
}
override val absoluteTargetToolchain: String get() = when (xcodePartsProvider) {
is XcodePartsProvider.Local -> xcodePartsProvider.xcode.toolchain
XcodePartsProvider.InternalServer -> absolute(toolchainDependency)
}
override val dependencies get() = super.dependencies + when (xcodePartsProvider) {
is XcodePartsProvider.Local -> emptyList()
XcodePartsProvider.InternalServer -> listOf(sdkDependency, toolchainDependency)
}
private val xcodePartsProvider = if (InternalServer.isAvailable) {
XcodePartsProvider.InternalServer
} else {
val xcode = Xcode.current
properties.getProperty("useFixedXcodeVersion")?.let { requiredXcodeVersion ->
val currentXcodeVersion = xcode.version
if (properties.getProperty("ignoreXcodeVersionCheck") != "true" &&
currentXcodeVersion != requiredXcodeVersion) {
error("expected Xcode version $requiredXcodeVersion, got $currentXcodeVersion, consider updating " +
"Xcode or use \"ignoreXcodeVersionCheck\" variable in konan.properties")
}
}
XcodePartsProvider.Local(xcode)
}
private sealed class XcodePartsProvider {
class Local(val xcode: Xcode) : XcodePartsProvider()
object InternalServer : XcodePartsProvider()
}
}
@@ -1,317 +0,0 @@
/*
* 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 -> 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.target
import org.jetbrains.kotlin.konan.file.File
class ClangArgs(private val configurables: Configurables) : Configurables by configurables {
val targetArg = if (configurables is NonAppleConfigurables)
configurables.targetArg
else null
val specificClangArgs: List<String>
get() {
val result = when (target) {
KonanTarget.LINUX_X64 ->
listOf("--sysroot=$absoluteTargetSysRoot") +
if (target != host) listOf("-target", targetArg!!) else emptyList()
KonanTarget.LINUX_ARM32_HFP ->
listOf("-target", targetArg!!,
"-mfpu=vfp", "-mfloat-abi=hard",
"--sysroot=$absoluteTargetSysRoot",
// TODO: those two are hacks.
"-I$absoluteTargetSysRoot/usr/include/c++/4.8.3",
"-I$absoluteTargetSysRoot/usr/include/c++/4.8.3/arm-linux-gnueabihf")
KonanTarget.LINUX_MIPS32 ->
listOf("-target", targetArg!!,
"--sysroot=$absoluteTargetSysRoot",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4/mips-unknown-linux-gnu")
KonanTarget.LINUX_MIPSEL32 ->
listOf("-target", targetArg!!,
"--sysroot=$absoluteTargetSysRoot",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4/mipsel-unknown-linux-gnu")
KonanTarget.MINGW_X64, KonanTarget.MINGW_X86 ->
listOf("-target", targetArg!!, "--sysroot=$absoluteTargetSysRoot", "-Xclang", "-flto-visibility-public-std")
KonanTarget.MACOS_X64 ->
listOf("--sysroot=$absoluteTargetSysRoot", "-mmacosx-version-min=10.11")
KonanTarget.IOS_ARM32 ->
listOf("-stdlib=libc++", "-arch", "armv7", "-isysroot", absoluteTargetSysRoot, "-miphoneos-version-min=9.0.0")
KonanTarget.IOS_ARM64 ->
listOf("-stdlib=libc++", "-arch", "arm64", "-isysroot", absoluteTargetSysRoot, "-miphoneos-version-min=9.0.0")
KonanTarget.IOS_X64 ->
listOf("-stdlib=libc++", "-isysroot", absoluteTargetSysRoot, "-miphoneos-version-min=9.0.0")
KonanTarget.ANDROID_ARM32 ->
listOf("-target", targetArg!!,
"--sysroot=$absoluteTargetSysRoot",
// HACKS!
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x/arm-linux-androideabi")
KonanTarget.ANDROID_ARM64 ->
listOf("-target", targetArg!!,
"--sysroot=$absoluteTargetSysRoot",
// HACKS!
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x/aarch64-linux-android")
// By default wasm target forces `hidden` visibility which causes
// linkage problems.
KonanTarget.WASM32 ->
listOf("-target", targetArg!!,
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=default",
"-D_LIBCPP_ABI_VERSION=2",
"-D_LIBCPP_NO_EXCEPTIONS=1",
"-nostdinc",
"-Xclang", "-nobuiltininc",
"-Xclang", "-nostdsysteminc",
"-Xclang", "-isystem$absoluteTargetSysRoot/include/libcxx",
"-Xclang", "-isystem$absoluteTargetSysRoot/lib/libcxxabi/include",
"-Xclang", "-isystem$absoluteTargetSysRoot/include/compat",
"-Xclang", "-isystem$absoluteTargetSysRoot/include/libc")
is KonanTarget.ZEPHYR ->
listOf("-target", targetArg!!,
"-fno-rtti",
"-fno-exceptions",
"-fno-asynchronous-unwind-tables",
"-fno-pie",
"-fno-pic",
"-fshort-enums",
"-nostdinc",
// TODO: make it a libGcc property?
// We need to get rid of wasm sysroot first.
"-isystem $targetToolchain/../lib/gcc/arm-none-eabi/7.2.1/include",
"-isystem $targetToolchain/../lib/gcc/arm-none-eabi/7.2.1/include-fixed",
"-isystem$absoluteTargetSysRoot/include/libcxx",
"-isystem$absoluteTargetSysRoot/include/libc"
) +
(configurables as ZephyrConfigurables).boardSpecificClangFlags
}
return result
}
val clangArgsSpecificForKonanSources
get() = when (target) {
KonanTarget.LINUX_X64 ->
listOf("-DUSE_GCC_UNWIND=1",
"-DKONAN_LINUX=1",
"-DKONAN_X64=1",
"-DUSE_ELF_SYMBOLS=1",
"-DELFSIZE=64",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.LINUX_ARM32_HFP ->
listOf("-DUSE_GCC_UNWIND=1",
"-DKONAN_LINUX=1",
"-DKONAN_ARM32=1",
"-DUSE_ELF_SYMBOLS=1",
"-DELFSIZE=32",
"-DKONAN_NO_UNALIGNED_ACCESS=1")
KonanTarget.LINUX_MIPS32 ->
listOf("-DUSE_GCC_UNWIND=1",
"-DKONAN_LINUX=1",
"-DKONAN_MIPS32=1",
"-DUSE_ELF_SYMBOLS=1",
"-DELFSIZE=32",
// TODO: reconsider, once target MIPS can do proper 64-bit load/store/CAS.
"-DKONAN_NO_64BIT_ATOMIC=1",
"-DKONAN_NO_UNALIGNED_ACCESS=1")
KonanTarget.LINUX_MIPSEL32 ->
listOf("-DUSE_GCC_UNWIND=1",
"-DKONAN_LINUX=1",
"-DKONAN_MIPSEL32=1",
"-DUSE_ELF_SYMBOLS=1",
"-DELFSIZE=32",
// TODO: reconsider, once target MIPS can do proper 64-bit load/store/CAS.
"-DKONAN_NO_64BIT_ATOMIC=1",
"-DKONAN_NO_UNALIGNED_ACCESS=1")
KonanTarget.MINGW_X64, KonanTarget.MINGW_X86 ->
listOf("-DUSE_GCC_UNWIND=1",
"-DUSE_PE_COFF_SYMBOLS=1",
"-DKONAN_WINDOWS=1",
if (target == KonanTarget.MINGW_X64) "-DKONAN_X64=1" else "-DKONAN_X86=1",
"-DKONAN_NO_MEMMEM=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.MACOS_X64 ->
listOf("-DKONAN_OSX=1",
"-DKONAN_MACOSX=1",
"-DKONAN_X64=1",
"-DKONAN_OBJC_INTEROP=1",
"-DKONAN_CORE_SYMBOLICATION=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.IOS_ARM32 ->
listOf("-DKONAN_OBJC_INTEROP=1",
"-DKONAN_IOS",
"-DKONAN_ARM32=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1",
"-DKONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG=1",
"-DMACHSIZE=32",
// While not 100% correct here, using atomic ops on iOS armv7 requires 8 byte alignment,
// and general ABI requires 4-byte alignment on 64-bit long fields as mentioned in
// https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW1
// See https://github.com/ktorio/ktor/issues/941 for the context.
"-DKONAN_NO_64BIT_ATOMIC=1",
"-DKONAN_NO_UNALIGNED_ACCESS=1")
KonanTarget.IOS_ARM64 ->
listOf("-DKONAN_OBJC_INTEROP=1",
"-DKONAN_IOS=1",
"-DKONAN_ARM64=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1",
"-DKONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG=1",
"-DMACHSIZE=64")
KonanTarget.IOS_X64 ->
listOf("-DKONAN_OBJC_INTEROP=1",
"-DKONAN_IOS=1",
"-DKONAN_X64=1",
"-DKONAN_CORE_SYMBOLICATION=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.ANDROID_ARM32 ->
listOf("-D__ANDROID__",
"-DUSE_GCC_UNWIND=1",
"-DUSE_ELF_SYMBOLS=1",
"-DELFSIZE=32",
"-DKONAN_ANDROID=1",
"-DKONAN_ARM32=1",
"-DKONAN_NO_UNALIGNED_ACCESS=1")
KonanTarget.ANDROID_ARM64 ->
listOf("-D__ANDROID__",
"-DUSE_GCC_UNWIND=1",
"-DUSE_ELF_SYMBOLS=1",
"-DELFSIZE=64",
"-DKONAN_ANDROID=1",
"-DKONAN_ARM64=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.WASM32 ->
listOf("-DKONAN_WASM=1",
"-DKONAN_NO_FFI=1",
"-DKONAN_NO_THREADS=1",
"-DKONAN_NO_EXCEPTIONS=1",
"-DKONAN_INTERNAL_DLMALLOC=1",
"-DKONAN_INTERNAL_SNPRINTF=1",
"-DKONAN_INTERNAL_NOW=1",
"-DKONAN_NO_MEMMEM",
"-DKONAN_NO_CTORS_SECTION=1")
is KonanTarget.ZEPHYR ->
listOf( "-DKONAN_ZEPHYR=1",
"-DKONAN_NO_FFI=1",
"-DKONAN_NO_THREADS=1",
"-DKONAN_NO_EXCEPTIONS=1",
"-DKONAN_NO_MATH=1",
"-DKONAN_INTERNAL_SNPRINTF=1",
"-DKONAN_INTERNAL_NOW=1",
"-DKONAN_NO_MEMMEM=1",
"-DKONAN_NO_CTORS_SECTION=1",
"-DKONAN_NO_UNALIGNED_ACCESS=1")
}
private val host = HostManager.host
private val binDir = when (host) {
KonanTarget.LINUX_X64 -> "$absoluteTargetToolchain/bin"
KonanTarget.MINGW_X64 -> "$absoluteTargetToolchain/bin"
KonanTarget.MACOS_X64 -> "$absoluteTargetToolchain/usr/bin"
else -> throw TargetSupportException("Unexpected host platform")
}
private val extraHostClangArgs =
if (configurables is LinuxBasedConfigurables) {
listOf("--gcc-toolchain=${configurables.absoluteGccToolchain}")
} else {
emptyList()
}
val commonClangArgs = listOf("-B$binDir", "-fno-stack-protector") + extraHostClangArgs
val clangPaths = listOf("$absoluteLlvmHome/bin", binDir)
private val jdkDir by lazy {
val home = File.javaHome.absoluteFile
if (home.child("include").exists)
home.absolutePath
else
home.parentFile.absolutePath
}
val hostCompilerArgsForJni = listOf("", HostManager.jniHostPlatformIncludeDir).map { "-I$jdkDir/include/$it" }.toTypedArray()
val clangArgs = (commonClangArgs + specificClangArgs).toTypedArray()
val clangArgsForKonanSources =
clangArgs + clangArgsSpecificForKonanSources
val targetLibclangArgs: List<String> =
// libclang works not exactly the same way as the clang binary and
// (in particular) uses different default header search path.
// See e.g. http://lists.llvm.org/pipermail/cfe-dev/2013-November/033680.html
// We workaround the problem with -isystem flag below.
listOf("-isystem", "$absoluteLlvmHome/lib/clang/$llvmVersion/include", *clangArgs)
val targetClangCmd
= listOf("${absoluteLlvmHome}/bin/clang") + clangArgs
val targetClangXXCmd
= listOf("${absoluteLlvmHome}/bin/clang++") + clangArgs
fun clangC(vararg userArgs: String) = targetClangCmd + userArgs.asList()
fun clangCXX(vararg userArgs: String) = targetClangXXCmd + userArgs.asList()
companion object {
@JvmStatic
fun filterGradleNativeSoftwareFlags(args: MutableList<String>) {
args.remove("/usr/include") // HACK: over gradle-4.4.
args.remove("-nostdinc") // HACK: over gradle-5.1.
when (HostManager.host) {
KonanTarget.LINUX_X64 -> args.remove("/usr/include/x86_64-linux-gnu") // HACK: over gradle-4.4.
KonanTarget.MACOS_X64 -> {
val indexToRemove = args.indexOf(args.find { it.contains("MacOSX.platform")}) // HACK: over gradle-4.7.
if (indexToRemove != -1) {
args.removeAt(indexToRemove - 1) // drop -I.
args.removeAt(indexToRemove - 1) // drop /Application/Xcode.app/...
}
}
}
}
}
}
@@ -1,95 +0,0 @@
/*
* 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 -> 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.target
import org.jetbrains.kotlin.konan.properties.*
interface Configurables : TargetableExternalStorage {
val target: KonanTarget
val llvmHome get() = hostString("llvmHome")
val llvmVersion get() = hostString("llvmVersion")
val libffiDir get() = hostString("libffiDir")
// TODO: Delegate to a map?
val llvmLtoNooptFlags get() = targetList("llvmLtoNooptFlags")
val llvmLtoOptFlags get() = targetList("llvmLtoOptFlags")
val llvmLtoFlags get() = targetList("llvmLtoFlags")
val llvmLtoDynamicFlags get() = targetList("llvmLtoDynamicFlags")
val entrySelector get() = targetList("entrySelector")
val linkerOptimizationFlags get() = targetList("linkerOptimizationFlags")
val linkerKonanFlags get() = targetList("linkerKonanFlags")
val linkerNoDebugFlags get() = targetList("linkerNoDebugFlags")
val linkerDynamicFlags get() = targetList("linkerDynamicFlags")
val llvmDebugOptFlags get() = targetList("llvmDebugOptFlags")
val targetSysRoot get() = targetString("targetSysRoot")
// Notice: these ones are host-target.
val targetToolchain get() = hostTargetString("targetToolchain")
val absoluteTargetSysRoot get() = absolute(targetSysRoot)
val absoluteTargetToolchain get() = absolute(targetToolchain)
val absoluteLlvmHome get() = absolute(llvmHome)
}
interface NonAppleConfigurables : Configurables {
val targetArg get() = targetString("quadruple")
}
interface AppleConfigurables : Configurables {
val arch get() = targetString("arch")!!
val osVersionMin get() = targetString("osVersionMin")!!
val osVersionMinFlagLd get() = targetString("osVersionMinFlagLd")!!
}
interface MingwConfigurables : NonAppleConfigurables
interface LinuxBasedConfigurables : NonAppleConfigurables {
val gccToolchain get() = hostString("gccToolchain")
val absoluteGccToolchain get() = absolute(gccToolchain)
val libGcc get() = targetString("libGcc")!!
val dynamicLinker get() = targetString("dynamicLinker")!!
val pluginOptimizationFlags get() = targetList("pluginOptimizationFlags")
val abiSpecificLibraries get() = targetList("abiSpecificLibraries")
}
interface LinuxConfigurables : LinuxBasedConfigurables
interface LinuxMIPSConfigurables : LinuxBasedConfigurables
interface RaspberryPiConfigurables : LinuxBasedConfigurables
interface AndroidConfigurables : NonAppleConfigurables
interface WasmConfigurables : NonAppleConfigurables {
val llcFlags get() = targetList("llcFlags")
val llcNooptFlags get() = targetList("llcNooptFlags")
val llcOptFlags get() = targetList("llcOptFlags")
val llcDebugFlags get() = targetList("llcDebugFlags")
val optFlags get() = targetList("optFlags")
val optNooptFlags get() = targetList("optNooptFlags")
val optOptFlags get() = targetList("optOptFlags")
val optDebugFlags get() = targetList("optDebugFlags")
val lldFlags get() = targetList("lld")
}
interface ZephyrConfigurables : NonAppleConfigurables {
val boardSpecificClangFlags get() = targetList("boardSpecificClangFlags")
}
@@ -1,56 +0,0 @@
/*
* 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 -> 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.target
import org.jetbrains.kotlin.konan.properties.*
class LinuxConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: LinuxConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class LinuxMIPSConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: LinuxMIPSConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class AndroidConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: AndroidConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class MingwConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: MingwConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class WasmConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: WasmConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class ZephyrConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: ZephyrConfigurables, KonanPropertiesLoader(target, properties, baseDir)
fun loadConfigurables(target: KonanTarget, properties: Properties, baseDir: String?) = when (target) {
KonanTarget.LINUX_X64, KonanTarget.LINUX_ARM32_HFP ->
LinuxConfigurablesImpl(target, properties, baseDir)
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxMIPSConfigurablesImpl(target, properties, baseDir)
KonanTarget.MACOS_X64, KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 ->
AppleConfigurablesImpl(target, properties, baseDir)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidConfigurablesImpl(target, properties, baseDir)
KonanTarget.MINGW_X64, KonanTarget.MINGW_X86 ->
MingwConfigurablesImpl(target, properties, baseDir)
KonanTarget.WASM32 ->
WasmConfigurablesImpl(target, properties, baseDir)
is KonanTarget.ZEPHYR ->
ZephyrConfigurablesImpl(target, properties, baseDir)
}
@@ -1,94 +0,0 @@
/*
* 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.target
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.properties.keepOnlyDefaultProfiles
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.util.DependencyProcessor
class Distribution(
private val onlyDefaultProfiles: Boolean = false,
private val konanHomeOverride: String? = null,
private val runtimeFileOverride: String? = null) {
val localKonanDir = DependencyProcessor.localKonanDir
private fun findKonanHome(): String {
if (konanHomeOverride != null) return konanHomeOverride
val value = System.getProperty("konan.home", "dist")
val path = File(value).absolutePath
return path
}
val konanHome = findKonanHome()
val konanSubdir = "$konanHome/konan"
val mainPropertyFileName = "$konanSubdir/konan.properties"
val experimentalEnabled by lazy {
File("$konanSubdir/experimentalTargetsEnabled").exists
}
private fun propertyFilesFromConfigDir(configDir: String, genericName: String): List<File> {
val directory = File(configDir, "platforms/$genericName")
return if (directory.exists && directory.isDirectory)
directory.listFiles
else
emptyList()
}
private fun preconfiguredPropertyFiles(genericName: String) =
propertyFilesFromConfigDir(konanSubdir, genericName)
private fun userPropertyFiles(genericName: String) =
propertyFilesFromConfigDir(localKonanDir.absolutePath, genericName)
fun additionalPropertyFiles(genericName: String) =
preconfiguredPropertyFiles(genericName) + userPropertyFiles(genericName)
val properties by lazy {
val loaded = File(mainPropertyFileName).loadProperties()
HostManager.knownTargetTemplates.forEach {
additionalPropertyFiles(it).forEach {
val additional = it.loadProperties()
loaded.putAll(additional)
}
}
if (onlyDefaultProfiles) {
loaded.keepOnlyDefaultProfiles()
}
loaded
}
val klib = "$konanHome/klib"
val stdlib = "$klib/common/stdlib"
fun defaultNatives(target: KonanTarget) = "$konanHome/konan/targets/${target.visibleName}/native"
fun runtime(target: KonanTarget) = runtimeFileOverride ?: "$stdlib/targets/${target.visibleName}/native/runtime.bc"
val launcherFiles = listOf("launcher.bc")
val dependenciesDir = DependencyProcessor.defaultDependenciesRoot.absolutePath
fun availableSubTarget(genericName: String) =
additionalPropertyFiles(genericName).map { it.name }
}
fun buildDistribution(konanHomeOverride: String? = null) = Distribution(true, konanHomeOverride, null)
fun customerDistribution(konanHomeOverride: String? = null) = Distribution(false, konanHomeOverride, null)
@@ -1,75 +0,0 @@
/*
* 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 -> 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.properties
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.Configurables
import org.jetbrains.kotlin.konan.util.DependencyProcessor
interface TargetableExternalStorage {
fun targetString(key: String): String?
fun targetList(key: String): List<String>
fun hostString(key: String): String?
fun hostList(key: String): List<String>
fun hostTargetString(key: String): String?
fun hostTargetList(key: String): List<String>
fun absolute(value: String?): String
fun downloadDependencies()
}
abstract class KonanPropertiesLoader(override val target: KonanTarget,
val properties: Properties,
val baseDir: String? = null) : Configurables {
open val dependencies get() = hostTargetList("dependencies")
override fun downloadDependencies() {
dependencyProcessor!!.run()
}
override fun targetString(key: String): String?
= properties.targetString(key, target)
override fun targetList(key: String): List<String>
= properties.targetList(key, target)
override fun hostString(key: String): String?
= properties.hostString(key)
override fun hostList(key: String): List<String>
= properties.hostList(key)
override fun hostTargetString(key: String): String?
= properties.hostTargetString(key, target)
override fun hostTargetList(key: String): List<String>
= properties.hostTargetList(key, target)
override fun absolute(value: String?): String =
dependencyProcessor!!.resolveRelative(value!!).absolutePath
private val dependencyProcessor by lazy {
baseDir?.let { DependencyProcessor(java.io.File(it), this) }
}
}
fun Properties.keepOnlyDefaultProfiles() {
val DEPENDENCY_PROFILES_KEY = "dependencyProfiles"
val dependencyProfiles = this.getProperty(DEPENDENCY_PROFILES_KEY)
if (dependencyProfiles != "default alt")
error("unexpected $DEPENDENCY_PROFILES_KEY value: expected 'default alt', got '$dependencyProfiles'")
// Force build to use only 'default' profile:
this.setProperty(DEPENDENCY_PROFILES_KEY, "default")
// Force build to use fixed Xcode version:
this.setProperty("useFixedXcodeVersion", "10.1")
// TODO: it actually affects only resolution made in :dependencies,
// that's why we assume that 'default' profile comes first (and check this above).
}
@@ -1,317 +0,0 @@
/*
* 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.target
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
import org.jetbrains.kotlin.konan.target.KonanTarget.*
import org.jetbrains.kotlin.konan.util.Named
import java.io.Serializable
enum class Family(val exeSuffix:String, val dynamicPrefix: String, val dynamicSuffix: String,
val staticPrefix: String, val staticSuffix: String) {
OSX ("kexe", "lib", "dylib", "lib", "a"),
IOS ("kexe", "lib", "dylib", "lib", "a"),
LINUX ("kexe", "lib", "so" , "lib", "a"),
MINGW ("exe" , "" , "dll" , "lib", "a"),
ANDROID ("so" , "lib", "so" , "lib", "a"),
WASM ("wasm", "" , "wasm" , "", "wasm"),
ZEPHYR ("o" , "lib", "a" , "lib", "a")
}
enum class Architecture(val bitness: Int) {
X64(64),
X86(32),
ARM64(64),
ARM32(32),
MIPS32(32),
MIPSEL32(32),
WASM32(32);
}
sealed class KonanTarget(override val name: String, val family: Family, val architecture: Architecture) : Named {
object ANDROID_ARM32 : KonanTarget( "android_arm32", Family.ANDROID, Architecture.ARM32)
object ANDROID_ARM64 : KonanTarget( "android_arm64", Family.ANDROID, Architecture.ARM64)
object IOS_ARM32 : KonanTarget( "ios_arm32", Family.IOS, Architecture.ARM32)
object IOS_ARM64 : KonanTarget( "ios_arm64", Family.IOS, Architecture.ARM64)
object IOS_X64 : KonanTarget( "ios_x64", Family.IOS, Architecture.X64)
object LINUX_X64 : KonanTarget( "linux_x64", Family.LINUX, Architecture.X64)
object MINGW_X86 : KonanTarget( "mingw_x86", Family.MINGW, Architecture.X86)
object MINGW_X64 : KonanTarget( "mingw_x64", Family.MINGW, Architecture.X64)
object MACOS_X64 : KonanTarget( "macos_x64", Family.OSX, Architecture.X64)
object LINUX_ARM32_HFP :KonanTarget( "linux_arm32_hfp", Family.LINUX, Architecture.ARM32)
object LINUX_MIPS32 : KonanTarget( "linux_mips32", Family.LINUX, Architecture.MIPS32)
object LINUX_MIPSEL32 : KonanTarget( "linux_mipsel32", Family.LINUX, Architecture.MIPSEL32)
object WASM32 : KonanTarget( "wasm32", Family.WASM, Architecture.WASM32)
// Tunable targets
class ZEPHYR(val subName: String, val genericName: String = "zephyr") : KonanTarget("${genericName}_$subName", Family.ZEPHYR, Architecture.ARM32)
override fun toString() = name
}
fun hostTargetSuffix(host: KonanTarget, target: KonanTarget) =
if (target == host) host.name else "${host.name}-${target.name}"
enum class CompilerOutputKind {
PROGRAM {
override fun suffix(target: KonanTarget?) = ".${target!!.family.exeSuffix}"
},
DYNAMIC {
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
override fun prefix(target: KonanTarget?) = "${target!!.family.dynamicPrefix}"
},
STATIC {
override fun suffix(target: KonanTarget?) = ".${target!!.family.staticSuffix}"
override fun prefix(target: KonanTarget?) = "${target!!.family.staticPrefix}"
},
FRAMEWORK {
override fun suffix(target: KonanTarget?): String = ".framework"
},
LIBRARY {
override fun suffix(target: KonanTarget?) = ".klib"
},
BITCODE {
override fun suffix(target: KonanTarget?) = ".bc"
};
abstract fun suffix(target: KonanTarget? = null): String
open fun prefix(target: KonanTarget? = null): String = ""
}
interface TargetManager {
val target: KonanTarget
val targetName : String
fun list() : Unit
val hostTargetSuffix: String
val targetSuffix: String
}
private class TargetManagerImpl(val userRequest: String?, val hostManager: HostManager): TargetManager {
override val target = determineCurrent()
override val targetName
get() = target.visibleName
override fun list() {
hostManager.enabled.forEach {
val isDefault = if (it == target) "(default)" else ""
val aliasList = HostManager.listAliases(it.visibleName).joinToString(", ")
println(String.format("%1$-30s%2$-10s%3\$s", "${it.visibleName}:", "$isDefault", aliasList))
}
}
fun determineCurrent(): KonanTarget {
return if (userRequest == null || userRequest == "host") {
HostManager.host
} else {
val resolvedAlias = HostManager.resolveAlias(userRequest)
hostManager.targets[hostManager.known(resolvedAlias)]!!
}
}
override val hostTargetSuffix get() = hostTargetSuffix(HostManager.host, target)
override val targetSuffix get() = target.name
}
open class HostManager(protected val distribution: Distribution = Distribution(), experimental: Boolean = false) {
fun targetManager(userRequest: String? = null): TargetManager = TargetManagerImpl(userRequest, this)
// TODO: need a better way to enumerated predefined targets.
private val predefinedTargets = listOf(
ANDROID_ARM32, ANDROID_ARM64,
IOS_ARM32, IOS_ARM64, IOS_X64,
LINUX_X64, LINUX_ARM32_HFP, LINUX_MIPS32, LINUX_MIPSEL32,
MINGW_X64, MINGW_X86,
MACOS_X64,
WASM32)
private val zephyrSubtargets = distribution.availableSubTarget("zephyr").map { ZEPHYR(it) }
private val experimentalEnabled = experimental || distribution.experimentalEnabled
private val configurableSubtargets = zephyrSubtargets
val targetValues: List<KonanTarget> by lazy {
predefinedTargets + configurableSubtargets
}
val targets = targetValues.associate{ it.visibleName to it }
fun toKonanTargets(names: Iterable<String>): List<KonanTarget> {
return names.map {
if (it == "host") HostManager.host
else targets[known(resolveAlias(it))]!!
}
}
fun known(name: String): String {
if (targets[name] == null) {
throw TargetSupportException("Unknown target: $name. Use -list_targets to see the list of available targets")
}
return name
}
fun targetByName(name: String): KonanTarget {
if (name == "host") return host
val target = targets[resolveAlias(name)]
if (target == null) throw TargetSupportException("Unknown target name: $name")
return target
}
val enabledRegular: List<KonanTarget> by lazy {
when (host) {
KonanTarget.LINUX_X64 -> listOf(
KonanTarget.LINUX_X64,
KonanTarget.LINUX_ARM32_HFP,
KonanTarget.LINUX_MIPS32,
KonanTarget.LINUX_MIPSEL32,
KonanTarget.ANDROID_ARM32,
KonanTarget.ANDROID_ARM64,
KonanTarget.WASM32
)
KonanTarget.MINGW_X64 -> listOf(
KonanTarget.MINGW_X64,
KonanTarget.MINGW_X86,
KonanTarget.LINUX_X64,
KonanTarget.LINUX_ARM32_HFP,
KonanTarget.ANDROID_ARM32,
// TODO: toolchain to be fixed for that to work.
// KonanTarget.ANDROID_ARM64,
KonanTarget.WASM32
)
KonanTarget.MACOS_X64 -> listOf(
KonanTarget.MACOS_X64,
KonanTarget.IOS_ARM32,
KonanTarget.IOS_ARM64,
KonanTarget.IOS_X64,
KonanTarget.LINUX_X64,
KonanTarget.LINUX_ARM32_HFP,
KonanTarget.ANDROID_ARM32,
KonanTarget.ANDROID_ARM64,
KonanTarget.WASM32
)
else ->
throw TargetSupportException("Unknown host platform: $host")
}
}
val enabledExperimental: List<KonanTarget> by lazy {
when (host) {
KonanTarget.LINUX_X64 -> listOf(
KonanTarget.MINGW_X86, KonanTarget.MINGW_X64
) + zephyrSubtargets
KonanTarget.MACOS_X64 -> listOf(
KonanTarget.MINGW_X86, KonanTarget.MINGW_X64
) + zephyrSubtargets
KonanTarget.MINGW_X64 -> listOf<KonanTarget>(
) + zephyrSubtargets
else -> throw TargetSupportException("Unknown host platform: $host")
}
}
val enabled : List<KonanTarget>
get() = if (experimentalEnabled) enabledRegular + enabledExperimental else enabledRegular
fun isEnabled(target: KonanTarget) = enabled.contains(target)
companion object {
fun host_os(): String {
val javaOsName = System.getProperty("os.name")
return when {
javaOsName == "Mac OS X" -> "osx"
javaOsName == "Linux" -> "linux"
javaOsName.startsWith("Windows") -> "windows"
else -> throw TargetSupportException("Unknown operating system: ${javaOsName}")
}
}
@JvmStatic
fun simpleOsName(): String {
val hostOs = host_os()
return if (hostOs == "osx") "macos" else hostOs
}
val jniHostPlatformIncludeDir: String
get() = when(host) {
KonanTarget.MACOS_X64 -> "darwin"
KonanTarget.LINUX_X64 -> "linux"
KonanTarget.MINGW_X64 ->"win32"
else -> throw TargetSupportException("Unknown host: $host.")
}
fun host_arch(): String {
val javaArch = System.getProperty("os.arch")
return when (javaArch) {
"x86_64" -> "x86_64"
"amd64" -> "x86_64"
"arm64" -> "arm64"
else -> throw TargetSupportException("Unknown hardware platform: ${javaArch}")
}
}
val host: KonanTarget = when (host_os()) {
"osx" -> KonanTarget.MACOS_X64
"linux" -> KonanTarget.LINUX_X64
"windows" -> KonanTarget.MINGW_X64
else -> throw TargetSupportException("Unknown host target: ${host_os()} ${host_arch()}")
}
// Note Hotspot-specific VM option enforcing C1-only, critical for decent compilation speed.
val defaultJvmArgs = listOf("-XX:TieredStopAtLevel=1", "-ea", "-Dfile.encoding=UTF-8")
val regularJvmArgs = defaultJvmArgs + "-Xmx3G"
val hostIsMac = (host.family == Family.OSX)
val hostIsLinux = (host.family == Family.LINUX)
val hostIsMingw = (host.family == Family.MINGW)
val hostSuffix get() = host.name
@JvmStatic
val hostName get() = host.name
val knownTargetTemplates = listOf("zephyr")
private val targetAliasResolutions = mapOf(
"linux" to "linux_x64",
"macbook" to "macos_x64",
"macos" to "macos_x64",
"imac" to "macos_x64",
"raspberrypi" to "linux_arm32_hfp",
"iphone32" to "ios_arm32",
"iphone" to "ios_arm64",
"ipad" to "ios_arm64",
"ios" to "ios_arm64",
"iphone_sim" to "ios_x64",
"mingw" to "mingw_x64"
)
private val targetAliases: Map<String, List<String>> by lazy {
val result = mutableMapOf<String, MutableList<String>>()
targetAliasResolutions.entries.forEach {
result.getOrPut(it.value, { mutableListOf() } ).add(it.key)
}
result
}
fun resolveAlias(request: String): String = targetAliasResolutions[request] ?: request
fun listAliases(target: String): List<String> = targetAliases[target] ?: emptyList()
}
}
class TargetSupportException (message: String = "", cause: Throwable? = null) : Exception(message, cause)
@@ -1,426 +0,0 @@
/*
* 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.target
import java.lang.ProcessBuilder
import java.lang.ProcessBuilder.Redirect
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.*
typealias ObjectFile = String
typealias ExecutableFile = String
enum class LinkerOutputKind {
DYNAMIC_LIBRARY,
STATIC_LIBRARY,
EXECUTABLE
}
// Here we take somewhat unexpected approach - we create the thin
// library, and then repack it during post-link phase.
// This way we ensure .a inputs are properly processed.
private fun staticGnuArCommands(ar: String, executable: ExecutableFile,
objectFiles: List<ObjectFile>, libraries: List<String>) = when {
HostManager.hostIsMingw -> {
val temp = executable.replace('/', '\\') + "__"
val arWindows = ar.replace('/', '\\')
listOf(
Command(arWindows, "-rucT", temp).apply {
+objectFiles
+libraries
},
Command("cmd", "/c").apply {
+"(echo create $executable & echo addlib ${temp} & echo save & echo end) | $arWindows -M"
},
Command("cmd", "/c", "del", "/q", temp))
}
HostManager.hostIsLinux || HostManager.hostIsMac -> listOf(
Command(ar, "cqT", executable).apply {
+objectFiles
+libraries
},
Command("/bin/sh", "-c").apply {
+"printf 'create $executable\\naddlib $executable\\nsave\\nend' | $ar -M"
})
else -> TODO("Unsupported host ${HostManager.host}")
}
// Use "clang -v -save-temps" to write linkCommand() method
// for another implementation of this class.
abstract class LinkerFlags(val configurables: Configurables)
/* : Configurables by configurables */ {
protected val llvmBin = "${configurables.absoluteLlvmHome}/bin"
protected val llvmLib = "${configurables.absoluteLlvmHome}/lib"
private val libLTODir = when (HostManager.host) {
KonanTarget.MACOS_X64, KonanTarget.LINUX_X64 -> llvmLib
KonanTarget.MINGW_X64 -> llvmBin
else -> error("Don't know libLTO location for this platform.")
}
open val useCompilerDriverAsLinker: Boolean get() = false // TODO: refactor.
abstract fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command>
abstract fun filterStaticLibraries(binaries: List<String>): List<String>
open fun linkStaticLibraries(binaries: List<String>): List<String> {
val libraries = filterStaticLibraries(binaries)
// Let's just pass them as absolute paths.
return libraries
}
}
open class AndroidLinker(targetProperties: AndroidConfigurables)
: LinkerFlags(targetProperties), AndroidConfigurables by targetProperties {
private val prefix = "$absoluteTargetToolchain/bin/"
private val clang = if (HostManager.hostIsMingw) "$prefix/clang.cmd" else "$prefix/clang"
private val ar = "$absoluteTargetToolchain/${targetProperties.targetArg}/bin/ar"
override val useCompilerDriverAsLinker: Boolean get() = true
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isUnixStaticLib }
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY)
return staticGnuArCommands(ar, executable, objectFiles, libraries)
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
// liblog.so must be linked in, as we use its functionality in runtime.
return listOf(Command(clang).apply {
+"-o"
+executable
+"-fPIC"
+"-shared"
+"-llog"
+objectFiles
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
if (dynamic) +"-Wl,-soname,${File(executable).name}"
+linkerKonanFlags
+libraries
+linkerArgs
})
}
}
open class MacOSBasedLinker(targetProperties: AppleConfigurables)
: LinkerFlags(targetProperties), AppleConfigurables by targetProperties {
private val libtool = "$absoluteTargetToolchain/usr/bin/libtool"
private val linker = "$absoluteTargetToolchain/usr/bin/ld"
private val dsymutil = "$absoluteLlvmHome/bin/llvm-dsymutil"
private fun provideCompilerRtLibrary(libraryName: String): String? {
val suffix = if (libraryName.isNotEmpty() && target == KonanTarget.IOS_X64) {
"iossim"
} else {
when (val family = configurables.target.family) {
Family.OSX -> "osx"
Family.IOS -> "ios"
else -> error("Family $family is unsupported")
}
}
val dir = File("$absoluteTargetToolchain/usr/lib/clang/").listFiles.firstOrNull()?.absolutePath
val mangledName = if (libraryName.isEmpty()) "" else "${libraryName}_"
return if (dir != null) "$dir/lib/darwin/libclang_rt.$mangledName$suffix.a" else null
}
private val compilerRtLibrary: String? by lazy {
provideCompilerRtLibrary("")
}
// Code coverage requires this library.
private val profileLibrary: String? by lazy {
provideCompilerRtLibrary("profile")
}
private val osVersionMinFlags: List<String> by lazy {
listOf(osVersionMinFlagLd, osVersionMin + ".0")
}
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isUnixStaticLib }
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean, kind: LinkerOutputKind,
outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY)
return listOf(Command(libtool).apply {
+"-static"
+listOf("-o", executable)
+objectFiles
+libraries
})
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
return listOf(Command(linker).apply {
+"-demangle"
+listOf("-dynamic", "-arch", arch)
+osVersionMinFlags
+listOf("-syslibroot", absoluteTargetSysRoot, "-o", executable)
+objectFiles
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+linkerKonanFlags
if (compilerRtLibrary != null) +compilerRtLibrary!!
if (profileLibrary != null) +profileLibrary!!
+libraries
+linkerArgs
+rpath(dynamic)
}) + if (debug) listOf(dsymUtilCommand(executable, outputDsymBundle)) else emptyList()
}
private fun rpath(dynamic: Boolean): List<String> = listOfNotNull(
when (target.family) {
Family.OSX -> "@executable_path/../Frameworks"
Family.IOS -> "@executable_path/Frameworks"
else -> error(target)
},
"@loader_path/Frameworks".takeIf { dynamic }
).flatMap { listOf("-rpath", it) }
fun dsymUtilCommand(executable: ExecutableFile, outputDsymBundle: String) =
object : Command(dsymutilCommand(executable, outputDsymBundle)) {
override fun runProcess(): Int =
executeCommandWithFilter(command)
}
// TODO: consider introducing a better filtering directly in Command.
private fun executeCommandWithFilter(command: List<String>): Int {
val builder = ProcessBuilder(command)
// Inherit main process output streams.
val isDsymUtil = (command[0] == dsymutil)
builder.redirectOutput(Redirect.INHERIT)
builder.redirectInput(Redirect.INHERIT)
if (!isDsymUtil)
builder.redirectError(Redirect.INHERIT)
val process = builder.start()
if (isDsymUtil) {
/**
* llvm-lto has option -alias that lets tool to know which symbol we use instead of _main,
* llvm-dsym doesn't have such a option, so we ignore annoying warning manually.
*/
val errorStream = process.errorStream
val outputStream = bufferedReader(errorStream)
while (true) {
val line = outputStream.readLine() ?: break
if (!line.contains("warning: could not find object file symbol for symbol _main"))
System.err.println(line)
}
outputStream.close()
}
val exitCode = process.waitFor()
return exitCode
}
open fun dsymutilCommand(executable: ExecutableFile, outputDsymBundle: String): List<String> =
listOf(dsymutil, executable, "-o", outputDsymBundle)
open fun dsymutilDryRunVerboseCommand(executable: ExecutableFile): List<String> =
listOf(dsymutil, "-dump-debug-map", executable)
}
open class LinuxBasedLinker(targetProperties: LinuxBasedConfigurables)
: LinkerFlags(targetProperties), LinuxBasedConfigurables by targetProperties {
private val ar = if (HostManager.hostIsMac) "$absoluteTargetToolchain/bin/llvm-ar"
else "$absoluteTargetToolchain/bin/ar"
override val libGcc: String = "$absoluteTargetSysRoot/${super.libGcc}"
private val linker = "$absoluteLlvmHome/bin/ld.lld"
private val specificLibs = abiSpecificLibraries.map { "-L${absoluteTargetSysRoot}/$it" }
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isUnixStaticLib }
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY)
return staticGnuArCommands(ar, executable, objectFiles, libraries)
val isMips = (configurables is LinuxMIPSConfigurables)
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
// TODO: Can we extract more to the konan.configurables?
return listOf(Command(linker).apply {
+"--sysroot=${absoluteTargetSysRoot}"
+"-export-dynamic"
+"-z"
+"relro"
+"--build-id"
+"--eh-frame-hdr"
+"-dynamic-linker"
+dynamicLinker
+"-o"
+executable
if (!dynamic) +"$absoluteTargetSysRoot/usr/lib64/crt1.o"
+"$absoluteTargetSysRoot/usr/lib64/crti.o"
+if (dynamic) "$libGcc/crtbeginS.o" else "$libGcc/crtbegin.o"
+"-L$llvmLib"
+"-L$libGcc"
if (!isMips) +"--hash-style=gnu" // MIPS doesn't support hash-style=gnu
+specificLibs
+listOf("-L$absoluteTargetSysRoot/../lib", "-L$absoluteTargetSysRoot/lib", "-L$absoluteTargetSysRoot/usr/lib")
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+objectFiles
+linkerKonanFlags
+listOf("-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed",
"-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed")
+if (dynamic) "$libGcc/crtendS.o" else "$libGcc/crtend.o"
+"$absoluteTargetSysRoot/usr/lib64/crtn.o"
+libraries
+linkerArgs
})
}
}
open class MingwLinker(targetProperties: MingwConfigurables)
: LinkerFlags(targetProperties), MingwConfigurables by targetProperties {
private val ar = "$absoluteTargetToolchain/bin/ar"
private val linker = "$absoluteTargetToolchain/bin/clang++"
override val useCompilerDriverAsLinker: Boolean get() = true
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isWindowsStaticLib || it.isUnixStaticLib }
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY)
return staticGnuArCommands(ar, executable, objectFiles, libraries)
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
return listOf(when {
HostManager.hostIsMingw -> Command(linker)
else -> Command("wine64", "$linker.exe")
}.apply {
+listOf("-o", executable)
+objectFiles
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+libraries
+linkerArgs
+linkerKonanFlags
})
}
}
open class WasmLinker(targetProperties: WasmConfigurables)
: LinkerFlags(targetProperties), WasmConfigurables by targetProperties {
override val useCompilerDriverAsLinker: Boolean get() = false
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isJavaScript }
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind != LinkerOutputKind.EXECUTABLE) throw Error("Unsupported linker output kind")
// TODO(horsh): maybe rethink it.
return listOf(object : Command() {
override fun execute() {
val src = File(objectFiles.single())
val dst = File(executable)
src.recursiveCopyTo(dst)
javaScriptLink(libraries, executable)
}
private fun javaScriptLink(jsFiles: List<String>, executable: String): String {
val linkedJavaScript = File("$executable.js")
val linkerHeader = "var konan = { libraries: [] };\n"
val linkerFooter = """|if (isBrowser()) {
| konan.moduleEntry([]);
|} else {
| konan.moduleEntry(arguments);
|}""".trimMargin()
linkedJavaScript.writeText(linkerHeader)
jsFiles.forEach {
linkedJavaScript.appendBytes(File(it).readBytes())
}
linkedJavaScript.appendBytes(linkerFooter.toByteArray())
return linkedJavaScript.name
}
})
}
}
open class ZephyrLinker(targetProperties: ZephyrConfigurables)
: LinkerFlags(targetProperties), ZephyrConfigurables by targetProperties {
private val linker = "$absoluteTargetToolchain/bin/ld"
override val useCompilerDriverAsLinker: Boolean get() = false
override fun filterStaticLibraries(binaries: List<String>) = emptyList<String>()
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind != LinkerOutputKind.EXECUTABLE) throw Error("Unsupported linker output kind: $kind")
return listOf(Command(linker).apply {
+listOf("-r", "--gc-sections", "--entry", "main")
+listOf("-o", executable)
+objectFiles
+libraries
+linkerArgs
})
}
}
fun linker(configurables: Configurables): LinkerFlags =
when (configurables.target) {
KonanTarget.LINUX_X64, KonanTarget.LINUX_ARM32_HFP ->
LinuxBasedLinker(configurables as LinuxConfigurables)
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxBasedLinker(configurables as LinuxMIPSConfigurables)
KonanTarget.MACOS_X64, KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 ->
MacOSBasedLinker(configurables as AppleConfigurables)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidLinker(configurables as AndroidConfigurables)
KonanTarget.MINGW_X64, KonanTarget.MINGW_X86 ->
MingwLinker(configurables as MingwConfigurables)
KonanTarget.WASM32 ->
WasmLinker(configurables as WasmConfigurables)
is KonanTarget.ZEPHYR ->
ZephyrLinker(configurables as ZephyrConfigurables)
}
@@ -1,48 +0,0 @@
/*
* Copyright 2010-2018 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.target
import org.jetbrains.kotlin.konan.util.DependencyProcessor
class Platform(val configurables: Configurables)
: Configurables by configurables {
val clang by lazy {
ClangArgs(configurables)
}
val linker by lazy {
linker(configurables)
}
}
class PlatformManager(distribution: Distribution = Distribution(), experimental: Boolean = false) :
HostManager(distribution, experimental) {
private val loaders = enabled.map {
it to loadConfigurables(it, distribution.properties, DependencyProcessor.defaultDependenciesRoot.absolutePath)
}.toMap()
private val platforms = loaders.map {
it.key to Platform(it.value)
}.toMap()
fun platform(target: KonanTarget) = platforms.getValue(target)
val hostPlatform = platforms.getValue(host)
fun loader(target: KonanTarget) = loaders.getValue(target)
}
@@ -1,64 +0,0 @@
/*
* 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.properties
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
import org.jetbrains.kotlin.konan.file.*
typealias Properties = java.util.Properties
fun File.loadProperties(): Properties {
val properties = java.util.Properties()
this.bufferedReader().use { reader ->
properties.load(reader)
}
return properties
}
fun loadProperties(path: String): Properties = File(path).loadProperties()
fun File.saveProperties(properties: Properties) {
this.outputStream().use {
properties.store(it, null)
}
}
fun Properties.saveToFile(file: File) = file.saveProperties(this)
fun Properties.propertyString(key: String, suffix: String? = null): String? = getProperty(key.suffix(suffix)) ?: this.getProperty(key)
/**
* TODO: this method working with suffixes should be replaced with
* functionality borrowed from def file parser and unified for interop tool
* and kotlin compiler.
*/
fun Properties.propertyList(key: String, suffix: String? = null): List<String> {
val value = this.getProperty(key.suffix(suffix)) ?: this.getProperty(key)
if (value?.isBlank() == true) return emptyList()
return value?.split(Regex("\\s+")) ?: emptyList()
}
fun Properties.hasProperty(key: String, suffix: String? = null): Boolean
= this.getProperty(key.suffix(suffix)) != null
fun String.suffix(suf: String?): String =
if (suf == null) this
else "${this}.$suf"
@@ -1,37 +0,0 @@
/*
* 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.properties
import org.jetbrains.kotlin.konan.target.*
fun Properties.hostString(name: String): String?
= this.propertyString(name, HostManager.hostName)
fun Properties.hostList(name: String): List<String>
= this.propertyList(name, HostManager.hostName)
fun Properties.targetString(name: String, target: KonanTarget): String?
= this.propertyString(name, target.name)
fun Properties.targetList(name: String, target: KonanTarget): List<String>
= this.propertyList(name, target.name)
fun Properties.hostTargetString(name: String, target: KonanTarget): String?
= this.propertyString(name, hostTargetSuffix(HostManager.host, target))
fun Properties.hostTargetList(name: String, target: KonanTarget): List<String>
= this.propertyList(name, hostTargetSuffix(HostManager.host, target))
@@ -1,57 +0,0 @@
/*
* Copyright 2010-2018 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.target
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.File
interface Xcode {
val toolchain: String
val macosxSdk: String
val iphoneosSdk: String
val iphonesimulatorSdk: String
val version: String
companion object {
val current: Xcode by lazy {
CurrentXcode
}
}
}
private object CurrentXcode : Xcode {
override val toolchain by lazy {
val ldPath = xcrun("-f", "ld") // = $toolchain/usr/bin/ld
File(ldPath).parentFile.parentFile.parentFile.absolutePath
}
override val macosxSdk by lazy { getSdkPath("macosx") }
override val iphoneosSdk by lazy { getSdkPath("iphoneos") }
override val iphonesimulatorSdk by lazy { getSdkPath("iphonesimulator") }
override val version by lazy {
xcrun("xcodebuild", "-version")
.removePrefix("Xcode ")
}
private fun xcrun(vararg args: String): String =
Command("/usr/bin/xcrun", *args).getOutputLines().first() // TODO: handle execution error
private fun getSdkPath(sdk: String) = xcrun("--sdk", sdk, "--show-sdk-path")
}
@@ -1,156 +0,0 @@
/*
* 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.util
import java.io.File
import java.io.StringReader
import java.util.*
class DefFile(val file:File?, val config:DefFileConfig, val manifestAddendProperties:Properties, val defHeaderLines:List<String>) {
private constructor(file0:File?, triple: Triple<Properties, Properties, List<String>>): this(file0, DefFileConfig(triple.first), triple.second, triple.third)
constructor(file:File?, substitutions: Map<String, String>) : this(file, parseDefFile(file, substitutions))
val name by lazy {
file?.nameWithoutExtension ?: ""
}
class DefFileConfig(private val properties: Properties) {
val headers by lazy {
properties.getSpaceSeparated("headers")
}
val modules by lazy {
properties.getSpaceSeparated("modules")
}
val language by lazy {
properties.getProperty("language")
}
val compilerOpts by lazy {
properties.getSpaceSeparated("compilerOpts")
}
val excludeSystemLibs by lazy {
properties.getProperty("excludeSystemLibs")?.toBoolean() ?: false
}
val excludeDependentModules by lazy {
properties.getProperty("excludeDependentModules")?.toBoolean() ?: false
}
val entryPoints by lazy {
properties.getSpaceSeparated("entryPoint")
}
val linkerOpts by lazy {
properties.getSpaceSeparated("linkerOpts")
}
val linker by lazy {
properties.getProperty("linker", "clang")
}
val excludedFunctions by lazy {
properties.getSpaceSeparated("excludedFunctions")
}
val excludedMacros by lazy {
properties.getSpaceSeparated("excludedMacros")
}
val staticLibraries by lazy {
properties.getSpaceSeparated("staticLibraries")
}
val libraryPaths by lazy {
properties.getSpaceSeparated("libraryPaths")
}
val packageName by lazy {
properties.getProperty("package")
}
val headerFilter by lazy {
properties.getSpaceSeparated("headerFilter")
}
val strictEnums by lazy {
properties.getSpaceSeparated("strictEnums")
}
val nonStrictEnums by lazy {
properties.getSpaceSeparated("nonStrictEnums")
}
val noStringConversion by lazy {
properties.getSpaceSeparated("noStringConversion")
}
val depends by lazy {
properties.getSpaceSeparated("depends")
}
val exportForwardDeclarations by lazy {
properties.getSpaceSeparated("exportForwardDeclarations")
}
val disableDesignatedInitializerChecks by lazy {
properties.getProperty("disableDesignatedInitializerChecks")?.toBoolean() ?: false
}
}
}
private fun Properties.getSpaceSeparated(name: String): List<String> {
return this.getProperty(name)?.split(' ')?.filter { it.isNotEmpty() } ?: emptyList()
}
private fun parseDefFile(file: File?, substitutions: Map<String, String>): Triple<Properties, Properties, List<String>> {
val properties = Properties()
if (file == null) {
return Triple(properties, Properties(), emptyList())
}
val lines = file.readLines()
val separator = "---"
val separatorIndex = lines.indexOf(separator)
val propertyLines: List<String>
val headerLines: List<String>
if (separatorIndex != -1) {
propertyLines = lines.subList(0, separatorIndex)
headerLines = lines.subList(separatorIndex + 1, lines.size)
} else {
propertyLines = lines
headerLines = emptyList()
}
val propertiesReader = StringReader(propertyLines.joinToString(System.lineSeparator()))
properties.load(propertiesReader)
// Pass unsubstituted copy of properties we have obtained from `.def`
// to compiler `-maniest`.
val manifestAddendProperties = properties.duplicate()
substitute(properties, substitutions)
return Triple(properties, manifestAddendProperties, headerLines)
}
private fun Properties.duplicate() = Properties().apply { putAll(this@duplicate) }
@@ -1,221 +0,0 @@
/*
* 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.util
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLConnection
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.concurrent.*
typealias ProgressCallback = (url: String, currentBytes: Long, totalBytes: Long) -> Unit
class DependencyDownloader(
var maxAttempts: Int = DEFAULT_MAX_ATTEMPTS,
var attemptIntervalMs: Long = DEFAULT_ATTEMPT_INTERVAL_MS,
customProgressCallback: ProgressCallback? = null
) {
private val progressCallback = customProgressCallback ?: { url, currentBytes, totalBytes ->
print("\rDownloading dependency: $url (${currentBytes.humanReadable}/${totalBytes.humanReadable}). ")
}
val executor = ExecutorCompletionService<Unit>(Executors.newSingleThreadExecutor(object : ThreadFactory {
override fun newThread(r: Runnable?): Thread {
val thread = Thread(r)
thread.name = "konan-dependency-downloader"
thread.isDaemon = true
return thread
}
}))
enum class ReplacingMode {
/** Redownload the file and replace the existing one. */
REPLACE,
/** Throw FileAlreadyExistsException */
THROW,
/** Don't download the file and return the existing one*/
RETURN_EXISTING
}
class HTTPResponseException(val url: URL, val responseCode: Int)
: IOException("Server returned HTTP response code: $responseCode for URL: $url")
class DownloadingProgress(@Volatile var currentBytes: Long) {
fun update(readBytes: Int) { currentBytes += readBytes }
}
private fun HttpURLConnection.checkHTTPResponse(expected: Int, originalUrl: URL = url) {
if (responseCode != expected) {
throw HTTPResponseException(originalUrl, responseCode)
}
}
private fun HttpURLConnection.checkHTTPResponse(originalUrl: URL, predicate: (Int) -> Boolean) {
if (!predicate(responseCode)) {
throw HTTPResponseException(originalUrl, responseCode)
}
}
private fun doDownload(originalUrl: URL,
connection: URLConnection,
tmpFile: File,
currentBytes: Long,
totalBytes: Long,
append: Boolean) {
val progress = DownloadingProgress(currentBytes)
// TODO: Implement multi-thread downloading.
executor.submit {
connection.getInputStream().use { from ->
FileOutputStream(tmpFile, append).use { to ->
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
var read = from.read(buffer)
while (read != -1) {
if (Thread.interrupted()) {
throw InterruptedException()
}
to.write(buffer, 0, read)
progress.update(read)
read = from.read(buffer)
}
if (progress.currentBytes != totalBytes) {
throw EOFException("The stream closed before end of downloading.")
}
}
}
}
var result: Future<Unit>?
do {
progressCallback(originalUrl.toString(), progress.currentBytes, totalBytes)
result = executor.poll(1, TimeUnit.SECONDS)
} while(result == null)
progressCallback(originalUrl.toString(), progress.currentBytes, totalBytes)
try {
result.get()
} catch (e: ExecutionException) {
throw e.cause ?: e
}
}
private fun resumeDownload(originalUrl: URL, originalConnection: HttpURLConnection, tmpFile: File) {
originalConnection.connect()
val totalBytes = originalConnection.contentLengthLong
val currentBytes = tmpFile.length()
if (currentBytes >= totalBytes || originalConnection.getHeaderField("Accept-Ranges") != "bytes") {
// The temporary file is bigger then expected or the server doesn't support resuming downloading.
// Download the file from scratch.
doDownload(originalUrl, originalConnection, tmpFile, 0, totalBytes, false)
} else {
originalConnection.disconnect()
val rangeConnection = originalUrl.openConnection() as HttpURLConnection
rangeConnection.setRequestProperty("range", "bytes=$currentBytes-")
rangeConnection.connect()
rangeConnection.checkHTTPResponse(originalUrl) {
it == HttpURLConnection.HTTP_PARTIAL || it == HttpURLConnection.HTTP_OK
}
doDownload(originalUrl, rangeConnection, tmpFile, currentBytes, totalBytes, true)
}
}
/** Performs an attempt to download a specified file into the specified location */
private fun tryDownload(url: URL, tmpFile: File) {
val connection = url.openConnection()
(connection as? HttpURLConnection)?.checkHTTPResponse(HttpURLConnection.HTTP_OK, url)
if (connection is HttpURLConnection && tmpFile.exists()) {
resumeDownload(url, connection, tmpFile)
} else {
connection.connect()
val totalBytes = connection.contentLengthLong
doDownload(url, connection, tmpFile, 0, totalBytes, false)
}
}
/** Downloads a file from [source] url to [destination]. Returns [destination]. */
fun download(source: URL,
destination: File,
replace: ReplacingMode = ReplacingMode.RETURN_EXISTING): File {
if (destination.exists()) {
when (replace) {
ReplacingMode.RETURN_EXISTING -> return destination
ReplacingMode.THROW -> throw FileAlreadyExistsException(destination)
ReplacingMode.REPLACE -> Unit // Just continue with downloading.
}
}
val tmpFile = File("${destination.canonicalPath}.$TMP_SUFFIX")
check(!tmpFile.isDirectory) {
"A temporary file is a directory: ${tmpFile.canonicalPath}. Remove it and try again."
}
check(!destination.isDirectory) {
"The destination file is a directory: ${destination.canonicalPath}. Remove it and try again."
}
var attempt = 1
var waitTime = 0L
while (true) {
try {
tryDownload(source, tmpFile)
break
} catch (e: HTTPResponseException) {
throw e
} catch (e: IOException) {
if (attempt >= maxAttempts) {
throw e
}
attempt++
waitTime += attemptIntervalMs
println("Cannot download a dependency: $e\n" +
"Waiting ${waitTime.toDouble() / 1000} sec and trying again (attempt: $attempt/$maxAttempts).")
// TODO: Wait better
Thread.sleep(waitTime)
}
}
Files.move(tmpFile.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING)
println("Done.")
return destination
}
private val Long.humanReadable: String
get() {
if (this < 0) {
return "-"
}
if (this < 1024) {
return "$this bytes"
}
val exp = (Math.log(this.toDouble()) / Math.log(1024.0)).toInt()
val prefix = "kMGTPE"[exp-1]
return "%.1f %siB".format(this / Math.pow(1024.0, exp.toDouble()), prefix)
}
companion object {
const val DEFAULT_MAX_ATTEMPTS = 10
const val DEFAULT_ATTEMPT_INTERVAL_MS = 3000L
const val TMP_SUFFIX = "part"
}
}
@@ -1,68 +0,0 @@
/*
* 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.util
import org.jetbrains.kotlin.konan.file.unzipTo
import java.io.File
import java.util.concurrent.TimeUnit
class DependencyExtractor {
internal val useZip = System.getProperty("os.name").startsWith("Windows")
internal val archiveExtension = if (useZip) {
"zip"
} else {
"tar.gz"
}
private fun extractTarGz(tarGz: File, targetDirectory: File) {
val tarProcess = ProcessBuilder().apply {
command("tar", "-xzf", tarGz.canonicalPath)
directory(targetDirectory)
inheritIO()
}.start()
val finished = tarProcess.waitFor(extractionTimeout, extractionTimeoutUntis)
when {
finished && tarProcess.exitValue() != 0 ->
throw RuntimeException(
"Cannot extract archive with dependency: ${tarGz.canonicalPath}.\n" +
"Tar exit code: ${tarProcess.exitValue()}."
)
!finished -> {
tarProcess.destroy()
throw RuntimeException(
"Cannot extract archive with dependency: ${tarGz.canonicalPath}.\n" +
"Tar process hasn't finished in ${extractionTimeoutUntis.toSeconds(extractionTimeout)} sec.")
}
}
}
fun extract(archive: File, targetDirectory: File) {
if (useZip) {
archive.toPath().unzipTo(targetDirectory.toPath())
} else {
extractTarGz(archive, targetDirectory)
}
}
companion object {
val extractionTimeout = 3600L
val extractionTimeoutUntis = TimeUnit.SECONDS
}
}
@@ -1,307 +0,0 @@
/*
* 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.util
import org.jetbrains.kotlin.konan.file.use
import org.jetbrains.kotlin.konan.properties.KonanPropertiesLoader
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.propertyList
import java.io.File
import java.io.FileNotFoundException
import java.io.RandomAccessFile
import java.net.InetAddress
import java.net.URL
import java.net.UnknownHostException
import java.nio.file.Paths
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
private val Properties.dependenciesUrl : String
get() = getProperty("dependenciesUrl")
?: throw IllegalStateException("No such property in konan.properties: dependenciesUrl")
private val Properties.airplaneMode : Boolean
get() = getProperty("airplaneMode")?.toBoolean() ?: false
private val Properties.downloadingAttempts : Int
get() = getProperty("downloadingAttempts")?.toInt()
?: DependencyDownloader.DEFAULT_MAX_ATTEMPTS
private val Properties.downloadingAttemptIntervalMs : Long
get() = getProperty("downloadingAttemptPauseMs")?.toLong()
?: DependencyDownloader.DEFAULT_ATTEMPT_INTERVAL_MS
private fun Properties.findCandidates(dependencies: List<String>): Map<String, List<DependencySource>> {
val dependencyProfiles = this.propertyList("dependencyProfiles")
return dependencies.map { dependency ->
dependency to dependencyProfiles.flatMap { profile ->
val candidateSpecs = propertyList("$dependency.$profile")
if (profile == "default" && candidateSpecs.isEmpty()) {
listOf(DependencySource.Remote.Public)
} else {
candidateSpecs.map { candidateSpec ->
when (candidateSpec) {
"remote:public" -> DependencySource.Remote.Public
"remote:internal" -> DependencySource.Remote.Internal
else -> DependencySource.Local(File(candidateSpec))
}
}
}
}
}.toMap()
}
private val KonanPropertiesLoader.dependenciesUrl : String get() = properties.dependenciesUrl
private val KonanPropertiesLoader.airplaneMode : Boolean get() = properties.airplaneMode
private val KonanPropertiesLoader.downloadingAttempts : Int get() = properties.downloadingAttempts
private val KonanPropertiesLoader.downloadingAttemptIntervalMs : Long get() = properties.downloadingAttemptIntervalMs
sealed class DependencySource {
data class Local(val path: File) : DependencySource()
sealed class Remote : DependencySource() {
object Public : Remote()
object Internal : Remote()
}
}
/**
* Inspects [dependencies] and downloads all the missing ones into [dependenciesDirectory] from [dependenciesUrl].
* If [airplaneMode] is true will throw a RuntimeException instead of downloading.
*/
class DependencyProcessor(dependenciesRoot: File,
val dependenciesUrl: String,
dependencyToCandidates: Map<String, List<DependencySource>>,
homeDependencyCache: File = defaultDependencyCacheDir,
val airplaneMode: Boolean = false,
maxAttempts: Int = DependencyDownloader.DEFAULT_MAX_ATTEMPTS,
attemptIntervalMs: Long = DependencyDownloader.DEFAULT_ATTEMPT_INTERVAL_MS,
customProgressCallback: ProgressCallback? = null,
val keepUnstable: Boolean = true,
val deleteArchives: Boolean = true) {
val dependenciesDirectory = dependenciesRoot.apply { mkdirs() }
val cacheDirectory = homeDependencyCache.apply { mkdirs() }
val lockFile = File(cacheDirectory, ".lock").apply { if (!exists()) createNewFile() }
var showInfo = true
private var isInfoShown = false
private val downloader = DependencyDownloader(maxAttempts, attemptIntervalMs, customProgressCallback)
private val extractor = DependencyExtractor()
private val archiveExtension get() = extractor.archiveExtension
constructor(dependenciesRoot: File,
properties: KonanPropertiesLoader,
dependenciesUrl: String = properties.dependenciesUrl,
keepUnstable:Boolean = true) : this(
dependenciesRoot,
properties.properties,
properties.dependencies,
dependenciesUrl,
keepUnstable = keepUnstable)
constructor(dependenciesRoot: File,
properties: Properties,
dependencies: List<String>,
dependenciesUrl: String = properties.dependenciesUrl,
keepUnstable:Boolean = true) : this(
dependenciesRoot,
dependenciesUrl,
dependencyToCandidates = properties.findCandidates(dependencies),
airplaneMode = properties.airplaneMode,
maxAttempts = properties.downloadingAttempts,
attemptIntervalMs = properties.downloadingAttemptIntervalMs,
keepUnstable = keepUnstable)
class DependencyFile(directory: File, fileName: String) {
val file = File(directory, fileName).apply { createNewFile() }
private val dependencies = file.readLines().toMutableSet()
fun contains(dependency: String) = dependencies.contains(dependency)
fun add(dependency: String) = dependencies.add(dependency)
fun remove(dependency: String) = dependencies.remove(dependency)
fun removeAndSave(dependency: String) {
remove(dependency)
save()
}
fun addAndSave(dependency: String) {
add(dependency)
save()
}
fun save() {
val writer = file.writer()
writer.use {
dependencies.forEach {
writer.write(it)
writer.write("\n")
}
}
}
}
private fun downloadDependency(dependency: String, baseUrl: String) {
val depDir = File(dependenciesDirectory, dependency)
val depName = depDir.name
val fileName = "$depName.$archiveExtension"
val archive = cacheDirectory.resolve(fileName)
val url = URL("$baseUrl/$fileName")
val extractedDependencies = DependencyFile(dependenciesDirectory, ".extracted")
if (extractedDependencies.contains(depName) &&
depDir.exists() &&
depDir.isDirectory &&
depDir.list().isNotEmpty()) {
if (!keepUnstable && depDir.list().contains(".unstable")) {
// The downloaded version of the dependency is unstable -> redownload it.
depDir.deleteRecursively()
archive.delete()
extractedDependencies.removeAndSave(dependency)
} else {
return
}
}
if (showInfo && !isInfoShown) {
println("Downloading native dependencies (LLVM, sysroot etc). This is a one-time action performed only on the first run of the compiler.")
isInfoShown = true
}
if (!archive.exists()) {
if (airplaneMode) {
throw FileNotFoundException("""
Cannot find a dependency locally: $dependency.
Set `airplaneMode = false` in konan.properties to download it.
""".trimIndent())
}
downloader.download(url, archive)
}
println("Extracting dependency: $archive into $dependenciesDirectory")
extractor.extract(archive, dependenciesDirectory)
if (deleteArchives) {
archive.delete()
}
extractedDependencies.addAndSave(depName)
}
companion object {
private val lock = ReentrantLock()
val localKonanDir: File by lazy {
File(System.getenv("KONAN_DATA_DIR") ?: (System.getProperty("user.home") + File.separator + ".konan"))
}
@JvmStatic
val defaultDependenciesRoot: File
get() = localKonanDir.resolve("dependencies")
val defaultDependencyCacheDir: File
get() = localKonanDir.resolve("cache")
}
private val resolvedDependencies = dependencyToCandidates.map { (dependency, candidates) ->
val candidate = candidates.asSequence().mapNotNull { candidate ->
when (candidate) {
is DependencySource.Local -> candidate.takeIf { it.path.exists() }
DependencySource.Remote.Public -> candidate
DependencySource.Remote.Internal -> candidate.takeIf { InternalServer.isAvailable }
}
}.firstOrNull()
candidate ?: error("$dependency is not available; candidates:\n${candidates.joinToString("\n")}")
dependency to candidate
}.toMap()
private fun resolveDependency(dependency: String): File {
val candidate = resolvedDependencies[dependency]
return when (candidate) {
is DependencySource.Local -> candidate.path
is DependencySource.Remote -> File(dependenciesDirectory, dependency)
null -> error("$dependency not declared as dependency")
}
}
fun resolveRelative(relative: String): File {
val path = Paths.get(relative)
if (path.isAbsolute) error("not a relative path: $relative")
val dependency = path.first().toString()
return resolveDependency(dependency).let {
if (path.nameCount > 1) {
it.toPath().resolve(path.subpath(1, path.nameCount)).toFile()
} else {
it
}
}
}
fun run() = lock.withLock {
RandomAccessFile(lockFile, "rw").channel.lock().use {
resolvedDependencies.forEach { (dependency, candidate) ->
val baseUrl = when (candidate) {
is DependencySource.Local -> null
DependencySource.Remote.Public -> dependenciesUrl
DependencySource.Remote.Internal -> InternalServer.url
}
// TODO: consider using different caches for different remotes.
if (baseUrl != null) {
downloadDependency(dependency, baseUrl)
}
}
}
}
}
internal object InternalServer {
private val host = "repo.labs.intellij.net"
val url = "http://$host/kotlin-native"
private val internalDomain = "labs.intellij.net"
val isAvailable by lazy {
val envKey = "KONAN_USE_INTERNAL_SERVER"
val envValue = System.getenv(envKey)
when (envValue) {
"0" -> false
"1" -> true
null -> checkAccessible()
else -> error("unexpected environment: $envKey=$envValue")
}
}
private fun checkAccessible() = try {
if (!InetAddress.getLocalHost().canonicalHostName.endsWith(".$internalDomain")) {
// Fast path:
false
} else {
InetAddress.getByName(host)
true
}
} catch (e: UnknownHostException) {
false
}
}
@@ -1,33 +0,0 @@
/*
* 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.util
import java.io.File
import java.util.*
class Helper0(val dependenciesDir: String,
val properties: Properties,
val dependencies: List<String>): Runnable {
override fun run() {
DependencyProcessor(File(dependenciesDir),
properties,
dependencies,
properties.getProperty("dependenciesUrl", "https://download.jetbrains.com/kotlin/native")
).run()
}
}
@@ -1,29 +0,0 @@
package org.jetbrains.kotlin.konan.util
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.util.*
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
fun defaultTargetSubstitutions(target: KonanTarget) =
mapOf<String, String>(
"target" to target.visibleName,
"arch" to target.architecture.visibleName,
"family" to target.family.visibleName)
// Performs substitution similar to:
// foo = ${foo} ${foo.${arch}} ${foo.${os}}
fun substitute(properties: Properties, substitutions: Map<String, String>) {
for (key in properties.stringPropertyNames()) {
for (substitution in substitutions.values) {
val suffix = ".$substitution"
if (key.endsWith(suffix)) {
val baseKey = key.removeSuffix(suffix)
val oldValue = properties.getProperty(baseKey, "")
val appendedValue = properties.getProperty(key, "")
val newValue = if (oldValue != "") "$oldValue $appendedValue" else appendedValue
properties.setProperty(baseKey, newValue)
}
}
}
}
@@ -1,6 +0,0 @@
package org.jetbrains.kotlin.konan.util
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
fun DefFile(file: File?, target: KonanTarget) = DefFile(file, defaultTargetSubstitutions(target))
@@ -1,61 +0,0 @@
/*
* 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.util
import kotlin.system.measureTimeMillis
import org.jetbrains.kotlin.konan.file.*
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
fun <T> printMillisec(message: String, body: () -> T): T {
var result: T? = null
val msec = measureTimeMillis{
result = body()
}
println("$message: $msec msec")
return result!!
}
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
fun profile(message: String, body: () -> Unit) = profileIf(
System.getProperty("konan.profile")?.equals("true") ?: false,
message, body)
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
fun profileIf(condition: Boolean, message: String, body: () -> Unit) =
if (condition) printMillisec(message, body) else body()
fun nTabs(amount: Int): String {
return String.format("%1$-${(amount+1)*4}s", "")
}
fun String.prefixIfNot(prefix: String) =
if (this.startsWith(prefix)) this else "$prefix$this"
fun String.prefixBaseNameIfNot(prefix: String): String {
val file = File(this).absoluteFile
val name = file.name
val directory = file.parent
return "$directory/${name.prefixIfNot(prefix)}"
}
fun String.suffixIfNot(suffix: String) =
if (this.endsWith(suffix)) this else "$this$suffix"
fun String.removeSuffixIfPresent(suffix: String) =
if (this.endsWith(suffix)) this.dropLast(suffix.length) else this
fun <T> Lazy<T>.getValueOrNull(): T? = if (isInitialized()) value else null
@@ -1,10 +0,0 @@
package org.jetbrains.kotlin.konan.util
typealias Logger = (String) -> Unit
interface WithLogger {
val logger: Logger
}
fun dummyLogger(message: String) {}
@@ -82,6 +82,9 @@ repositories {
maven {
url kotlinCompilerRepo
}
maven {
url sharedRepo
}
}
configurations {
@@ -102,7 +105,8 @@ dependencies {
bundleDependencies "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion"
bundleDependencies "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
bundleDependencies "org.jetbrains.kotlin:kotlin-gradle-plugin-api:$kotlinVersion"
bundleDependencies "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
bundleDependencies "org.jetbrains.kotlin:kotlin-native-shared:$sharedVersion"
bundleDependencies "org.jetbrains.kotlin:kotlin-native-version"
testImplementation 'junit:junit:4.12'
testImplementation "org.jetbrains.kotlin:kotlin-test:$buildKotlinVersion"
@@ -1,2 +1,2 @@
rootProject.name = "kotlin-native-gradle-plugin"
includeBuild '../../shared'
includeBuild '../../version'
@@ -24,6 +24,8 @@ import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanArtifactWithLibrariesTask
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanBuildingTask
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.SearchPathResolver
import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.target.Distribution
@@ -146,7 +148,8 @@ open class KonanLibrariesSpec(val task: KonanArtifactWithLibrariesTask, val proj
defaultResolver(
repos.map { it.absolutePath },
task.konanTarget,
Distribution(konanHomeOverride = project.konanHome)
Distribution(konanHomeOverride = project.konanHome),
listOf(KonanVersion.CURRENT)
)
)
@@ -34,6 +34,7 @@ import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin.Companion.COMPILE_ALL_TASK_NAME
import org.jetbrains.kotlin.gradle.plugin.model.KonanToolingModelBuilder
import org.jetbrains.kotlin.gradle.plugin.tasks.*
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.parseKonanVersion
import org.jetbrains.kotlin.konan.target.HostManager
@@ -25,6 +25,8 @@ import org.gradle.process.CommandLineArgumentProvider
import org.jetbrains.kotlin.gradle.plugin.konan.*
import org.jetbrains.kotlin.gradle.plugin.model.KonanModelArtifact
import org.jetbrains.kotlin.gradle.plugin.model.KonanModelArtifactImpl
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Distribution
@@ -234,7 +236,8 @@ abstract class KonanCompileTask: KonanBuildingTask(), KonanCompileSpec {
val resolver = defaultResolver(
repos.map { it.absolutePath },
konanTarget,
Distribution(konanHomeOverride = project.konanHome)
Distribution(konanHomeOverride = project.konanHome),
listOf(KonanVersion.CURRENT)
)
return KonanModelArtifactImpl(
@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.gradle.plugin.konan.*
import org.jetbrains.kotlin.gradle.plugin.konan.KonanInteropSpec.IncludeDirectoriesSpec
import org.jetbrains.kotlin.gradle.plugin.model.KonanModelArtifact
import org.jetbrains.kotlin.gradle.plugin.model.KonanModelArtifactImpl
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Distribution
@@ -171,7 +173,8 @@ open class KonanInteropTask @Inject constructor(val workerExecutor: WorkerExecut
val resolver = defaultResolver(
repos.map { it.absolutePath },
konanTarget,
Distribution(konanHomeOverride = project.konanHome)
Distribution(konanHomeOverride = project.konanHome),
listOf(KonanVersion.CURRENT)
)
return KonanModelArtifactImpl(
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.plugin.konan.konanArtifactsContainer
import org.jetbrains.kotlin.gradle.plugin.konan.konanExtension
import org.jetbrains.kotlin.gradle.plugin.konan.konanHome
import org.jetbrains.kotlin.gradle.plugin.konan.konanVersion
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import java.io.File
@@ -22,6 +22,7 @@ import org.gradle.testfixtures.ProjectBuilder
import org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin
import org.jetbrains.kotlin.gradle.plugin.konan.konanArtifactsContainer
import org.jetbrains.kotlin.gradle.plugin.model.KonanToolingModelBuilder
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.junit.Rule
import org.junit.rules.TemporaryFolder
@@ -4,6 +4,7 @@
*/
package org.jetbrains.kotlin.cli.utilities
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.library.*
@@ -11,6 +12,7 @@ import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.native.interop.gen.jvm.interop
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kliopt.ArgParser
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.native.interop.tool.*
// TODO: this function should eventually be eliminated from 'utilities'.
@@ -48,7 +50,8 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String>? {
repos,
libraries.filter { it.contains(File.separator) },
target,
Distribution()
Distribution(),
listOf(KonanVersion.CURRENT)
).libraryResolver()
val allLibraries = resolver.resolveWithDependencies(
libraries.toUnresolvedLibraries, noStdLib = true, noDefaultLibs = noDefaultLibs
+5 -3
View File
@@ -32,6 +32,9 @@ repositories {
maven {
url buildKotlinCompilerRepo
}
maven {
url sharedRepo
}
}
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: drop generation of KonanVersion!
@@ -39,8 +42,6 @@ task generateCompilerVersion(type: VersionGenerator){}
sourceSets {
main.kotlin {
srcDir 'src/main/kotlin'
srcDir 'src/library/kotlin'
srcDir generateCompilerVersion.versionSourceDirectory
}
}
@@ -57,9 +58,10 @@ clean {
}
jar {
archiveName = "shared.jar"
archiveName = "version.jar"
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-native-shared:$sharedVersion"
}
@@ -20,7 +20,6 @@ buildscript {
}
apply plugin: 'kotlin'
repositories {
@@ -0,0 +1,60 @@
package org.jetbrains.kotlin
import groovy.lang.Closure
import org.gradle.api.DefaultTask
import org.gradle.api.Task
import org.gradle.api.tasks.*
import java.io.File
open class VersionGenerator: DefaultTask() {
@OutputDirectory
val versionSourceDirectory = project.file("build/generated")
@OutputFile
val versionFile:File = project.file("${versionSourceDirectory.path}/org/jetbrains/kotlin/konan/KonanVersionGenerated.kt")
val konanVersion: String
@Input get() = project.properties["konanVersion"].toString()
val buildNumber: String?
// TeamCity passes all configuration parameters into a build script as project properties.
// Thus we can use them here instead of environment variables.
@Optional @Input get() = project.findProperty("build.number")?.toString()
val meta: String
@Input get() = project.properties["konanMetaVersion"]?.let {
"MetaVersion.${it.toString().toUpperCase()}"
} ?: "MetaVersion.DEV"
override fun configure(closure: Closure<*>): Task {
val result = super.configure(closure)
doFirst {
val content = buildString {
operator fun String.unaryPlus() = this@buildString.append(this)
val version = konanVersion.split(".")
val major = version[0].toInt()
val minor = version[1].toInt()
val maintenance = if (version.size > 2) version[2].toInt() else 0
project.logger.info("BUILD_NUMBER: $buildNumber")
val build = buildNumber?.let {
it.split("-")[2].toInt() //7-dev-buildcount
}?: -1
+ """
|package org.jetbrains.kotlin.konan
|
|internal val currentKonanVersion: KonanVersion =
| KonanVersionImpl($meta, $major, $minor, $maintenance, $build)
|
|val KonanVersion.Companion.CURRENT: KonanVersion
| get() = currentKonanVersion
""".trimMargin()
}
versionFile.printWriter().use {
it.println(content)
}
}
return result
}
}
+1
View File
@@ -0,0 +1 @@
rootProject.name = "kotlin-native-version"