LSP integration with CMake and nightly toolchains

Hi, this might be a weird question

How does everyone use Swift nowadays? I must be missing something, from the editors mentioned on the website and a few others I tried:

  • Atom is a dead project, and so is the link on the website
  • Vim is not exactly my preference
  • CLion removed support for Swift ages ago
  • Zed has support for the language but it's broken
  • VSCode sometimes works but it's incredibly slow and ugly
  • Xcode is completely unusable, I only get syntax errors and there's false positives, and then it breaks with different toolchains even more

Of the above none even work with Cmake as far as I can tell so I am forced to maintain a separate Package.swift file for anything to work.

Does no one else find this to be an issue? Compared to Rust or C++ the experience has become rather terrible over the past year.


I just returned to a Swift project I've been working on for about a year after a few months of C++ and I found the situation to be even more dire than last time, I genuinely can't get anything to work.

2 Likes
  • Xcode works for me just fine (version 15.2).
  • On Windows, I have tried VSCode and it worked (not used it for actual development).

On Windows, I am working on my custom solution, an IDE which is planned to support GUI apps in the future.

1 Like

I like Xcode very much, sometimes you have to remove all error messages (in the menu) because previous messages still stick around.

2 Likes

I like Xcode as an IDE, but every year the quality of Swift support has declined to a point where I can't rely on it. It worked a month or two ago, now I try to use it and it just doesn't.

And ever since the AI code completion got added the normal completions which are often useful sometimes stop working entirely.

For me, I write a lot of cross-platform Swift code in VSCode, and use Xcode when writing code specific to Apple platforms. There are no critical unusability issues with either.

  • Xcode works (macOS).
  • VSCode works with Swift extension (macOS, Windows, Linux).
  • Zed works (macOS), just tried.

Maybe you should show some (legal) code that makes these IDEs not work.

1 Like

Sure, here is only slightly modified output of swift package init --type executable

// swift-tools-version: 6.1

import PackageDescription

let package = Package(
    name: "MyPackage",
    targets: [.executableTarget(name: "MyPackage")]
)

print("Hello, world!")

It does not in fact work, I get no completions or anything, and the IDE itself seems completely confused. I have a newer toolchain selected in the menu, yet it shows an error that the Swift version 6.1 is not the installed version


Zed does work on this hello world but not on my actual code

Is there any particular reason to use a pre-release instead of a stable release?

1 Like

Yeah, I am working on a software/hardware 2d renderer and with how many low level features are getting added lately there is a significant difference in what I can do.

Probably the biggest reason is the embedded mode, I can finally compile everything to a very small webassembly binary and run in a browser :slight_smile:

2 Likes

Xcode 16.1 does not recognize the pre-release version, even I had the right toolchain selected in the menu (It seems to be a bug). VSCode worked though (after setting the "swift.path" option).
I have written some C++ code for the ESP32, but have not tried Swift. Swift's embedded mode is quite new, so it's normal to have bugs or unavailable.

3 Likes

Xcode's toolchain support (and toolchain support of Xcode, honestly) is hit or miss. If you need a reliable IDE experience with development toolchains, VSCode is probably your best bet. Its Swift plugin allows you to set whichever toolchain you want, and will use that toolchain for all of its functionality (which yes, may be less reliable given the toolchain's development status), unlike Xcode, which uses its own internal version of various toolchain bits and, for various Apple platforms, has requirements that may not be met by the toolchain at all. I haven't been able to build for iOS using a toolchain in years.

3 Likes

By the way, do you get errors in Zed? I thought it doesn't work for me but it kind of partially does, I get no error checking but the types are known and completions work. This seems very odd.

Maybe the subject/title of this thread should be changed? It seems this thread is about which IDEs support using the nightly toolchain.

For myself (I have experimented some with nightly toolchains, and even have one or two installed right now), Xcode is working just fine.

2 Likes

It's not just about nightly toolchains, the state of editor support is quite bad in general. There's basically none, and the ones that work require a Swift package, as far as I can tell CMake is completely unsupported.

It's not unusable, but compared to similar languages like Rust or C++ it's a night and day difference.

I don't know if this is relevant to your interests, but coming from gcc land rather than CLang I wasn't aware of compile_commands.json, and the role it can play in telling sourcekit-lsp where your files are. I literally just learned about it as a way to tell the sourcekit-lsp what to do without a Package.swift

