8000 Allow AOT executables to be cross-compiled · Issue #28617 · dart-lang/sdk · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Allow AOT executables to be cross-compiled #28617

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

Open
nex3 opened this issue Feb 2, 2017 · 57 comments
Open

Allow AOT executables to be cross-compiled #28617

nex3 opened this issue Feb 2, 2017 · 57 comments
Assignees
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. customer-dart-sass type-enhancement A request for a change that isn't a bug

Comments

@nex3
Copy link
Member
nex3 commented Feb 2, 2017

Currently application snapshots (as described here) can only be compiled for the architecture of the machine doing the compilation. This makes releasing cross-platform apps using these snapshots much more difficult, requiring multiple machines (including at least one physical machine, since OS X isn't virtualizable) to compile for all platforms.

It seems that the compilation process could do the initial run on the current platform, but then preserve the profiling information and use it to cross-compile the result to other platforms.


Admin note: This is being implemented gradually via new --target-os and --target-arch flags on dart compile exe.

The current status is as follows:

Developer OS
(OS where the compiler is run)
Target OS
(OS where the exe is run)
Status

macOS macOS Supported in 2.15 and later
macOS Windows Not supported
macOS Linux Supported in 3.8 and later
Windows macOS Not supported
Windows Windows Supported in 2.15 and later
Windows Linux Supported in 3.8 and later
Linux macOS Not supported
Linux Windows Not supported
Linux Linux Supported in 2.15 and later
@nex3 nex3 added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. enhancement customer-dart-sass labels Feb 2, 2017
@kevmoo kevmoo added type-enhancement A request for a change that isn't a bug and removed enhancement labels Feb 9, 2017
nex3 added a commit to sass/dart-sass that referenced this issue Feb 2, 2018
Might as well give some subset of our users a speed-up while we wait
for dart-lang/sdk#28617.
nex3 added a commit to sass/dart-sass that referenced this issue Feb 2, 2018
Might as well give some subset of our users a speed-up while we wait
for dart-lang/sdk#28617.
@rmacnak-google
Copy link
Contributor

App snapshots are tied to the target ABI of the VM, not the host OS and not the host ABI. If you create an app snapshot using an IA32 VM, you can run the same snapshot on Windows, Mac or Linux. If you create an app snapshot using an X64 VM on Mac or Linux, you run it on the other (they share the sysv ABI), but not Windows (which has its own ABI). If you create an app snapshot using a SIMARM VM on your desktop, you can run it with an ARM VM on, say, an Android device (this is how Flutter works).

We will not produce VMs that target multiple ABIs. The assumption of a single target ABI as a build-time decision is quite deep in the VM.

@nex3
Copy link
Member Author
nex3 commented Jun 29, 2018

I want to push back strongly on this. Startup performance is very important for providing my users with a good experience, and the Dart VM's startup performance without using application snapshots compares poorly to just about any other language (including Ruby, whose Sass implementation we're in the process of deprecating because of performance issues).

Other languages are able to do this. Easy cross-compilation is a major reason that Go is so popular for writing command-line tools, and if Dart provided it with similar ease it would make the server-side Dart world very compelling. But without it, Dart users are forced to deal with sub-par performance when they could easily get performance and portability with another language.

@nex3
Copy link
Member Author
nex3 commented Jul 9, 2018

Ping... efficient startup speeds across all platforms are a very important customer feature.

@nex3 nex3 reopened this Aug 3, 2018
@nex3
Copy link
Member Author
nex3 commented Aug 3, 2018

I haven't received any response, so I'm re-opening this. It's a pressing customer issue.

@passsy
Copy link
passsy commented Aug 22, 2018

One workaround is https://github.com/filiph/dartbin which creates a go wrapper. Not Dart2 compatible though and it requires go as dependency.

@nex3 nex3 changed the title Allow application snapshots to be cross-compiled Allow AOT executables to be cross-compiled May 20, 2019
@nex3
Copy link
Member Author
nex3 commented May 20, 2019

Updating to AOT executables, since that's not the best way to distribute CLI applications.

@nex3
Copy link
Member Author
nex3 commented May 30, 2019

