diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart index a67a7c55dc3..9ce1ed12810 100644 --- a/pkg/dartdev/lib/src/sdk.dart +++ b/pkg/dartdev/lib/src/sdk.dart @@ -30,7 +30,7 @@ class Sdk { // 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 => Platform.resolvedExecutable; + String get dart => Platform.executable; String get dartAotRuntime => _runFromBuildRoot ? path.absolute( @@ -149,22 +149,37 @@ class Sdk { 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; + if (!Directory(snapshotsDir).existsSync()) { + // 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; + } - // The common case, and how cli_util.dart computes the Dart SDK directory, - // [path.dirname] called twice on Platform.resolvedExecutable. We confirm by - // asserting that the directory `./bin/snapshots/` exists in this directory: - var sdkPath = - path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable))); - var snapshotsDir = path.join(sdkPath, 'bin', 'snapshots'); - var runFromBuildRoot = false; - if (!Directory(snapshotsDir).existsSync()) { - // 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(Platform.resolvedExecutable)); - 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). + if (!File(path.join(snapshotsDir, 'dartdev.dart.snapshot')) + .existsSync()) { + return null; + } + return (sdkPath, runFromBuildRoot); } + final (sdkPath, runFromBuildRoot) = + trySDKPath(Platform.resolvedExecutable) ?? + trySDKPath(Platform.executable)!; + // Defer to [Runtime] for the version. var version = Runtime.runtime.version; diff --git a/runtime/bin/dartdev_isolate.cc b/runtime/bin/dartdev_isolate.cc index 7116b7dad56..d00a10e9236 100644 --- a/runtime/bin/dartdev_isolate.cc +++ b/runtime/bin/dartdev_isolate.cc @@ -80,25 +80,37 @@ bool DartDevIsolate::ShouldParseCommand(const char* script_uri) { } CStringUniquePtr DartDevIsolate::TryResolveArtifactPath(const char* filename) { - // |dir_prefix| includes the last path separator. - auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName(); + auto try_resolve_path = [&](CStringUniquePtr dir_prefix) { + // First assume we're in dart-sdk/bin. + char* snapshot_path = + Utils::SCreate("%ssnapshots/%s", dir_prefix.get(), filename); + if (File::Exists(nullptr, snapshot_path)) { + return CStringUniquePtr(snapshot_path); + } + free(snapshot_path); - // First assume we're in dart-sdk/bin. - char* snapshot_path = - Utils::SCreate("%ssnapshots/%s", dir_prefix.get(), filename); - if (File::Exists(nullptr, snapshot_path)) { - return CStringUniquePtr(snapshot_path); - } - free(snapshot_path); + // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/* + // directories. Try to use a snapshot from a previously built SDK. + snapshot_path = Utils::SCreate("%s%s", dir_prefix.get(), filename); + if (File::Exists(nullptr, snapshot_path)) { + return CStringUniquePtr(snapshot_path); + } + free(snapshot_path); + return CStringUniquePtr(nullptr); + }; - // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/* - // directories. Try to use a snapshot from a previously built SDK. - snapshot_path = Utils::SCreate("%s%s", dir_prefix.get(), filename); - if (File::Exists(nullptr, snapshot_path)) { - return CStringUniquePtr(snapshot_path); + // Try to find the artifact using the resolved EXE path first. This can fail + // if the Dart SDK file structure is faked using symlinks and the actual + // artifacts are spread across directories on the file system (e.g., some + // google3 execution environments). + auto result = + try_resolve_path(EXEUtils::GetDirectoryPrefixFromResolvedExeName()); + if (result == nullptr) { + result = + try_resolve_path(EXEUtils::GetDirectoryPrefixFromUnresolvedExeName()); } - free(snapshot_path); - return CStringUniquePtr(nullptr); + + return result; } CStringUniquePtr DartDevIsolate::TryResolveDartDevSnapshotPath() { diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc index 898c29562c0..12e2546bba2 100644 --- a/runtime/bin/dfe.cc +++ b/runtime/bin/dfe.cc @@ -101,7 +101,7 @@ void DFE::InitKernelServiceAndPlatformDills() { } // |dir_prefix| includes the last path separator. - auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName(); + auto dir_prefix = EXEUtils::GetDirectoryPrefixFromResolvedExeName(); // Look for the frontend snapshot next to the executable. frontend_filename_ = diff --git a/runtime/bin/exe_utils.cc b/runtime/bin/exe_utils.cc index 3b8d6fa50e1..2e4049ea322 100644 --- a/runtime/bin/exe_utils.cc +++ b/runtime/bin/exe_utils.cc @@ -65,7 +65,7 @@ static const char* GetFileNameFromPath(const char* path) { return path; } -CStringUniquePtr EXEUtils::GetDirectoryPrefixFromExeName() { +CStringUniquePtr EXEUtils::GetDirectoryPrefixFromResolvedExeName() { const char* name = nullptr; const int kTargetSize = PATH_MAX; char target[kTargetSize]; @@ -119,6 +119,12 @@ CStringUniquePtr EXEUtils::GetDirectoryPrefixFromExeName() { return CStringUniquePtr(result == nullptr ? Utils::StrDup("") : result); } +CStringUniquePtr EXEUtils::GetDirectoryPrefixFromUnresolvedExeName() { + const char* exe = Platform::GetExecutableName(); + return CStringUniquePtr(exe == nullptr ? nullptr + : GetDirectoryFromPath(exe, nullptr)); +} + #if !defined(DART_HOST_OS_WINDOWS) void EXEUtils::LoadDartProfilerSymbols(const char* argv0) { char* path = reinterpret_cast(malloc(PATH_MAX + 5)); diff --git a/runtime/bin/exe_utils.h b/runtime/bin/exe_utils.h index 1540cd53287..b2fba1bcc62 100644 --- a/runtime/bin/exe_utils.h +++ b/runtime/bin/exe_utils.h @@ -17,8 +17,15 @@ namespace bin { class EXEUtils { public: - // Returns the path to the directory the current executable resides in. - static CStringUniquePtr GetDirectoryPrefixFromExeName(); + // Returns the resolved path to the directory the current executable resides + // in. + static CStringUniquePtr GetDirectoryPrefixFromResolvedExeName(); + + // Returns the path to the directory the current executable resides + // in without following symlinks. + // + // Returns null if Platform::GetExecutableName() returns null. + static CStringUniquePtr GetDirectoryPrefixFromUnresolvedExeName(); #if !defined(DART_HOST_OS_WINDOWS) // Loads a compact symbolization table from "$exepath.sym" that is used by the