This is where I'm playing around around. README will be improved, but that may need to wait until Jan. Let me know what needs clarifying and I will here.

Hope it helps?

(Edit: Note that the build.sh can load a specific toolchain. I haven't tested that yet against how sourcekit-lsp behaves)

1 Like

Okay, so I tried generating compile_commands, however at least in Zed it doesn't do anything, it seems to be treating all the files individually, which is its default behavior with no Package.swift

When I open that repo in VScode or Zed (on mac) it works (after running the build script once). Xcode wont talk to that folder at all. I won't be able to check Linux before Friday, but I can look then.

You may need to open and close the project.

Doing embedded stuff in a manner to which I am accustom is also my motivation.

I haven't had luck yet hand rolling a compile_commands file that works or a compile_flags.txt file. I want to be able to do that because the generated files give full paths so they're sort of useless for passing around with the project.

Oh one more thing - did you add the config.json, too?

I did add a config.json file :frowning:

I think sourcekit-lsp is at fault, the issues are the same no matter which editor I download. It's weird though, it's as if it works, and if I get a Swift function like print wrong it will show an error, but if I write nonsensical code it accepts it.

Or in this case, an imported type is not recognized, but rather than getting an error abound an undefined symbol it just shows an <<error type>>

Note that this can be built so there is nothing wrong with the code

The demo project I did was stuck in a similar state at one point too. I had to keep fussing.

Did you check run my repo? That way we can isolate if the trouble is in your toolchain or in your project's config files? (I agree the code and the build itself I'm sure are fine) If my project doesn't work for you, then its a problem with the toolchain/sourcekit working together. If it does, we just haven't figured out the right config for yours yet? Does that make sense?

Yours seems to work. Mine looks like this:

CMake file
cmake_minimum_required(VERSION 3.31)
project(Minecraft LANGUAGES CXX C Swift)

set(CMAKE_Swift_LANGUAGE_VERSION 6)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_library(GLAD STATIC lib/glad/src/glad.c)
target_include_directories(GLAD PUBLIC lib/glad/include)

set(CMAKE_Swift_FLAGS
    "-parse-as-library -wmo\
    -enable-experimental-feature BuiltinModule\
    -enable-experimental-feature Embedded"
)

file(GLOB_RECURSE CORE_MODULE      src/Core/*.swift)
file(GLOB_RECURSE ENGINE_MODULE    src/Engine/*.swift)
file(GLOB_RECURSE MINECRAFT_MODULE src/Minecraft/*.swift)

add_library(Core STATIC ${CORE_MODULE})

add_library(Engine STATIC ${ENGINE_MODULE})
target_link_libraries(Engine PRIVATE Core)
target_link_libraries(Engine PRIVATE GLAD)
target_compile_options(Engine PUBLIC -Xcc -fmodule-map-file=${CMAKE_SOURCE_DIR}/lib/glad/include/module.modulemap)

add_library(Minecraft STATIC ${MINECRAFT_MODULE})
target_link_libraries(Minecraft PRIVATE Engine)

find_package(SDL3 REQUIRED COMPONENTS SDL3)
target_link_libraries(Engine PRIVATE SDL3::SDL3)
target_link_libraries(Engine PRIVATE GLAD)

add_executable(mc src/main.swift)
target_link_libraries(mc PRIVATE Core)
target_link_libraries(mc PRIVATE Engine)
target_link_libraries(mc PRIVATE Minecraft)

file(GLOB_RECURSE ASSETS assets/*)

foreach(ASSET ${ASSETS})
    file(COPY ${ASSET} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/bundle")
endforeach()

Would the compile commands file handle modules correctly?

Minecraft!!! Love it.

I believe it should, but I haven't done that yet! Now you're ahead of me! Trying it with the pico C sdk is in my nearish term goals!

Did you use the CMake generate or the Ninja generate? Try the other. (LOL). They look very different and I'm not clear on why yet.

I wonder if it's struggling with the glob. When you look in the generated file does it list each of the files out (CMake version only)? From what I understand each entry HAS to have a file.

You might also look into using the compile_flags.txt style since your project actually has libraries. The demo project doesn't have any compile flags to speak of really so I hadn't been sure what to put.

(Edit: The readme is improved. Note the

TODO: Can I use generatedFilesPath: or index to side step the need for a separate compile_commands.json?

Its possible some of this can be done just with the config.json, but I haven't found an example, and I'm not super clear on the role of those two entries yet as candidates to do that.