xcode-build-server icon indicating copy to clipboard operation
xcode-build-server copied to clipboard

Fix missing iOS flags for SwiftPM packages (for ~/Library/Developer/Xcode/*/DerivedData/* files related to project)

Open mishabunte opened this issue 8 months ago • 6 comments

Fix: SwiftPM/CocoaPods source files in SourcePackages/checkouts/* were indexed with MacOSX.sdk because the upward search never found a .compile-* file.

Change:

findSwiftModuleRoot() accepts an optional start directory.

On a miss, InferFlagsForSwift() retries from os.getcwd() (workspace root), where the real .compile-* lives.

Result: package sources now receive the correct iOS/iOS-sim flags, so SourceKit-LSP regains hover and go-to-definition for library code.

mishabunte avatar Jul 15 '25 06:07 mishabunte

Normally, xcode-build-server will find and use the corresponding compile file through the configuration in buildServer.json to provide compilation information. Infer Flags indicates that the corresponding compilation information is not found under the current buildServer.json configuration. This is just a fallback configuration and cannot guarantee accuracy. The .compile file information in the current directory usually is the same as the buildServer.json generated by xcode-build-server parse. Therefore, if the information in buildServer.json was not found before, there should be no corresponding information in the .compile file in the current directory.

On the other hand, SourcePackages/checkouts/* is outside the current directory. Most editors will generate a new root directory. There is no buildServer.json in this root directory, and sourcekit-lsp will not get flags through BSP.

So I am curious about your Integrated environment and configuration. I will try to reproduce the usage scenario and see if there is a better solution.

SolaWing avatar Jul 16 '25 06:07 SolaWing

I’m working on this project: https://github.com/mishabunte/unstoppable-wallet-ios

  1. I cloned the repository to ~/prj/unstoppable-wallet-ios and built it.
  2. I generated buildServer.json in the project root.
  3. After building, a .compile file appeared in the project root (~/prj/unstoppable-wallet-ios).
  4. I opened a source file from the project, e.g. Modules/Wallet/Views/BalanceButtonsView.swift.
  5. xcode-build-server (findSwiftModuleRoot) finds the .compile file, so LspDefinition works—because it can resolve the correct compilation flags.
  6. From that file, I use LspDefinition to jump to the PrimaryButton class.
  7. PrimaryButton.swift isn’t part of the app’s source; it’s from a dependency located at: ~/Library/Developer/Xcode/DerivedData/UnstoppableWallet-adhiqabesrsupjdlzfgzqspnbqlj/SourcePackages/checkouts/ComponentKit.Swift/Sources/ComponentKit/Classes/Buttons/PrimaryButton.swift
  8. When findSwiftModuleRoot walks up the path starting in ~/Library/Developer/Xcode/DerivedData/.../ComponentKit.Swift/Sources/ComponentKit/Classes/Buttons/, it can’t find a .compile file. As a result, SourceKit-LSP features fail because xcode-build-server doesn’t know the compilation flags for that library file.

Fix: I added a fallback in InferFlagsForSwift and findSwiftModuleRoot that checks the current working directory if no .compile file is found. With this change, I can navigate both the project’s source code and the dependency sources.

mishabunte avatar Jul 17 '25 08:07 mishabunte

see https://github.com/SolaWing/xcode-build-server/blob/5d1012ce5d008c77cec8be963d4c525ddb683635/server.py#L121C1-L121C73 flags = GetFlags(file_path, self.compile_file, store=self.store)

BSP server already pass current compile_file to get flags, if it contains flags for file, there shouldn't enter the infer branch. Except you start another BSP server instance for different root.

Did you have any buildServer.json in parent directory of ~/Library/Developer/Xcode/DerivedData/.../ComponentKit.Swift/Sources/ComponentKit/Classes/Buttons/

Or Can upload your logs? it can be export to a file by start LSP with environment XBS_LOGPATH=/tmp/xbs.log

SolaWing avatar Jul 18 '25 03:07 SolaWing

Did you have any buildServer.json in parent directory of ~/Library/Developer/Xcode/DerivedData/.../ComponentKit.Swift/Sources/ComponentKit/Classes/Buttons/

No, I don't have buildServer.json in Xcode/DerivedData. Xcode creates this folder automatically for the third-party libraries

My project has buildServer.json. But my project is in my home folder - ~/prj/unstoppable-wallet-ios

The fix is propose is very simple: xcode-build-server will use project's buildServer.json for all third-party libraries for the specific project

(Xcode puts the source code for the third-party libraries into ~/Library/Developer/Xcode/DerivedData/ ~/Library/Developer/Xcode/DerivedData/UnstoppableWallet-adhiqabesrsupjdlzfgzqspnbqlj/SourcePackages/checkouts/ComponentKit.Swift/Sources/ComponentKit/Classes/Buttons/PrimaryButton.swift)

The easiest way is to use project's buildServer.json for third-party libraries and it works perfect - check the FilesChanged:

mishabunte avatar Jul 28 '25 02:07 mishabunte

I perform these steps

  1. Open BalanceButtonView.swift file from my project directory ~/prj/unstoppable-wallet-ios (I have buildServer.json for it)
  2. Navigate to PrimaryButton in BalanceButtonView and go to definition (LspDefinition)
  3. PrimaryButton.swift is from the third-party library and source code is in ~/Library/Developer/Xcode/DerivedData/UnstoppableWallet-adhiqabesrsupjdlzfgzqspnbqlj/SourcePackages/checkouts/ComponentKit.Swift/Sources/ComponentKit/Classes/Buttons/PrimaryButton.swift
  4. Without my patch xcode-build-server does not know compile options for PrimaryButton
  5. With the patch xcode-build-server uses buildServer.json from the project directory for the third-party source code as well - everything works perfect

Please find logs before and after the patch:

xbs_before_patch.log xbs_after_patch.log

mishabunte avatar Jul 28 '25 03:07 mishabunte

I noticed that BalanceButtonsView.swift in your project directory also retrieves flags via infer. If all your flags are retrieved from the .compile file of cwd , the kind property in your buildServer.json should be "manual" instead of "xcode." Also, .compile and buildServer.json should be in the same directory. See the corresponding logic for retrieval of the compile file: https://github.com/SolaWing/xcode-build-server/blob/e541f03c977c32c150aaf7bbe033156d88bf4f9e/server.py#L76-L85 and the logic for using the compile file: https://github.com/SolaWing/xcode-build-server/blob/e541f03c977c32c150aaf7bbe033156d88bf4f9e/server.py#L121 You should get flags by binding .compile information correctly, not by inferring them through fallback unknown files.

If the kind field in your buildServer.json is indeed xcode, I am curious about how you generate the .compile file. Corresponding to the two methods of using flags in the Readme, when the kind is xcode, it should use xcode to compile the app, and automatically obtain the information of the corresponding log directory of xcode to create an isolated cache compile file. Another way, the manual parsing log .compile (including xcode post-build-action) will generated in the current directory by default unless the output path is explicitly specified, and will overwrite the kind of buildServer.json to manual

SolaWing avatar Jul 29 '25 03:07 SolaWing