@mit-mit has told me offline that "getting to full cross-compilation is going to be a long journey", but "the journey has already started; we just don't have a timeline for when it will end".

@shinayser
Copy link

Looking forward to see this feature! Loving to work with dart ❤

@Schwusch
Copy link
Schwusch commented Nov 13, 2019

This feature is a show stopper for us in order to adopt Dart in AWS Lambda. Since the AWS CLI runs the compiled executable in a Docker container, offline development is only possible in a Linux environment. Manual deployment without CI/CD is also impossible in Mac and Windows.

@t0mmar
Copy link
t0mmar commented Nov 15, 2019

Also a cross-compile option for linux ARM architectures please!

@mit-mit
Copy link
Member
mit-mit commented Nov 18, 2019

Potential work-around that may work for some: https://blog.dantup.com/2019/11/easily-compiling-dart-to-native-executables-for-windows-linux-macos-with-github-actions/

@DrSensor
Copy link

Just found this wiki: https://github.com/dart-lang/sdk/wiki/Building-Dart-SDK-for-ARM-processors#building

I wonder if dart2native and the produced executable/snapshot works on RaspberryPi 🤔?

@ifree92
Copy link
ifree92 commented May 18, 2020

Ah, that would be awesome to have a cross compilation !
I just was looking for this functionality, but found this issue.
If my vote for this topic can change the priorities for dart2native tools improvement - I would be really glad.

I'm trying to use Dart for several projects for Raspberry, but that's hard to easily win this battle without ability to get ARM binary using my host OS (MacOS).

What's about plan? Will this feature be included once?

@ThomasJaeger
Copy link

Is there an update to this? Really interested in cross-compilation!

@jpnurmi
Copy link
jpnurmi commented Sep 6, 2020

Would something like this be an interesting mid-term solution?

 $ dart2native foo.dart \
    --gen-snapshot out/ProductSIMARM/dart-sdk/bin/utils/gen_snapshot \
    --aot-runtime out/ProductXARM/dart-sdk/bin/dartaotruntime

jpnurmi@9625310

@mraleph
Copy link
Member

Would something like this be an interesting mid-term solution?

That's pretty close to how it would be implemented in the long term too (if we had resources or if we had somebody willing to contribute external implementation). Few missing pieces to take it all the way:

  • We need to create X-configurations for producing gen_snapshot for all configurations of host-target OSes and architectures.
  • We need to figure out packaging and distribution for these binary artifacts. I don't think including them into SDK is scalable - we need to figure out "out of band" delivery mechanism (which might somewhat complicate Dart SDK release process).

@mraleph
Copy link
Member
mraleph commented Dec 12, 2022

@maks Flutter does it in the same way which is described in #28617 (comment) and other comments on the thread.

They build a bunch of gen_snapshot binaries for each host -> target combination they support as well as building a bunch of libflutter.so for all target configurations they support. flutter tool then dynamically downloads necessary pieces.

Dart's dart compile exe could do the same. For combinations that we already support the biggest open question is packaging this all together, rather than anything else. For combinations that we don't support (e.g. building Windows exe on Linux) more work needs to be done in VM innards.

@maks
Copy link
maks commented Dec 12, 2022

Thanks @mraleph 👍🏻 that gives me a good place to go start looking into the Flutter code to learn how they build the separate gen_snapshot binaries for each target.

In regards to the packaging and distribution for doing this in Dart, is there the possibility of reusing the infrastructure that Flutter has setup or do the Dart & Flutter projects prefer to keep these separate?

@mraleph
Copy link
Member
mraleph commented Dec 13, 2022

Thanks @mraleph 👍🏻 that gives me a good place to go start looking into the Flutter code to learn how they build the separate gen_snapshot binaries for each target.

