Skip to content

[WIP] Fully support cross-compilation model based on destination.json #386

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

Closed
wants to merge 3 commits into from
Closed
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
17 changes: 14 additions & 3 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,22 @@ This is a list of environment variables to set when running swift (build, resolv

- **Runtime Path**

Where to find Swift runtime libraries. This is mainly of use when these libraries cannot be discovered via the RPATH. On Windows the runtime path is added to the `Path` environment variable. This is of less use on macOS and Linux but will be added to `DYLD_LIBRARY_PATH` and `LD_LIBRARY_PATH` environment variables respectively on each platform. This is of use when supporting non-standard SDK layouts on Windows
Where to find Swift runtime libraries. This is mainly of use when these libraries cannot be discovered via the RPATH. On Windows the runtime path is added to the `Path` environment variable. This is of less use on macOS and Linux but will be added to `DYLD_LIBRARY_PATH` and `LD_LIBRARY_PATH` environment variables respectively on each platform.

- **SDK**
- **Destination**

The path of the target SDK to compile against. The default SDK is determined by the environment on macOS and Windows. This is of use when supporting non-standard SDK layouts on Windows and using custom SDKs. This adds the `--sdk` command line parameter to the relevant `swift` calls.
The build destination for SwiftPM projects. If the value is a string, the plugin will load the `destination.json` file at the given path. If the value is an object, the plugin will map the value as follows and generate the `destination.json` automatically.

| Configuration key | Description | `destination.json` key | Default value |
|---|---|---|---|
| `target`| The target triple of build destination. | `target` | `null` |
| `sdk` | The path of the SDK to build against. | `sdk` | `null` |
| `binDir` | The path of the folder containing tool binaries. | `toolchain-bin-dir` | The `usr/bin` subdirectory of the Swift toolchain. |
| `extraSwiftCFlags` | Additional arguments to pass to the Swift compiler. | `extra-swiftc-flags` | `[]` |
| `extraCCFlags` | Additional arguments to pass to the C compiler. | `extra-cc-flags` | `[]` |
| `extraCPPFlags` | Additional arguments to pass to the C++ compiler. | `extra-cpp-flags` | `[]` |

Hot reload is available for either way of specifying build destination.

- **Diagnostics**

Expand Down
47 changes: 43 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,49 @@
"description": "The path of the folder containing the Swift runtime libraries. Only effective when they can't be discovered by RPath.",
"order": 2
},
"swift.SDK": {
"type": "string",
"swift.destination": {
"type": [
"object",
"string"
],
"properties": {
"target": {
"type": "string",
"default": "",
"description": "The target triple of build destination."
},
"sdk": {
"type": "string",
"default": "",
"description": "The path of the SDK to build against."
},
"binDir": {
"type": "string",
"default": "",
"description": "The path of the folder containing tool binaries. The default is to look in current toolchain."
},
"extraSwiftCFlags": {
"type": "array",
"items": "string",
"default": [],
"description": "Additional arguments to pass to the Swift compiler."
},
"extraCCFlags": {
"type": "array",
"items": "string",
"default": [],
"description": "Additional arguments to pass to the C compiler."
},
"extraCPPFlags": {
"type": "array",
"items": "string",
"default": [],
"description": "Additional arguments to pass to the C++ compiler."
}
},
"additionalProperties": false,
"default": "",
"description": "The path of the SDK to compile against (`--sdk` parameter). The default SDK is determined by the environment on macOS and Windows.",
"markdownDescription": "Destination configuration object or path to the `destination.json` file.",
"order": 3
},
"swift.diagnostics": {
Expand Down Expand Up @@ -433,4 +472,4 @@
"plist": "^3.0.5",
"vscode-languageclient": "^8.0.0"
}
}
}
6 changes: 3 additions & 3 deletions src/SwiftPluginTaskProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import * as path from "path";
import { WorkspaceContext } from "./WorkspaceContext";
import { PackagePlugin } from "./SwiftPackage";
import configuration from "./configuration";
import { getSwiftExecutable, swiftRuntimeEnv, withSwiftSDKFlags } from "./utilities/utilities";
import { getSwiftExecutable, swiftRuntimeEnv, withSwiftFlags } from "./utilities/utilities";

