Sourcekit-lsp targeting iOS simulator seems to break with Xcode 12.2

a couple months ago, i got vim set up to play nice with sourcekit-lsp for an iOS app created in Xcode. the idea here was just to do my development in vim, build using a dummy Package.swift configuration to get inline errors and autocomplete, and then manually refresh in Xcode and run previews and launch the simulator from there. a little janky, but better than the other options like self-signing my Xcode so i could stuff a mediocre vim clone inside of it (or actually using Xcode normally... shudder).

the process i used was basically identical to what folks have investigated for getting sourcekit-lsp to work for iOS apps developed in VSCode; references here and here.

i took a break from development for about two months, and now this system no longer works. in particular, if i'm in file A, sourcekit-lsp no longer seems to recognize symbols defined in file B.

to be extra clear, here's how i'm starting sourcekit-lsp:

xcrun sourcekit-lsp -Xswiftc -sdk -Xswiftc $(xcrun --sdk iphonesimulator --show-sdk-path) -Xswiftc -target -Xswiftc "x86_64-apple-ios$(xcrun --sdk iphonesimulator --show-sdk-version)-simulator"

here's my build command (note the identical options):

xcrun swift build -Xswiftc -sdk -Xswiftc $(xcrun --sdk iphonesimulator --show-sdk-path) -Xswiftc -target -Xswiftc "x86_64-apple-ios$(xcrun --sdk iphonesimulator --show-sdk-version)-simulator"

here's my directory structure:

toplevel/
|__Package.swift
|__MyApp/
   |__Info.plist
   |__MyApp.swift
   |__A.swift
   |__B.swift

here's what the Package.swift looks like:

// swift-tools-version:5.3

import PackageDescription

let package = Package(
  name: "MyApp",
  platforms: [.iOS(.v14)],
  products: [
    .library(
      name: "MyApp",
      targets: ["MyApp"]
    ),
  ],
  dependencies: [],
  targets: [
    .target(
      name: "MyApp",
      dependencies: [],
      path: "./MyApp",
      exclude: ["Info.plist"]
    ),
  ]
)

here's file A.swift:

import SwiftUI

struct FooView: View {
  var foo: Foo

  var body: some View {
    Text("sup")
  }
}

and here's B.swift:

struct Foo {
  var heh: String
}

i've tried moving Package.swift into the MyApp/ directory (and updating paths), which did nothing (it was broken in the exact same way). one thing i noticed is that the Swift version is 5.3.1:

$ xcrun swift --version
Apple Swift version 5.3.1 (swiftlang-1200.0.41 clang-1200.0.32.8)
Target: x86_64-apple-darwin19.6.0

but if i try to change the swift-tools-version pragma to insist on 5.3.1, i get:

error: package at '/path/to/MyApp' is using Swift tools version 5.3.1 but the installed version is 5.3.0

this seems suspiciously like some sort of version mismatch, but everything is invoked with xcrun and it's not clear to me where the "swift tools" might live if not within $(xcrun swift) (and additionally googling suggests that there is no such thing as swift-tools-version:5.3.1).

any help would be appreciated (and hopefully this can help out others trying a non-Xcode iOS workflow post Xcode 12).

1 Like

If you add --log-level info to your sourcekit-lsp commnad, do you get any additional information about what is going on? I'm not sure where the logging will get output when running in vim. In VSCode or Sublime Text there is a console for it.

I tried creating a fresh package with the files you described and the same arguments passed to sourcekit-lsp, and I am able to see symbols from other files without issues.

A few additional questions

  • To confirm, when you build from command line with your swift build command, it is working?
  • When you open your package in vim, do you know what the workspace root directory is being set to? This should be visible in the log output for the initialize request. If it's not toplevel in your example, that might affect finding the Package.swift file.

You will get the same error if you try to build the package with swift build. I think 5.3 is still the correct tools version even for the newer toolchains. Maybe @NeoNacho can confirm.

thanks for the response @blangmuir. i found a workaround last night and earlier this morning was able to trace this issue to unexpected behavior in a helper function in the vim-lsp package.

the issue was as you suggested—the rootdir was being set to toplevel/.. instead of toplevel, essentially because that's where .git/ was, and previously .git/ and Package.swift were both in toplevel. everything else seems to be working as expected.

in case anyone else stumbles across this problem, the root cause from my perspective is that if lsp#utils#find_nearest_parent_file_directory() is passed an array of filenames, it doesn't find the closest parent dir which contains [any one of those filenames]. instead, it finds, for each of those filenames, the closest parent dir for containing it, then chooses the most frequent dir among all those—or if there's a tie, it chooses any of them, based on the sort order of an unordered dictionary :confused:

1 Like