Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dart2native: support creating self-contained binary executables #36915

Closed
joshirio opened this issue May 9, 2019 · 43 comments

Comments

@joshirio
Copy link

@joshirio joshirio commented May 9, 2019

Feature request originally split from the related and now solved issue #34343 (comment).

Thanks to Dart 2.3 AOT mode compiling is now supported through the dart2aot utility.
For easier deployment and usability creating a single binary executable file would be a great feature to have.

@ismlsmile

This comment has been minimized.

Copy link

@ismlsmile ismlsmile commented May 11, 2019

I think this feature is very useful for deployment.

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Jun 21, 2019

Just want to say: i really like flutter and Dart; every time i look into some introductions, i am waiting for AOT single binary to use it as main programming language overall 💯

So, this maybe thoughts of many people, which are interested in flutter and / or Dart itself, but waiting for AOT the last years.

Very happy if it´s available 🥇

@pmundt

This comment has been minimized.

Copy link

@pmundt pmundt commented Jun 25, 2019

I also second the request for single (self-contained) binary output - this would be a welcome step in enabling e.g. multistage builds in Docker where we can throw out most of the dart run-time and get the container sizes down to something more manageable for FaaS and microservice deployments.

@mraleph

This comment has been minimized.

Copy link
Contributor

@mraleph mraleph commented Jun 25, 2019

@pmundt single binary would not be much smaller than AOT snapshot + AOT runtime combination you get now, because it would be just these two things linked together.

In fact if you have multiple AOT compiled apps it would be better to not use single binary if you are concerned about the size - because you would just duplicate runtime.

AOT runtime is already the smallest runtime version which has all unnecessary stuff removed

@shinayser

This comment has been minimized.

Copy link

@shinayser shinayser commented Jul 22, 2019

Oh God I need this so much! It's amazing! Deploying my code and deliverying to my clients withouth worrying about dart vm setup, everything self-contained into a single executable file? Would be a dream!

PLEASE..... JUST.......... DO IT!

@zhujintao

This comment has been minimized.

Copy link

@zhujintao zhujintao commented Aug 15, 2019

Very supportive. Need this, Expect!

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Aug 15, 2019

Can we get some update? How long will we stay here? There is nothing upcoming in changelog till now...

Thanks 👍

@thomasb892

This comment has been minimized.

Copy link

@thomasb892 thomasb892 commented Aug 26, 2019

Well, this is one of the best features after a long time. Do we have any language which is compiled and typed as well as high level and pretty much CONCISE + Supports OOP?
There is OCaml which has some weird syntax(double semicolons required for line breaks, etc. Not concise also datatypes are weird, they use 1bit from every data type for garbage collection). Also there is Pascal but really who wants to add BEGIN and END blocks every where, such a time waste. So we are down to C++ which is actually quite complex and not concise and clean.

At last we got Swift, but you know Apple right? they open sourced swift(that too a limited one with less libraries supported) to gain devs, so let's skip apple.
Now Go is pretty good, but does it support OOP? No. And Rust is quite low level and I didn't really like it because it complicates simple tasks, its like java. BuildHorse(CoverWithSkin(AttachBones(CreateSkeleton())), Horse.Sane, Horse.Trained ......., Horse.ShouldBePolite, Horse.Alive);

Dart is the only concise, simple, compiled language which you can count on.
I can understand that JIT is far better for dynamic languages as it can intelligently check whether the type is changing.
But anyone who says that a JIT is better for a typed language than ahead of time compilation, slap The C language on his face. What optimizations would a JIT do in typed language? There is very few to none, which is actually detrimental once you add the cost for JITing.

@javaddict

This comment has been minimized.

Copy link

@javaddict javaddict commented Aug 27, 2019

Well, this is one of the best features after a long time. Do we have any language which is compiled and typed as well as high level and pretty much CONCISE + Supports OOP?

