Last active
July 30, 2024 22:06
-
-
Save aSemy/0ec58b89f79702ea9822f198ccef0dc3 to your computer and use it in GitHub Desktop.
Revisions
-
aSemy revised this gist
Aug 18, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ Kotlin/Native has a utility, [`run_konan`](https://github.com/JetBrains/kotlin/blob/v1.9.0/kotlin-native/HACKING.md#running-clang-the-same-way-kotlinnative-compiler-does), that can be used to compile C/C++ code. I've written two Gradle tasks, `RunKonanClangTask` and `RunKonanClangTask`, that can be used to compile [JoltC](https://github.com/michal-z/zig-gamedev/blob/c517effe8c476c5c75ccbf735440fdabc35e42e5/libs/zphysics/libs/README.md). A lot of credit goes to https://github.com/michal-z for writing C wrappers for [Jolt](https://github.com/jrouwe/JoltPhysics)! -
aSemy revised this gist
Aug 18, 2023 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -34,9 +34,10 @@ This Gist is very scrappy, and is missing a lot of information. ### Example usage ```kts // build.gradle.kts import org.jetbrains.kotlin.konan.util.DependencyDirectories.localKonanDir plugins { kotlin("multiplatform") } -
aSemy revised this gist
Aug 18, 2023 . 1 changed file with 5 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,7 @@ This Gist is very scrappy, and is missing a lot of information. * Kotlin 1.9.0 * I've only tested it on Windows. * The Kotlin target must be set manually - is it possible to make this automatic? * While the `.konan` dir can be retrieved from a KGP util function, the path to `konan_run` file must be set manually (e.g. `kotlin-native-prebuilt-windows-x86_64-1.9.0`) - is it possible to make this automatic? * I had to remove `#define private public` and amend the Jolt source code to make everything public, otherwise compilation failed in `sstreams` * I moved `JoltPhysicsC.h` into a `JoltC/` dir, and updated `#include "JoltPhysicsC.h"` to `#include <JoltC/JoltPhysicsC.h>` @@ -34,6 +34,8 @@ This Gist is very scrappy, and is missing a lot of information. ### Example usage ```kts import org.jetbrains.kotlin.konan.util.DependencyDirectories.localKonanDir // build.gradle.kts plugins { kotlin("multiplatform") @@ -84,15 +86,15 @@ val konanClangCompile by tasks.registering(RunKonanClangTask::class) { "-D" + "JPH_ENABLE_ASSERTS", ) runKonan.set(localKonanDir.resolve("kotlin-native-prebuilt-windows-x86_64-1.9.0/bin/run_konan.bat")) } val konanLink by tasks.registering(RunKonanLinkTask::class) { group = project.name libName.set("zphysics") objectFiles.from(konanClangCompile) runKonan.set(localKonanDir.resolve("kotlin-native-prebuilt-windows-x86_64-1.9.0/bin/run_konan.bat")) } ``` -
aSemy revised this gist
Aug 18, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -263,7 +263,7 @@ abstract class RunKonanLinkTask @Inject constructor( @get:Internal val workingDir: DirectoryProperty = objects.directoryProperty().convention( // workaround for https://github.com/gradle/gradle/issues/23708 objects.directoryProperty().fileValue(temporaryDir) ) -
aSemy revised this gist
Aug 18, 2023 . 1 changed file with 53 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,13 +1,64 @@ Kotlin/Native has a utility, `run_konan`, that can be used to compile C/C++ code. I've written two Gradle tasks, `RunKonanClangTask` and `RunKonanClangTask`, that can be used to compile [JoltC](https://github.com/michal-z/zig-gamedev/blob/c517effe8c476c5c75ccbf735440fdabc35e42e5/libs/zphysics/libs/README.md). A lot of credit goes to https://github.com/michal-z for writing C wrappers for [Jolt](https://github.com/jrouwe/JoltPhysics)! This Gist is very scrappy, and is missing a lot of information. * Kotlin 1.9.0 * I've only tested it on Windows. * The Kotlin target must be set manually - is it possible to make this automatic? * The `konan_run` file must be set manually - is it possible to make this automatic? * I had to remove `#define private public` and amend the Jolt source code to make everything public, otherwise compilation failed in `sstreams` * I moved `JoltPhysicsC.h` into a `JoltC/` dir, and updated `#include "JoltPhysicsC.h"` to `#include <JoltC/JoltPhysicsC.h>` ### Project layout ``` ├── buildSrc/ │ ├── src/main/kotlin/ │ │ ├── RunKonanClangTask.kt │ │ ├── RunKonanLinkTask.kt │ │ └── utils.kt │ ├── build.gradle.kts │ └── settings.gradle.kts ├── src/main/cpp/ │ ├── Jolt/ (Jolt C++ sources) │ └── JoltC/ (from zphysics) ├── zphysics.def ├── build.gradle.kts └── settings.gradle.kts ``` <!-- https://tree.nathanfriend.io/?s=(%27options!(%27fancy7~fullPath!false~trailFgSlash7~rootDot7)~4!(%274!%278SG*3kotlI5ClangH5LFkH*0utilsB*8-*923cpp*E6E%20C%2B%2B%204s%7D*EC6from%20A%7D2A.def28-29%27)~version!%271%27)*20-.gradleBs0%20%202%5Cn3sGmaI4source5*0RunKonan6%2F%20%7B7!true8build9settFgs-AzphysicsB.ktEJoltFinGrc%2FHTaskBIF%2F%01IHGFEBA987654320-* --> ### Example usage ```kts // build.gradle.kts plugins { kotlin("multiplatform") } description = "Kotlin/Native C-interop bindings for Jolt Physics, via zig-gamedev zphysics" kotlin { targets.withType<KotlinNativeTarget>().configureEach { compilations.getByName("main") { cinterops { register("zphysics") { defFileProperty.set(file("zphysics.def")) } } } binaries { staticLib() } } } //region lots of utilities for downloading JoltC // ... //endregion val konanClangCompile by tasks.registering(RunKonanClangTask::class) { group = project.name -
aSemy revised this gist
Aug 18, 2023 . 1 changed file with 51 additions and 39 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,52 @@ Kotlin/Native has a utility, `run_konan`, that can be used to compile C/C++ code. I've written two Gradle tasks, `RunKonanClangTask` and `RunKonanClangTask`, that can be used to compile Jolt. This Gist is very scrappy, and is missing a lot of information. I've only tested it on Windows. ### Example usage ```kts // build.gradle.kts val konanClangCompile by tasks.registering(RunKonanClangTask::class) { group = project.name kotlinTarget.set(KonanTarget.MINGW_X64) sourceFiles.from( layout.projectDirectory .dir("src/main/cpp/") .asFileTree .matching { include("**/*.cpp") exclude("**/*_Tests*") } ) includeDirs.from(layout.projectDirectory.dir("src/main/cppHeaders/")) arguments.addAll( "-std=c++17", "-fno-sanitize=undefined", "-D" + "JPH_CROSS_PLATFORM_DETERMINISTIC", "-D" + "JPH_ENABLE_ASSERTS", ) runKonan.set(file("C:/Users/Me/.konan/kotlin-native-prebuilt-windows-x86_64-1.9.0/bin/run_konan.bat")) } val konanLink by tasks.registering(RunKonanLinkTask::class) { group = project.name libName.set("zphysics") objectFiles.from(konanClangCompile) runKonan.set(file("C:/Users/Me/.konan/kotlin-native-prebuilt-windows-x86_64-1.9.0/bin/run_konan.bat")) } ``` ### RunKonanClangTask ```kotlin import execCapture import org.gradle.api.DefaultTask @@ -114,6 +163,8 @@ abstract class RunKonanClangTask @Inject constructor( } ``` ### RunKonanLinkTask ```kotlin import execCapture import org.gradle.api.DefaultTask @@ -204,45 +255,6 @@ abstract class RunKonanLinkTask @Inject constructor( } ``` ### Utils ```kotlin -
aSemy created this gist
Aug 18, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,282 @@ ```kotlin import execCapture import org.gradle.api.DefaultTask import org.gradle.api.file.* import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.api.tasks.PathSensitivity.NAME_ONLY import org.gradle.api.tasks.PathSensitivity.RELATIVE import org.gradle.process.ExecOperations import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs import javax.inject.Inject /** * Compile C/C++ source files using the * [`run_konan`](https://github.com/JetBrains/kotlin/blob/v1.9.0/kotlin-native/HACKING.md#running-clang-the-same-way-kotlinnative-compiler-does) * utility. */ abstract class RunKonanClangTask @Inject constructor( private val exec: ExecOperations, private val fs: FileSystemOperations, private val objects: ObjectFactory, ) : DefaultTask() { /** Destination of compiled `.o` object files */ @get:OutputDirectory val outputDir: Provider<Directory> get() = objects.directoryProperty().fileValue(temporaryDir.resolve("output")) /** C and C++ source files to compile to object files */ @get:InputFiles @get:PathSensitive(RELATIVE) abstract val sourceFiles: ConfigurableFileCollection /** Directories that include `.h` header files */ @get:InputFiles @get:PathSensitive(RELATIVE) abstract val includeDirs: ConfigurableFileCollection /** Path to the (platform specific) `run_konan` utility */ @get:InputFile @get:PathSensitive(NAME_ONLY) abstract val runKonan: RegularFileProperty /** Kotlin target platform, e.g. `mingw_x64` */ @get:Input abstract val kotlinTarget: Property<KonanTarget> @get:Input @get:Optional abstract val arguments: ListProperty<String> @get:Internal abstract val workingDir: DirectoryProperty @TaskAction fun compile() { val workingDir = workingDir.asFile.getOrElse(temporaryDir) val kotlinTarget = kotlinTarget.get() // prepare output dirs val sourcesDir = workingDir.resolve("sources") val headersDir = workingDir.resolve("headers") val compileDir = workingDir.resolve("compile") fs.sync { from(sourceFiles) into(sourcesDir) } fs.sync { from(includeDirs) into(headersDir) } fs.delete { delete(compileDir) } compileDir.mkdirs() // prepare args file val sourceFilePaths = sourcesDir.walk() .filter { it.extension in listOf("cpp", "c") } .joinToString("\n") { it.invariantSeparatorsPath } compileDir.resolve("args").writeText(/*language=text*/ """ |--include-directory ${headersDir.invariantSeparatorsPath} |${arguments.getOrElse(emptyList()).joinToString("\n")} |-c $sourceFilePaths """.trimMargin() ) // compile files val compileResult = exec.execCapture { executable(runKonan.asFile.get()) args(parseSpaceSeparatedArgs( "clang clang $kotlinTarget @args" )) workingDir(compileDir) } // verify output val outputLog = workingDir.resolve("compileResult.log").apply { writeText(compileResult.output) } logger.lifecycle("compilation output log: file://${outputLog.invariantSeparatorsPath}") compileResult.assertNormalExitValue() // move compiled files to output directory fs.sync { from(compileDir) { include("**/*.o") } into(outputDir) } } } ``` ```kotlin import execCapture import org.gradle.api.DefaultTask import org.gradle.api.file.* import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.process.ExecOperations import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs import javax.inject.Inject /** * Link compiled C/C++ source files using the * [`run_konan`](https://github.com/JetBrains/kotlin/blob/v1.9.0/kotlin-native/HACKING.md#running-clang-the-same-way-kotlinnative-compiler-does) * utility. */ abstract class RunKonanLinkTask @Inject constructor( private val exec: ExecOperations, private val fs: FileSystemOperations, objects: ObjectFactory, ) : DefaultTask() { /** The linked file */ @get:OutputFile val compiledLib: Provider<RegularFile> get() = workingDir.file(libFileName) /** All `.o` object files that will be linked */ @get:InputFiles @get:PathSensitive(PathSensitivity.NAME_ONLY) abstract val objectFiles: ConfigurableFileCollection /** Path to the (platform specific) `run_konan` utility */ @get:InputFile @get:PathSensitive(PathSensitivity.NAME_ONLY) abstract val runKonan: RegularFileProperty @get:Input abstract val libName: Property<String> private val libFileName: Provider<String> get() = libName.map { "lib${it}.a" } @get:Internal val workingDir: DirectoryProperty = objects.directoryProperty().convention( // workaround for objects.directoryProperty().fileValue(temporaryDir) ) @TaskAction fun compile() { val workingDir = workingDir.asFile.get() val libFileName = libFileName.get() // prepare output dir fs.delete { delete(workingDir) } workingDir.mkdirs() // prepare args file val sourceFilePaths = objectFiles .asFileTree .matching { include("**/*.o") } .joinToString("\n") { it.invariantSeparatorsPath } workingDir.resolve("args").writeText(/*language=text*/ """ |-rv |$libFileName |$sourceFilePaths """.trimMargin() ) // compile files val linkResult = exec.execCapture { executable(runKonan.asFile.get()) args(parseSpaceSeparatedArgs( "llvm llvm-ar @args" )) workingDir(workingDir) } val outputLog = workingDir.resolve("linkResult.log").apply { writeText(linkResult.output) } logger.lifecycle("compilation output log: file://${outputLog.invariantSeparatorsPath}") linkResult.assertNormalExitValue() } } ``` ```kts // build.gradle.kts val konanClangCompile by tasks.registering(RunKonanClangTask::class) { group = project.name kotlinTarget.set(KonanTarget.MINGW_X64) sourceFiles.from( layout.projectDirectory .dir("src/main/cpp/") .asFileTree .matching { include("**/*.cpp") exclude("**/*_Tests*") } ) includeDirs.from(layout.projectDirectory.dir("src/main/cppHeaders/")) arguments.addAll( "-std=c++17", "-fno-sanitize=undefined", "-D" + "JPH_CROSS_PLATFORM_DETERMINISTIC", "-D" + "JPH_ENABLE_ASSERTS", ) runKonan.set(file("C:/Users/Me/.konan/kotlin-native-prebuilt-windows-x86_64-1.9.0/bin/run_konan.bat")) } val konanLink by tasks.registering(RunKonanLinkTask::class) { group = project.name libName.set("zphysics") objectFiles.from(konanClangCompile) runKonan.set(file("C:/Users/Me/.konan/kotlin-native-prebuilt-windows-x86_64-1.9.0/bin/run_konan.bat")) } ``` ### Utils ```kotlin import org.gradle.process.ExecOperations import org.gradle.process.ExecResult import org.gradle.process.ExecSpec import java.io.ByteArrayOutputStream fun ExecOperations.execCapture( configure: ExecSpec.() -> Unit, ): ExecCaptureResult { val (result, output) = ByteArrayOutputStream().use { os -> exec { isIgnoreExitValue = true standardOutput = os errorOutput = os configure() } to os.toString() } return if (result.exitValue != 0) { ExecCaptureResult.Error(output, result) } else { ExecCaptureResult.Success(output, result) } } sealed class ExecCaptureResult( val output: String, private val result: ExecResult, ) : ExecResult by result { class Success(output: String, result: ExecResult) : ExecCaptureResult(output, result) class Error(output: String, result: ExecResult) : ExecCaptureResult(output, result) } ```