Now that <https://github.com/Kotlin/kotlinx-cli> i...
# kotlin-native
e
Now that https://github.com/Kotlin/kotlinx-cli is marked as obsolete, are there alternatives for CLIs in Native?
k
e
Literally checking that one ATM! Looks good to me. Did you ever try it out?
k
Yes I've used it several times. It's fantastic.
e
Nice! Can I ask what's a typical binary size when targeting Native? I've got CLIs built with Quarkus and GraalVM that reach the 12 MB mark
k
I'm not sure off the top of my head. Should be pretty easy for you to spin up a simple hello world CLI and see what the size is in release mode!
I'd check, but I'm not at my computer right now. Sorry
I would be surprised if it came anywhere close to 12MB though
e
I've seen the only dependency is https://github.com/ajalt/mordant, which is also KMP, so I expect optimized outputs. I'll give it a try!
I would be surprised if it came anywhere close to 12MB though
You mean you expect smaller sizes?
k
Correct, definitely smaller.
thank you color 1
e
Nice. I'm converting a lot of stuff in our organization to Kotlin, CLIs are definitely one of the most painful stuff to build I have because of GraalVM
w
https://github.com/varabyte/kotter This is my most frequently used library, and it is also KMP.
gratitude thank you 1
โž• 1
k
If I were to build a totally interactive CLI I would use clikt + mosaic ๐Ÿ˜„ https://github.com/JakeWharton/mosaic
e
Mosaic seems to have issues on Windows tho. It's still highly experimental. And unfortunately we primarily run Windows machines ๐Ÿ‘€
๐Ÿ˜ž 1
4272 KB with Clickt and a sample command. It's very similar to Go, for which I was able to get down to 3 MB
I think the size of the standard library also plays a big role here.
k
Definitely. I wonder if there's anything dead code elimination happening in native release builds?
e
Docs says
When you export a dependency, it includes all of its API to the framework API. The compiler adds the code from this dependency to the framework, even if you use a small fraction of it. This disables dead code elimination for the exported dependency (and for its dependencies, to some extent).
So I suppose there is. Mordant exports colormath as
api(libs.colormath)
for example.
k
Kind of sucks that a top level binary in release mode isn't able to do dead code elimination since everything at that point is effectively an implementation detail of your binary.
e
There is a JetBrains plugin for UPX
org.jetbrains.gradle.upx
k
Is UPX dead code elimination? I haven't heard that term before.
e
UPX compresses binaries, no dead code elimination.
๐Ÿ‘ 1
Copy code
> Task :compressReleaseExecutableNative
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2023
UPX 4.0.2       Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 30th 2023

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   4374528 ->   2650624   60.59%    win64/pe     untitled25.upxexe

Packed 1 file.
Cut in half!
k
Does binary compression impact performance?
I would guess yes
e
Slightly, but it's like on the >ms scale. At startup the injected UPX code runs to decompress the native code.
k
Oh neat.
I'm curious -- if you're working on internal company tooling, why do you care about binary size so much?
e
CLIs are downloaded by our Jenkins pipelines, and the VMs network is not one of the best, so the download speed is not optimal. The more stuff weight, the more time the build pipeline takes to execute. I could cache, but tbh caching introduces another level of complexity I don't want to maintain
๐Ÿ‘ 1
Also, I'm the infra/tooling person so I can do whatever I want. And 10MB+ CLIs are just... nope
k
For what it's worth, I'm pretty sure the dead code elimination snippet from the docs you posted above only applied to shared lib and apple framework generation.
e
Sad ๐Ÿ˜ž
k
No I think that's a good thing. For final executables it should still be able to perform elimination for things which are
api(libs.whatever)
236 Views