Help getting started with a Kotlin native port #17

Closed
opened 2021-01-25 01:48:08 -06:00 by napperley · 15 comments
napperley commented 2021-01-25 01:48:08 -06:00 (Migrated from github.com)

With the SDK there is no CMake target for generating static C libraries. For some programming languages like Kotlin it needs the header files, and the dynamic/static library files in order to do interop with the C libraries. Rust also has similar requirements.

The maintainers need to decide if the SDK will be accessible to programming languages other than C/C++ like Kotlin, and Rust for example.

With the SDK there is no CMake target for generating static C libraries. For some programming languages like Kotlin it needs the header files, and the dynamic/static library files in order to do [interop with the C libraries](https://kotlinlang.org/docs/curl.html). Rust also has [similar requirements](https://rust-embedded.github.io/book/interoperability/c-with-rust.html). The maintainers need to decide if the SDK will be **accessible** to programming languages other than C/C++ like Kotlin, and Rust for example.
msink commented 2021-01-25 06:27:18 -06:00 (Migrated from github.com)

Well, usually it works just opposite - Kotlin (or Rust, or whatever) creates static library (*.a) file, and that file is linked by SDK to create flashable image file.

Well, usually it works just opposite - Kotlin (or Rust, or whatever) creates static library (*.a) file, and that file is linked by SDK to create flashable image file.
JamesH65 commented 2021-01-25 06:40:05 -06:00 (Migrated from github.com)

Well, usually it works just opposite - Kotlin (or Rust, or whatever) creates static library (*.a) file, and that file is linked by SDK to create flashable image file.

That is certainly the preferred approach. Just having a static library of the SDK linked in to your "kotlin" is unlikely to work.

> Well, usually it works just opposite - Kotlin (or Rust, or whatever) creates static library (*.a) file, and that file is linked by SDK to create flashable image file. That is certainly the preferred approach. Just having a static library of the SDK linked in to your "kotlin" is unlikely to work.
kilograham commented 2021-01-25 11:07:11 -06:00 (Migrated from github.com)

@napperley would be really good to know your exact use case (in terms of how much runtime scaffolding you need under Kotlin native)

I have made this standalone example in branch of pico-playground

https://github.com/raspberrypi/pico-playground/tree/wip_make_helper/standalone/static_sdk

which isn't the solution, but might help you if you really need it

@napperley would be really good to know your exact use case (in terms of how much runtime scaffolding you need under Kotlin native) I have made this standalone example in branch of pico-playground https://github.com/raspberrypi/pico-playground/tree/wip_make_helper/standalone/static_sdk which isn't the solution, but might help you _if you really need it_
napperley commented 2021-01-25 14:45:28 -06:00 (Migrated from github.com)

Well, usually it works just opposite - Kotlin (or Rust, or whatever) creates static library (*.a) file, and that file is linked by SDK to create flashable image file.

That is certainly the preferred approach. Just having a static library of the SDK linked in to your "kotlin" is unlikely to work.

Wouldn't the elf2uf2 tool (included in the SDK) fix the problem?

> > Well, usually it works just opposite - Kotlin (or Rust, or whatever) creates static library (*.a) file, and that file is linked by SDK to create flashable image file. > > That is certainly the preferred approach. Just having a static library of the SDK linked in to your "kotlin" is unlikely to work. Wouldn't the **elf2uf2** tool ([included](https://github.com/raspberrypi/pico-sdk/tree/master/tools/elf2uf2) in the SDK) fix the problem?
kilograham commented 2021-01-25 15:08:33 -06:00 (Migrated from github.com)

No; elf2uf2 just translates the mapped segments in the ELF into UF2 sectors, it doesn't modify the binary itself

No; elf2uf2 just translates the mapped segments in the ELF into UF2 sectors, it doesn't modify the binary itself
kilograham commented 2021-01-25 15:11:38 -06:00 (Migrated from github.com)

It is hard to help you further when you haven't answered any of the questions that have been asked.

Asked another way, what do you need?

  1. Runtime startup
  2. C-runtime startup
  3. C-runtime libraries
    etc.

If you are just taking a native application and hoping to link it for the RP2040/Pico then, once again, far and away the simplest/best thing to do is to create a static library with your stuff, and link it into a binary using the SDK build

Anything else requires more thought, and more information

It is hard to help you further when you haven't answered any of the questions that have been asked. Asked another way, what do you need? 1) Runtime startup 2) C-runtime startup 3) C-runtime libraries etc. If you are just taking a native application and hoping to link it for the RP2040/Pico then, once again, far and away the simplest/best thing to do is to create a static library with your stuff, and link it into a binary using the SDK build Anything else requires more thought, and more information
napperley commented 2021-01-25 16:56:21 -06:00 (Migrated from github.com)

It is hard to help you further when you haven't answered any of the questions that have been asked.

Asked another way, what do you need?

  1. Runtime startup
  2. C-runtime startup
  3. C-runtime libraries
    etc.

If you are just taking a native application and hoping to link it for the RP2040/Pico then, once again, far and away the simplest/best thing to do is to create a static library with your stuff, and link it into a binary using the SDK build

Anything else requires more thought, and more information

In response to your questions:

  1. Standard Kotlin library, Kotlin Native runtime, and KotlinX Cinterop library (essential for C interop especially with C pointers) statically linked into the static library
  2. Can you please elaborate on this question
  3. All the high level static libraries from the Raspberry Pi Pico SDK

Since static libraries don't have an entry point how is the SDK going to link a static library with a binary? What is providing the binary that knows how to call the static library, and what is the standard structure used by a static library?

> It is hard to help you further when you haven't answered any of the questions that have been asked. > > Asked another way, what do you need? > > 1. Runtime startup > 2. C-runtime startup > 3. C-runtime libraries > etc. > > If you are just taking a native application and hoping to link it for the RP2040/Pico then, once again, far and away the simplest/best thing to do is to create a static library with your stuff, and link it into a binary using the SDK build > > Anything else requires more thought, and more information In response to your questions: 1. Standard Kotlin library, Kotlin Native runtime, and KotlinX Cinterop library (essential for C interop especially with C pointers) statically linked into the static library 2. Can you please elaborate on this question 3. All the high level static libraries from the Raspberry Pi Pico SDK Since static libraries don't have an entry point how is the SDK going to link a static library with a binary? What is providing the binary that knows how to call the static library, and what is the standard structure used by a static library?
kilograham commented 2021-01-25 17:13:01 -06:00 (Migrated from github.com)

Ok, so you arent needing to do something low level like Rust, you are basically a C app with some extra libraries (and static compiled Kotlin code)?

To link the static library, i had intended that you create a bootstrap main() method app which calls a method in your static library with calls your main

Ok, so you arent needing to do something low level like Rust, you are basically a C app with some extra libraries (and static compiled Kotlin code)? To link the static library, i had intended that you create a bootstrap main() method app which calls a method in your static library with calls your main
napperley commented 2021-01-25 17:58:16 -06:00 (Migrated from github.com)

Ok, so you arent needing to do something low level like Rust, you are basically a C app with some extra libraries (and static compiled Kotlin code)?

Correct. Kotlin unlike Rust is a high level, statically typed programming language. With Linux for example Kotlin can be used to do high level Linux development (aka user space programs), and Kotlin's C/platform interop/integration is deep enough that many existing tools which support C programs can be used with Kotlin programs (readelf, gdb, lldb etc).

To link the static library, i had intended that you create a bootstrap main() method app which calls a method in your static library with calls your main

Sounds like some thought needs to be put into the SDK with how the embedded software life cycle works, and how to architect embedded programs. Your proposed structure is ok, however it would be better to call the method onApplicationStart since that method handles the event when the application starts up. The name main is a bit confusing since it implies a entry point in a program, when in fact a static library is being used as part of the bootstrapping process.

> Ok, so you arent needing to do something low level like Rust, you are basically a C app with some extra libraries (and static compiled Kotlin code)? Correct. Kotlin unlike Rust is a high level, statically typed programming language. With Linux for example Kotlin can be used to do high level Linux development (aka **user space** programs), and Kotlin's C/platform interop/integration is deep enough that many existing tools which support C programs can be used with Kotlin programs (**readelf**, **gdb**, **lldb** etc). > > To link the static library, i had intended that you create a bootstrap main() method app which calls a method in your static library with calls your main Sounds like some thought needs to be put into the SDK with how the embedded software life cycle works, and how to architect embedded programs. Your proposed structure is ok, however it would be better to call the method **onApplicationStart** since that method handles the event when the application starts up. The name **main** is a bit confusing since it implies a entry point in a program, when in fact a static library is being used as part of the bootstrapping process.
kilograham commented 2021-01-25 18:11:53 -06:00 (Migrated from github.com)

Yup, I know what Kotlin is (ardent IntelliJ user), however I haven't looked at Kotlin native, so was asking.

We provide scaffolding that does c-runtime initialization and calls main(), because that seemed friendly to C users. I assume your Kotlin runtime starts at main() too.

You can call your method whatever you like... you said that your static library had no entry point, so I said make one and call it from the main method.

Yup, I know what Kotlin is (ardent IntelliJ user), however I haven't looked at Kotlin native, so was asking. We provide scaffolding that does c-runtime initialization and calls main(), because that seemed friendly to C users. I assume your Kotlin runtime starts at main() too. You can call your method whatever you like... you said that your static library had no entry point, so I said make one and call it from the main method.
msink commented 2021-01-25 18:26:43 -06:00 (Migrated from github.com)

Currently Kotlin/Native does not support baremetall applications in default distribution, but two years ago it experimented with Zephyr RTOS on STM32F4 board (essentially same as RPi Pico)
LED blinking example: https://github.com/JetBrains/kotlin-native/blob/master/samples/zephyr/src/main.kt

Currently Kotlin/Native does not support baremetall applications in default distribution, but two years ago it experimented with Zephyr RTOS on STM32F4 board (essentially same as RPi Pico) LED blinking example: https://github.com/JetBrains/kotlin-native/blob/master/samples/zephyr/src/main.kt
kilograham commented 2021-01-25 18:41:49 -06:00 (Migrated from github.com)

That's cool; it shouldn't be too hard to get going, and we'd love to help more, but we're working on lots of things right now!

The SDK works the way it does with good reasons; it isn't the same for embedded as it is for your desktop compile source, link against a library and run. However we designed the CMake build to hide lots of complexity from you and build nicely tuned binaries off the bat, and give the user the power to cleanly have finer control if they want. A c user is very familiar with a main() method that runs their code.

You can read https://datasheets.raspberrypi.org/pico/sdk/pico_c_sdk.pdf for some intro on this.

That's cool; it shouldn't be too hard to get going, and we'd love to help more, but we're working on _lots_ of things right now! The SDK works the way it does with good reasons; it isn't the same for embedded as it is for your desktop compile source, link against a library and run. However we designed the CMake build to hide *lots* of complexity from you and build nicely tuned binaries off the bat, and give the user the power to cleanly have finer control if they want. A c user is very familiar with a main() method that runs their code. You can read https://datasheets.raspberrypi.org/pico/sdk/pico_c_sdk.pdf for some intro on this.
napperley commented 2021-01-25 19:20:38 -06:00 (Migrated from github.com)

We provide scaffolding that does c-runtime initialization and calls main(), because that seemed friendly to C users. I assume your Kotlin runtime starts at main() too.

Yes, although the type signature(s) are different from the C version:

Plain Version

fun main() {
    println("Program without arguments")
}

Program Arguments Version

fun main(args: Array<String>) {
    println("Program with arguments: $args")
}

If Kotlin Native is used then the entry point (usually packageName.fileName without the kt file extension) needs to be passed to konan (the Kotlin Native compiler), eg with the main function in the main.kt file (in the org.example.blinky package) that would be org.example.blinky.main.

> We provide scaffolding that does c-runtime initialization and calls main(), because that seemed friendly to C users. I assume your Kotlin runtime starts at main() too. Yes, although the type signature(s) are different from the C version: **Plain Version** ```kotlin fun main() { println("Program without arguments") } ``` **Program Arguments Version** ```kotlin fun main(args: Array<String>) { println("Program with arguments: $args") } ``` If Kotlin Native is used then the entry point (usually **packageName.fileName** without the **kt** file extension) needs to be passed to **konan** (the Kotlin Native compiler), eg with the **main** function in the **main.kt** file (in the **org.example.blinky** package) that would be **org.example.blinky.main**.
msink commented 2021-01-25 19:25:30 -06:00 (Migrated from github.com)
See Kotlin/Native runtime: https://github.com/JetBrains/kotlin-native/blob/1f0dd817421aba7a044d623094fe584d609fb68b/runtime/src/launcher/cpp/launcher.cpp#L66
kilograham commented 2021-04-07 08:26:04 -05:00 (Migrated from github.com)

inactive

inactive
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#17
No description provided.