9#include "lldb/Host/Config.h"
14#include "llvm/ADT/STLFunctionalExtras.h"
15#include "llvm/ADT/ScopeExit.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/Support/FileSystem.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/Path.h"
21#include "llvm/Support/Program.h"
33constexpr llvm::StringLiteral kAppleFrameworkSuffix =
34 "Library/Frameworks/Python3.framework/Versions/Current/Python3";
35constexpr llvm::StringLiteral kPythonOrgFrameworkSuffix =
36 "Library/Frameworks/Python.framework/Versions/Current/Python";
38bool TryIfExists(llvm::function_ref<
bool(
const char *)> callback,
39 llvm::StringRef base, llvm::StringRef relative) {
40 llvm::SmallString<256> path(base);
41 llvm::sys::path::append(path, relative);
42 if (!llvm::sys::fs::exists(path))
44 return callback(path.c_str());
49std::string FindPythonViaXcrun() {
50 llvm::ErrorOr<std::string>
xcrun = llvm::sys::findProgramByName(
"xcrun");
54 llvm::SmallString<128> stdout_path;
55 if (llvm::sys::fs::createTemporaryFile(
"xcrun-python3",
"txt", stdout_path))
58 llvm::scope_exit([&] { llvm::sys::fs::remove(stdout_path.str()); });
60 std::optional<llvm::StringRef> redirects[3] = {
61 llvm::StringRef(
""), llvm::StringRef(stdout_path), llvm::StringRef(
"")};
62 llvm::StringRef args[] = {*
xcrun,
"-f",
"python3"};
64 llvm::sys::ExecuteAndWait(*
xcrun, args, std::nullopt, redirects);
68 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buf =
69 llvm::MemoryBuffer::getFile(stdout_path.str());
73 llvm::StringRef
python = (*buf)->getBuffer().rtrim();
79 if (llvm::sys::path::filename(
python) !=
"python3")
81 llvm::StringRef parent = llvm::sys::path::parent_path(
python);
82 if (llvm::sys::path::filename(parent) !=
"bin")
84 llvm::StringRef grandparent = llvm::sys::path::parent_path(parent);
85 if (llvm::sys::path::filename(grandparent) !=
"usr")
87 llvm::StringRef developer = llvm::sys::path::parent_path(grandparent);
89 llvm::SmallString<256> framework(developer);
90 llvm::sys::path::append(framework, kAppleFrameworkSuffix);
91 if (llvm::sys::fs::exists(framework))
92 return std::string(framework);
100 llvm::function_ref<
bool(
const char *)> callback) {
101 if (
const char *developer_dir = std::getenv(
"DEVELOPER_DIR");
102 developer_dir && *developer_dir)
103 if (TryIfExists(callback, developer_dir, kAppleFrameworkSuffix))
106 if (TryIfExists(callback,
"/Applications/Xcode.app/Contents/Developer",
107 kAppleFrameworkSuffix))
109 if (TryIfExists(callback,
"/Library/Developer/CommandLineTools",
110 kAppleFrameworkSuffix))
112 if (TryIfExists(callback,
"/", kPythonOrgFrameworkSuffix))
114 if (TryIfExists(callback,
"/opt/homebrew", kPythonOrgFrameworkSuffix))
116 if (TryIfExists(callback,
"/usr/local", kPythonOrgFrameworkSuffix))
120 if (std::string xcrun_path = FindPythonViaXcrun(); !xcrun_path.empty())
121 if (callback(xcrun_path.c_str()))
125 callback(
"libpython3.dylib");
static llvm::Expected< std::string > xcrun(const std::string &sdk, llvm::ArrayRef< llvm::StringRef > arguments, llvm::StringRef developer_dir="")
A class that represents a running process on the host machine.
void ForEachPythonRuntimeCandidate(llvm::function_ref< bool(const char *)> callback)
Visits candidate Python runtime paths in priority order, stopping at the first call that returns true...