Skip to content

Commit

Permalink
πŸ‘©β€πŸ’» Create a build dart script, add github actions
Browse files Browse the repository at this point in the history
I want to be able to create usable arifacts quickly, and be able to update versions of dart quickly, so I've added a script to fetch and build dart, and a github action to try to automatically build artifacts
  • Loading branch information
fuzzybinary committed Sep 23, 2023
1 parent 8ccb606 commit c20be63
Show file tree
Hide file tree
Showing 12 changed files with 797 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .dart_version
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This file contains the current Dart version we build against
3.0.7
21 changes: 21 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Build Dart Shared Library
on:
push:
branches:
- main
pull_request:
jobs:
build_windows:
runs-on: [windows-latest]
steps:
- uses: actions/checkout@v3
- uses: dart-lang/setup-dart@v1
- uses: ilammy/msvc-dev-cmd@v1
- uses: threal/cmake-action@v1
- run: dart pub get
working-directory: ./scripts/build_helpers
- name: Build Dart
run: dart ./scripts/build_helpers/bin/build_dart.dart
- name: Build Shared Library
run: cmake -B .\.build . && cmake --build .\.build --config release

8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"files.exclude": {
"**/.git": true, // this is a default value
"**/.DS_Store": true, // this is a default value

"dart-sdk/": true
}
}
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ The hope is that the the dynamic library will eventually support the following t
* A "Fully Featured" .dll / .so that supports booting Dart in different configurations:
* Boot (or not) the service and kernel isolates
* Support Dart Source Compilation and / or Kernel Isolates
* Support "AOT only" mode? (aka, just the runtime)
* A JIT Only .dll / .so
* A AOT Only .dll / .so (aka, just the runtime)
* JIT from source or .dil
* An AOT Only .dll / .so

Additionally we may have a static target that uses the same interface as the dynamic library, so the VM can be embedded on platforms that don't support dynamic linking.

Expand Down
3 changes: 3 additions & 0 deletions scripts/build_helpers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
3 changes: 3 additions & 0 deletions scripts/build_helpers/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
25 changes: 25 additions & 0 deletions scripts/build_helpers/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

linter:
rules:
- camel_case_types
- prefer_relative_imports

# analyzer:
# exclude:
# - path/to/excluded/files/**
162 changes: 162 additions & 0 deletions scripts/build_helpers/bin/build_dart.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import 'dart:async';
import 'dart:io';

import 'package:args/args.dart';
import 'package:build_helpers/build_helpers.dart';
import 'package:logger/logger.dart';
import 'package:path/path.dart' as path;

void main(List<String> args) async {
final parser = ArgParser();
parser.addFlag('verbose', abbr: 'v');

final argResults = parser.parse(args);
Level logLevel = Level.info;
if (argResults['verbose'] == true) {
logLevel = Level.debug;
}

if (!checkRightDirectory()) {
// Not run from root. Exit.
exit(-1);
}

if (Platform.isWindows) {
final depotToolsEnv = Platform.environment['DEPOT_TOOLS_WIN_TOOLCHAIN'];
if (depotToolsEnv == null) {
BuildToolsLogger.shared.e(
'DEPOT_TOOLS_WIN_TOOOLCHAIN not set! Run ./setup_env.ps1 before running this script!');
exit(-1);
}
}

BuildToolsLogger.initLogger(logLevel: logLevel);
if (!await checkForDepotTools()) {
if (!await getDepotTools()) {
// Fatal. Can't do this without depot_tools
exit(-1);
}
}

try {
if (!await _fetchOrUpdateDartSdk()) {
exit(-1);
}

if (!await _patchDartSdk()) {
exit(-1);
}

if (!await _buildDart()) {
exit(-1);
}
} catch (e) {
BuildToolsLogger.shared.f('Caught an exception building the Dart SDK:');
BuildToolsLogger.shared.f(e);
exit(-1);
}
}