Personally, I think Kotlin is better than Dart in many ways in language design. (Of course, Dart got its own niche, too.) And for JVM languages, now the new toy, Graalvm, looks really promising. Especially, It comes with tools to compile .class/.jar into a single standalone executable binary. No something like dartaotruntime needed, no accompanies (*.dill).

Yes, it would be nice to see Dart having the same tools.

I can understand that JIT is far better for dynamic languages as it can intelligently check whether the type is changing.
But anyone who says that a JIT is better for a typed language than ahead of time compilation, slap The C language on his face. What optimizations would a JIT do in typed language? There is very few to none, which is actually detrimental once you add the cost for JITing.

I used to have the same image as you. AoT should mean more performant, right? But actually, after playing a while with the new Dart AoT functionality and Graalvm native-image (both Dart and Java/Kotlin are static-typed languages), they all are slower, much slower, compared to the version run on JIT-enabled VM. (I used some computation-intensive benchmarks to do these tests: snapshot vs AoT and Jar vs binary from native-image) You can verify it by yourself. The advantage of AoT is actually the fast start-up time because no VM stuff needed to be initialized. Not the performance.

I don't know all the factors that make JIT faster than AoT, but one thing I know that is interesting about Dart. When Dart VM does the JIT things, it keeps an un-optimized version and goes with another version with as aggressive optimization as it can. If that optimization went too far, it falls back to the safe version and tries again with something less aggressive. This approach really pushes the codes to its limit. On the other hand, AoT compilers must be conservative about the optimization. There are no chances to fix if the generated codes are wrong because the optimization is too aggressive.

But JIT takes time, right? Fortunately, there is a mode, --snapshot-kind=app-jit, that let you train and save the optimized status. I didn't test it much. The default mode(--snapshot-kind=kernel) beats AoT already.

@thomasb892

This comment has been minimized.

Copy link

@thomasb892 thomasb892 commented Aug 27, 2019

javaddict have you benchmarked or just guessing.
This benchmark shows just the opposite #34343 (comment)

