diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index f9f1b8eb2a6..9b55e94d0a1 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -30,7 +30,6 @@ fun main(args: Array) { "arch" to (System.getenv("TARGET_ARCH") ?: "x86-64"), "os" to (System.getenv("TARGET_OS") ?: host) ) - processLib(konanHome, substitutions, parseArgs(args)) } @@ -256,11 +255,17 @@ private fun loadProperties(file: File?, substitutions: Map): Pro return result } -private fun parseDefFile(file: File?, substitutions: Map): Pair> { +private fun Properties.storeProperties(file: File) { + file.outputStream().use { + this.store(it, null) + } +} + +private fun parseDefFile(file: File?, substitutions: Map): Triple> { val properties = Properties() if (file == null) { - return properties to emptyList() + return Triple(properties, Properties(), emptyList()) } val lines = file.readLines() @@ -281,11 +286,18 @@ private fun parseDefFile(file: File?, substitutions: Map): Pair< 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 properties to headerLines + return Triple(properties, manifestAddendProperties, headerLines) } +private fun Properties.duplicate() = Properties().apply{ putAll(this@duplicate) } + private fun usage() { println(""" Run interop tool with -def .def @@ -316,13 +328,15 @@ private fun processLib(konanHome: String, val flavor = KotlinPlatform.values().single { it.name.equals(flavorName, ignoreCase = true) } val target = args["-target"]?.single()?.targetSuffix() ?: defaultTarget val defFile = args["-def"]?.single()?.let { File(it) } + val manifestAddend = args["-manifest"]?.single()?.let { File(it) } if (defFile == null && args["-pkg"] == null) { usage() return } - val (config, defHeaderLines) = parseDefFile(defFile, substitutions) + val (config, manifestAddendProperties, defHeaderLines) + = parseDefFile(defFile, substitutions) val konanFileName = args["-properties"]?.single() ?: "${konanHome}/konan/konan.properties" @@ -409,6 +423,9 @@ private fun processLib(konanHome: String, } } + manifestAddend?.parentFile?.mkdirs() + manifestAddend ?.let { manifestAddendProperties.storeProperties(it) } + val workDir = defFile?.absoluteFile?.parentFile ?: File(userDir) if (flavor == KotlinPlatform.JVM) { diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 7edd318dd1c..f3a057e4f7a 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -124,6 +124,7 @@ class K2Native : CLICompiler() { put(ABI_VERSION, 1) arguments.mainPackage ?.let{ put(ENTRY, it) } + arguments.manifestFile ?.let{ put(MANIFEST_FILE, it) } arguments.runtimeFile ?.let{ put(RUNTIME_FILE, it) } arguments.propertyFile ?.let{ put(PROPERTY_FILE, it) } diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index 34185131d47..e8a9438718a 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -36,6 +36,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @field:Argument(value = "-list_targets", description = "List available hardware targets") @JvmField var listTargets: Boolean = false + @field:Argument(value = "-manifest", valueDescription = "", description = "Provide a maniferst addend file") + @JvmField var manifestFile: String? = null + @field:Argument(value = "-nativelibrary", shortName = "-nl", valueDescription = "", description = "Include the native library") @JvmField var nativeLibraries: Array? = null diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index e45fc2b349d..8be963dd725 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -43,6 +43,8 @@ class KonanConfigKeys { = CompilerConfigurationKey.create("list backend phases") val LIST_TARGETS: CompilerConfigurationKey = CompilerConfigurationKey.create("list available targets") + val MANIFEST_FILE: CompilerConfigurationKey + = CompilerConfigurationKey.create("provide manifest addend file") val META_INFO: CompilerConfigurationKey> = CompilerConfigurationKey.create("generate metadata") val MODULE_KIND: CompilerConfigurationKey diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt index cf3ccc15c0e..e05284a8714 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt @@ -248,13 +248,14 @@ internal class LinkStage(val context: Context) { val entryPointSelector: List get() = if (nomain) emptyList() else platform.entrySelector - fun link(objectFiles: List): ExecutableFile { + fun link(objectFiles: List, libraryProvidedLinkerFlags: List): ExecutableFile { val executable = context.config.outputFile val linkCommand = platform.linkCommand(objectFiles, executable, optimize, config.getBoolean(KonanConfigKeys.DEBUG)) + distribution.libffi + asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) + entryPointSelector + - platform.linkCommandSuffix() + platform.linkCommandSuffix() + + libraryProvidedLinkerFlags runTool(*linkCommand.toTypedArray()) if (platform is MacOSBasedPlatform && context.shouldContainDebugInfo()) { @@ -312,6 +313,9 @@ internal class LinkStage(val context: Context) { val bitcodeFiles = listOf(emitted) + libraries.map{it -> it.bitcodePaths}.flatten() + val libraryProvidedLinkerFlags = + libraries.map{it -> it.linkerOpts}.flatten() + var objectFiles: List = listOf() val phaser = PhaseManager(context) @@ -319,7 +323,7 @@ internal class LinkStage(val context: Context) { objectFiles = listOf( llvmLto(bitcodeFiles ) ) } phaser.phase(KonanPhase.LINKER) { - link(objectFiles) + link(objectFiles, libraryProvidedLinkerFlags) } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryReader.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryReader.kt index 471bebe3c47..e4121336628 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryReader.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryReader.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor interface KonanLibraryReader { val libraryName: String val bitcodePaths: List + val linkerOpts: List fun moduleDescriptor(specifics: LanguageVersionSettings): ModuleDescriptor } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt index 4efc15e0ef0..93e4b950619 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt @@ -22,6 +22,7 @@ interface KonanLibraryWriter { fun addLinkData(linkData: LinkData) fun addNativeBitcode(library: String) fun addKotlinBitcode(llvmModule: LLVMModuleRef) + fun addManifestAddend(path: String) val mainBitcodeFileName: String fun commit() } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryReaderImpl.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryReaderImpl.kt index 9dbef53e111..c36a71ad548 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryReaderImpl.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryReaderImpl.kt @@ -89,5 +89,7 @@ class LibraryReaderImpl(override val libDir: File, currentAbiVersion: Int, override val bitcodePaths: List get() = (kotlinDir.listFiles + nativeDir.listFiles).map{it.absolutePath} + override val linkerOpts: List + get() = manifestProperties.propertyList("linkerOpts", target!!.targetSuffix) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt index 77e18933dee..882e9cef921 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt @@ -71,6 +71,12 @@ class LibraryWriterImpl(override val libDir: File, currentAbiVersion: Int, File(library).copyTo(File(nativeDir, basename)) } + override fun addManifestAddend(path: String) { + val properties = File(path).loadProperties() + manifestProperties.putAll(properties) + println("manifest addend: ${properties.stringPropertyNames().joinToString(" ")}") + } + override fun commit() { manifestProperties.saveToFile(manifestFile) if (!nopack) { @@ -80,7 +86,15 @@ class LibraryWriterImpl(override val libDir: File, currentAbiVersion: Int, } } -internal fun buildLibrary(natives: List, linkData: LinkData, abiVersion: Int, target: KonanTarget, output: String, llvmModule: LLVMModuleRef, nopack: Boolean): KonanLibraryWriter { +internal fun buildLibrary( + natives: List, + linkData: LinkData, + abiVersion: Int, + target: KonanTarget, + output: String, + llvmModule: LLVMModuleRef, + nopack: Boolean, + manifest: String?): KonanLibraryWriter { val library = LibraryWriterImpl(output, abiVersion, target, nopack) @@ -89,6 +103,7 @@ internal fun buildLibrary(natives: List, linkData: LinkData, abiVersion: natives.forEach { library.addNativeBitcode(it) } + manifest ?.let { library.addManifestAddend(it) } library.commit() return library diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index d899f7eb27f..0c9febd8b7d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -110,6 +110,7 @@ internal fun produceOutput(context: Context) { val abiVersion = context.config.currentAbiVersion val target = context.config.targetManager.target val nopack = config.getBoolean(KonanConfigKeys.NOPACK) + val manifest = config.get(KonanConfigKeys.MANIFEST_FILE) val library = buildLibrary( context.config.nativeLibraries, @@ -118,7 +119,8 @@ internal fun produceOutput(context: Context) { target, libraryName, llvmModule, - nopack) + nopack, + manifest) context.library = library context.bitcodeFileName = library.mainBitcodeFileName diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt index 671e080f166..dce8a40b978 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt @@ -131,6 +131,8 @@ open class KonanCompileTask: KonanTargetableTask() { internal set @Optional @Input var apiVersion : String? = null internal set + @Input var manifest : String? = null + internal set @Input var dumpParameters: Boolean = false // TODO: Is there a better way to rerun tasks when the compiler version changes? @@ -150,6 +152,7 @@ open class KonanCompileTask: KonanTargetableTask() { addArgIfNotNull("-target", target) addArgIfNotNull("-language-version", languageVersion) addArgIfNotNull("-api-version", apiVersion) + addArgIfNotNull("-manifest", manifest) addKey("-g", enableDebug) addKey("-nostdlib", noStdLib) @@ -232,6 +235,7 @@ open class KonanCompileConfig( builtBy(generateStubsTask) include("**/*.bc") }) + generateStubsTask.manifest ?.let {manifest(it)} } fun useInterops(interops: ArrayList) { @@ -287,6 +291,10 @@ open class KonanCompileConfig( linkerOpts.addAll(args) } + fun manifest(arg: String) = with(compilationTask) { + manifest = arg + } + fun target(tgt: String) = with(compilationTask) { target = tgt } diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropTask.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropTask.kt index 6ef8d98ead4..c2d153387ec 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropTask.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropTask.kt @@ -82,6 +82,9 @@ open class KonanInteropTask: KonanTargetableTask() { @Optional @Input var linker: String? = null internal set + @Optional @Input var manifest: String? = null + internal set + @Input var dumpParameters: Boolean = false @Input val compilerOpts = mutableListOf() @Input val linkerOpts = mutableListOf() @@ -118,6 +121,7 @@ open class KonanInteropTask: KonanTargetableTask() { addArg("-generated", stubsDir.canonicalPath) addArg("-natives", libsDir.canonicalPath) + manifest ?.let {addArg("-manifest", it)} addArgIfNotNull("-target", target) val defFilePath = defFile?.canonicalPath ?: @@ -156,14 +160,16 @@ open class KonanInteropConfig( val generateStubsTask: KonanInteropTask = project.tasks.create( "gen${name.capitalize()}InteropStubs", KonanInteropTask::class.java - ) { it.init(name) } - - // Config and task to compile *.kt stubs in a *.bc library + ) { it.init(name) + it.manifest = "${it.stubsDir.path}/manifest.properties" + } + // Config and task to compile *.kt stubs into a library internal val compileStubsConfig = KonanCompileConfig("${name}InteropStubs", project, "compile").apply { compilationTask.dependsOn(generateStubsTask) outputDir("${project.konanInteropCompiledStubsDir}/$name") produce("library") inputFiles(project.fileTree(generateStubsTask.stubsDir).apply { builtBy(generateStubsTask) }) + manifest("${generateStubsTask.stubsDir.path}/manifest.properties") } val compileStubsTask = compileStubsConfig.compilationTask diff --git a/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt b/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt index e3eafbd0953..987ce722c26 100644 --- a/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt +++ b/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt @@ -19,11 +19,13 @@ fun invokeCinterop(args: Array) { val generatedDir = File(buildDir, "kotlin") val nativesDir = File(buildDir, "natives") val cstubsName ="cstubs" + val manifest = File(buildDir, "manifest.properties") val additionalArgs = listOf( "-generated", generatedDir.path, "-natives", nativesDir.path, "-cstubsname", cstubsName, + "-manifest", manifest.path, "-flavor", "native") val cinteropArgs = (additionalArgs + args.toList()).toTypedArray() @@ -34,7 +36,9 @@ fun invokeCinterop(args: Array) { "-produce", "library", "-nativelibrary", File(nativesDir, "$cstubsName.bc").path, "-o", outputFileName, - "-target", target) + "-target", target, + "-manifest", manifest.path + ) konancMain(konancArgs) }