1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
|
# How to Set Up an Edit-Build-Test-Debug Loop
This document describes how to set up a development loop for people interested
in contributing to Swift.
If you are only interested in building the
toolchain as a one-off, there are a couple of differences:
1. You can ignore the parts related to Sccache.
2. You can stop reading after
[Building the project for the first time](#building-the-project-for-the-first-time).
## Table of Contents
- [System Requirements](#system-requirements)
- [Cloning the project](#cloning-the-project)
- [Troubleshooting cloning issues](#troubleshooting-cloning-issues)
- [Installing dependencies](#installing-dependencies)
- [macOS](#macos)
- [Linux](#linux)
- [Building the project for the first time](#building-the-project-for-the-first-time)
- [Spot check dependencies](#spot-check-dependencies)
- [The roles of different tools](#the-roles-of-different-tools)
- [The actual build](#the-actual-build)
- [Troubleshooting build issues](#troubleshooting-build-issues)
- [Editing code](#editing-code)
- [Setting up your fork](#setting-up-your-fork)
- [Using Ninja with Xcode](#using-ninja-with-xcode)
- [Regenerating the Xcode project](#regenerating-the-xcode-project)
- [Troubleshooting editing issues in Xcode](#troubleshooting-editing-issues-in-xcode)
- [Other IDEs setup](#other-ides-setup)
- [Editing](#editing)
- [Incremental builds with Ninja](#incremental-builds-with-ninja)
- [Spot checking an incremental build](#spot-checking-an-incremental-build)
- [Reproducing an issue](#reproducing-an-issue)
- [Running tests](#running-tests)
- [Debugging issues](#debugging-issues)
- [Print debugging](#print-debugging)
- [Debugging using LLDB](#debugging-using-lldb)
- [Next steps](#next-steps)
## System Requirements
1. Operating system:
The supported operating systems for developing the Swift toolchain are:
macOS, Ubuntu Linux LTS, and the latest Ubuntu Linux release.
At the moment, Windows is not supported as a host development operating
system. Experimental instructions for Windows are available under
[Windows.md](/docs/Windows.md).
2. Python 3: Several utility scripts are written in Python.
3. Git 2.x to check out the sources. We find that older versions of Git
can't successfully check out all of the required repositories or
fail during a rebase when switching between checkout schemes.
4. Disk space:
Make sure that you have enough available disk space before starting.
The source code, including full git history, requires about 3.5 GB.
Build artifacts take anywhere between 5 GB to 100 GB, depending on the
build settings. It is recommended to have at least 150 GB of available disk space.
5. RAM:
It is recommended to have at least 8 GB for building a toolchain and 16 GB
for development. When building for development on a virtual machine or
emulator, you might need more than 32 GB.
6. Time:
Depending on your machine and build settings,
a from-scratch build can take a few minutes to several hours,
so you might want to grab a beverage while you follow the instructions.
Incremental builds are much faster.
## Cloning the project
1. Create a directory for the whole project:
```sh
mkdir swift-project
cd swift-project
```
> **Warning**
> Make sure the absolute path to your `swift-project` directory **does not** contain spaces,
since that might cause issues during the build step.
2. Clone the sources:
- Via SSH (recommended):
If you plan on contributing regularly, cloning over SSH provides a better
experience. After you've [uploaded your SSH keys to GitHub][]:
```sh
git clone git@github.com:apple/swift.git swift
cd swift
utils/update-checkout --clone-with-ssh
```
- Via HTTPS:
If you want to check out the sources as read-only,
or are not familiar with setting up SSH,
you can use HTTPS instead:
```sh
git clone https://github.com/apple/swift.git swift
cd swift
utils/update-checkout --clone
```
> **Note**
> If you've already forked the project on GitHub at this stage, **do not
> clone your fork** to start off. We describe [how to setup your fork](#setting-up-your-fork)
> in a subsection below.
<!-- Recommending against cloning the fork due to https://github.com/apple/swift/issues/55918 and https://github.com/apple/swift/issues/55947. -->
3. Double-check that `swift`'s sibling directories are present.
```sh
ls ..
```
This should list directories like `llvm-project`, `swiftpm` and so on.
4. Checkout the right branch/tag:
If you are building the toolchain for local development, you can skip this
step, as Step 2 will checkout `swift`'s `main` branch and matching
branches for other projects.
If you are building the toolchain as a one-off, it is more likely that you
want a specific branch or a tag, often corresponding to a specific release
or a specific snapshot. You can update the branch/tag for all repositories
as follows:
```sh
utils/update-checkout --scheme mybranchname
# OR
utils/update-checkout --tag mytagname
```
Detailed branching information, including names for release branches, can
be found in [Branches.md](/docs/Branches.md).
> **Note**
> The commands used in the rest of this guide assumes that the absolute path
> to your working directory is something like `/path/to/swift-project/swift`.
> Double-check that running `pwd` prints a path ending with `swift`.
[uploaded your SSH keys to GitHub]: https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/
### Troubleshooting cloning issues
- If `update-checkout` failed, double-check that the absolute path to your
working directory does not have non-ASCII characters.
- Before running `update-checkout`, double-check that `swift` is the only
repository inside the `swift-project` directory. Otherwise,
`update-checkout` may not clone the necessary dependencies.
## Installing dependencies
### macOS
1. Install Xcode. The minimum required version is specified in the node
information on <https://ci.swift.org>, may change frequently, and is often
a beta release.
1. Install [CMake][], [Ninja][] and [Sccache][]:
- Via [Homebrew][] (recommended):
```sh
brew install cmake ninja sccache
```
- Via [Homebrew Bundle][]:
```sh
brew bundle
```
[Xcode]: https://developer.apple.com/xcode/resources/
[CMake]: https://cmake.org
[Ninja]: https://ninja-build.org
[Homebrew]: https://brew.sh/
[Homebrew Bundle]: https://github.com/Homebrew/homebrew-bundle
### Linux
1. The latest Linux dependencies are listed in the respective Dockerfiles:
* [Ubuntu 18.04](https://github.com/apple/swift-docker/blob/main/swift-ci/master/ubuntu/18.04/Dockerfile)
* [Ubuntu 20.04](https://github.com/apple/swift-docker/blob/main/swift-ci/master/ubuntu/20.04/Dockerfile)
* [Ubuntu 22.04](https://github.com/apple/swift-docker/blob/main/swift-ci/master/ubuntu/22.04/Dockerfile)
* [CentOS 7](https://github.com/apple/swift-docker/blob/main/swift-ci/master/centos/7/Dockerfile)
* [Amazon Linux 2](https://github.com/apple/swift-docker/blob/main/swift-ci/master/amazon-linux/2/Dockerfile)
Note that [a prebuilt Swift release toolchain](https://www.swift.org/download/)
is installed and added to the `PATH` in all these Docker containers: it is
recommended that you do the same, in order to build the portions of the Swift
compiler written in Swift.
2. To install [Sccache][] (optional):
* If you're not building within a Docker container:
```sh
sudo snap install sccache --candidate --classic
```
* If you're building within a Docker container, you'll have to install
`sccache` manually, since [`snap` is not available in environments
without `systemd`](https://unix.stackexchange.com/questions/541230/do-snaps-require-systemd):
```sh
SCCACHE_VERSION=v0.3.0
curl -L "https://github.com/mozilla/sccache/releases/download/${SCCACHE_VERSION}/sccache-${SCCACHE_VERSION}-$(uname -m)-unknown-linux-musl.tar.gz" -o sccache.tar.gz
tar xzpvf sccache.tar.gz
sudo cp "sccache-${SCCACHE_VERSION}-$(uname -m)-unknown-linux-musl/sccache" /usr/local/bin
sudo chmod +x /usr/local/bin/sccache
```
> **Note**
> LLDB currently requires at least `swig-1.3.40` but will successfully build
> with version 2 shipped with Ubuntu.
[Sccache]: https://github.com/mozilla/sccache
## Building the project for the first time
### Spot check dependencies
* Run `cmake --version`; this should be at least 3.19.6 (3.24.2 if you want to use Xcode for editing on macOS).
* Run `python3 --version`; this should be at least 3.6.
* Run `ninja --version`; check that this succeeds.
* If you installed and want to use Sccache: Run `sccache --version`; check
that this succeeds.
> **Note**
> If you are running on Apple Silicon hardware (M1, M2, etc), ensure you have
> the native arm64 build of these dependencies installed and configured in your PATH.
>
> e.g. running `file $(which python3)` should print "arm64".
>
> If it prints "x86_64", you are running Python in compatibility mode (Rosetta), and building Swift will fail.
> Running `uname -m` should also print "arm64", otherwise your terminal is running in Rosetta mode.
### The roles of different tools
At this point, it is worthwhile to pause for a moment
to understand what the different tools do:
1. On macOS and Windows, IDEs (Xcode and Visual Studio resp.) serve as an
easy way to install development dependencies such as a C++ compiler,
a linker, header files, etc. The IDE's build system need not be used to
build Swift. On Linux, these dependencies are installed by the
distribution's package manager.
2. CMake is a cross-platform build system for C and C++.
It forms the core infrastructure used to _configure_ builds of
Swift and its companion projects.
3. Ninja is a low-level build system that can be used to _build_ the project,
as an alternative to Xcode's build system. Ninja is somewhat faster,
especially for incremental builds, and supports more build environments.
4. Sccache is a caching tool:
If you ever delete your build directory and rebuild from scratch
(i.e. do a "clean build"), Sccache can accelerate the new build
significantly. There are few things more satisfying than seeing Sccache
cut through build times.
> **Note**
> Sccache defaults to a cache size of 10GB, which is relatively small
> compared to build artifacts. You can bump it up, say, by setting
> `export SCCACHE_CACHE_SIZE="50G"` in your dotfile(s).
5. `utils/update-checkout` is a script to help you work with all the individual
git repositories together, instead of manually cloning/updating each one.
6. `utils/build-script` (we will introduce this shortly)
is a high-level automation script that handles configuration (via CMake),
building (via Ninja), caching (via Sccache), running tests and more.
> **Pro Tip**: Most tools support `--help` flags describing the options they
> support. Additionally, both Clang and the Swift compiler have hidden flags
> (`clang --help-hidden`/`swiftc --help-hidden`) and frontend flags
> (`clang -cc1 --help`/`swiftc -frontend --help`) and the Swift compiler
> even has hidden frontend flags (`swiftc -frontend --help-hidden`). Sneaky!
Phew, that's a lot to digest! Now let's proceed to the actual build itself!
### The actual build
Build the toolchain with optimizations, debuginfo, and assertions, using Ninja:
- macOS:
```sh
utils/build-script --skip-build-benchmarks \
--skip-ios --skip-watchos --skip-tvos --swift-darwin-supported-archs "$(uname -m)" \
--sccache --release-debuginfo --swift-disable-dead-stripping \
--bootstrapping=hosttools
```
- Linux:
```sh
utils/build-script --release-debuginfo
```
- If you want to additionally build the Swift core libraries, i.e.,
swift-corelibs-libdispatch, swift-corelibs-foundation, and
swift-corelibs-xctest, add `--xctest` to the invocation.
- If you installed and want to use Sccache, add `--sccache` to the invocation.
- If you want to use a debugger such as LLDB on compiler sources, add
`--debug-swift` to the invocation: a fruitful debugging experience warrants
non-optimized code besides debug information.
This will create a directory `swift-project/build/Ninja-RelWithDebInfoAssert`
containing the Swift compiler and standard library and clang/LLVM build artifacts.
If the build fails, see [Troubleshooting build issues](#troubleshooting-build-issues).
In the following sections, for simplicity, we will assume that you are using a
`Ninja-RelWithDebInfoAssert` build on macOS, unless explicitly mentioned otherwise.
You will need to slightly tweak the paths for other build configurations.
### Troubleshooting build issues
- Double-check that all projects are checked out at the right branches.
A common failure mode is using `git checkout` to change the branch only
for `swift` (often to a release branch), leading to an unsupported
configuration. See Step 4 of [Cloning the Project](#cloning-the-project)
on how to fix this.
- Double-check that all your dependencies
[meet the minimum required versions](#spot-check-dependencies).
- Check if there are spaces in the paths being used by `build-script` in
the log. While `build-script` should work with paths containing spaces,
sometimes bugs do slip through, such as [#55883](https://github.com/apple/swift/issues/55883).
If this is the case, please [file a bug report][Swift Issues] and change the path
to work around it.
- Check that your `build-script` invocation doesn't have typos. You can compare
the flags you passed against the supported flags listed by
`utils/build-script --help`.
- Check the error logs and see if there is something you can fix.
In many situations, there are several errors, so scrolling further back
and looking at the first error may be more helpful than simply looking
at the last error.
- Check if others have encountered the same issue on the [Swift Forums](https://forums.swift.org/c/development/compiler) or on [Swift repository 'Issues' tab][Swift Issues]. Here is a list of threads that describe common issues:
* [Problems with `build-script` building compiler with `โxcode`](https://forums.swift.org/t/problems-with-build-script-building-compiler-with-xcode/53477)
* [Error building the compiler (even with ninja)](https://forums.swift.org/t/error-building-the-compiler-even-with-ninja/54834)
* [Build failure on Apple MacBook Pro with Apple M1 Chip](https://forums.swift.org/t/build-failure-on-apple-silicon-m1-mac-mini/45011)
* [CMake cannot compile a test program](https://forums.swift.org/t/build-failure-locally/55695)
* [Building Swift compiler from source fails when not using Ninja](https://forums.swift.org/t/building-swift-compiler-from-source-fails-when-not-using-ninja/54656)
* [ALL_BUILD Target failing at validation](https://forums.swift.org/t/help-building-swift-in-xcode-error/49728)
* [โgtest/gtest.hโ not found while compiling the compiler](https://forums.swift.org/t/gtest-gtest-h-not-found-in-typeref-cpp-while-compiling-the-compiler/44399)
- If you still could not find a solution to your issue, feel free to create a new Swift Forums thread in the [Development/Compiler](https://forums.swift.org/c/development/compiler) category:
- Include information about your configuration and the errors you are seeing.
- You can [create a gist](https://gist.github.com) with the entire build
output and link it, while highlighting the most important part of the
build log in the post.
- Include the output of `utils/update-checkout --dump-hashes`.
[Swift Issues]: https://github.com/apple/swift/issues
[Swift Forums]: https://forums.swift.org
## Editing code
### Setting up your fork
If you are building the toolchain for development and submitting patches,
you will need to setup a GitHub fork.
First fork the `apple/swift` [repository](https://github.com/apple/swift.git),
using the "Fork" button in the web UI, near the top-right. This will create a
repository `username/swift` for your GitHub username. Next, add it as a remote:
```sh
# Using 'my-remote' as a placeholder name.
# If you set up SSH in step 2
git remote add my-remote git@github.com:username/swift.git
# If you used HTTPS in step 2
git remote add my-remote https://github.com/username/swift.git
```
Finally, create a new branch.
```sh
# Using 'my-branch' as a placeholder name
git checkout -b my-branch
git push --set-upstream my-remote my-branch
```
<!-- TODO: Insert paragraph about the main Ninja targets. -->
<!--
Note: utils/build-script contains a link to this heading that needs an update
whenever the heading is modified.
-->
### Using Ninja with Xcode
This workflow enables you to edit, build, run, and debug in Xcode. The
following steps assume that you have already [built the toolchain with Ninja](#the-actual-build).
> **Note**
> A seamless LLDB debugging experience requires that your `build-script`
invocation for Ninja is tuned to produce build rules for the
[debug variant](#debugging-issues) of the component you intend to debug.
* <p id="generate-xcode">
Generate the Xcode project with
```sh
utils/build-script --swift-darwin-supported-archs "$(uname -m)" --xcode --clean
```
This can take a few minutes due to metaprogrammed sources that depend on LLVM
tools that are built from source.
</p>
* Create an empty Xcode workspace.
* Add `build/Xcode-*/swift-macosx-*/Swift.xcodeproj` to the workspace. If Xcode
prompts to autocreate schemes, select *Manually Manage Schemes* and don't
create any schemes just yet.
This project includes the sources for almost everything in the repository,
including the compiler, standard library and runtime. If you intend to work on
a compiler subcomponent that is written in Swift and has a `Package.swift`
file (e.g. `lib/ASTGen`), first choose *Product > Scheme > Manage Schemes...*
and select the *Autocreate schemes* checkbox, then add the package directory
to the workspace by choosing *File > Add Files to "\<workspace name>"*. Xcode
will automatically create schemes for package manifest.
* Create an Xcode project using the _External Build System_ template, and add
it to the workspace.
* Create a target in the new project, using the _External Build System_
template.
* In the _Info_ pane of the target settings, set
* _Build Tool_ to the absolute path of the `ninja` executable (the output of
`which ninja` on the command line)
* _Arguments_ to a Ninja target (e.g. `bin/swift-frontend` is the compiler)
* _Directory_ to the absolute path of the `build/Ninja-*/swift-macosx-*`
directory
* Create a scheme in the workspace, making sure to select the target you just
created. Be *extra* careful not to choose a target from the generated Xcode
project you added to the workspace.
* Spot-check your target in the settings for the _Build_ scheme action.
* If the target is executable, adjust the settings for the _Run_ scheme action:
* In the _Info_ pane, select the _Executable_ produced by the Ninja target
from `build/Ninja-*/swift-macosx-*/bin` (e.g. `swift-frontend`).
* In the _Arguments_ pane, add command line arguments that you want to pass to
the executable on launch (e.g. `path/to/file.swift -typecheck` for
`bin/swift-frontend`).
* Optionally set a custom working directory in the _Options_ pane.
* Follow the previous steps to create more targets and schemes per your line
of work.
#### Regenerating the Xcode project
The structure of the generated Xcode project is distinct from the underlying
organization of the files on disk, and does not adapt to changes in the file
system, such as file/directory additions/deletions/renames. Over the course of
multiple `update-checkout` rounds, the resulting divergence is likely to begin
affecting your editing experience. To fix this, regenerate the project by
running the invocation from the <a href="#generate-xcode">first step</a>.
#### Troubleshooting editing issues in Xcode
* If a syntax highlighting or code action issue does not resolve itself after
regenerating the Xcode project, select a scheme that covers the affected area
and try *Product > Analyze*.
* Xcode has been seen to sometimes get stuck on indexing after switching back
and forth between distant branches. To sort things out, close the workspace
and delete the _Index_ directory from its derived data.
### Other IDEs setup
You can also use other editors and IDEs to work on Swift.
#### IntelliJ CLion
CLion supports CMake and Ninja. In order to configure it properly, build the swift project first using the `build-script`, then open the `swift` directory with CLion and proceed to project settings (`cmd + ,`).
In project settings, locate `Build, Execution, Deployment > CMake`. You will need to create a new profile named `RelWithDebInfoAssert` (or `Debug` if going to point it at the debug build). Enter the following information:
- Name: mirror the name of the build configuration here, e.g. `RelWithDebInfoAssert` or `Debug`
- Build type: This corresponds to `CMAKE_BUILD_TYPE` so should be e.g. `RelWithDebInfoAssert` or `Debug`
- latest versions of the IDE suggest valid values here. Generally `RelWithDebInfoAssert` is a good one to work with
- Toolchain: Default should be fine
- Generator: Ninja
- CMake options: You want to duplicate the essential CMake flags that `build-script` had used here, so CLion understands the build configuration. You can get the full list of CMake arguments from `build-script` by providing the `-n` dry-run flag; look for the last `cmake` command with a `-G Ninja`. Here is a minimal list of what you should provide to CLion here for this setting:
- `-D SWIFT_PATH_TO_CMARK_BUILD=SOME_PATH/swift-project/build/Ninja-RelWithDebInfoAssert/cmark-macosx-arm64 -D LLVM_DIR=SOME_PATH/swift-project/build/Ninja-RelWithDebInfoAssert/llvm-macosx-arm64/lib/cmake/llvm -D Clang_DIR=SOME_PATH/swift-project/build/Ninja-RelWithDebInfoAssert/llvm-macosx-arm64/lib/cmake/clang -D CMAKE_BUILD_TYPE=RelWithDebInfoAssert -D
SWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=SOME_PATH/swift-project/swift-syntax -G Ninja -S .`
- replace the `SOME_PATH` to the path where your `swift-project` directory is
- the CMAKE_BUILD_TYPE should match the build configuration name, so if you named this profile `RelWithDebInfo` the CMAKE_BUILD_TYPE should also be `RelWithDebInfo`
- **Note**: If you're using an Intel machine to build swift, you'll need to replace the architecture in the options. (ex: `arm64` with `x86_64`)
- Build Directory: change this to the Swift build directory corresponding to the `build-script` run you did earlier, for example, `SOME_PATH/swift-project/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64`.
With this done, CLion should be able to successfully import the project and have full autocomplete and code navigation powers.
### Editing
Make changes to the code as appropriate. Implement a shiny new feature!
Or fix a nasty bug! Update the documentation as you go! <!-- please ๐ -->
The codebase is your oyster!
:construction::construction_worker::building_construction:
Now that you have made some changes, you will need to rebuild...
### Incremental builds with Ninja
Subsequent steps in this and the next subsections are specific to the platform you're building on, so we'll try to detect it first and reuse as a shell variable:
```sh
platform=$([[ $(uname) == Darwin ]] && echo macosx || echo linux)
```
After setting that variable you can rebuild the compiler incrementally with this command:
```sh
ninja -C ../build/Ninja-RelWithDebInfoAssert/swift-${platform}-$(uname -m) bin/swift-frontend
```
To rebuild everything that has its sources located in the `swift` repository, including the standard library:
```sh
ninja -C ../build/Ninja-RelWithDebInfoAssert/swift-${platform}-$(uname -m)
```
Similarly, you can rebuild other projects like Foundation or Dispatch by substituting their respective subdirectories in the commands above.
### Spot checking an incremental build
As a quick test, go to `lib/Basic/Version.cpp` and tweak the version
printing code slightly. Next, do an incremental build as above. This incremental
build should be much faster than the from-scratch build at the beginning.
Now check if the version string has been updated (assumes you have `platform` shell variable
defined as specified in the previous subsection:
```sh
../build/Ninja-RelWithDebInfoAssert/swift-$(platform)-$(uname -m)/bin/swift-frontend --version
```
This should print your updated version string.
## Reproducing an issue
[Good first issues](https://github.com/apple/swift/contribute) typically have
small code examples that fit within a single file. You can reproduce such an
issue in various ways, such as compiling it from the command line using
`/path/to/swiftc MyFile.swift`, pasting the code into [Compiler Explorer](https://godbolt.org)
(aka godbolt) or using an Xcode Playground.
For files using frameworks from an SDK bundled with Xcode, you need the pass
the SDK explicitly. Here are a couple of examples:
```sh
# Compile a file to an executable for your local machine.
xcrun -sdk macosx /path/to/swiftc MyFile.swift
# Say you are trying to compile a file importing an iOS-only framework.
xcrun -sdk iphoneos /path/to/swiftc -target arm64-apple-ios13.0 MyFile.swift
```
You can see the full list of `-sdk` options using `xcodebuild -showsdks`,
and check some potential `-target` options for different operating systems by
skimming the compiler's test suite under `test/`.
Sometimes bug reports come with SwiftPM packages or Xcode projects as minimal
reproducers. While we do not add packages or projects to the compiler's test
suite, it is generally helpful to first reproduce the issue in context before
trying to create a minimal self-contained test case. If that's the case with
the bug you're working on, check out our
[instructions on building packages and Xcode projects with a locally built compiler](/docs/HowToGuides/FAQ.md#how-do-i-use-a-locally-built-compiler-to-build-x).
## Running tests
There are two main ways to run tests:
1. `utils/run-test`: By default, `run-test` builds the tests' dependencies
before running them.
```sh
# Rebuild all test dependencies and run all tests under test/.
utils/run-test --lit ../llvm-project/llvm/utils/lit/lit.py \
../build/Ninja-RelWithDebInfoAssert/swift-macosx-$(uname -m)/test-macosx-$(uname -m)
# Rebuild all test dependencies and run tests containing "MyTest".
utils/run-test --lit ../llvm-project/llvm/utils/lit/lit.py \
../build/Ninja-RelWithDebInfoAssert/swift-macosx-$(uname -m)/test-macosx-$(uname -m) \
--filter="MyTest"
```
2. `lit.py`: lit doesn't know anything about dependencies. It just runs tests.
```sh
# Run all tests under test/.
../llvm-project/llvm/utils/lit/lit.py -s -vv \
../build/Ninja-RelWithDebInfoAssert/swift-macosx-$(uname -m)/test-macosx-$(uname -m)
# Run tests containing "MyTest"
../llvm-project/llvm/utils/lit/lit.py -s -vv \
../build/Ninja-RelWithDebInfoAssert/swift-macosx-$(uname -m)/test-macosx-$(uname -m) \
--filter="MyTest"
```
The `-s` and `-vv` flags print a progress bar and the executed commands
respectively.
If you are making small changes to the compiler or some other component, you'll
likely want to [incrementally rebuild](#editing-code) only the relevant
target and use `lit.py` with `--filter`. One potential failure mode with this
approach is accidental use of stale binaries. For example, say that you want to
rerun a SourceKit test but you only incrementally rebuilt the compiler. Then
your changes will not be reflected when the test runs because the `sourcekitd`
binary was not rebuilt. Using `run-test` instead is the safer option, but it
will lead to a longer feedback loop due to more things getting rebuilt.
In the rare event that a local test failure happens to be unrelated to your
changes (is not due to stale binaries and reproduces without your changes),
there is a good chance that it has already been caught by our continuous
integration infrastructure, and it may be ignored.
If you want to rerun all the tests, you can either rebuild the whole project
and use `lit.py` without `--filter` or use `run-test` to handle both aspects.
For more details on running tests and understanding the various Swift-specific
lit customizations, see [Testing.md](/docs/Testing.md). Also check out the
[lit documentation](https://llvm.org/docs/CommandGuide/lit.html) to understand
how the different lit commands work.
## Debugging issues
In this section, we briefly describe two common ways of debugging: print
debugging and using LLDB.
Depending on the code you're interested in, LLDB may be significantly more
effective when using a debug build. Depending on what components you are
working on, you could turn off optimizations for only a few things.
Here are some example invocations:
```sh
# optimized Stdlib + debug Swiftc + optimized Clang/LLVM
utils/build-script --release-debuginfo --debug-swift # other flags...
# debug Stdlib + optimized Swiftc + optimized Clang/LLVM
utils/build-script --release-debuginfo --debug-swift-stdlib # other flags...
# optimized Stdlib + debug Swiftc (except typechecker) + optimized Clang/LLVM
utils/build-script --release-debuginfo --debug-swift --force-optimized-typechecker
# Last resort option, it is highly unlikely that you will need this
# debug Stdlib + debug Swiftc + debug Clang/LLVM
utils/build-script --debug # other flags...
```
Debug builds have two major drawbacks:
- A debug compiler is much slower, leading to longer feedback loops in case you
need to repeatedly compile the Swift standard library and/or run a large
number of tests.
- The build artifacts consume a lot more disk space.
[DebuggingTheCompiler.md](/docs/DebuggingTheCompiler.md) goes into a LOT
more detail on how you can level up your debugging skills! Make sure you check
it out in case you're trying to debug a tricky issue and aren't sure how to
go about it.
### Print debugging
A large number of types have `dump(..)`/`print(..)` methods which can be used
along with `llvm::errs()` or other LLVM streams. For example, if you have a
variable `std::vector<CanType> canTypes` that you want to print, you could do:
```cpp
auto &e = llvm::errs();
e << "canTypes = [";
llvm::interleaveComma(canTypes, e, [&](auto ty) { ty.dump(e); });
e << "]\n";
```
You can also crash the compiler using `assert`/`llvm_unreachable`/
`llvm::report_fatal_error`, after accumulating the result in a stream:
```cpp
std::string msg; llvm::raw_string_ostream os(msg);
os << "unexpected canTypes = [";
llvm::interleaveComma(canTypes, os, [&](auto ty) { ty.dump(os); });
os << "] !!!\n";
llvm::report_fatal_error(os.str());
```
### Debugging using LLDB
When the compiler crashes, the commandline arguments passed to it will be
printed to stderr. It will likely look something like:
```
/path/to/swift-frontend <args>
```
- Using LLDB on the commandline: Copy the entire invocation and pass it to LLDB.
```sh
lldb -- /path/to/swift-frontend <args>
```
Now you can use the usual LLDB commands like `run`, `breakpoint set` and so
on. If you are new to LLDB, check out the [official LLDB documentation][] and
[nesono's LLDB cheat sheet][].
- Using LLDB within Xcode:
Select the current scheme 'swift-frontend' โ Edit Scheme โ Run phase โ
Arguments tab. Under "Arguments Passed on Launch", copy-paste the `<args>`
and make sure that "Expand Variables Based On" is set to swift-frontend.
Close the scheme editor. If you now run the compiler
(<kbd>โ</kbd>+<kbd>R</kbd> or Product โ Run), you will be able to use the
Xcode debugger.
Xcode also has the ability to attach to and debug Swift processes launched
elsewhere. Under Debug โ Attach to Process by PID or name..., you can enter
a compiler process's PID or name (`swift-frontend`) to debug a compiler
instance invoked elsewhere. This can be helpful if you have a single compiler
process being invoked by another tool, such as SwiftPM or another open Xcode
project.
> **Pro Tip**: Xcode 12's terminal does not support colors, so you may see
> explicit color codes printed by `dump()` methods on various types. To avoid
> color codes in dumped output, run `expr llvm::errs().enable_color(false)`.
[official LLDB documentation]: https://lldb.llvm.org
[nesono's LLDB cheat sheet]: https://www.nesono.com/sites/default/files/lldb%20cheat%20sheet.pdf
## Next steps
Make sure you check out the following resources:
* [LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html): A style
guide followed by both LLVM and Swift. If there is a mismatch between the LLVM
Coding Standards and the surrounding code that you are editing, please match
the style of existing code.
* [LLVM Programmer's Manual](https://llvm.org/docs/ProgrammersManual.html):
A guide describing common programming idioms and data types used by LLVM and
Swift.
* [docs/README.md](/docs/README.md): Provides a bird's eye view of the available
documentation.
* [Lexicon.md](/docs/Lexicon.md): Provides definitions for jargon. If you run
into a term frequently that you don't recognize, it's likely that this file
has a definition for it.
* [Testing.md](/docs/Testing.md) and
[DebuggingTheCompiler.md](/docs/DebuggingTheCompiler.md): These cover more
ground on testing and debugging respectively.
* [Development Tips](/docs/DevelopmentTips.md): Tips for being more productive.
<!-- Link to Compiler Architecture.md once that is ready -->
If you see mistakes in the documentation (including typos, not just major
errors) or identify gaps that you could potentially improve the contributing
experience, please start a discussion on the forums, submit a pull request
or file a bug report on [Swift repository 'Issues' tab][Swift Issues]. Thanks!
|