Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions kotlin-native/HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,47 @@ will print and run the following command:
```

The similar helper is available for LLVM tools, `$dist/bin/run_konan llvm $tool $arguments`.

### Convenient cross-compilation wrappers

For easier cross-compilation of C/C++ code, Kotlin/Native provides wrapper scripts that follow
the LLVM target triple naming convention. These scripts are auto-generated from `konan/konan.properties`
during the distribution build (via the `generateCrossCompilationWrappers` Gradle task).

The script names use the full LLVM target triple from `konan.properties`, for example:

| Target | C Compiler | C++ Compiler |
|--------|------------|--------------|
| `linux_x64` | `x86_64-unknown-linux-gnu-clang` | `x86_64-unknown-linux-gnu-clang++` |
| `linux_arm64` | `aarch64-unknown-linux-gnu-clang` | `aarch64-unknown-linux-gnu-clang++` |
| `linux_arm32_hfp` | `arm-unknown-linux-gnueabihf-clang` | `arm-unknown-linux-gnueabihf-clang++` |
| `mingw_x64` | `x86_64-pc-windows-gnu-clang` | `x86_64-pc-windows-gnu-clang++` |
| `android_arm64` | `aarch64-unknown-linux-android-clang` | `aarch64-unknown-linux-android-clang++` |
| `android_arm32` | `arm-unknown-linux-androideabi-clang` | `arm-unknown-linux-androideabi-clang++` |
| `android_x64` | `x86_64-unknown-linux-android-clang` | `x86_64-unknown-linux-android-clang++` |
| `android_x86` | `i686-unknown-linux-android-clang` | `i686-unknown-linux-android-clang++` |
| `macos_x64` | `x86_64-apple-macos-clang` | `x86_64-apple-macos-clang++` |
| `macos_arm64` | `arm64-apple-macos-clang` | `arm64-apple-macos-clang++` |
| `ios_arm64` | `arm64-apple-ios-clang` | `arm64-apple-ios-clang++` |
| ... | ... | ... |

Scripts are generated for all targets defined in `konan.properties`, including Apple targets.
Users run only the scripts that work on their host platform.

Usage example:
```bash
# Compile a C file for Linux x64
$dist/bin/x86_64-unknown-linux-gnu-clang -c myfile.c -o myfile.o

# Compile a C++ file for Windows (MinGW)
$dist/bin/x86_64-pc-windows-gnu-clang++ -c myfile.cpp -o myfile.o

# Compile a C file for Linux ARM64
$dist/bin/aarch64-unknown-linux-gnu-clang -c myfile.c -o myfile.o

# Compile a C++ file for Android ARM64
$dist/bin/aarch64-unknown-linux-android-clang++ -c myfile.cpp -o myfile.o
```

These wrappers automatically use Kotlin/Native's sysroot and the correct compiler flags,
making it easier to build static libraries that are compatible with Kotlin/Native linking.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/

package org.jetbrains.kotlin.nativeDistribution

import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.util.Properties

/**
* Generates cross-compilation wrapper scripts (clang/clang++) for all targets
* defined in konan.properties.
*
* These scripts wrap run_konan to invoke clang with the appropriate sysroot
* for each target, enabling cross-compilation of C libraries that will be
* linked with Kotlin/Native.
*/
abstract class GenerateCrossCompilationWrappers : DefaultTask() {

@get:InputFile
abstract val konanProperties: RegularFileProperty

@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty

@TaskAction
fun generate() {
val props = Properties().apply {
konanProperties.get().asFile.inputStream().use { load(it) }
}

val outputDir = outputDirectory.get().asFile
outputDir.mkdirs()

// Find all targetTriple.* entries
props.stringPropertyNames()
.filter { it.startsWith("targetTriple.") }
.forEach { key ->
val target = key.removePrefix("targetTriple.")
val triple = props.getProperty(key).trim()

generateBashScript(outputDir, triple, "clang", target)
generateBashScript(outputDir, triple, "clang++", target)
generateBatchScript(outputDir, triple, "clang", target)
generateBatchScript(outputDir, triple, "clang++", target)
}
}

private fun generateBashScript(outputDir: File, triple: String, compiler: String, target: String) {
val file = File(outputDir, "$triple-$compiler")
file.writeText(bashTemplate(compiler, target))
file.setExecutable(true)
}

private fun generateBatchScript(outputDir: File, triple: String, compiler: String, target: String) {
val file = File(outputDir, "$triple-$compiler.bat")
file.writeText(batchTemplate(compiler, target))
}

private fun bashTemplate(compiler: String, target: String) = """
|#!/usr/bin/env bash
|
|# Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
|# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|# Wrapper for running $compiler with Kotlin/Native's $target sysroot.
|
|DIR="${'$'}{BASH_SOURCE[0]%/*}"
|: ${'$'}{DIR:="."}
|
|"${'$'}{DIR}"/run_konan clang $compiler $target "${'$'}@"
""".trimMargin() + "\n"

private fun batchTemplate(compiler: String, target: String) = """
|@echo off
|
|rem Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
|rem Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|rem Wrapper for running $compiler with Kotlin/Native's $target sysroot.
|
|call %~dps0run_konan.bat clang $compiler $target %*
""".trimMargin() + "\n"
}
23 changes: 23 additions & 0 deletions kotlin-native/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.nativeDistribution.LLVMDistributionKind
import org.jetbrains.kotlin.nativeDistribution.LLVMDistributionSourceKt
import org.jetbrains.kotlin.nativeDistribution.NativeDistributionKt
import org.jetbrains.kotlin.nativeDistribution.NativeProtoDistributionKt
import org.jetbrains.kotlin.nativeDistribution.GenerateCrossCompilationWrappers
import org.jetbrains.kotlin.nativeDistribution.PrepareDistributionFingerprint
import org.jetbrains.kotlin.nativeDistribution.PrepareKonanProperties
import org.jetbrains.kotlin.xcode.XcodeOverridePlugin
Expand Down Expand Up @@ -268,8 +269,30 @@ tasks.register("distTools", Sync) {
into(nativeDistribution.map { it.tools })
}

tasks.register("generateCrossCompilationWrappers", GenerateCrossCompilationWrappers) {
konanProperties = file('konan/konan.properties')
outputDirectory = layout.buildDirectory.dir("generated-cmd")
}

tasks.register("distBin", Sync) {
dependsOn("generateCrossCompilationWrappers")

// Core tools from cmd/ (excluding manual wrapper scripts that are now auto-generated)
from(file('cmd')) {
exclude('*-clang')
exclude('*-clang++')
exclude('*-clang.bat')
exclude('*-clang++.bat')
filePermissions {
unix("0755")
}
if (!PlatformInfo.isWindows()) {
exclude('**/*.bat')
}
}

// Generated cross-compilation wrappers
from(tasks.named("generateCrossCompilationWrappers").map { it.outputDirectory }) {
filePermissions {
unix("0755")
}
Expand Down