If we leave the almost negligible speed difference aside, JIT is a RAM hog compared to AOT. Also do you know Apple doesn't allow using JIT on their iPhones, though the main concern is security but the other reasons are memory usage and performance optimisations. Also Dart required AOT to support iOS.
A JIT is extremely non deterministic. for long running tasks, JIT might not be efficient with memory as well as CPU cycles. Even if the JIT version does beat aot version (even though I haven't seen a benchmark to reproduce that), the AOT version would be lacking some optimizations(because well, you cannot beat C/C++ with a JIT maybe you can, with very biased codes). But anyways, JIT has just too many disadvantages. We can better accept a 3-5% slower program(if AOT is in any way slower by chance) more than a program which uses 40-100% more RAM, especially on a server.

PS: one example where AOT beats the JIT, is in Haskell. Haskell is a very high level language which is very hard to optimise during compile time due to its pure functional nature and immutable data types, lazy data types, etc. However GHC(AOT) is always miles faster than Hugs(JIT implementation). The optimizations are possible because of Haskell's Type system. GHC is the main Haskell compiler now because who really wants to run their programs 3-5 times slower on JIT with RAM hogging?

@mraleph

This comment has been minimized.

Copy link
Contributor

@mraleph mraleph commented Aug 27, 2019

Performance comparison between AOT and JIT is very nuanced and highly dependant on a particular workload. In general Dart AOT can't necessarily devirtualize all the same calls that JIT can e.g. just declaring a variable as List<int> v does not actually give enough information to compiler to produce the best code for v[i] or similarly declaring a variable as int x; int y does not tell compiler anything (it can be null, or maybe smi, or maybe boxed 64-bit integer), so compiler can't necessarily compile x + y into the best possible instruction sequence. JIT compiler compensates for the lack of information by collecting dynamic type profile and by performing speculative optimisations based on that type profile. AOT compensates for the lack of information by trying to do some global analyses. Sometimes one approach is more powerful, sometimes another.

In any case - discussion of JIT vs AOT performance characteristics does not necessarily belong to this issue and should better be taken on other mediums (e.g. on Dart mailing list).

@javaddict

This comment has been minimized.

Copy link

@javaddict javaddict commented Aug 28, 2019

Sorry. Not trying to start a serious discussion of JIT vs AOT here, nor to troll on it.

I am fully aware of the importance and necessity of AOT in those cases @thomasb892 has mentioned and totally agree that the performance difference of JIT vs AOT goes case by case, just as @mraleph illustrated.

I took some time to summarize my (not very strict) test results of the benchmarks listed here.
Check it out if you are interested.

@n8crwlr

This comment has been minimized.

Copy link

@n8crwlr n8crwlr commented Aug 30, 2019

@javaddict sorry, i downvoted you (#36915 (comment)) because this is a discussion about getting a tool to create a single binary out of the code. There is no discussion to compare against Java nor Kotlin, nor to replace native android programming.

The only discussion background here is to create a single binary out of the box, because with Dart we have a language which is:

  • cross-platform, web
  • android, iOS, Windows, Mac OS, Linux, JS
  • front-end and back-end

which means we are able to write mobile apps, web-apps and desktop-apps (which all will have their compiled format) and we are able to compile the whole server backend to a / several binaries.

This is: to have a language which suites much needs and to have compiled binarys instead of naked code files, which is simply more safe and usable. In my intention this is not about AOT vs. JIT, vs. Kotlin, whatever.

Simply: it is about generating single binaries.

So, i would really like to have this feature 👍

@0xbkt

This comment has been minimized.

Copy link

@0xbkt 0xbkt commented Sep 14, 2019

I always thought that ahead-of-time compilation was meant to produce native executable that is system-dependent. AOT Wikipedia article also states that. But it looks dart2aot and dartaotruntime do not really accord with this. Then why it's called AOT? Am I missing something? Isn't AOT compiled code already supposed to have an integrated runtime?

@mit-mit mit-mit changed the title dart2aot: support creating single binary file dart2native: support creating single binary file Sep 26, 2019
@mit-mit

This comment has been minimized.

Copy link
Member

@mit-mit mit-mit commented Sep 26, 2019

Then why it's called AOT? Am I missing something? Isn't AOT compiled code already supposed to have an integrated runtime?

AOT (ahead-of time) just means that the machine code is prepared during development, not during execution in production (as in a JIT, just-in-time, compiler inside a traditional VM; virtual machine).

Strongly typed languages with garbage collection still need runtime systems, even when executing AOT-compiled machine code. This runtime system is responsible for performing dynamic type checks, and for freeing memory no longer used.

@mit-mit mit-mit added this to the D26 Release milestone Sep 26, 2019
@petrichor

This comment has been minimized.

Copy link

@petrichor petrichor commented Sep 27, 2019

Strongly typed languages with garbage collection still need runtime systems, even when executing AOT-compiled machine code. This runtime system is responsible for performing dynamic type checks, and for freeing memory no longer used.

Can we get a single binary that contains both runtime and machine code? I want to distribute a single file like golang without install dart runtime on other devices. @mit-mit

@mit-mit

This comment has been minimized.

Copy link
Member

@mit-mit mit-mit commented Sep 27, 2019

Yes, that is what this bug tracks. We're getting pretty close.

@sebe

This comment has been minimized.

Copy link

@sebe sebe commented Sep 27, 2019

Hey looks cool, Dart VM version: 2.6.0-dev.3.0 on "linux_x64" is working fine.
dart2native helloworld.dart
Generated: /home/xxx/helloworld.dart.exe

Are you going to or can we have the option to name the generated executable,
so the following is possible?
dart2native helloworld.dart helloworld
Generated: /home/xxx/helloworld

Anyway on my i5 nuc - NUC6i5SYH
time ./helloworld.dart.exe
hello world!

real 0m0.011s
user 0m0.001s
sys 0m0.011s

time dart helloworld.dart
hello world!

real 0m0.129s
user 0m0.172s
sys 0m0.063s

@sebe

This comment has been minimized.

Copy link

@sebe sebe commented Sep 27, 2019

thanks, that's great
dart2native helloworld.dart -o helloworld
Generated: /home/xxx/helloworld

Yeah I missed this "Put the output in file"
-o, --output=<path> Put the output in file <path>.

@mit-mit

This comment has been minimized.

Copy link
Member

@mit-mit mit-mit commented Sep 27, 2019

Yeah, we're still working on tweaking the --help messages to be clearer

@asaarnak

This comment has been minimized.

Copy link

@asaarnak asaarnak commented Sep 28, 2019

Cool stuff, tested out with Ubuntu 19.10 with i7-8750H, seems useful for Cloud Run.
10k runs with empty main method took 1m 25sec.

time for i in {1..10000}; do ./emptyMain; done

real    1m24,885s
user    0m42,053s
sys     0m44,544s
@mkustermann

This comment has been minimized.

Copy link
Member

@mkustermann mkustermann commented Oct 3, 2019

A simple dart2native approach has been implemented, with the caveat that re-signing the generated binaries might not be possible.

If we wanted to remove our signature from the AOT runtime we could consider doing that with codesign --remove-signature. Otherwise there is no further work planned atm.

@mit-mit @mraleph Can we remove the D26 milestone from this issue and/or close it?

@n8crwlr

This comment has been minimized.

Copy link

@n8crwlr n8crwlr commented Oct 3, 2019

@mkustermann excuse me, i do not fully understand. What does your comment above mean? Do you want to stop the work?

with the caveat that re-signing the generated binaries might not be possible

What does that mean?

@pmundt

This comment has been minimized.

Copy link

@pmundt pmundt commented Oct 4, 2019

I can confirm success with dart2native - I'm able to reduce my container size from ~250MB to 25MB, which is a great improvement, especially as we begin to use Dart for cloud functions in OpenFaaS. An option for static linking so that we can toss out more of the runtime environment would be nice, and would likely bring this down to ~10MB, in line wither other languages (e.g. Golang).

@n8crwlr

This comment has been minimized.

Copy link

@n8crwlr n8crwlr commented Oct 4, 2019

As asarnaak and sebe i have done some tests against startup time compared to C and Go, where Dart is ~20 times slower, but, all in all, this is a very big enhancement, and i would like to use Dart now whenever possible. For me, this issue is a game changer to all. Pretty cool!

@pmundt

This comment has been minimized.

Copy link

@pmundt pmundt commented Oct 4, 2019

I've also written up some of our experiences in working on container size reduction, for anyone that is interested in this topic: https://medium.com/@paulmundt/experiments-with-dart-microservices-fa117aa408c7

@mraleph

This comment has been minimized.

Copy link
Contributor

@mraleph mraleph commented Oct 6, 2019

@n8crwlr some operating systems (Windows and Mac OS X) have builtin support for signed executables. The way we implemented dart2native does not necessarily play well with these mechanisms. We currently don't plan on fixing these issues.

@mraleph

This comment has been minimized.

Copy link
Contributor

@mraleph mraleph commented Oct 6, 2019

Basic functionality implemented - closing this issue. If signing becomes important - we will file a separate one for that.

@mraleph mraleph closed this Oct 6, 2019
@n8crwlr

This comment has been minimized.

Copy link

@n8crwlr n8crwlr commented Oct 6, 2019

I do not need signing. Thank you very much for supporting the single binary 👍

@mit-mit mit-mit changed the title dart2native: support creating single binary file dart2native: support creating self-contained binary executables Oct 25, 2019
@rknell

This comment has been minimized.

Copy link

@rknell rknell commented Oct 27, 2019

Just wanted to say thanks, i wanted to use dart for a command line application about a month ago and found I couldn't package a single binary for my customer, so I had to skip it and write it in NodeS instead (it will likely need to be embedded into an interface at some point). Would have loved to use this - and now that its available I will definitely be using this in the future.

IMO this is the final piece of the dart puzzle to go almost exclusively dart.

So once again, a big thanks for listening to the community and prioritising a needed feature.

@shinayser

This comment has been minimized.

Copy link

@shinayser shinayser commented Oct 27, 2019

Agreed with @rknell, dart team is doing an awesome work. Congratulations, and more than that, thank you!

@cachapa

This comment has been minimized.

Copy link

@cachapa cachapa commented Oct 28, 2019

I'm having issues when I try to move the binary to the system bin path:

$ dart2native main.dart -o fireutil
Generated: /home/cachapa/fireutil/bin/fireutil

$ ./fireutil 
Utility to manage Firestore databases.
[...]

$ sudo mv fireutil /usr/local/bin
$ fireutil 
Usage: dart [<vm-flags>] <dart-script-file> [<script-arguments>]
[...]
@mkustermann

This comment has been minimized.

Copy link
Member

@mkustermann mkustermann commented Oct 28, 2019

Can you report the version of Dart you're using?

The changes in 8d8faa7 and a9fc9f7 should have fixed this particular issue. AFAIK those fixes should be available in the latest dev channel and will be included in the stable release coming out the next few days.

@cachapa

This comment has been minimized.

Copy link

@cachapa cachapa commented Oct 28, 2019

I'm on the dev channel:

$ dart --version
Dart VM version: 2.6.0-dev.5.0 (Thu Oct 3 15:21:01 2019 +0200) on "linux_arm"

The changes you mentioned seem to be more recent. Any idea how long it'll take for them to reach the Debian dev channel?

@mkustermann

This comment has been minimized.

Copy link
Member

@mkustermann mkustermann commented Oct 28, 2019

The latest version on dev channel, 2.6.0-dev.8.2, should have this fix I believe. It can be downloaded at dart.dev/tools/sdk/archive.

Normally when we release new versions they are pushed to all distribution channels, so I would assume the debian repository has this version as well.

In fact they seem to be in our cloud storage bucket:
gs://download.dartlang.org/linux/debian/pool/main/d/dart/dart_2.6.0-dev.8.2-1_amd64.deb

@cachapa

This comment has been minimized.

Copy link

@cachapa cachapa commented Oct 28, 2019

My bad, I was running it on my Raspberry Pi and didn't realise there's no .deb for ARM.
I downloaded the archive and installed it manually, and now it works perfectly.

Thanks!

@shinayser

This comment has been minimized.

Copy link

@shinayser shinayser commented Oct 30, 2019

Anyone knows if I can generate the binaries for Linux from a Windows 10 computer? There is any way of doing that?

@mkustermann

This comment has been minimized.

Copy link
Member

@mkustermann mkustermann commented Oct 30, 2019

Anyone knows if I can generate the binaries for Linux from a Windows 10 computer?
There is any way of doing that?

Unfortunately not. Right now cross compiling from Windows to Linux is not possible (and there is also no planned timeline for making this work)

@jodinathan

This comment has been minimized.

Copy link

@jodinathan jodinathan commented Oct 30, 2019

@n8crwlr

This comment has been minimized.

Copy link

@n8crwlr n8crwlr commented Oct 31, 2019

@shinayser

Anyone knows if I can generate the binaries for Linux from a Windows 10 computer? There is any way of doing that?

You can try WSL (Windows subsystem for Linux). I have used it much for such things in the past. You can work on the same files on both platforms (as long you are building a CLI). Than you will be able to compile on Windows for Windows and on WSL for Linux easily. But i have not used the all new WSL 2 since that.

@mit-mit

This comment has been minimized.

Copy link
Member

@mit-mit mit-mit commented Oct 31, 2019

You could also use a CI provider, e.g. TravisCI

@mit-mit

This comment has been minimized.

Copy link
Member

@mit-mit mit-mit commented Nov 11, 2019

This has now formally launched; for details see the blog post: https://medium.com/dartlang/dart2native-a76c815e6baf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.