Initial checkin of klib support.

The libraries exist in two incarnations:
    packed foo.klib and unpacked foo/ .
The compiler when given '-library foo' expects to find either
a foo.klib file and unpack it, or an already unpacked foo/ directory.

The stdlib is always unpacked in dist/klib .

The semantics of -o has changed slightly.
It now accepts '-o foo' and the compiler
either produces foo.kexe or foo.klib .
This commit is contained in:
Alexander Gorshenev
2017-04-27 16:14:17 +03:00
committed by alexander-gorshenev
parent 77e093354f
commit 3b5ce031f8
24 changed files with 564 additions and 203 deletions
+3
View File
@@ -38,6 +38,9 @@ model {
include '**/*.c' include '**/*.c'
} }
binaries.all { binaries.all {
def host = rootProject.ext.host
def hostLibffiDir = rootProject.ext.get("${host}LibffiDir")
cCompiler.args compilerArgsForJniIncludes cCompiler.args compilerArgsForJniIncludes
cCompiler.args "-I$hostLibffiDir/include" cCompiler.args "-I$hostLibffiDir/include"
+10 -10
View File
@@ -153,7 +153,7 @@ kotlinNativeInterop {
compilerOpts '-fPIC' compilerOpts '-fPIC'
linkerOpts '-fPIC' linkerOpts '-fPIC'
linker 'clang++' linker 'clang++'
linkOutputs ':common:hostHash' linkOutputs ":common:${host}Hash"
headers fileTree('../common/src/hash/headers') { headers fileTree('../common/src/hash/headers') {
include '**/*.h' include '**/*.h'
@@ -194,8 +194,8 @@ build.dependsOn 'compilerClasses','cli_bcClasses','bc_frontendClasses'
// These are just a couple of aliases // These are just a couple of aliases
task stdlib(dependsOn: 'hostStdlib') task stdlib(dependsOn: "${host}Stdlib")
task start(dependsOn: 'hostStart') task start(dependsOn: "${host}Start")
// These files are built before the 'dist' is complete, // These files are built before the 'dist' is complete,
// so we provide custom values for // so we provide custom values for
@@ -208,8 +208,8 @@ targetList.each { target ->
jvmArgs "-ea", jvmArgs "-ea",
"-Dkonan.home=${project.parent.file('dist')}", "-Dkonan.home=${project.parent.file('dist')}",
"-Djava.library.path=${project.buildDir}/nativelibs" "-Djava.library.path=${project.buildDir}/nativelibs"
args('-output', project(':runtime').file("build/${target}/stdlib.kt.bc"), args('-output', project(':runtime').file("build/${target}Stdlib"),
'-nolink', '-nostdlib', '-ea', '-nolink', '-nopack', '-nostdlib','-ea',
'-target', target, '-target', target,
'-runtime', project(':runtime').file("build/${target}/runtime.bc"), '-runtime', project(':runtime').file("build/${target}/runtime.bc"),
'-properties', project(':backend.native').file('konan.properties'), '-properties', project(':backend.native').file('konan.properties'),
@@ -221,7 +221,7 @@ targetList.each { target ->
inputs.dir(project(':runtime').file('src/main/kotlin')) inputs.dir(project(':runtime').file('src/main/kotlin'))
inputs.dir(project(':Interop:Runtime').file('src/main/kotlin')) inputs.dir(project(':Interop:Runtime').file('src/main/kotlin'))
inputs.dir(project(':Interop:Runtime').file('src/native/kotlin')) inputs.dir(project(':Interop:Runtime').file('src/native/kotlin'))
outputs.file(project(':runtime').file("build/${target}/stdlib.kt.bc")) outputs.file(project(':runtime').file("build/${target}Stdlib"))
dependsOn ":runtime:${target}Runtime" dependsOn ":runtime:${target}Runtime"
} }
@@ -234,17 +234,17 @@ targetList.each { target ->
jvmArgs "-ea", jvmArgs "-ea",
"-Dkonan.home=${project.parent.file('dist')}", "-Dkonan.home=${project.parent.file('dist')}",
"-Djava.library.path=${project.buildDir}/nativelibs" "-Djava.library.path=${project.buildDir}/nativelibs"
args('-output', project(':runtime').file("build/${target}/start.kt.bc"), args('-output', project(':runtime').file("build/${target}Start"),
'-nolink', '-nostdlib', '-ea', '-nolink', '-nopack', '-nostdlib', '-ea',
'-target', target, '-target', target,
'-library', project(':runtime').file("build/${target}/stdlib.kt.bc"), '-library', project(':runtime').file("build/${target}Stdlib"),
'-runtime', project(':runtime').file("build/${target}/runtime.bc"), '-runtime', project(':runtime').file("build/${target}/runtime.bc"),
'-properties', project(':backend.native').file('konan.properties'), '-properties', project(':backend.native').file('konan.properties'),
project(':runtime').file('src/launcher/kotlin'), project(':runtime').file('src/launcher/kotlin'),
*project.globalBuildArgs) *project.globalBuildArgs)
inputs.dir(project(':runtime').file('src/launcher/kotlin')) inputs.dir(project(':runtime').file('src/launcher/kotlin'))
outputs.file(project(':runtime').file("build/${target}/start.kt.bc")) outputs.file(project(':runtime').file("build/${target}Start"))
dependsOn ":runtime:${target}Runtime", "${target}Stdlib" dependsOn ":runtime:${target}Runtime", "${target}Stdlib"
} }
@@ -90,36 +90,38 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(NOSTDLIB, arguments.nostdlib) put(NOSTDLIB, arguments.nostdlib)
put(NOLINK, arguments.nolink) put(NOLINK, arguments.nolink)
put(NOPACK, arguments.nopack)
put(NOMAIN, arguments.nomain) put(NOMAIN, arguments.nomain)
put(LIBRARY_FILES, put(LIBRARY_FILES,
arguments.libraries.toNonNullList()) arguments.libraries.toNonNullList())
put(LINKER_ARGS, arguments.linkerArguments.toNonNullList()) put(LINKER_ARGS, arguments.linkerArguments.toNonNullList())
if (arguments.target != null)
put(TARGET, arguments.target)
put(NATIVE_LIBRARY_FILES, put(NATIVE_LIBRARY_FILES,
arguments.nativeLibraries.toNonNullList()) arguments.nativeLibraries.toNonNullList())
// TODO: Collect all the explicit file names into an object // TODO: Collect all the explicit file names into an object
// and teach the compiler to work with temporaries and -save-temps. // and teach the compiler to work with temporaries and -save-temps.
val bitcodeFile = if (arguments.nolink) { val library = arguments.outputFile ?: "library"
arguments.outputFile ?: "program.kt.bc" if (arguments.nolink)
} else { put(LIBRARY_NAME, library)
"${arguments.outputFile ?: "program"}.kt.bc" put(LIBRARY_FILE, "${library}.klib")
val program = arguments.outputFile ?: "program"
if (!arguments.nolink) {
put(PROGRAM_NAME,program)
put(EXECUTABLE_FILE,"${program}.kexe")
} }
put(BITCODE_FILE, bitcodeFile)
// This is a decision we could change // This is a decision we could change
put(CommonConfigurationKeys.MODULE_NAME, bitcodeFile) val module = if (arguments.nolink) library else program
put(CommonConfigurationKeys.MODULE_NAME, module)
put(ABI_VERSION, 1) put(ABI_VERSION, 1)
put(EXECUTABLE_FILE,
arguments.outputFile ?: "program.kexe")
if (arguments.runtimeFile != null) if (arguments.runtimeFile != null)
put(RUNTIME_FILE, arguments.runtimeFile) put(RUNTIME_FILE, arguments.runtimeFile)
if (arguments.propertyFile != null) if (arguments.propertyFile != null)
put(PROPERTY_FILE, arguments.propertyFile) put(PROPERTY_FILE, arguments.propertyFile)
if (arguments.target != null)
put(TARGET, arguments.target)
put(LIST_TARGETS, arguments.listTargets) put(LIST_TARGETS, arguments.listTargets)
put(OPTIMIZATION, arguments.optimization) put(OPTIMIZATION, arguments.optimization)
put(DEBUG, arguments.debug) put(DEBUG, arguments.debug)
@@ -38,6 +38,9 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments {
@Argument(value = "-nolink", description = "Don't link, just produce a bitcode file") @Argument(value = "-nolink", description = "Don't link, just produce a bitcode file")
public boolean nolink; public boolean nolink;
@Argument(value = "-nopack", description = "Don't pack the library into a klib file")
public boolean nopack;
@Argument(value = "-nomain", description = "Assume 'main' entry point to be provided by external libraries") @Argument(value = "-nomain", description = "Assume 'main' entry point to be provided by external libraries")
public boolean nomain; public boolean nomain;
@@ -55,11 +55,6 @@ import java.util.*
import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
internal class LinkData(
val module: String,
val fragments: List<String>,
val fragmentNames: List<String> )
internal class SpecialDescriptorsFactory(val context: Context) { internal class SpecialDescriptorsFactory(val context: Context) {
private val enumSpecialDescriptorsFactory by lazy { EnumSpecialDescriptorsFactory(context) } private val enumSpecialDescriptorsFactory by lazy { EnumSpecialDescriptorsFactory(context) }
private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>() private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>()
@@ -270,6 +265,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
lateinit var llvm: Llvm lateinit var llvm: Llvm
lateinit var llvmDeclarations: LlvmDeclarations lateinit var llvmDeclarations: LlvmDeclarations
lateinit var bitcodeFileName: String
lateinit var library: KonanLibraryWriter
var phase: KonanPhase? = null var phase: KonanPhase? = null
var depth: Int = 0 var depth: Int = 0
@@ -22,9 +22,7 @@ import java.io.File
class Distribution(val config: CompilerConfiguration) { class Distribution(val config: CompilerConfiguration) {
val targetManager = TargetManager(config) val targetManager = TargetManager(config)
val target = val target = targetManager.currentName
if (!targetManager.crossCompile) "host"
else targetManager.current.name.toLowerCase()
val suffix = targetManager.currentSuffix() val suffix = targetManager.currentSuffix()
val hostSuffix = TargetManager.host.suffix val hostSuffix = TargetManager.host.suffix
init { if (!targetManager.crossCompile) assert(suffix == hostSuffix) } init { if (!targetManager.crossCompile) assert(suffix == hostSuffix) }
@@ -40,16 +38,14 @@ class Distribution(val config: CompilerConfiguration) {
?: "$konanHome/konan/konan.properties" ?: "$konanHome/konan/konan.properties"
val properties = KonanProperties(propertyFile) val properties = KonanProperties(propertyFile)
val lib = "$konanHome/lib/$target" val klib = "$konanHome/klib"
val dependenciesDir = "$konanHome/dependencies" val dependenciesDir = "$konanHome/dependencies"
val dependencies = properties.propertyList("dependencies.$suffix") val dependencies = properties.propertyList("dependencies.$suffix")
val stdlib = "$lib/stdlib.kt.bc" val stdlib = "$klib/stdlib"
val start = "$lib/start.kt.bc"
val launcher = "$lib/launcher.bc"
val runtime = config.get(KonanConfigKeys.RUNTIME_FILE) val runtime = config.get(KonanConfigKeys.RUNTIME_FILE)
?: "$lib/runtime.bc" ?: "$stdlib/$target/native/runtime.bc"
val llvmHome = "$dependenciesDir/${properties.propertyString("llvmHome.$hostSuffix")}" val llvmHome = "$dependenciesDir/${properties.propertyString("llvmHome.$hostSuffix")}"
val sysRoot = "$dependenciesDir/${properties.propertyString("sysRoot.$hostSuffix")}" val sysRoot = "$dependenciesDir/${properties.propertyString("sysRoot.$hostSuffix")}"
@@ -28,6 +28,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val moduleId: String val moduleId: String
get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME) get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
internal val targetManager = TargetManager(configuration)
internal val distribution = Distribution(configuration) internal val distribution = Distribution(configuration)
private val libraryNames: List<String> private val libraryNames: List<String>
@@ -39,16 +40,15 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
return fromCommandLine + distribution.stdlib return fromCommandLine + distribution.stdlib
} }
internal val libraries: List<KonanLibrary> by lazy { internal val libraries: List<KonanLibraryReader> by lazy {
// Here we have chosen a particular .kt.bc KonanLibrary implementation // Here we have chosen a particular KonanLibraryReader implementation
libraryNames.map{it -> KtBcLibrary(it, configuration)} libraryNames.map{it -> SplitLibraryReader(it, configuration)}
} }
private val loadedDescriptors = loadLibMetadata() private val loadedDescriptors = loadLibMetadata()
internal val nativeLibraries: List<String> = configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES) internal val nativeLibraries: List<String> = configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES)
fun loadLibMetadata(): List<ModuleDescriptorImpl> { fun loadLibMetadata(): List<ModuleDescriptorImpl> {
val allMetadata = mutableListOf<ModuleDescriptorImpl>() val allMetadata = mutableListOf<ModuleDescriptorImpl>()
@@ -25,8 +25,12 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("library file paths") = CompilerConfigurationKey.create("library file paths")
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>> val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("native library file paths") = CompilerConfigurationKey.create("native library file paths")
val BITCODE_FILE: CompilerConfigurationKey<String> val LIBRARY_NAME: CompilerConfigurationKey<String>
= CompilerConfigurationKey.create("emitted bitcode file path") = CompilerConfigurationKey.create("library name")
val LIBRARY_FILE: CompilerConfigurationKey<String>
= CompilerConfigurationKey.create("library file path")
val PROGRAM_NAME: CompilerConfigurationKey<String>
= CompilerConfigurationKey.create("program name")
val EXECUTABLE_FILE: CompilerConfigurationKey<String> val EXECUTABLE_FILE: CompilerConfigurationKey<String>
= CompilerConfigurationKey.create("final executable file path") = CompilerConfigurationKey.create("final executable file path")
val RUNTIME_FILE: CompilerConfigurationKey<String?> val RUNTIME_FILE: CompilerConfigurationKey<String?>
@@ -43,6 +47,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("don't link with stdlib") = CompilerConfigurationKey.create("don't link with stdlib")
val NOLINK: CompilerConfigurationKey<Boolean> val NOLINK: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("don't link, only produce a bitcode file ") = CompilerConfigurationKey.create("don't link, only produce a bitcode file ")
val NOPACK: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("don't the library into a klib file")
val NOMAIN: CompilerConfigurationKey<Boolean> val NOMAIN: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries") = CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries")
val LINKER_ARGS: CompilerConfigurationKey<List<String>> val LINKER_ARGS: CompilerConfigurationKey<List<String>>
@@ -48,7 +48,7 @@ public fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEn
val config = konanConfig.configuration val config = konanConfig.configuration
val targets = TargetManager(config) val targets = konanConfig.targetManager
if (config.get(KonanConfigKeys.LIST_TARGETS) ?: false) { if (config.get(KonanConfigKeys.LIST_TARGETS) ?: false) {
targets.list() targets.list()
} }
@@ -1,69 +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.backend.konan
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.backend.konan.llvm.MetadataReader
import org.jetbrains.kotlin.backend.konan.llvm.loadSerializedModule
import org.jetbrains.kotlin.backend.konan.llvm.loadSerializedPackageFragment
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.backend.konan.serialization.Base64
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
import java.io.File
interface KonanLibrary {
val libraryName: String
val moduleName: String
val moduleDescriptor: ModuleDescriptorImpl
val bitcodePaths: List<String>
}
class KtBcLibrary(val file: File, val configuration: CompilerConfiguration): KonanLibrary {
constructor(path: String, configuration: CompilerConfiguration) : this(File(path), configuration)
init {
if (!file.exists())
error("Path '" + file.path + "' does not exist")
}
override val libraryName: String
get() = file.path
override val bitcodePaths: List<String>
get() = listOf(libraryName)
private val reader = MetadataReader(file)
private val namedModuleData by lazy {
val currentAbiVersion = configuration.get(KonanConfigKeys.ABI_VERSION)!!
reader.loadSerializedModule(currentAbiVersion)
}
override val moduleName = namedModuleData.name
private val tableOfContentsAsString = namedModuleData.base64
private fun packageMetadata(fqName: String): Base64 =
reader.loadSerializedPackageFragment(fqName)
override val moduleDescriptor: ModuleDescriptorImpl by lazy {
deserializeModule(configuration,
{it -> packageMetadata(it)},
tableOfContentsAsString, moduleName)
}
}
@@ -77,6 +77,7 @@ object KonanPhases {
// Don't serialize anything to a final executable. // Don't serialize anything to a final executable.
KonanPhase.SERIALIZER.enabled = getBoolean(NOLINK) KonanPhase.SERIALIZER.enabled = getBoolean(NOLINK)
KonanPhase.METADATOR.enabled = getBoolean(NOLINK)
val disabled = get(DISABLED_PHASES) val disabled = get(DISABLED_PHASES)
disabled?.forEach { phases[known(it)]!!.enabled = false } disabled?.forEach { phases[known(it)]!!.enabled = false }
@@ -30,6 +30,8 @@ enum class KonanTarget(val suffix: String, var enabled: Boolean = false) {
class TargetManager(val config: CompilerConfiguration) { class TargetManager(val config: CompilerConfiguration) {
val targets = KonanTarget.values().associate{ it.name.toLowerCase() to it } val targets = KonanTarget.values().associate{ it.name.toLowerCase() to it }
val current = determineCurrent() val current = determineCurrent()
val currentName
get() = current.name.toLowerCase()
init { init {
when (host) { when (host) {
@@ -147,9 +147,9 @@ internal class LinkStage(val context: Context) {
val config = context.config.configuration val config = context.config.configuration
val targetManager = TargetManager(config) val targetManager = context.config.targetManager
private val distribution = private val distribution =
Distribution(context.config.configuration) context.config.distribution
private val properties = distribution.properties private val properties = distribution.properties
val platform = when (TargetManager.host) { val platform = when (TargetManager.host) {
@@ -164,8 +164,8 @@ internal class LinkStage(val context: Context) {
val suffix = targetManager.currentSuffix() val suffix = targetManager.currentSuffix()
val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
val emitted = config.get(KonanConfigKeys.BITCODE_FILE)!!
val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
val emitted = context.bitcodeFileName
val libraries = context.config.libraries val libraries = context.config.libraries
fun llvmLto(files: List<BitcodeFile>): ObjectFile { fun llvmLto(files: List<BitcodeFile>): ObjectFile {
@@ -265,8 +265,7 @@ internal class LinkStage(val context: Context) {
fun linkStage() { fun linkStage() {
context.log{"# Compiler root: ${distribution.konanHome}"} context.log{"# Compiler root: ${distribution.konanHome}"}
val bitcodeFiles = listOf<BitcodeFile>(emitted, distribution.start, val bitcodeFiles = listOf<BitcodeFile>(emitted) +
distribution.runtime, distribution.launcher) +
libraries.map{it -> it.bitcodePaths}.flatten() libraries.map{it -> it.bitcodePaths}.flatten()
var objectFiles: List<String> = listOf() var objectFiles: List<String> = listOf()
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan
import java.io.File
import java.net.URI
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
val File.zipUri: URI
get() = URI.create("jar:file:${this.absolutePath}")
val File.zipRootPath: Path
get() {
val zipUri = this.zipUri
val allowCreation = hashMapOf("create" to "true")
val zipfs = FileSystems.newFileSystem(zipUri, allowCreation, null)
return zipfs.getPath("/")
}
fun File.zipDirAs(zipFile: File) {
val zipPath = zipFile.zipRootPath
this.toPath().recursiveCopyTo(zipPath)
zipPath.fileSystem.close()
}
fun File.unzipAs(directory: File) {
val zipPath = this.zipRootPath
zipPath.recursiveCopyTo(directory.toPath())
zipPath.fileSystem.close()
}
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 Sting.
val newPath = destFs.getPath(destPath.toString(), relative.toString())
// File systems don't allow replacing an existing root.
if (newPath == newPath.getRoot()) return@next
Files.copy(oldPath, newPath,
StandardCopyOption.REPLACE_EXISTING)
}
}
fun File.copyTo(destination: File) {
Files.copy(this.toPath(), destination.toPath())
}
@@ -0,0 +1,225 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan
import llvm.LLVMLinkModules2
import llvm.LLVMModuleRef
import llvm.LLVMWriteBitcodeToFile
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.serialization.Base64
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import java.io.File
interface KonanLibraryReader {
val libraryName: String
val moduleName: String
val moduleDescriptor: ModuleDescriptorImpl
val bitcodePaths: List<String>
}
abstract class FileBasedLibraryReader(
val file: File,
val configuration: CompilerConfiguration,
val reader: MetadataReader): KonanLibraryReader {
override val libraryName: String
get() = file.path
protected val namedModuleData by lazy {
val currentAbiVersion = configuration.get(KonanConfigKeys.ABI_VERSION)!!
reader.loadSerializedModule(currentAbiVersion)
}
override val moduleName: String
get() = namedModuleData.name
protected val tableOfContentsAsString : String
get() = namedModuleData.base64
protected fun packageMetadata(fqName: String): Base64 =
reader.loadSerializedPackageFragment(fqName)
override val moduleDescriptor: ModuleDescriptorImpl by lazy {
deserializeModule(configuration,
{it -> packageMetadata(it)},
tableOfContentsAsString, moduleName)
}
}
class KtBcLibraryReader(file: File, configuration: CompilerConfiguration)
: FileBasedLibraryReader(file, configuration, KtBcMetadataReader(file)) {
public constructor(path: String, configuration: CompilerConfiguration) : this(File(path), configuration)
override val bitcodePaths: List<String>
get() = listOf(libraryName)
}
// TODO: Get rid of the configuration here.
class SplitLibraryReader(val libDir: File, configuration: CompilerConfiguration)
: FileBasedLibraryReader(libDir, configuration, SplitMetadataReader(libDir)) {
public constructor(path: String, configuration: CompilerConfiguration) : this(File(path), configuration)
val klibFile = File("${libDir.path}.klib")
init {
unpackIfNeeded()
}
// TODO: Search path processing is also goes somewhere around here.
fun unpackIfNeeded() {
// TODO: Clarify the policy here.
if (libDir.exists()) {
if (libDir.isDirectory()) return
}
if (!klibFile.exists()) {
error("Could not find neither $libDir nor $klibFile.")
}
if (klibFile.isFile()) {
klibFile.unzipAs(libDir)
if (!libDir.exists()) error("Could not unpack $klibFile as $libDir.")
} else {
error("Expected $klibFile to be a regular libDir.")
}
}
private val File.dirAbsolutePaths: List<String>
get() = this.listFiles()!!.toList()!!.map{it->it.absolutePath}
private val targetDir: File
get() {
val target = TargetManager(configuration).currentName
val dir = File(libDir, target)
return dir
}
override val bitcodePaths: List<String>
get() = File(targetDir, "kotlin").dirAbsolutePaths +
File(targetDir, "native").dirAbsolutePaths
}
/* ------------ writer part ----------------*/
interface KonanLibraryWriter {
fun addLinkData(linkData: LinkData)
fun addNativeBitcode(library: String)
fun addKotlinBitcode(llvmModule: LLVMModuleRef)
fun commit()
val mainBitcodeFileName: String
}
class LinkData(
val abiVersion: Int,
val module: String,
val moduleName: String,
val fragments: List<String>,
val fragmentNames: List<String> )
abstract class FileBasedLibraryWriter (
val file: File): KonanLibraryWriter {
}
class KtBcLibraryWriter(file: File, val llvmModule: LLVMModuleRef)
: FileBasedLibraryWriter(file) {
override val mainBitcodeFileName = file.path
public constructor(path: String, llvmModule: LLVMModuleRef)
: this(File(path), llvmModule)
override fun addKotlinBitcode(llvmModule: LLVMModuleRef) {
// This is a noop for .kt.bc based libraries,
// because the bitcode itself is the container.
}
override fun addLinkData(linkData: LinkData) {
MetadataGenerator(llvmModule).addLinkData(linkData)
}
override fun addNativeBitcode(library: String) {
val libraryModule = parseBitcodeFile(library)
val failed = LLVMLinkModules2(llvmModule, libraryModule)
if (failed != 0) {
throw Error("failed to link $library") // TODO: retrieve error message from LLVM.
}
}
override fun commit() {
LLVMWriteBitcodeToFile(llvmModule, file.path)
}
}
class SplitLibraryWriter(val libDir: File, target: String, val nopack: Boolean = false): FileBasedLibraryWriter(libDir) {
public constructor(path: String, target: String, nopack: Boolean): this(File(path), target, nopack)
val klibFile = File("${libDir.path}.klib")
val linkdataDir = File(libDir, "linkdata")
val resourcesDir = File(libDir, "resources")
val targetDir = File(libDir, target)
val kotlinDir = File(targetDir, "kotlin")
val nativeDir = File(targetDir, "native")
// TODO: Experiment with separate bitcode files.
// Per package or per class.
val mainBitcodeFile = File(kotlinDir, "program.kt.bc")
override val mainBitcodeFileName = mainBitcodeFile.path
init {
// TODO: figure out the proper policy here.
libDir.deleteRecursively()
klibFile.delete()
libDir.mkdirs()
linkdataDir.mkdirs()
targetDir.mkdirs()
kotlinDir.mkdirs()
nativeDir.mkdirs()
resourcesDir.mkdirs()
}
var llvmModule: LLVMModuleRef? = null
override fun addKotlinBitcode(llvmModule: LLVMModuleRef) {
this.llvmModule = llvmModule
LLVMWriteBitcodeToFile(llvmModule, mainBitcodeFileName)
}
override fun addLinkData(linkData: LinkData) {
SplitMetadataGenerator(linkdataDir).addLinkData(linkData)
}
override fun addNativeBitcode(library: String) {
val basename = File(library).getName()
File(library).copyTo(File(nativeDir, basename))
}
override fun commit() {
if (!nopack) {
// This is no-op for the Split library.
// Or should we zip the directory?
libDir.zipDirAs(klibFile)
libDir.deleteRecursively()
}
}
}
@@ -22,6 +22,7 @@ import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.KonanVersion import org.jetbrains.kotlin.backend.konan.KonanVersion
import org.jetbrains.kotlin.backend.konan.TargetManager
import org.jetbrains.kotlin.backend.konan.util.File import org.jetbrains.kotlin.backend.konan.util.File
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -94,7 +95,15 @@ internal fun String?.toFileAndFolder():FileAndFolder {
internal fun generateDebugInfoHeader(context: Context) { internal fun generateDebugInfoHeader(context: Context) {
if (context.shouldContainDebugInfo()) { if (context.shouldContainDebugInfo()) {
val path = context.config.configuration.get(KonanConfigKeys.BITCODE_FILE).toFileAndFolder()
val path = with(context.config.configuration) {
if (!getBoolean(KonanConfigKeys.NOLINK)) {
get(KonanConfigKeys.EXECUTABLE_FILE)!!
} else {
get(KonanConfigKeys.LIBRARY_NAME)!!
}
}.toFileAndFolder()
context.debugInfo.module = DICreateModule( context.debugInfo.module = DICreateModule(
builder = context.debugInfo.builder, builder = context.debugInfo.builder,
scope = context.llvmModule as DIScopeOpaqueRef, scope = context.llvmModule as DIScopeOpaqueRef,
@@ -23,9 +23,14 @@ import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.KonanPhase import org.jetbrains.kotlin.backend.konan.KonanPhase
import org.jetbrains.kotlin.backend.konan.LinkData
import org.jetbrains.kotlin.backend.konan.PhaseManager import org.jetbrains.kotlin.backend.konan.PhaseManager
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.TargetManager
import org.jetbrains.kotlin.backend.konan.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.KtBcLibraryWriter
import org.jetbrains.kotlin.backend.konan.SplitLibraryWriter
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -52,7 +57,9 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
internal fun emitLLVM(context: Context) { internal fun emitLLVM(context: Context) {
val config = context.config.configuration
val irModule = context.irModule!! val irModule = context.irModule!!
// Note that we don't set module target explicitly. // Note that we don't set module target explicitly.
// It is determined by the target of runtime.bc // It is determined by the target of runtime.bc
// (see Llvm class in ContextUtils) // (see Llvm class in ContextUtils)
@@ -61,7 +68,6 @@ internal fun emitLLVM(context: Context) {
val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose
context.llvmModule = llvmModule context.llvmModule = llvmModule
context.debugInfo.builder = DICreateBuilder(llvmModule) context.debugInfo.builder = DICreateBuilder(llvmModule)
context.llvmDeclarations = createLlvmDeclarations(context) context.llvmDeclarations = createLlvmDeclarations(context)
val phaser = PhaseManager(context) val phaser = PhaseManager(context)
@@ -70,33 +76,74 @@ internal fun emitLLVM(context: Context) {
irModule.acceptVoid(RTTIGeneratorVisitor(context)) irModule.acceptVoid(RTTIGeneratorVisitor(context))
} }
generateDebugInfoHeader(context) generateDebugInfoHeader(context)
phaser.phase(KonanPhase.CODEGEN) { phaser.phase(KonanPhase.CODEGEN) {
irModule.acceptVoid(CodeGeneratorVisitor(context)) irModule.acceptVoid(CodeGeneratorVisitor(context))
} }
phaser.phase(KonanPhase.METADATOR) {
irModule.acceptVoid(MetadatorVisitor(context))
}
phaser.phase(KonanPhase.BITCODE_LINKER) {
for (library in context.config.nativeLibraries) {
val libraryModule = parseBitcodeFile(library)
val failed = LLVMLinkModules2(llvmModule, libraryModule)
if (failed != 0) {
throw Error("failed to link $library") // TODO: retrieve error message from LLVM.
}
}
}
if (context.shouldContainDebugInfo()) { if (context.shouldContainDebugInfo()) {
DIFinalize(context.debugInfo.builder) DIFinalize(context.debugInfo.builder)
} }
LLVMWriteBitcodeToFile(llvmModule, context.config.configuration.get(KonanConfigKeys.BITCODE_FILE)!!)
if (!config.getBoolean(KonanConfigKeys.NOLINK)) {
val program = config.get(KonanConfigKeys.PROGRAM_NAME)!!
val output = "$program}.kt.bc"
context.bitcodeFileName = output
phaser.phase(KonanPhase.BITCODE_LINKER) {
for (library in context.config.nativeLibraries) {
val libraryModule = parseBitcodeFile(library)
val failed = LLVMLinkModules2(llvmModule, libraryModule)
if (failed != 0) {
throw Error("failed to link $library") // TODO: retrieve error message from LLVM.
}
}
}
LLVMWriteBitcodeToFile(llvmModule, output)
} else {
val libraryName = config.get(KonanConfigKeys.LIBRARY_NAME)!!
val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
val targetName = context.config.targetManager.currentName
val library = buildLibrary(
phaser,
context.config.nativeLibraries,
context.serializedLinkData!!,
targetName,
libraryName,
llvmModule,
nopack)
context.library = library
context.bitcodeFileName =
library.mainBitcodeFileName
}
} }
internal fun buildLibrary(phaser: PhaseManager, natives: List<String>, linkData: LinkData, target: String, output: String, llvmModule: LLVMModuleRef, nopack: Boolean): KonanLibraryWriter {
// TODO: May be we need a factory?
//val library = KtBcLibraryWriter(output, llvmModule)
val library = SplitLibraryWriter(output, target, nopack)
library.addKotlinBitcode(llvmModule)
phaser.phase(KonanPhase.METADATOR) {
library.addLinkData(linkData)
}
phaser.phase(KonanPhase.BITCODE_LINKER) {
natives.forEach {
library.addNativeBitcode(it)
}
}
library.commit()
return library
}
internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") { internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") {
memScoped { memScoped {
@@ -134,19 +181,6 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
internal class MetadatorVisitor(val context: Context) : IrElementVisitorVoid {
val metadator = MetadataGenerator(context)
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitModuleFragment(module: IrModuleFragment) {
module.acceptChildrenVoid(this)
metadator.endModule(module)
}
}
/** /**
* Defines how to generate context-dependent operations. * Defines how to generate context-dependent operations.
@@ -20,13 +20,51 @@ import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.LinkData
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import java.io.Closeable import java.io.Closeable
import java.io.File import java.io.File
import kotlin.io.readText
import java.util.Properties
class NamedModuleData(val name:String, val base64: String) class NamedModuleData(val name:String, val base64: String)
fun MetadataReader.loadSerializedModule(currentAbiVersion: Int): NamedModuleData { interface MetadataReader {
fun loadSerializedModule(currentAbiVersion: Int): NamedModuleData
fun loadSerializedPackageFragment(fqName: String): String
}
class SplitMetadataReader(file: File) : MetadataReader {
val linkDataDir = File(file, "linkdata")
override fun loadSerializedModule(currentAbiVersion: Int): NamedModuleData {
val header = Properties()
val file = File(linkDataDir, "module")
file.bufferedReader().use { reader ->
header.load(reader)
}
val headerAbiVersion = header.getProperty("abi_version")!!
val moduleName = header.getProperty("module_name")!!
val moduleData = header.getProperty("module_data")!!
if ("$currentAbiVersion" != headerAbiVersion)
error("ABI version mismatch. Compiler expects: $currentAbiVersion, the library is $headerAbiVersion")
return NamedModuleData(moduleName, moduleData)
}
override fun loadSerializedPackageFragment(fqName: String): String {
val realName = if (fqName == "") "<root>" else fqName
return File(linkDataDir, realName).readText()
}
}
class KtBcMetadataReader(file: File) : Closeable, MetadataReader {
override fun loadSerializedModule(currentAbiVersion: Int): NamedModuleData {
val (nodeCount, kmetadataNodeArg) = namedMetadataNode("kmetadata") val (nodeCount, kmetadataNodeArg) = namedMetadataNode("kmetadata")
if (nodeCount != 1) { if (nodeCount != 1) {
@@ -48,7 +86,7 @@ fun MetadataReader.loadSerializedModule(currentAbiVersion: Int): NamedModuleData
return NamedModuleData(moduleName, tableOfContentsAsString) return NamedModuleData(moduleName, tableOfContentsAsString)
} }
fun MetadataReader.loadSerializedPackageFragment(fqName: String): String { override fun loadSerializedPackageFragment(fqName: String): String {
val (nodeCount, kpackageNodeArg) = namedMetadataNode("kpackage:$fqName") val (nodeCount, kpackageNodeArg) = namedMetadataNode("kpackage:$fqName")
if (nodeCount != 1) { if (nodeCount != 1) {
@@ -61,8 +99,6 @@ fun MetadataReader.loadSerializedPackageFragment(fqName: String): String {
return base64 return base64
} }
class MetadataReader(file: File) : Closeable {
lateinit var llvmModule: LLVMModuleRef lateinit var llvmModule: LLVMModuleRef
lateinit var llvmContext: LLVMContextRef lateinit var llvmContext: LLVMContextRef
@@ -141,7 +177,7 @@ class MetadataReader(file: File) : Closeable {
} }
} }
internal class MetadataGenerator(override val context: Context): ContextUtils { internal class MetadataGenerator(val llvmModule: LLVMModuleRef) {
private fun metadataNode(args: List<LLVMValueRef?>): LLVMValueRef { private fun metadataNode(args: List<LLVMValueRef?>): LLVMValueRef {
return LLVMMDNode(args.toCValues(), args.size)!! return LLVMMDNode(args.toCValues(), args.size)!!
@@ -154,38 +190,52 @@ internal class MetadataGenerator(override val context: Context): ContextUtils {
} }
private fun emitModuleMetadata(name: String, md: LLVMValueRef?) { private fun emitModuleMetadata(name: String, md: LLVMValueRef?) {
LLVMAddNamedMetadataOperand(context.llvmModule, name, md) LLVMAddNamedMetadataOperand(llvmModule, name, md)
} }
private fun metadataString(str: String): LLVMValueRef { private fun metadataString(str: String): LLVMValueRef {
return LLVMMDString(str, str.length)!! return LLVMMDString(str, str.length)!!
} }
private fun addLinkData(module: IrModuleFragment) { fun addLinkData(linkData: LinkData) {
val linkData = context.serializedLinkData
if (linkData == null) return if (linkData == null) return
val abiVersion = context.config.configuration.get(KonanConfigKeys.ABI_VERSION) val abiNode = metadataString("${linkData.abiVersion}")
val abiNode = metadataString("$abiVersion") val moduleNameNode = metadataString(linkData.moduleName)
val moduleName = metadataString(module.descriptor.name.asString())
val module = linkData.module val module = linkData.module
val fragments = linkData.fragments val fragments = linkData.fragments
val fragmentNames = linkData.fragmentNames val fragmentNames = linkData.fragmentNames
val dataNode = metadataString(module) val dataNode = metadataString(module)
val kmetadataArg = metadataNode(listOf(abiNode, moduleName, dataNode)) val kmetadataArg = metadataNode(listOf(abiNode, moduleNameNode, dataNode))
emitModuleMetadata("kmetadata", kmetadataArg) emitModuleMetadata("kmetadata", kmetadataArg)
fragments.forEachIndexed { index, it -> fragments.forEachIndexed { index, it ->
val name = fragmentNames.get(index) val name = fragmentNames[index]
val dataNode = metadataString(it) val dataNode = metadataString(it)
val kpackageArg = metadataNode(listOf(dataNode)) val kpackageArg = metadataNode(listOf(dataNode))
emitModuleMetadata("kpackage:$name", kpackageArg) emitModuleMetadata("kpackage:$name", kpackageArg)
} }
} }
}
internal fun endModule(module: IrModuleFragment) { internal class SplitMetadataGenerator(val file: File) {
addLinkData(module)
fun addLinkData(linkData: LinkData) {
val header = Properties()
header.putAll(hashMapOf(
"abi_version" to "${linkData.abiVersion}",
"module_name" to "${linkData.moduleName}",
"module_data" to "${linkData.module}"
))
header.store(File(file, "module").outputStream(), null)
linkData.fragments.forEachIndexed { index, it ->
val name = linkData.fragmentNames[index]
val realName = if (name == "") "<root>" else name
File(file, realName).writeText(it)
}
} }
} }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.LinkData import org.jetbrains.kotlin.backend.konan.LinkData
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.llvm.base64Decode import org.jetbrains.kotlin.backend.konan.llvm.base64Decode
import org.jetbrains.kotlin.backend.konan.llvm.base64Encode import org.jetbrains.kotlin.backend.konan.llvm.base64Encode
import org.jetbrains.kotlin.backend.konan.llvm.isExported import org.jetbrains.kotlin.backend.konan.llvm.isExported
@@ -274,7 +275,9 @@ internal class KonanSerializationUtil(val context: Context) {
} }
val libraryAsByteArray = libraryProto.build().toByteArray() val libraryAsByteArray = libraryProto.build().toByteArray()
val library = byteArrayToBase64(libraryAsByteArray) val library = byteArrayToBase64(libraryAsByteArray)
return LinkData(library, fragments, fragmentNames) val abiVersion = context.config.configuration.get(KonanConfigKeys.ABI_VERSION)!!
val moduleName = moduleDescriptor.name.asString()
return LinkData(abiVersion, library, moduleName, fragments, fragmentNames)
} }
} }
+52 -26
View File
@@ -67,8 +67,9 @@ void setupCompilationFlags() {
final String binDir final String binDir
if (isLinux()) { if (isLinux()) {
ext.host = "linux"
ext.targetArgs << ext.targetArgs <<
["host": [(ext.host):
["--sysroot=${gccToolchainDir}/${gnuTriplet}/sysroot"], ["--sysroot=${gccToolchainDir}/${gnuTriplet}/sysroot"],
"raspberrypi": "raspberrypi":
["-target", "armv7-unknown-linux-gnueabihf", ["-target", "armv7-unknown-linux-gnueabihf",
@@ -79,9 +80,10 @@ void setupCompilationFlags() {
"-I$raspberryPiSysrootDir/usr/include/c++/4.8.3/arm-linux-gnueabihf"] "-I$raspberryPiSysrootDir/usr/include/c++/4.8.3/arm-linux-gnueabihf"]
] ]
} else { } else {
ext.host = "macbook"
ext.targetArgs << ext.targetArgs <<
["host": [(ext.host):
["--sysroot=$hostSysrootDir", "-mmacosx-version-min=$minMacOsVersion"], ["--sysroot=$macbookSysrootDir", "-mmacosx-version-min=$minMacOsVersion"],
"iphone": "iphone":
["-stdlib=libc++", "-arch", "arm64", "-isysroot", "$iphoneSysrootDir", ["-stdlib=libc++", "-arch", "arm64", "-isysroot", "$iphoneSysrootDir",
"-miphoneos-version-min=8.0.0"] "-miphoneos-version-min=8.0.0"]
@@ -99,11 +101,11 @@ void setupCompilationFlags() {
"-L$llvmDir/lib" "-L$llvmDir/lib"
]) ])
} else { } else {
binDir = "$hostSysrootDir/usr/bin" binDir = "$macbookSysrootDir/usr/bin"
} }
ext.clangArgs << "-B$binDir" ext.clangArgs << "-B$binDir"
ext.hostClangArgs = ext.clangArgs.clone() ext.hostClangArgs = ext.clangArgs.clone()
ext.hostClangArgs.addAll(ext.targetArgs['host']) ext.hostClangArgs.addAll(ext.targetArgs[host])
ext.clangPath << binDir ext.clangPath << binDir
ext.jvmArgs = ["-ea"] ext.jvmArgs = ["-ea"]
@@ -164,7 +166,12 @@ class PlatformInfo {
} }
} }
task dist_compiler(type: Copy) { task dist_compiler(dependsOn: "distCompiler")
task dist_runtime(dependsOn: "distRuntime")
task cross_dist(dependsOn: "crossDist")
task list_dist(dependsOn: "listDist")
task distCompiler(type: Copy) {
dependsOn ':backend.native:jars' dependsOn ':backend.native:jars'
dependsOn ':tools:helpers:jar' dependsOn ':tools:helpers:jar'
@@ -221,46 +228,65 @@ task dist_compiler(type: Copy) {
} }
} }
task list_dist(type: Exec) { task listDist(type: Exec) {
commandLine 'find', 'dist' commandLine 'find', 'dist'
} }
task dist_runtime(type: Copy) { task distRuntime(type: Copy) {
dependsOn ':runtime:hostRuntime' dependsOn "${host}CrossDistRuntime"
dependsOn ':backend.native:hostStdlib' dependsOn('commonDistRuntime')
dependsOn ':backend.native:hostStart' }
task commonDistRuntime(type: Copy) {
destinationDir file('dist') destinationDir file('dist')
from(project(':runtime').file('build')) { // Target independant common part.
include('*/*.bc') from(project(':runtime').file("build/${host}Stdlib")) {
into('lib') include('**')
into('klib/stdlib')
} }
} }
task cross_dist_runtime(type: Copy) { task crossDistRuntime(type: Copy) {
dependsOn.addAll(targetList.collect { ":runtime:${it}Runtime" }) dependsOn.addAll(targetList.collect { "${it}CrossDistRuntime" })
dependsOn.addAll(targetList.collect { ":backend.native:${it}Stdlib" }) dependsOn('commonDistRuntime')
dependsOn.addAll(targetList.collect { ":backend.native:${it}Start" }) }
destinationDir file('dist') targetList.each { target ->
task("${target}CrossDistRuntime", type: Copy) {
dependsOn ":runtime:${target}Runtime"
dependsOn ":backend.native:${target}Stdlib"
dependsOn ":backend.native:${target}Start"
from(project(':runtime').file('build')) { destinationDir file('dist')
include('*/*.bc')
into('lib') from(project(':runtime').file("build/$target")) {
include("*.bc")
eachFile {println("eachfile= $it")}
into("klib/stdlib/$target/native")
}
from(project(':runtime').file("build/${target}Stdlib")) {
include('**')
into('klib/stdlib')
}
from(project(':runtime').file("build/${target}Start/$target/kotlin")) {
include("program.kt.bc")
rename('program.kt.bc', 'start.kt.bc')
into("klib/stdlib/$target/native")
}
} }
} }
task dist { task dist {
dependsOn 'dist_compiler', 'dist_runtime', ':tools:gradle-plugin:dist' dependsOn 'distCompiler', 'distRuntime', ':tools:gradle-plugin:dist'
} }
task cross_dist { task crossDist {
dependsOn 'cross_dist_runtime', 'dist' dependsOn 'crossDistRuntime', 'distCompiler'
} }
task bundle(type: Tar) { task bundle(type: Tar) {
dependsOn('cross_dist') dependsOn('crossDist')
baseName = "kotlin-native-${simpleOsName()}-${project.konanVersion}" baseName = "kotlin-native-${simpleOsName()}-${project.konanVersion}"
from("$project.rootDir/dist") { from("$project.rootDir/dist") {
include '**' include '**'
@@ -117,7 +117,7 @@ abstract class KonanTest extends JavaExec {
} }
String buildExePath() { String buildExePath() {
def exeName = project.file(source).name.replace(".kt", ".kt.exe") def exeName = project.file(source).name.replace(".kt", "")
return "$outputDirectory/$exeName" return "$outputDirectory/$exeName"
} }
@@ -206,9 +206,10 @@ fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = ob
@TaskAction @TaskAction
void executeTest() { void executeTest() {
createOutputDirectory() createOutputDirectory()
def exe = buildExePath() def program = buildExePath()
def exe = "${program}.kexe"
compileTest(buildCompileList(), exe) compileTest(buildCompileList(), program)
if (!run) { if (!run) {
println "to be executed manually: $exe" println "to be executed manually: $exe"
+1 -1
View File
@@ -27,7 +27,7 @@ targetList.each { targetName ->
} }
task build { task build {
dependsOn hostHash dependsOn "${host}Hash"
} }
task clean << { task clean << {
+12 -11
View File
@@ -178,16 +178,14 @@ class HelperNativeDep extends TgzNativeDep {
} }
} }
task hostLibffi(type: HelperNativeDep) {
baseName = "libffi-3.2.1-2-$host"
}
task llvm(type: HelperNativeDep) { task llvm(type: HelperNativeDep) {
baseName = "clang-llvm-$llvmVersion-$host" baseName = "clang-llvm-$llvmVersion-$host"
} }
if (isLinux()) { if (isLinux()) {
task linuxLibffi(type: HelperNativeDep) {
baseName = "libffi-3.2.1-2-$host"
}
task gccToolchain(type: HelperNativeDep) { task gccToolchain(type: HelperNativeDep) {
baseName = "target-gcc-toolchain-3-$host" baseName = "target-gcc-toolchain-3-$host"
} }
@@ -198,7 +196,10 @@ if (isLinux()) {
baseName = "libffi-3.2.1-2-raspberrypi" baseName = "libffi-3.2.1-2-raspberrypi"
} }
} else { } else {
task hostSysroot(type: HelperNativeDep) { task macbookLibffi(type: HelperNativeDep) {
baseName = "libffi-3.2.1-2-$host"
}
task macbookSysroot(type: HelperNativeDep) {
baseName = "target-sysroot-1-$host" baseName = "target-sysroot-1-$host"
} }
task iphoneSysroot(type: HelperNativeDep) { task iphoneSysroot(type: HelperNativeDep) {
@@ -207,11 +208,11 @@ if (isLinux()) {
task iphoneLibffi(type: HelperNativeDep) { task iphoneLibffi(type: HelperNativeDep) {
baseName = "libffi-3.2.1-2-darwin-ios" baseName = "libffi-3.2.1-2-darwin-ios"
} }
// TODO: re-enable when we known how to bring the simulator // TODO: re-enable when we known how to bring the simulator
// sysroot to dependencies. // sysroot to dependencies.
// task iphoneSimSysroot(type: TgzNativeDep) { // task iphoneSimSysroot(type: TgzNativeDep) {
// baseName = "target-sysroot-1-darwin-ios-sim" // baseName = "target-sysroot-1-darwin-ios-sim"
// } // }
} }
+2
View File
@@ -43,6 +43,8 @@ targetList.each { targetName ->
} }
} }
task hostRuntime(dependsOn: "${rootProject.ext.host}Runtime")
task clean << { task clean << {
delete buildDir delete buildDir
} }