Future<bool> _fetchOrUpdateDartSdk() async {
final logger = BuildToolsLogger.shared;
final dartVersion = await _fetchRequestedDartVersion();

if (!Directory('dart-sdk').existsSync()) {
logger.i('dart-sdk does not exist. Doing full fetch');

Directory('dart-sdk').create();

final fetchResult = await inDir('dart-sdk', () async {
final fetchProcess =
await startAppendingDepotToolsPath('fetch', ['--no-history', 'dart']);
var fetchResult = await waitForProcessFinish(fetchProcess);
return fetchResult;
});
if (fetchResult != 0) return false;
}

final finalResult = await inDir(path.join('dart-sdk', 'sdk'), () async {
logger.i('Checking out tag $dartVersion');
final fetchProcess = await Process.start(
'git',
['fetch', 'origin', 'refs/tags/$dartVersion:refs/tags/$dartVersion'],
runInShell: true,
);
var fetchResult = await waitForProcessFinish(fetchProcess);
if (fetchResult != 0) return fetchResult;

final checkoutProcess = await Process.start(
'git',
['checkout', '-f', 'tags/$dartVersion'],
runInShell: true,
);
var checkoutResult = await waitForProcessFinish(checkoutProcess);
if (checkoutResult != 0) return checkoutResult;

logger.i('Performing `gclient sync -D --no-history');
final syncProcess = await Process.start(
'gclient',
['sync', '-D', '--no-history'],
runInShell: true,
);
var syncResult = await waitForProcessFinish(syncProcess);
if (syncResult != 0) return syncResult;

return 0;
});

return finalResult == 0;
}

Future<String> _fetchRequestedDartVersion() async {
final lines = await File('.dart_version').readAsLines();
for (var line in lines) {
if (line.startsWith('#')) {
continue;
}

return line;
}
throw Exception('Only found comments in the `.dart_version` file!');
}

Future<bool> _patchDartSdk() async {
final logger = BuildToolsLogger.shared;
final result = await inDir('dart-sdk/sdk', () async {
logger.i("Patching the Dart SDK to create libdart");
var result = await Process.run('git', ['apply', '../../dart_sdk.patch'],
runInShell: true);
logger.d(result.stdout);
return result.exitCode;
});
if (result != 0) {
logger.f('Failed to apply patch.');
}

return result == 0;
}

Future<bool> _buildDart() async {
final logger = BuildToolsLogger.shared;
final result = await inDir('dart-sdk/sdk', () async {
logger.i("Building libdart");
var script = './tools/build.py';
var args = ['--no-goma', '-m', 'release', 'libdart'];
var command = script;
if (Platform.isWindows) {
command = 'python';
args.insert(0, script);
}
final buildProcess = await Process.start(
command,
args,
runInShell: true,
);
var buildResult = await waitForProcessFinish(buildProcess);
return buildResult;
});
if (result != 0) {
logger.f('Failed to build dart.');
}
return result == 0;
}
81 changes: 81 additions & 0 deletions scripts/build_helpers/lib/build_helpers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:logger/logger.dart';
import 'package:path/path.dart' as path;

export 'depot_tools.dart';

class BuildToolsLogger {
static Logger? _shared;
static Logger get shared {
_shared ??= initLogger();
return _shared!;
}

static Logger initLogger({Level logLevel = Level.info}) {
return Logger(
filter: ProductionFilter(),
level: logLevel,
printer: SimplePrinter(),
);
}
}

bool checkRightDirectory() {
final logger = BuildToolsLogger.shared;

final currentDir = Directory.current;
// Check if the .dart_version and the patch file are there.
if (!File(path.join(currentDir.path, '.dart_version')).existsSync()) {
logger.f(
'Could not find `.dart_version`. Make sure you\'re running from the root of the `dart_dll` repo.');
return false;
}

if (!File(path.join(currentDir.path, 'dart_sdk.patch')).existsSync()) {
logger.f(
'Could not find `dart_sdk.pathch`. Make sure you\'re running from the root of the `dart_dll` repo.');
return false;
}

return true;
}

// Waits for the process to finish, outputting output to the BuildToolsLogger
Future<int> waitForProcessFinish(Process process) async {
final logger = BuildToolsLogger.shared;
final stdoutCompleter = Completer();
final stderrCompleter = Completer();

process.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen(
(l) {
logger.i(l);
},
).onDone(() {
stdoutCompleter.complete();
});

process.stderr.transform(utf8.decoder).transform(const LineSplitter()).listen(
(l) {
logger.i(l);
},
).onDone(() {
stderrCompleter.complete();
});

var exitCode = await process.exitCode;

await (Future.wait([stdoutCompleter.future, stderrCompleter.future]));

return exitCode;
}

Future<T> inDir<T>(String directory, Future<T> Function() callback) async {
final oldDir = Directory.current;
Directory.current = Directory(directory);
final result = await callback();
Directory.current = oldDir;
return result;
}
Loading

0 comments on commit c20be63

Please sign in to comment.