forked from bazelbuild/rules_swift
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add remotely debuggable Swift document (bazelbuild#576)
- Loading branch information
Showing
2 changed files
with
117 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Debuggable Remotely Built Swift | ||
|
||
This is a guide to using remotely built Swift modules in local debug builds. | ||
|
||
At the time of writing, `lldb` depends on debugging options embedded in `.swiftmodule` files. These options include paths that are only valid on the build host. For local builds, this all just works, but for remote builds, it doesn't. | ||
|
||
The solution is two parts: | ||
|
||
1. Use `-no-serialize-debugging-options` globally, to prevent embedded paths | ||
2. Use `-serialize-debugging-options` locally in one empty module | ||
|
||
Globally disabling debugging options makes those `.swiftmodule`s usable on any machine. Locally enabling debugging options for one module provides lldb with enough info to make debugging work. | ||
|
||
An lldb bug has been filed here: https://bugs.swift.org/browse/SR-11485 | ||
|
||
### Disable Debugging Options Globally | ||
|
||
To globally disable debugging options, use the `swift.cacheable_swiftmodules` feature in rules_swift. For example, your `.bazelrc` could look like this: | ||
|
||
``` | ||
build --features=swift.cacheable_swiftmodules | ||
``` | ||
|
||
What this does is ensure all modules are built explicitly with `-no-serialize-debugging-options`. It has to be explicit because `swiftc` enables `-serialize-debugging-options` in some cases. | ||
|
||
### Add Debug Build Config | ||
|
||
In a `BUILD` file - in this example, the root `BUILD` file, define the following [`config_setting`](https://docs.bazel.build/versions/master/be/general.html#config_setting). This will allow targets to conditionally depend on the locally built debugging module. | ||
|
||
```python | ||
config_setting( | ||
name = "debug", | ||
values = { | ||
"compilation_mode": "dbg", | ||
}, | ||
) | ||
``` | ||
|
||
### Define Local Debug Target | ||
|
||
In the `BUILD` file of your choice, define a `swift_library` with: | ||
|
||
* A single empty source file | ||
* Enables `-serialize-debugging-options` | ||
* Built locally, not remote - using the `no-remote` tag | ||
|
||
Here is one way to define the `BUILD` file, using a [`genrule`](https://docs.bazel.build/versions/master/be/general.html#genrule) to create the empty swift file. | ||
|
||
```python | ||
genrule( | ||
name = "empty", | ||
outs = ["empty.swift"], | ||
cmd = "touch $(OUTS)", | ||
) | ||
|
||
swift_library( | ||
name = "_LocalDebugOptions", | ||
srcs = [":empty"], | ||
copts = [ | ||
"-Xfrontend", | ||
"-serialize-debugging-options", | ||
], | ||
module_name = "_LocalDebugOptions", | ||
tags = ["no-remote"], | ||
visibility = ["//visibility:public"], | ||
) | ||
``` | ||
|
||
### Update Top Level Test Targets | ||
|
||
Finally, for each top-level test target (`ios_unit_test`, `ios_ui_test`*, etc), conditionally add the local debugging module to the deps. This is done via the [debug config](#add-debug-build-config). In the past this also had to be done for `ios_application` targets but that has since been fixed in lldb. | ||
|
||
```python | ||
debug_deps = select({ | ||
"//:debug": ["//some/path:_LocalDebugOptions"], | ||
"//conditions:default": [], | ||
}) | ||
|
||
ios_unit_test( | ||
name = "...", | ||
deps = debug_deps + [ | ||
# ... | ||
], | ||
# ... | ||
) | ||
``` | ||
|
||
##### Note about `ios_unit_test` | ||
|
||
When using a test host, the debugging module must be added to the test host target only, not the unit test target. _However_, for tests without a test host, the debugging module must be added to the unit test target. | ||
|
||
### LLDB Settings | ||
|
||
Additional settings may be required, depending on your build setup. For example, an Xcode Run Script may look like: | ||
|
||
``` | ||
echo "settings set target.sdk-path $SDKROOT" | ||
echo "settings set target.swift-framework-search-paths $FRAMEWORK_SEARCH_PATHS" | ||
``` | ||
|
||
Other settings you can try customizing are: | ||
|
||
* `target.clang-module-search-paths` | ||
* `target.debug-file-search-paths` | ||
* `target.sdk-path` | ||
* `target.swift-extra-clang-flags` | ||
* `target.swift-framework-search-paths` | ||
* `target.swift-module-search-paths` | ||
* `target.use-all-compiler-flags` | ||
* `symbols.clang-modules-cache-path` | ||
|
||
These settings would be written to some project specific lldbinit file which you can include directly in Xcode's scheme. |