When Xcode updates, it might change the format of its messages to XCBBuildService. This requires changes to the proxy to support.
There are two ways to debug: reading logs, and debugging using Xcode. Both have their own benefits and drawbacks, and it's likely you'll lean on both when working to update the library.
This project makes thorough use of swift-logging, so to see what's wrong, look in the logs!
You can start recording logs by executing write_shim.sh
. You'll need your built BazelXCBBuildService
and the path to where Xcode is expecting XCBBuildService
. You also pass in the Xcode version, so your logs will be split based on the Xcode version.
The XCBBuildService
lives here: $(XCODE_DIR)/Contents/SharedFrameworks/XCBuild.framework/PlugIns/XCBBuildService.bundle/Contents/MacOS/XCBBuildService
write_shim.sh
will create a fake XCBBuildService
that simply calls the BazelXCBBuildService
while redirecting STDERR
to a log file in /tmp/Bazel-trace/
.
- Create a new module inside
/Sources
following the established pattern. (e.g.XCBProtocol_14_0
). - You'll notice we make use of symlinks to old versions of the files. Rather than copying every single file into the new
XCBProtocol
version, only copy files you need to change. For the rest, create a symlink to the previous version of the file (which may be a symlink itself). You'll see lots of symlinks pointing all the way back to the Xcode 11.4 versions! - Update
Examples/BazelXCBBuildService/BUILD.bazel
andExamples/BazelXCBBuildService/Packge.swift
to point at that new module. - Update
Examples/BazelXCBBuildService/Sources/RequestHandler.swift
to assign the appropriateRequestPayload
andResponsePayload
types to theBazelXCBBuildServiceRequestPayload
andBazelXCBBuildServiceResponsePayload
typealiases. - Rename the original
XCBBuildService
in the Xcode bundle toXCBBuildService.original
, just in case you want it again.
- Rebuild with
bazel build BazelXCBBuildService
. - Move it into the proper folder:
My-New-Xcode.app/Contents/SharedFrameworks/XCBuild.framework/PlugIns/XCBBuildService.bundle/Contents/MacOS/BazelXCBBuildService
. - Run
write_shim.sh
to set up logging into/tmp/Bazel-trace/
. - Restart Xcode.
- Do some actions in Xcode, then view the logs. Are there any errors?
- Make a change in the project fixing an error or adding extra logs you deem necessary.
- Repeat as necessary.
To debug BazelXCBBuildService
while it is being used by Xcode, you will need to have two instances of Xcode running:
- "Main" Xcode: An instance of Xcode that uses our XCBBuildServiceProxyKit. This version will be used to build and run your app.
- "Debugging" Xcode: An instance of Xcode that uses the original XCBBuildService shipped with Xcode. This version will be used to debug the "main" instance of Xcode.
Getting two instances of Xcode going can be done a couple of ways:
- Use two separate versions of Xcode (e.g. 12.5.0 and 13.0.0).
- Modify the
XCBBUILDSERVICE_PATH
environment variable, and launch two instances of the same Xcode version.- Xcode looks to see if
XCBBUILDSERVICE_PATH
is set. If it is, it will use that instead ofContents/SharedFrameworks/XCBuild.framework/PlugIns/XCBBuildService.bundle/Contents/MacOS/XCBBuildService
. So after launching your "main" instance of Xcode, you can launch a "debugging" instance of Xcode that uses the original XCBBuildService by using the following command:env XCBBUILDSERVICE_PATH=/Application/Xcode.app/Contents/SharedFrameworks/XCBuild.framework/PlugIns/XCBBuildService.bundle/Contents/MacOS/XCBBuildService.original /Application/Xcode.app/Contents/MacOS/Xcode`
- Xcode looks to see if
To set up BazelXCBBuildService
for debugging:
- Remove
BazelXCBBuildService
from the "debugging" Xcode if it is installed. In the "debugging" Xcode, we want to use the official XCBBuildService, not our custom one.- To see if it is installed, open this folder inside Xcode:
open /Applications/Xcode-<debugging-version-number>.app/Contents/SharedFrameworks/XCBuild.framework/PlugIns/XCBBuildService.bundle/Contents/MacOS/
- If there are three files (
XCBBuildService.original
,XCBBuildService
, andBazelXCBBuildService
),BazelXCBBuildService
is installed in that version of Xcode. To uninstall it, deleteXCBBuildService
andBazelXCBBuildService
, and renameXCBBuildService.original
toXCBBuildService
.
- To see if it is installed, open this folder inside Xcode:
- Open
tools/BazelXCBBuildService
in the "debugging" Xcode and build a debug version of BazelXCBBuildService. - Copy the built, debug version of
BazelXCBBuildService
from the DerivedData folder into the "main" version of Xcode:FOLDER=$(ls ~/Library/Developer/Xcode/DerivedData | grep BazelXCBBuildService) cp ~/Library/Developer/Xcode/DerivedData/$FOLDER/Build/Products/Debug/BazelXCBBuildService \ /Applications/Xcode-<main-version>.app/Contents/SharedFrameworks/XCBuild.framework/PlugIns/XCBBuildService.bundle/Contents/MacOS/
- Prepare the debugger to attach to the service.
- Open the scheme for this build, and navigate to the "Run" section on the left-hand sidebar.
- In the "Info" tab, for the "Launch" option, select "Wait for the executable to be launched".
- Set some breakpoints if desired
- Build and run as normal, Xcode will wait for the binary to be launched and automatically attache its debugger
- Start the "main" Xcode (Note: it may freeze if breakpoints are hit in
BazelXCBBuildService
) - Check that the "debugging" Xcode has attached to
BazelXCBBuildService
- Perform build actions in the "main" Xcode and debug
BazelXCBBuildService
using the "debugging" Xcode 🎉