You will have to read their buildbot recipes for that (https://flutter.googlesource.com/recipes). It's all done on the CI and uploaded to the cloud storage bucket.

Ultimately it is just about configuring the engine build with the right flags.

In regards to the packaging and distribution for doing this in Dart, is there the possibility of reusing the infrastructure

We will probably have some variation of the same infrastructure. We had a brief chat with @mit-mit and we might lay some ground work for this next quarter.

@yingshaoxo
Copy link

I think "dart can't cross compile" is simply a lie !!!

Because apparently, flutter can compile an arm apk file directly on window, linux amd64 machine.

@NBSgamesAT
Copy link
NBSgamesAT commented Sep 13, 2023

With Mac moving over to arm. Being able to cross-compile because even more important. Because people on mac will not be able to run a windows vm and do the compiling there. So we will need 2 seperated machines now just to get our executables for all platforms...

But I'll need to ask then: Why does the dart compile command mention the --target-os option to begin with? Why does it not print a warning that --target-os is currently ignored when entered?

@TarasMazepa
Copy link

With MacOS having two different architectures arm and intell I need to have two Mac machines to compile all the variants. Note that not all CI platforms, as GitHub offer Arm Mac machines. So you would need to search to cover your Mac compilation needs.

copybara-service bot pushed a commit that referenced this issue Nov 13, 2023
Upstreamed changes from cl/579854752.

The cross-compiler checks some things that are check on Windows.
* Correct capitalization of filenames in includes.
* Field initialization order in constructors.

In the cross compilation process, some binaries are run on the host.
This unveiled missing `UnwindingRecords::GenerateRecordsInto`.

Finally, when emitting blob data with a symbol in assembly, the
`.type` directive is not supported but the format should still be
unix style assemble. So this CL introduces "win_gnu". This tool is
directly invoked from the build-rules in cl/579854752, and will not be
used until we address #28617.

TEST=windows bots

Change-Id: I94256589e8c231b45b8e14a63727c782416c2e98
Cq-Include-Trybots: luci.dart.try:vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,pkg-win-release-try,pkg-win-release-arm64-try,vm-win-debug-arm64-try,vm-win-debug-x64c-try,vm-win-debug-x64-try,vm-msvc-windows-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335520
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
@SittiphanSittisak
Copy link
SittiphanSittisak commented Dec 12, 2023

I used this GitHub action workflow to get cross-platform builds

# This is a basic workflow to help you get started with Actions

name: CI Building native server

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the main branch
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  build:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macOS-latest]
        include:
          - os: ubuntu-latest
            output-name: server-linux
          - os: macOS-latest
            output-name: server-mac
          - os: windows-latest
            output-name: server-windows.exe
    steps:
          - uses: actions/checkout@v2
          - uses: dart-lang/setup-dart@v1.3
          - name: Install dependencies
            run: dart pub get
          - run: mkdir build
          - name: Install Dependencies
            run: dart pub get
          - run: dart compile exe ./bin/server.dart -v -o build/${{ matrix.output-name }}
          - uses: actions/upload-artifact@v1
            with:
                name: native-executables
                path: build

and here is the result

Screen Shot 2022-02-18 at 12 37 14 AM

Hi, thank you for this solution. I am new to git workflows/actions!?
I wonder about the Install Dependencies step. Why have the install dependencies 2 times?

          - name: Install dependencies   *1
            run: dart pub get
          - run: mkdir build
          - name: Install Dependencies   *2

My root folder seems like this.

root
     - .github
          - workflows
               - github-actions-demo.yml
               
     - dart_server
          - bin
               - dart_server.dart
          - pubspec.yaml

     - dart_share                       //include the object, and function these were used in dart_share
          - pubspec.yaml

So I should change some steps in github-actions-demo.yml, right?

UPDATE
I am using this.

# This is a basic workflow to help you get started with Actions

name: CI Building native server

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the main branch
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  build:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macOS-latest]
        include:
          - os: ubuntu-latest
            output-name: server-linux
          - os: macOS-latest
            output-name: server-mac
          - os: windows-latest
            output-name: server-windows.exe
    steps:
      - uses: actions/checkout@v2
      - uses: dart-lang/setup-dart@v1.3
      - name: Install dependencies for share project
        working-directory: ./share_dart
        run: dart pub get
      - name: Install dependencies for server project
        working-directory: ./server
        run: dart pub get
      - run: mkdir build
      - name: Install Dependencies for share project
        working-directory: ./share_dart
        run: dart pub get
      - name: Install Dependencies for server project
        working-directory: ./server
        run: dart pub get
      - run: dart compile exe ./server/bin/server.dart -v -o build/${{ matrix.output-name }}
      - uses: actions/upload-artifact@v1
        with:
          name: native-executables
          path: build

