| // Copyright (c) 2020, 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 'dart:io'; |
| |
| import 'package:path/path.dart' as path; |
| |
| final Sdk sdk = Sdk._instance; |
| |
| /// A utility class for finding and referencing paths within the Dart SDK. |
| class Sdk { |
| static final Sdk _instance = _createSingleton(); |
| |
| /// Path to SDK directory. |
| final String sdkPath; |
| |
| /// The SDK's semantic versioning version (x.y.z-a.b.channel). |
| final String version; |
| |
| /// The SDK's git revision, if known. |
| final String? revision; |
| |
| final bool runFromBuildRoot; |
| |
| factory Sdk() => _instance; |
| |
| Sdk._(this.sdkPath, this.version, this.revision, this.runFromBuildRoot); |
| |
| // Assume that we want to use the same Dart executable that we used to spawn |
| // DartDev. We should be able to run programs with out/ReleaseX64/dart even |
| // if the SDK isn't completely built. |
| String get dart => _executablePathFor( |
| path.basename(Platform.executable), |
| ); |
| |
| String get dartvm => _executablePathFor( |
| 'dartvm', |
| ); |
| |
| String get dartAotRuntime => _executablePathFor( |
| 'dartaotruntime', |
| forceProductInBuildRoot: true, |
| ); |
| |
| String get genSnapshot => _executablePathFor( |
| 'gen_snapshot', |
| forceProductInBuildRoot: true, |
| sdkRelativePath: 'utils', |
| ); |
| |
| String get genKernelSnapshot => _snapshotPathFor( |
| 'gen_kernel_aot.dart.snapshot', |
| ); |
| |
| String get analysisServerAotSnapshot => _snapshotPathFor( |
| 'analysis_server_aot.dart.snapshot', |
| ); |
| |
| String get analysisServerSnapshot => _snapshotPathFor( |
| 'analysis_server.dart.snapshot', |
| ); |
| |
| String get ddcAotSnapshot => runFromBuildRoot |
| ? _snapshotPathFor( |
| 'dartdevc_aot_product.dart.snapshot', |
| ) |
| : _snapshotPathFor( |
| 'dartdevc_aot.dart.snapshot', |
| ); |
| |
| String get dart2jsAotSnapshot => runFromBuildRoot |
| ? _snapshotPathFor( |
| 'dart2js_aot_product.dart.snapshot', |
| ) |
| : _snapshotPathFor( |
| 'dart2js_aot.dart.snapshot', |
| ); |
| |
| String get dart2wasmSnapshot => _snapshotPathFor( |
| 'dart2wasm_product.snapshot', |
| ); |
| |
| String get dartMCPServerAotSnapshot => _snapshotPathFor( |
| 'dart_mcp_server_aot.dart.snapshot', |
| ); |
| |
| String get ddsAotSnapshot => _snapshotPathFor( |
| 'dds_aot.dart.snapshot', |
| ); |
| |
| String get frontendServerAotSnapshot => runFromBuildRoot |
| ? _snapshotPathFor( |
| 'frontend_server_aot_product.dart.snapshot', |
| ) |
| : _snapshotPathFor( |
| 'frontend_server_aot.dart.snapshot', |
| ); |
| |
| String get dtdAotSnapshot => _snapshotPathFor( |
| 'dart_tooling_daemon_aot.dart.snapshot', |
| ); |
| |
| String get devToolsBinaries => path.absolute( |
| runFromBuildRoot |
| ? sdkPath |
| : path.absolute( |
| sdkPath, |
| 'bin', |
| 'resources', |
| ), |
| 'devtools', |
| ); |
| |
| String get wasmOpt => path.absolute( |
| runFromBuildRoot |
| ? sdkPath |
| : path.absolute( |
| sdkPath, |
| 'bin', |
| 'utils', |
| ), |
| Platform.isWindows ? 'wasm-opt.exe' : 'wasm-opt', |
| ); |
| |
| // This file is only generated when building the SDK and isn't generated for |
| // non-SDK build targets. |
| String get librariesJson => path.absolute(sdkPath, 'lib', 'libraries.json'); |
| |
| String get vmPlatformDill => _dillPathFor( |
| 'vm_platform.dill', |
| ); |
| |
| String get vmPlatformProductDill => _dillPathFor( |
| 'vm_platform_product.dill', |
| ); |
| |
| String get wasmPlatformDill => _dillPathFor( |
| 'dart2wasm_platform.dill', |
| ); |
| |
| String _dillPathFor(String dillName) => path.absolute( |
| runFromBuildRoot |
| ? sdkPath |
| : path.join( |
| sdkPath, |
| 'lib', |
| '_internal', |
| ), |
| dillName); |
| |
| String _executablePathFor(String executableName, |
| {bool forceProductInBuildRoot = false, String? sdkRelativePath}) { |
| if (Platform.isWindows && executableName.endsWith('.exe')) { |
| // Don't modify the executable name on Windows if it already includes |
| // the extension. |
| assert(!forceProductInBuildRoot); |
| } else { |
| if (runFromBuildRoot && forceProductInBuildRoot) { |
| executableName = '${executableName}_product'; |
| } |
| if (Platform.isWindows) { |
| executableName = '$executableName.exe'; |
| } |
| } |
| return path.absolute( |
| runFromBuildRoot |
| ? sdkPath |
| : path.absolute( |
| sdkPath, |
| 'bin', |
| sdkRelativePath, |
| ), |
| executableName); |
| } |
| |
| String _snapshotPathFor(String snapshotName) => path.absolute( |
| runFromBuildRoot |
| ? sdkPath |
| : path.absolute( |
| sdkPath, |
| 'bin', |
| 'snapshots', |
| ), |
| snapshotName, |
| ); |
| |
| static Sdk _createSingleton() { |
| // Find SDK path. |
| (String, bool)? trySDKPath(String executablePath) { |
| // The common case, and how cli_util.dart computes the Dart SDK directory, |
| // [path.dirname] called twice on Platform.executable. We confirm by |
| // asserting that the directory `./bin/snapshots/` exists in this directory: |
| var sdkPath = path.absolute(path.dirname(path.dirname(executablePath))); |
| var snapshotsDir = path.join(sdkPath, 'bin', 'snapshots'); |
| var runFromBuildRoot = false; |
| final type = FileSystemEntity.typeSync(snapshotsDir); |
| if (type != FileSystemEntityType.directory && |
| type != FileSystemEntityType.link) { |
| // This is the less common case where the user is in |
| // the checked out Dart SDK, and is executing `dart` via: |
| // ./out/ReleaseX64/dart ... or in google3. |
| sdkPath = path.absolute(path.dirname(executablePath)); |
| snapshotsDir = sdkPath; |
| runFromBuildRoot = true; |
| } |
| |
| // Try to locate the DartDev snapshot to determine if we're able to find |
| // the SDK snapshots with this SDK path. This is meant to handle |
| // non-standard SDK layouts that can involve symlinks (e.g., Brew |
| // installations, google3 tests, etc). |
| final snapshot = path.join(snapshotsDir, 'dartdev_aot.dart.snapshot'); |
| if (FileSystemEntity.typeSync(snapshot) == |
| FileSystemEntityType.notFound) { |
| return null; |
| } |
| return (sdkPath, runFromBuildRoot); |
| } |
| |
| final (sdkPath, runFromBuildRoot) = |
| trySDKPath(Platform.resolvedExecutable) ?? |
| trySDKPath(Platform.executable)!; |
| |
| // Defer to [Runtime] for the version. |
| final version = Runtime.runtime.version; |
| |
| return Sdk._(sdkPath, version, getRevision(sdkPath), runFromBuildRoot); |
| } |
| |
| /// Reads the contents of `revision` file at SDK root. |
| /// |
| /// Returns `null` if the file does not exist. |
| static String? getRevision(String sdkPath) { |
| String? revision; |
| final revisionFile = File(path.join(sdkPath, 'revision')); |
| if (revisionFile.existsSync()) { |
| revision = revisionFile.readAsStringSync().trim(); |
| } |
| return revision; |
| } |
| } |
| |
| /// Information about the current runtime. |
| class Runtime { |
| static Runtime runtime = _createSingleton(); |
| |
| /// The SDK's semantic versioning version (x.y.z-a.b.channel). |
| final String version; |
| |
| /// The SDK's release channel (`main`, `dev`, `beta`, `stable`). |
| /// |
| /// May be null if [Platform.version] does not have the expected format. |
| final String? channel; |
| |
| Runtime._(this.version, this.channel); |
| |
| static Runtime _createSingleton() { |
| final versionString = Platform.version; |
| // Expected format: "version (channel) ..." |
| var version = versionString; |
| String? channel; |
| final versionEnd = versionString.indexOf(' '); |
| if (versionEnd > 0) { |
| version = versionString.substring(0, versionEnd); |
| var channelEnd = versionString.indexOf(' ', versionEnd + 1); |
| if (channelEnd < 0) channelEnd = versionString.length; |
| if (versionString.startsWith('(', versionEnd + 1) && |
| versionString.startsWith(')', channelEnd - 1)) { |
| channel = versionString.substring(versionEnd + 2, channelEnd - 1); |
| } |
| } |
| return Runtime._(version, channel); |
| } |
| } |
| |
| const useAotSnapshotFlag = 'use-aot-snapshot'; |