Skip to content
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

iOS Swift development IDE for Windows/Linux. Create, build, and test apps without owning a Mac.

Supports Swift 6.1 and the Swift Package Manager.
Supports Swift 6.2 and the Swift Package Manager.

### Demo

Expand All @@ -30,7 +30,7 @@ Check out the [Getting Started](https://github.com/nab138/CrossCode/wiki#getting

## Features

- Generate a Darwin SDK for linux from a user provided copy of Xcode 16.3 to build the apps
- Generate a Darwin SDK for linux from a user provided copy of Xcode 26 to build the apps
- Build apps using swift package manager
- Log in with your Apple ID to sign apps
- Install apps on device
Expand All @@ -49,7 +49,7 @@ Please note that I am one person, so development may be slow. If you want to hel

## How it works

- A darwin SDK is generated from a user provided copy of Xcode 16.3 (extracted with [unxip-rs](https://github.com/nab138/unxip-rs)) and darwin tools from [darwin-tools-linux-llvm](https://github.com/xtool-org/darwin-tools-linux-llvm)
- A darwin SDK is generated from a user provided copy of Xcode 26 (extracted with [unxip-rs](https://github.com/nab138/unxip-rs)) and darwin tools from [darwin-tools-linux-llvm](https://github.com/xtool-org/darwin-tools-linux-llvm)
- Swift uses the darwin SDK to build an executable which is packaged into an .app bundle.
- The code to sign and install apps onto a device has been removed from CrossCode's source and moved to a standalone package, [isideload](https://github.com/nab138/isideload). It was built on a lot of other libraries, so check out its README for more info.

Expand Down
2 changes: 1 addition & 1 deletion bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@types/vscode": "^1.102.0",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.0.2",
"vite": "^7.0.0",
"vite": "^7.1.6",
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,6 @@
"@types/vscode": "^1.102.0",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.0.2",
"vite": "^7.0.0"
"vite": "^7.1.6"
}
}
}
47 changes: 42 additions & 5 deletions src-tauri/src/builder/swift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,24 +159,61 @@ impl SwiftBin {
}

#[tauri::command]
pub fn has_darwin_sdk(toolchain_path: &str) -> bool {
pub fn has_darwin_sdk(toolchain_path: &str) -> String {
let swift_bin = SwiftBin::new(toolchain_path);
if swift_bin.is_err() {
return false;
return "none".to_string();
}
let swift_bin = swift_bin.unwrap();

let output = swift_bin.output(&["sdk", "list"]);
if output.is_err() {
return false;
return "none".to_string();
}
let output = output.unwrap();
if !output.status.success() {
return false;
return "none".to_string();
}
let output_str = String::from_utf8_lossy(&output.stdout);
if !output_str.contains("darwin") {
return "none".to_string();
}

let output = swift_bin.output(&[
"sdk",
"configure",
"--show-configuration",
"darwin",
"arm64-apple-ios",
]);
if output.is_err() {
return "none".to_string();
}
let output = output.unwrap();
if !output.status.success() {
return "none".to_string();
}

let output_str = String::from_utf8_lossy(&output.stdout);

output_str.contains("darwin")
let sdk_version = output_str.lines().find_map(|line| {
if line.starts_with("sdkRootPath:") {
let parts: Vec<&str> = line.split('/').collect();
for part in parts {
if part.starts_with("iPhoneOS") && part.ends_with(".sdk") {
let version = part.trim_start_matches("iPhoneOS").trim_end_matches(".sdk");
return Some(version.to_string());
}
}
}
None
});

if let Some(version) = sdk_version {
version
} else {
"none".to_string()
}
}

#[tauri::command]
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/lsp_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn validate_project(project_path: String, toolchain_path: String) -> Project
// let config_path = project_path.join(".sourcekit-lsp").join("config.json");
// if !config_path.exists() {
// fs::write(config_path, "{
// \"$schema\": \"https://raw.githubusercontent.com/swiftlang/sourcekit-lsp/refs/heads/release/6.1/config.schema.json\",
// \"$schema\": \"https://raw.githubusercontent.com/swiftlang/sourcekit-lsp/refs/heads/release/6.2/config.schema.json\",
// \"swiftPM\": {
// \"swiftSDK\": \"arm64-apple-ios\"
// }
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/templates/swiftui/Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 6.1
// swift-tools-version: 6.2

import PackageDescription

Expand Down
2 changes: 1 addition & 1 deletion src-tauri/templates/uikit/Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 6.1
// swift-tools-version: 6.2

import PackageDescription

Expand Down
68 changes: 42 additions & 26 deletions src/components/SDKMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { openUrl } from "@tauri-apps/plugin-opener";
import { installSdkOperation } from "../utilities/operations";
import ErrorIcon from "@mui/icons-material/Error";
import WarningIcon from "@mui/icons-material/Warning";
import { DARWIN_SDK_VERSION } from "../utilities/constants";

export default () => {
const {
selectedToolchain,
hasDarwinSDK,
darwinSDKVersion,
checkSDK,
startOperation,
isWindows,
Expand Down Expand Up @@ -86,32 +88,46 @@ export default () => {
gap: "var(--padding-md)",
}}
>
<Typography
level="body-md"
color={
hasDarwinSDK ? "success" : selectedToolchain ? "danger" : "warning"
}
sx={{
alignContent: "center",
display: "flex",
gap: "var(--padding-xs)",
}}
>
{isWindowsReady ? (
hasDarwinSDK ? (
"Darwin SDK is installed!"
<div>
<Typography
level="body-md"
color={
hasDarwinSDK ? "success" : selectedToolchain ? "danger" : "warning"
}
sx={{
alignContent: "center",
display: "flex",
gap: "var(--padding-xs)",
}}
>
{isWindowsReady ? (
hasDarwinSDK ? (
"Darwin SDK is installed!"
) : (
<>
{selectedToolchain ? <ErrorIcon /> : <WarningIcon />}
{selectedToolchain
? "Darwin SDK is not installed"
: "Select a swift toolchain first"}
</>
)
) : (
<>
{selectedToolchain ? <ErrorIcon /> : <WarningIcon />}
{selectedToolchain
? "Darwin SDK is not installed"
: "Select a swift toolchain first"}
</>
)
) : (
"Install WSL and Swift first."
"Install WSL and Swift first."
)}
</Typography>
{hasDarwinSDK && (
<Typography
level="body-sm"
color={
darwinSDKVersion === DARWIN_SDK_VERSION ? undefined : "warning"
}
>
{darwinSDKVersion === DARWIN_SDK_VERSION
? `Version: ${darwinSDKVersion}`
: `Unsupported SDK version (${darwinSDKVersion}). Apps may compile, but you may not be able to use newer features (like liquid glass). Please re-install with Xcode 26.`}
</Typography>
)}
</Typography>
</div>
<div
style={{
display: "flex",
Expand All @@ -123,11 +139,11 @@ export default () => {
onClick={(e) => {
e.preventDefault();
openUrl(
"https://developer.apple.com/services-account/download?path=/Developer_Tools/Xcode_16.3/Xcode_16.3.xip"
"https://developer.apple.com/services-account/download?path=/Developer_Tools/Xcode_26/Xcode_26_Universal.xip"
);
}}
>
Download XCode 16.3
Download XCode 26
</Button>
<Button
variant="soft"
Expand Down
14 changes: 11 additions & 3 deletions src/components/SwiftMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useEffect, useState } from "react";
import { openUrl } from "@tauri-apps/plugin-opener";
import ErrorIcon from "@mui/icons-material/Error";
import { invoke } from "@tauri-apps/api/core";
import { SWIFT_VERSION_PREFIX } from "../utilities/constants";

export default () => {
const {
Expand Down Expand Up @@ -92,7 +93,7 @@ export default () => {
fontFamily: "monospace",
}}
>
swiftly install 6.1
swiftly install {SWIFT_VERSION_PREFIX}
</span>
" or manually. If you have already done so, but it is not showing up,
your toolchain installation may be broken. For help, refer to the{" "}
Expand All @@ -110,6 +111,13 @@ export default () => {
.
</Typography>
)}
{selectedToolchain !== null && !isCompatable(selectedToolchain) && (
<Typography level="body-md" color="danger">
Your selected toolchain is not compatible. Please select a swift{" "}
{SWIFT_VERSION_PREFIX}
toolchain.
</Typography>
)}
{toolchains !== null && allToolchains.length > 0 && (
<div>
<Typography level="body-md">Select a toolchain:</Typography>
Expand Down Expand Up @@ -195,9 +203,9 @@ export default () => {
);
};

function isCompatable(toolchain: Toolchain | null): boolean {
export function isCompatable(toolchain: Toolchain | null): boolean {
if (!toolchain) return false;
return toolchain.version.startsWith("6.1");
return toolchain.version.startsWith(SWIFT_VERSION_PREFIX);
}

function stringifyToolchain(toolchain: Toolchain | null): string | null {
Expand Down
75 changes: 73 additions & 2 deletions src/pages/IDE.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { restartServer } from "../utilities/lsp-client";
import BottomBar from "../components/Tiles/BottomBar";
import { open as openFileDialog } from "@tauri-apps/plugin-dialog";
import { IStandaloneCodeEditor } from "@codingame/monaco-vscode-api/vscode/vs/editor/standalone/browser/standaloneCodeEditor";
import { DARWIN_SDK_VERSION } from "../utilities/constants";

export interface IDEProps {}

Expand All @@ -46,8 +47,14 @@ export default () => {
const [redo, setRedo] = useState<(() => void) | null>(null);
const [theme] = useStore<"light" | "dark">("appearance/theme", "dark");
const { path } = useParams<"path">();
const { openFolderDialog, selectedToolchain, hasLimitedRam, initialized } =
useIDE();
const {
openFolderDialog,
selectedToolchain,
hasLimitedRam,
initialized,
ready,
darwinSDKVersion,
} = useIDE();
const [sourcekitStartup, setSourcekitStartup] = useStore<boolean | null>(
"sourcekit/startup",
null
Expand All @@ -57,6 +64,11 @@ export default () => {
false
);

const [hasIgnoredDarwinSDK, setHasIgnoredDarwinSDK] = useStore<boolean>(
"has-ignored-darwin-sdk",
false
);

if (!path) {
throw new Error("Path parameter is required in IDE component");
}
Expand All @@ -70,6 +82,17 @@ export default () => {
const [editor, setEditor] = useState<IStandaloneCodeEditor | null>(null);
const { addToast } = useToast();

useEffect(() => {
if (ready === false && initialized) {
console.log(
"IDE not ready, returning to welcome page",
ready,
initialized
);
navigate("/");
}
}, [ready, initialized, navigate]);

useEffect(() => {
(async () => {
if (!store || !storeInitialized || !path) return;
Expand Down Expand Up @@ -327,6 +350,54 @@ export default () => {
</ModalDialog>
</Modal>
)}
{initialized &&
selectedToolchain !== null &&
hasIgnoredDarwinSDK === false &&
darwinSDKVersion !== DARWIN_SDK_VERSION && (
<Modal
open={true}
onClose={() => {
setHasIgnoredDarwinSDK(true);
}}
>
<ModalDialog sx={{ maxWidth: "90vw" }}>
<ModalClose />
<div>
<div style={{ display: "flex", gap: "var(--padding-md)" }}>
<div style={{ width: "1.25rem" }}>
<WarningIcon />
</div>
<Typography level="h3">Incompatible SDK Version</Typography>
</div>
<Typography level="body-lg">
This version of CrossCode is designed to work with Darwin SDK{" "}
{DARWIN_SDK_VERSION}, but you have version {darwinSDKVersion}{" "}
installed. Things may still work, but you will miss out on
newer features (like liquid glass) and may run into issues.
</Typography>
</div>

<Divider sx={{ mb: "var(--padding-xs)" }} />
<div style={{ display: "flex", gap: "var(--padding-lg)" }}>
<Button
onClick={() => {
navigate("/#install-sdk");
}}
>
Install Correct SDK
</Button>
<Button
onClick={() => {
setHasIgnoredDarwinSDK(true);
}}
variant="outlined"
>
Ignore
</Button>
</div>
</ModalDialog>
</Modal>
)}
</div>
);
};
Expand Down
Loading
Loading