// Interface class for defining task configuration
interface TaskConfig {
Expand Down Expand Up @@ -80,7 +80,7 @@ export class SwiftPluginTaskProvider implements vscode.TaskProvider {
task.definition.command,
...task.definition.args,
];
swiftArgs = withSwiftSDKFlags(swiftArgs);
swiftArgs = withSwiftFlags(swiftArgs, undefined);

const newTask = new vscode.Task(
task.definition,
Expand Down Expand Up @@ -108,7 +108,7 @@ export class SwiftPluginTaskProvider implements vscode.TaskProvider {
createSwiftPluginTask(plugin: PackagePlugin, args: string[], config: TaskConfig): vscode.Task {
const swift = getSwiftExecutable();
let swiftArgs = ["package", plugin.command, ...args];
swiftArgs = withSwiftSDKFlags(swiftArgs);
swiftArgs = withSwiftFlags(swiftArgs, undefined);

// Add relative path current working directory
const relativeCwd = path.relative(config.scope.uri.fsPath, config.cwd?.fsPath);
Expand Down
9 changes: 7 additions & 2 deletions src/SwiftTaskProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import { WorkspaceContext } from "./WorkspaceContext";
import { FolderContext } from "./FolderContext";
import { Product } from "./SwiftPackage";
import configuration from "./configuration";
import { getSwiftExecutable, swiftRuntimeEnv, withSwiftSDKFlags } from "./utilities/utilities";
import { getSwiftExecutable, swiftRuntimeEnv, withSwiftFlags } from "./utilities/utilities";
import { Version } from "./utilities/version";
import { Destination } from "./toolchain/destination";

/**
* References:
Expand All @@ -40,6 +41,7 @@ interface TaskConfig {
problemMatcher?: string | string[];
presentationOptions?: vscode.TaskPresentationOptions;
prefix?: string;
destination?: Destination;
}

/** flag for enabling test discovery */
Expand Down Expand Up @@ -92,6 +94,7 @@ export function createBuildAllTask(folderContext: FolderContext): vscode.Task {
reveal: vscode.TaskRevealKind.Silent,
},
problemMatcher: configuration.problemMatchCompileErrors ? "$swiftc" : undefined,
destination: folderContext.workspaceContext.toolchain.destination,
}
);
}
Expand Down Expand Up @@ -160,6 +163,7 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
reveal: vscode.TaskRevealKind.Silent,
},
problemMatcher: configuration.problemMatchCompileErrors ? "$swiftc" : undefined,
destination: folderContext.workspaceContext.toolchain.destination,
}
),
createSwiftTask(
Expand All @@ -173,6 +177,7 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
reveal: vscode.TaskRevealKind.Silent,
},
problemMatcher: configuration.problemMatchCompileErrors ? "$swiftc" : undefined,
destination: folderContext.workspaceContext.toolchain.destination,
}
),
];
Expand All @@ -183,7 +188,7 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
*/
export function createSwiftTask(args: string[], name: string, config: TaskConfig): vscode.Task {
const swift = getSwiftExecutable();
args = withSwiftSDKFlags(args);
args = withSwiftFlags(args, config.destination);

// Add relative path current working directory
const cwd = config.cwd.fsPath;
Expand Down
4 changes: 2 additions & 2 deletions src/WorkspaceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ export class WorkspaceContext implements vscode.Disposable {
}

/** Get swift version and create WorkspaceContext */
static async create(): Promise<WorkspaceContext> {
static async create(context: vscode.ExtensionContext): Promise<WorkspaceContext> {
const tempFolder = await TemporaryFolder.create();
const toolchain = await SwiftToolchain.create();
const toolchain = await SwiftToolchain.create(context.storageUri!);
return new WorkspaceContext(tempFolder, toolchain);
}

Expand Down
28 changes: 24 additions & 4 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ export interface LSPConfiguration {
readonly inlayHintsEnabled: boolean;
}

/** build destination configuration */
export interface DestinationConfiguration {
/** Target triple */
target: string | undefined;
/** Path to destination SDK */
sdk: string | undefined;
/** Path to tools directory */
binDir: string | undefined;
/** Extra arguments to pass to Swift compiler */
extraSwiftCFlags: string[] | undefined;
/** Extra arguments to pass to C compiler */
extraCCFlags: string[] | undefined;
/** Extra arguments to pass to C++ compiler */
extraCPPFlags: string[] | undefined;
}

/**
* Type-safe wrapper around configuration settings.
*/
Expand All @@ -49,6 +65,14 @@ const configuration = {
};
},

/** build destination configuration */
get destination(): DestinationConfiguration | string {
const configuration = vscode.workspace
.getConfiguration("swift")
.get<string | DestinationConfiguration>("destination", "");
return configuration;
},

/** Files and directories to exclude from the Package Dependencies view. */
get excludePathsFromPackageDependencies(): string[] {
return vscode.workspace
Expand All @@ -69,10 +93,6 @@ const configuration = {
get runtimePath(): string {
return vscode.workspace.getConfiguration("swift").get<string>("runtimePath", "");
},
/** Path to custom swift sdk */
get sdk(): string {
return vscode.workspace.getConfiguration("swift").get<string>("SDK", "");
},
/** swift build arguments */
get buildArguments(): string[] {
return vscode.workspace.getConfiguration("swift").get<string[]>("buildArguments", []);
Expand Down
2 changes: 1 addition & 1 deletion src/debugger/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export function createTestConfiguration(
if (xcTestPath !== runtimePath) {
testEnv.Path = `${xcTestPath};${testEnv.Path ?? process.env.Path}`;
}
const sdkroot = configuration.sdk === "" ? process.env.SDKROOT : configuration.sdk;
const sdkroot = ctx.workspaceContext.toolchain.targetSDK;
if (sdkroot === undefined) {
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
try {
console.debug("Activating Swift for Visual Studio Code...");

const workspaceContext = await WorkspaceContext.create();
const workspaceContext = await WorkspaceContext.create(context);

context.subscriptions.push(workspaceContext);

Expand Down
10 changes: 6 additions & 4 deletions src/sourcekit-lsp/LanguageClientManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
filterArguments,
getSwiftExecutable,
isPathInsidePath,
swiftDriverSDKFlags,
buildPathFlags,
swiftRuntimeEnv,
} from "../utilities/utilities";
Expand All @@ -29,6 +28,7 @@ import { FolderEvent, WorkspaceContext } from "../WorkspaceContext";
import { activateLegacyInlayHints } from "./inlayHints";
import { FolderContext } from "../FolderContext";
import { LanguageClient } from "vscode-languageclient/node";
import { Destination } from "../toolchain/destination";

/** Manages the creation and destruction of Language clients as we move between
* workspace folders
Expand Down Expand Up @@ -80,11 +80,13 @@ export class LanguageClientManager {
// used by single server support to keep a record of the project folders
// that are not at the root of their workspace
private subFolderWorkspaces: vscode.Uri[];
private destination?: Destination;

constructor(public workspaceContext: WorkspaceContext) {
this.singleServerSupport = workspaceContext.swiftVersion >= new Version(5, 7, 0);
this.subscriptions = [];
this.subFolderWorkspaces = [];
this.destination = workspaceContext.toolchain.destination;
if (this.singleServerSupport) {
// add/remove folders from server
const observeFoldersDisposable = workspaceContext.observeFolders(
Expand Down Expand Up @@ -343,8 +345,8 @@ export class LanguageClientManager {
const serverPathConfig = lspConfig.serverPath;
const serverPath =
serverPathConfig.length > 0 ? serverPathConfig : getSwiftExecutable("sourcekit-lsp");
const sdkArguments = [
...swiftDriverSDKFlags(true),
const extraArguments = [
...(this.destination?.extraSourcekitLSPFlags ?? []),
...filterArguments(
configuration.buildArguments.concat(buildPathFlags()),
LanguageClientManager.buildArgumentFilter
Expand All @@ -353,7 +355,7 @@ export class LanguageClientManager {

const sourcekit: langclient.Executable = {
command: serverPath,
args: lspConfig.serverArguments.concat(sdkArguments),
args: lspConfig.serverArguments.concat(extraArguments),
options: {
env: {
...process.env,
Expand Down
Loading