Standalone Dart runtime library for embedders
For now we use a static library, but I am planning to add support for a shared library in a follow-up CL. Tested: locally on macOS and Linux, also ci should at least build samples. Change-Id: I277239359de226c56633884f350b22a030759ab6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392640 Commit-Queue: Ivan Inozemtsev <iinozemtsev@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
76717f2930
commit
53ba9af361
@@ -0,0 +1,25 @@
|
||||
# Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import("../../utils/application_snapshot.gni")
|
||||
|
||||
# All samples.
|
||||
group("all") {
|
||||
deps = [ ":run_kernel" ]
|
||||
}
|
||||
|
||||
# Sample binary to run given kernel snapshot.
|
||||
executable("run_kernel") {
|
||||
sources = [ "run_kernel.cc" ]
|
||||
deps = [ "../../runtime/bin:dart_embedder_runtime_jit" ]
|
||||
include_dirs = [ "../../runtime" ]
|
||||
data_deps = [ ":hello_kernel" ]
|
||||
}
|
||||
|
||||
# Kernel snapshot of ./hello.dart.
|
||||
application_snapshot("hello_kernel") {
|
||||
main_dart = "hello.dart"
|
||||
dart_snapshot_kind = "kernel"
|
||||
training_args = [] # Not used
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# Dart VM Embedding examples
|
||||
|
||||
Examples of using Dart VM and executing Dart code from C++ binaries.
|
||||
|
||||
## run_kernel.cc
|
||||
|
||||
To run the example:
|
||||
|
||||
```sh
|
||||
./tools/build.py --no-rbe --mode=release samples/embedder:run_kernel && out/ReleaseX64/run_kernel
|
||||
```
|
||||
|
||||
The example initializes Dart VM, creates an isolate from a kernel file (by
|
||||
default it uses kernel-compiled `hello.dart`), launches its `main` function with
|
||||
args and exits.
|
||||
|
||||
You can also compile your own Dart kernel like this:
|
||||
|
||||
```sh
|
||||
dart compile kernel --no-link-platform my.dart
|
||||
out/ReleaseX64/run_kernel my.dill
|
||||
```
|
||||
|
||||
Since the kernel file format is unstable, the `dart` binary needs to be of a
|
||||
matching version. The simplest way to ensure this is to build Dart SDK from the
|
||||
same checkout, see
|
||||
[Building Dart SDK](https://github.com/dart-lang/sdk/blob/main/docs/Building.md#building).
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
void main(List<String>? args) {
|
||||
final greetee = args?.singleOrNull ?? 'world';
|
||||
print('Hello, $greetee!');
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Executes `main` function from given Dart kernel binary (by default uses
|
||||
// compiled ./hello.dart).
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/dfe.h"
|
||||
#include "bin/platform.h"
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_embedder_api.h"
|
||||
#include "platform/assert.h"
|
||||
|
||||
Dart_Handle CheckHandle(Dart_Handle handle,
|
||||
const char* context = "unknown context") {
|
||||
if (Dart_IsError(handle)) {
|
||||
FATAL("Dart error (%s): %s", context, Dart_GetError(handle));
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void CheckError(bool condition, const char* error, const char* context) {
|
||||
if (!condition) {
|
||||
FATAL("Dart error (%s): %s", context, error);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckError(const char* error, const char* context) {
|
||||
if (error != nullptr) {
|
||||
FATAL("Dart error (%s): %s", context, error);
|
||||
}
|
||||
}
|
||||
|
||||
Dart_InitializeParams CreateInitializeParams() {
|
||||
Dart_InitializeParams params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
|
||||
return params;
|
||||
}
|
||||
|
||||
std::string GetExecutablePath() {
|
||||
const size_t kPathBufSize = PATH_MAX + 1;
|
||||
char executable_path[kPathBufSize] = {};
|
||||
|
||||
intptr_t path_length = dart::bin::Platform::ResolveExecutablePathInto(
|
||||
executable_path, kPathBufSize);
|
||||
CheckError(path_length > 0, "empty executable path",
|
||||
"ResolveExecutablePathInfo");
|
||||
return std::string(executable_path, path_length);
|
||||
}
|
||||
|
||||
std::string GetDefaultSnapshotPath() {
|
||||
std::string executable_path = GetExecutablePath();
|
||||
std::string directory =
|
||||
executable_path.substr(0, executable_path.find_last_of("/\\"));
|
||||
return directory + "/gen/hello_kernel.dart.snapshot";
|
||||
}
|
||||
|
||||
std::string ReadSnapshot(std::string_view path) {
|
||||
std::string path_string{path};
|
||||
std::ifstream source_file{path_string, std::ios::binary};
|
||||
|
||||
ASSERT(source_file.good());
|
||||
source_file.seekg(0, source_file.end);
|
||||
uint64_t length = source_file.tellg();
|
||||
source_file.seekg(0, source_file.beg);
|
||||
|
||||
char* bytes = static_cast<char*>(std::malloc(length));
|
||||
source_file.read(bytes, length);
|
||||
return std::string(bytes, length);
|
||||
}
|
||||
|
||||
Dart_Handle ToDartStringList(const std::vector<std::string>& values) {
|
||||
Dart_Handle string_type =
|
||||
CheckHandle(dart::bin::DartUtils::GetDartType("dart:core", "String"));
|
||||
Dart_Handle filler = CheckHandle(Dart_NewStringFromCString(""));
|
||||
|
||||
Dart_Handle result =
|
||||
CheckHandle(Dart_NewListOfTypeFilled(string_type, filler, values.size()));
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
Dart_Handle element =
|
||||
CheckHandle(Dart_NewStringFromCString(values[i].c_str()));
|
||||
CheckHandle(Dart_ListSetAt(result, i, element));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::string snapshot_path =
|
||||
argc == 1 ? GetDefaultSnapshotPath() : std::string(argv[1]);
|
||||
|
||||
std::string snapshot_name =
|
||||
snapshot_path.substr(snapshot_path.find_last_of("/\\") + 1);
|
||||
std::string snapshot_data = ReadSnapshot(snapshot_path);
|
||||
std::string snapshot_uri = "file://" + snapshot_path;
|
||||
std::cout << "Snapshot path: " << snapshot_path << std::endl;
|
||||
char* error;
|
||||
|
||||
// Start Dart VM.
|
||||
CheckError(dart::embedder::InitOnce(&error), error,
|
||||
"dart::embedder::InitOnce");
|
||||
|
||||
std::vector<const char*> flags{};
|
||||
CheckError(Dart_SetVMFlags(flags.size(), flags.data()), "Dart_SetVMFlags");
|
||||
|
||||
Dart_InitializeParams initialize_params = CreateInitializeParams();
|
||||
CheckError(Dart_Initialize(&initialize_params), "Dart_Initialize");
|
||||
|
||||
dart::bin::DFE dfe;
|
||||
dfe.Init();
|
||||
const uint8_t* platform_buffer = nullptr;
|
||||
intptr_t platform_buffer_size = 0;
|
||||
|
||||
dfe.LoadPlatform(&platform_buffer, &platform_buffer_size);
|
||||
|
||||
// Start an isolate from a platform kernel.
|
||||
Dart_IsolateFlags isolate_flags;
|
||||
|
||||
Dart_CreateIsolateGroupFromKernel(
|
||||
/*script_uri=*/snapshot_uri.c_str(),
|
||||
/*name=*/snapshot_name.c_str(),
|
||||
/*kernel_buffer=*/platform_buffer,
|
||||
/*kernel_buffer_size=*/platform_buffer_size,
|
||||
/*flags=*/&isolate_flags,
|
||||
/*isolate_group_data=*/nullptr,
|
||||
/*isolate_data=*/nullptr, &error);
|
||||
CheckError(error, "Dart_CreateIsolateGroupFromKernel");
|
||||
Dart_EnterScope();
|
||||
CheckHandle(dart::bin::DartUtils::PrepareForScriptLoading(
|
||||
/*is_service_isolate=*/false, /*trace_loading=*/false),
|
||||
"PrepareForScriptLoading");
|
||||
|
||||
// Load kernel snapshot to run `main` from.
|
||||
Dart_Handle library =
|
||||
CheckHandle(Dart_LoadLibraryFromKernel(
|
||||
reinterpret_cast<const uint8_t*>(snapshot_data.c_str()),
|
||||
snapshot_data.size()),
|
||||
"Dart_LoadLibraryFromKernel");
|
||||
|
||||
// Call main function with args.
|
||||
std::initializer_list<Dart_Handle> main_args{ToDartStringList({"universe"})};
|
||||
CheckHandle(Dart_Invoke(library, Dart_NewStringFromCString("main"), 1,
|
||||
const_cast<Dart_Handle*>(main_args.begin())),
|
||||
"Dart_Invoke('main')");
|
||||
Dart_ExitScope();
|
||||
Dart_ShutdownIsolate();
|
||||
}
|
||||
Reference in New Issue
Block a user