Pass arguments to Kotlin/native run tasks
Asked Answered
W

3

7

I am developing a Kotlin/Native app and I would like to pass arguments to it via Gradle. There are tasks like runDebugExecutableNative. Is there some way to do something like:

./gradlew runDebugExecutableNative --args='myFirstArg mySecondArg'

Wilie answered 27/10, 2020 at 10:36 Comment(0)
B
3

The program entry point of any Kotlin application is the main function. This function accepts a variable number of String arguments which resemble the command line arguments. If you build your native app executable with such a function, then you can pass it arguments when you run the app. You can either run the built executable manually or from Gradle.

Sample Project

Here’s a small sample project (tested with Gradle 8.0.2, leaving out the Gradle Wrapper files for brevity):

.
├── build.gradle
├── settings.gradle
└── src
    └── commonMain
        └── kotlin
            └── main.kt

build.gradle

plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '1.8.20'
}

kotlin {
    // Instead of "linuxX64", use the target platform you’re interested in, see:
    // <https://kotlinlang.org/docs/multiplatform-dsl-reference.html#targets>
    linuxX64('myApp') {
        // See also:
        // <https://kotlinlang.org/docs/multiplatform-dsl-reference.html#binaries>
        binaries {
            executable {
                // The following adds support for passing in command line args
                // via the custom Gradle property "runArgs" when running the app
                // with Gradle. This is required as long as
                // <https://youtrack.jetbrains.com/issue/KT-55617> is not fixed.
                if (runTask != null) {
                    def args = providers.gradleProperty("runArgs")
                    // The "runTask" is an "Exec" task, so it has the
                    // "argumentProviders" list property to which we can add our
                    // own arg provider which is based on the project property
                    // value; see also:
                    // <https://docs.gradle.org/8.0.2/javadoc/org/gradle/api/tasks/AbstractExecTask.html#getArgumentProviders-->
                    runTask.argumentProviders.add({
                            args.orNull?.split(' ') as List ?: []
                        } as CommandLineArgumentProvider)
                }
            }
        }
    }
}

repositories {
    mavenCentral()
}

settings.gradle

rootProject.name = 'myApp'

src/commonMain/kotlin/main.kt

fun main(args: Array<String>) {
    println("Hello, ${args.asList()}!")
}

Running the Application

From Gradle

$ ./gradlew runReleaseExecutableMyApp -PrunArgs='my friend'

> Task :runReleaseExecutableMyApp
Hello, [my, friend]!

See also the Gradle docs on project properties for details on this -P… option.

Manually Building and Running

$ ./gradlew myAppBinaries
$ ./build/bin/myApp/releaseExecutable/myApp.kexe my friend
Hello, [my, friend]!
Babul answered 12/4, 2023 at 9:16 Comment(0)
S
2

Please try using binaries runTask parameter, described here. For the example you mention, it should probably go like this(based on the code from samples/gitchurn)

       binaries {
            executable {
                runTask?.args("myFirstArg mySecondArg")
            }
        }
Starlight answered 27/10, 2020 at 14:24 Comment(4)
This is not what I'm looking for, I would like to just set them from command line but this could be helpful if I would wrap it.Wilie
I think it's possible to expose properties like JavaExec does but it needs to be done with annotation.Wilie
Did you find a solution? Otherwise, I would create an issue.Outspoken
Support for --args with Native is tracked via: youtrack.jetbrains.com/issue/KT-55617Maximamaximal
A
2

Following on from the great answer from @Chriki, only a couple of tweaks are needed to make it work in a build.gradle.kts file. I'll use the current auto-generated file by IntelliJ IDEA as a base.

plugins {
    kotlin("multiplatform") version "1.8.20"
}

kotlin {
    val hostOs = System.getProperty("os.name")
    val isMacOs = hostOs == "Mac OS X"
    val isLinux = hostOs == "Linux"
    val isMingwX64 = hostOs.startsWith("Windows")
    val nativeTarget = when {
        isMacOs -> macosArm64("native") // Apple silicon. Use `macosX64("native")` for Intel
        isLinux -> linuxX64("native")
        isMingwX64 -> mingwX64("native")
        else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native.")
    }

    nativeTarget.apply {
        binaries {
            executable {
                entryPoint = "main"
                runTask?.run {
                    val args = providers.gradleProperty("runArgs")
                    argumentProviders.add(CommandLineArgumentProvider {
                        args.orNull?.split(' ') ?: emptyList()
                    })
                }
            }
        }
    }

    sourceSets {...}
}

repositories {
    mavenCentral()
}
Ardor answered 17/4, 2023 at 6:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.