Skip to content

LLDB setup backup plan #303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/WorkspaceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { FolderContext } from "./FolderContext";
import { StatusItem } from "./ui/StatusItem";
import { SwiftOutputChannel } from "./ui/SwiftOutputChannel";
import {
getSwiftExecutable,
pathExists,
isPathInsidePath,
swiftLibraryPathKey,
Expand Down Expand Up @@ -283,7 +282,7 @@ export class WorkspaceContext implements vscode.Disposable {

/** find LLDB version and setup path in CodeLLDB */
async setLLDBVersion() {
const libPathResult = await getLLDBLibPath(getSwiftExecutable("lldb"));
const libPathResult = await getLLDBLibPath(this.toolchain);
if (!libPathResult.success) {
const errorMessage = libPathResult.failure
? `Error: ${getErrorDescription(libPathResult.failure)}`
Expand Down
22 changes: 12 additions & 10 deletions src/debugger/lldb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,33 @@ import * as path from "path";
import * as fs from "fs/promises";
import { execFile } from "../utilities/utilities";
import { Result } from "../utilities/result";
import { SwiftToolchain } from "../toolchain/toolchain";

/**
* Get LLDB library for given LLDB executable
* @param executable LLDB executable
* @returns Library path for LLDB
*/
export async function getLLDBLibPath(executable: string): Promise<Result<string>> {
export async function getLLDBLibPath(toolchain: SwiftToolchain): Promise<Result<string>> {
const executable = path.join(toolchain.swiftFolderPath, "lldb");
let pathHint = path.dirname(toolchain.swiftFolderPath);
try {
const statement = `print('<!' + lldb.SBHostOS.GetLLDBPath(lldb.ePathTypeLLDBShlibDir).fullpath + '!>')`;
const args = ["-b", "-O", `script ${statement}`];
const { stdout } = await execFile(executable, args);
const m = /^<!([^!]*)!>/m.exec(stdout);
if (m) {
const lldbPath = await findLibLLDB(m[1]);
if (lldbPath) {
return Result.makeSuccess(lldbPath);
} else {
return Result.makeFailure("Failed to find Swift version of LLDB.");
}
pathHint = m[1];
}
} catch (error) {
// ignore error just return undefined
return Result.makeFailure(error);
// ignore error
}
const lldbPath = await findLibLLDB(pathHint);
if (lldbPath) {
return Result.makeSuccess(lldbPath);
} else {
return Result.makeFailure("LLDB failed to provide a library path");
}
return Result.makeFailure("LLDB failed to provide a library path");
}

async function findLibLLDB(pathHint: string): Promise<string | undefined> {
Expand Down
9 changes: 6 additions & 3 deletions src/sourcekit-lsp/LanguageClientManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,14 @@ export class LanguageClientManager {
configuration.path.length > 0 &&
serverPathConfig !== getSwiftExecutable("sourcekit-lsp")
) {
const toolchainPath = this.workspaceContext.toolchain.toolchainPath;
if (toolchainPath) {
// if configuration has custom swift path then set toolchain path
if (configuration.path) {
// eslint-disable-next-line @typescript-eslint/naming-convention
sourcekit.options = {
env: { ...sourcekit.options?.env, SOURCEKIT_TOOLCHAIN_PATH: toolchainPath },
env: {
...sourcekit.options?.env,
SOURCEKIT_TOOLCHAIN_PATH: this.workspaceContext.toolchain.toolchainPath,
},
};
}
}
Expand Down
61 changes: 44 additions & 17 deletions src/toolchain/toolchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ interface SwiftTargetInfo {

export class SwiftToolchain {
constructor(
public swiftFolderPath: string,
public toolchainPath: string,
public swiftVersionString: string,
public swiftVersion: Version,
Expand All @@ -59,7 +60,8 @@ export class SwiftToolchain {
) {}

static async create(): Promise<SwiftToolchain> {
const toolchainPath = await this.getToolchainPath();
const swiftFolderPath = await this.getSwiftFolderPath();
const toolchainPath = await this.getToolchainPath(swiftFolderPath);
const targetInfo = await this.getSwiftTargetInfo();
const swiftVersion = await this.getSwiftVersion(targetInfo);
const runtimePath = await this.getRuntimePath(targetInfo);
Expand All @@ -72,6 +74,7 @@ export class SwiftToolchain {
customSDK ?? defaultSDK
);
return new SwiftToolchain(
swiftFolderPath,
toolchainPath,
targetInfo.compilerVersion,
swiftVersion,
Expand All @@ -84,6 +87,7 @@ export class SwiftToolchain {
}

logDiagnostics(channel: SwiftOutputChannel) {
channel.logDiagnostic(`Swift Path: ${this.swiftFolderPath}`);
channel.logDiagnostic(`Toolchain Path: ${this.toolchainPath}`);
if (this.runtimePath) {
channel.logDiagnostic(`Runtime Library Path: ${this.runtimePath}`);
Expand All @@ -102,24 +106,22 @@ export class SwiftToolchain {
}
}

/**
* @returns path to Toolchain folder
*/
private static async getToolchainPath(): Promise<string> {
private static async getSwiftFolderPath(): Promise<string> {
if (configuration.path !== "") {
return path.dirname(path.dirname(configuration.path));
return configuration.path;
}
try {
let swift: string;
switch (process.platform) {
case "darwin": {
const { stdout } = await execFile("xcrun", ["--find", "swiftc"]);
const swiftc = stdout.trimEnd();
return path.dirname(path.dirname(path.dirname(swiftc)));
const { stdout } = await execFile("which", ["swift"]);
swift = stdout.trimEnd();
break;
}
case "win32": {
const { stdout } = await execFile("where", ["swiftc"]);
const swiftc = stdout.trimEnd();
return path.dirname(path.dirname(path.dirname(swiftc)));
const { stdout } = await execFile("where", ["swift"]);
swift = stdout.trimEnd();
break;
}
default: {
// use `type swift` to find `swift`. Run inside /bin/sh to ensure
Expand All @@ -128,19 +130,44 @@ export class SwiftToolchain {
const { stdout } = await execFile("/bin/sh", ["-c", "type swift"]);
const swiftMatch = /^swift is (.*)$/.exec(stdout.trimEnd());
if (swiftMatch) {
const swift = swiftMatch[1];
// swift may be a symbolic link
const realSwift = await fs.realpath(swift);
return path.dirname(path.dirname(path.dirname(realSwift)));
swift = swiftMatch[1];
} else {
throw Error("Failed to find swift executable");
}
throw Error("Failed to find swift executable");
break;
}
}
// swift may be a symbolic link
const realSwift = await fs.realpath(swift);
return path.dirname(realSwift);
} catch {
throw Error("Failed to find swift executable");
}
}

/**
* @returns path to Toolchain folder
*/
private static async getToolchainPath(swiftPath: string): Promise<string> {
if (configuration.path !== "") {
return path.dirname(path.dirname(configuration.path));
}
try {
switch (process.platform) {
case "darwin": {
const { stdout } = await execFile("xcrun", ["--find", "swift"]);
const swift = stdout.trimEnd();
return path.dirname(path.dirname(path.dirname(swift)));
}
default: {
return path.dirname(path.dirname(path.dirname(swiftPath)));
}
}
} catch {
throw Error("Failed to find swift toolchain");
}
}

/**
* @param targetInfo swift target info
* @returns path to Swift runtime
Expand Down