@geocode
Copy link
geocode commented Dec 12, 2023

Alternative approach Using node.js to create executables

I have a work around that I would like to share as it does not require any GitHub services, etc. It can all be done from command line.

I am compiling to JS, then using node.js tools to convert to executable. I wrote a bash script to simplify the process. This is certainly not going to be the most efficient and probably has gaps (that I haven't found), but for the command line tools I've been building it has worked well so far.

Until it is supported natively...

Example Steps

Create the js files

dart compile js bin/hello.dart -o js/hello.js

Command line arguments don’t work in generated js

It turns out that for some reason the command line arguments passed to the program are not picked up by the generated node program, unless you do a special little trick. I found out about the trick from this site: https://japhr.blogspot.com/2014/07/command-line-arguments-with-nodejs-and.html

Basically the trick is to add a function to the generated node.js file:

function dartMainRunner(main, args) {
  main(process.argv.slice(2)); 
}

Create the executable using node.js tools

Create the package.json file in js directory

{
    "name": "hello",
    "version": "0.0.1",
    "description": "Say hello.",
    "main": "hello.js",
    "bin": "hello.js", 
    "author": "anybody",
    "license": "MIT"
}

Then build the executable

pkg .

Script to do all of this

In order to automate this I created a script dart2js in ~/local/bin that does all of these steps.

#!/bin/bash

if [[ "$1" == "" ]]; then
  echo -e "Usage:\n\t$0 [basename]"
  exit 1
fi

if [[ ! -f bin/$1.dart ]]; then
  echo "bin/$1.dart does not exist"
  exit 2
fi

dart compile js bin/$1.dart -o js/$1.js
if [ $? -ne 0 ]; then
  echo "Compiling js failed, exiting build script"
  exit 3
fi

wrapper='function dartMainRunner(main, args) { main(process.argv.slice(2)); }';
echo $wrapper >> js/$1.js

cat <<EOT > js/package.json
{
    "name": "$1",
    "version": "0.0.1",
    "description": "Do amazing $1 stuff.",
    "main": "$1.js",
    "bin": "$1.js", 
    "author": "Geoff Ruscoe",
    "license": "MIT"
}
EOT

cd js
pkg .

@liudonghua123
Copy link

Alternative approach Using node.js to create executables

I have a work around that I would like to share as it does not require any GitHub services, etc. It can all be done from command line.

I am compiling to JS, then using node.js tools to convert to executable. I wrote a bash script to simplify the process. This is certainly not going to be the most efficient and probably has gaps (that I haven't found), but for the command line tools I've been building it has worked well so far.

Until it is supported natively...

Example Steps

Create the js files

dart compile js bin/hello.dart -o js/hello.js

Command line arguments don’t work in generated js

It turns out that for some reason the command line arguments passed to the program are not picked up by the generated node program, unless you do a special little trick. I found out about the trick from this site: https://japhr.blogspot.com/2014/07/command-line-arguments-with-nodejs-and.html

Basically the trick is to add a function to the generated node.js file:

function dartMainRunner(main, args) {
  main(process.argv.slice(2)); 
}

Create the executable using node.js tools

Create the package.json file in js directory

{
    "name": "hello",
    "version": "0.0.1",
    "description": "Say hello.",
    "main": "hello.js",
    "bin": "hello.js", 
    "author": "anybody",
    "license": "MIT"
}

Then build the executable

pkg .

Script to do all of this

In order to automate this I created a script dart2js in ~/local/bin that does all of these steps.

#!/bin/bash

if [[ "$1" == "" ]]; then
  echo -e "Usage:\n\t$0 [basename]"
  exit 1
fi

if [[ ! -f bin/$1.dart ]]; then
  echo "bin/$1.dart does not exist"
  exit 2
fi

dart compile js bin/$1.dart -o js/$1.js
if [ $? -ne 0 ]; then
  echo "Compiling js failed, exiting build script"
  exit 3
fi

wrapper='function dartMainRunner(main, args) { main(process.argv.slice(2)); }';
echo $wrapper >> js/$1.js

cat <<EOT > js/package.json
{
    "name": "$1",
    "version": "0.0.1",
    "description": "Do amazing $1 stuff.",
    "main": "$1.js",
    "bin": "$1.js", 
    "author": "Geoff Ruscoe",
    "license": "MIT"
}
EOT

cd js
pkg .

this method produces much big sized binary. For simple hello world example, the binary maybe almost 100MB.

I would prefer to use github action using matrix to build the aot binary.

@amrgetment
Copy link

as 32bit support will be removed from dart language I think it is possible to make cross-platform building

@mraleph
Copy link
Member
mraleph commented Jan 2, 2025

as 32bit support will be removed from dart language I think it is possible to make cross-platform building

Removal of X86 support (which I think what you are referring to here cause we have other 32-bit platforms which we will continue to support, like e.g. ARM) has not relationship to this issue.

I hope that we tackle cross compilation in the 2025 by building and shipping necessary tooling in SDK (cc @iinozemtsev)

copybara-service bot pushed a commit that referenced this issue Apr 28, 2025
Issue description: currently cross-compilation is guarded by a flag.
What is the fix: remove the flag.
Why cherry-pick: so that we don't have this flag in 3.8.0 stable
Risk: Low, the flag is a no-op.
Issue link: #28617

Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/424442
Change-Id: Iab7f15aa6f5a05babca592e68b9521478e0232b7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/424743
Reviewed-by: Alexander Thomas <athom@google.com>
Commit-Queue: Ivan Inozemtsev <iinozemtsev@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
@mit-mit
Copy link
Member
mit-mit commented May 6, 2025

Current status is now captured in a table in the top-most comment. Rows listed as 3.8 require 3.8.0-278.3.beta or later (which will become 3.8 stable).

@cpswan
Copy link
Contributor
cpswan commented May 6, 2025

@mit-mit would you consider expanding the table to cover the full range of --target-os --target-arch combinations?

I'm particularly interested in being able to cross compile to linux-arm and linux-riscv as these are things where I presently need to build inside of Docker BuildX (with QEMU) as they're not native platforms in GitHub Actions. The 'Developer OS' for those targets could be any of the Actions hosted runners, though I'd expect that linux-arm64 or linux-x64 would be the most likely choice (we've presently settled on linux-arm64 runners, as QEMU runs better on that for linux-arm and linux-riscv targets as there's less of an impedance mismatch between the runner and target ISAs).

@maks
Copy link
maks commented May 6, 2025

@mit-mit I'll second that request. I'm very excited to see the cross compiling support! but for me linux-riscv has been and still is the driving interest for cross compile support, though linux-arm64 would also be very useful and in both cases I would likewise only be using linux host for both those combinations.

@cpswan
Copy link
Contributor
cpswan commented May 7, 2025

@maks you can already cross compile to linux-arm64 from linux-x64. I tested it last week with dev channel (and looks like it's slated to be in the 3.8 stable).

@maks
Copy link
maks commented May 7, 2025

Brilliant thanks for letting me know @cpswan !
I'll keep my fingers crossed for RISCV then as I've been waiting for it for a while now: #49253

@mit-mit
Copy link
Member
mit-mit commented May 8, 2025

Wrt. RISC-V, would riscv64 be sufficient? We don't list 32-bit risc as a supported platform on https://dart.dev/get-dart

@maks
Copy link
maks commented May 8, 2025

@mit-mit yes I think riscv32 was never supported by Dart (would be lovely if it was) so yes just 64bit would be awesome for now. 🙏🏻

@cpswan
Copy link
Contributor
cpswan commented May 8, 2025

@mit-mit I should have been more precise in my comments above. Where I wrote linux-riscv I meant linux-riscv64.

All of the RISC-V dev boards we've been testing with are using riscv64 SoCs. So far as I can tell riscv32 is more of an MCU thing, and I have no expectation of Dart ever running on those (or the underlying Linux distro support that would be needed to make that happen).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. customer-dart-sass type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

0