Skip to content

Commit a9efa84

Browse files
authored
Merge pull request #77406 from hamishknight/a-new-generation
Introduce swift-xcodegen
2 parents 998b350 + 03d8ea5 commit a9efa84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+8308
-61
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,15 @@
261261

262262
# utils
263263
/utils/*windows* @compnerd
264+
/utils/generate-xcode @hamishknight
264265
/utils/gyb_sourcekit_support/ @ahoppen @bnbarham @hamishknight @rintaro
265266
/utils/sourcekit_fuzzer/ @ahoppen @bnbarham @hamishknight @rintaro
266267
/utils/swift_build_support/products/earlyswiftsyntax.py @ahoppen @bnbarham @hamishknight @rintaro
267268
/utils/swift_build_support/products/skstresstester.py @ahoppen @bnbarham @hamishknight @rintaro
268269
/utils/swift_build_support/products/sourcekitlsp.py @ahoppen @bnbarham @hamishknight @rintaro
269270
/utils/swift_build_support/products/swiftformat.py @ahoppen @allevato @bnbarham @hamishknight @rintaro
270271
/utils/swift_build_support/products/swiftsyntax.py @ahoppen @bnbarham @hamishknight @rintaro
272+
/utils/swift-xcodegen/ @hamishknight
271273
/utils/update-checkout* @shahmishal
272274
/utils/update_checkout/ @shahmishal
273275
/utils/vim/ @compnerd

docs/HowToGuides/GettingStarted.md

Lines changed: 16 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ toolchain as a one-off, there are a couple of differences:
2626
- [Setting up your fork](#setting-up-your-fork)
2727
- [Using Ninja with Xcode](#using-ninja-with-xcode)
2828
- [Regenerating the Xcode project](#regenerating-the-xcode-project)
29-
- [Troubleshooting editing issues in Xcode](#troubleshooting-editing-issues-in-xcode)
3029
- [Other IDEs setup](#other-ides-setup)
3130
- [Editing](#editing)
3231
- [Incremental builds with Ninja](#incremental-builds-with-ninja)
@@ -367,55 +366,21 @@ following steps assume that you have already [built the toolchain with Ninja](#t
367366
[debug variant](#debugging-issues) of the component you intend to debug.
368367

369368
* <p id="generate-xcode">
370-
Generate the Xcode project with
369+
Generate the Xcode project with:
371370

372371
```sh
373-
utils/build-script --swift-darwin-supported-archs "$(uname -m)" --xcode --clean
372+
utils/generate-xcode <build dir>
374373
```
375374

376-
This can take a few minutes due to metaprogrammed sources that depend on LLVM
377-
tools that are built from source.
378-
</p>
379-
* Create an empty Xcode workspace and open it.
380-
* Add `build/Xcode-*/swift-macosx-*/Swift.xcodeproj` to the workspace by
381-
selecting the Project navigator and choosing
382-
*File > Add Files to "\<workspace name>"*.
383-
384-
> **Important**\
385-
> If upon addition Xcode prompts to autocreate schemes, select *Manually
386-
Manage Schemes*.
387-
388-
This Xcode project includes the sources for almost everything in the
389-
repository, including the compiler, standard library and runtime.
390-
If you intend to work on a compiler subcomponent that is written in Swift and
391-
has a `Package.swift` file, e.g. `lib/ASTGen`, first choose
392-
*Product > Scheme > Manage Schemes* and select the *Autocreate schemes*
393-
checkbox, then add the package directory to the workspace the same way you
394-
added the Xcode project.
395-
Xcode will automatically create schemes for the package manifest.
396-
* Create an Xcode project using the _External Build System_ template, and add
397-
it to the workspace.
398-
* Create a target in the new Xcode project, using the _External Build System_
399-
template.
400-
* In the _Info_ pane of the target settings, set
401-
* _Build Tool_ to the absolute path of the `ninja` executable (the output of
402-
`which ninja` on the command line)
403-
* _Arguments_ to a Ninja target (e.g. `bin/swift-frontend` is the compiler)
404-
* _Directory_ to the absolute path of the `build/Ninja-*/swift-macosx-*`
405-
directory
406-
* Create a scheme in the workspace, making sure to select the target you just
407-
created. Be *extra* careful not to choose a target from the generated Xcode
408-
project you added to the workspace.
409-
* Spot-check your target in the settings for the _Build_ scheme action.
410-
* If the target is executable, adjust the settings for the _Run_ scheme action:
411-
* In the _Info_ pane, select the _Executable_ produced by the Ninja target
412-
from `build/Ninja-*/swift-macosx-*/bin` (e.g. `swift-frontend`).
413-
* In the _Arguments_ pane, add command line arguments that you want to pass to
414-
the executable on launch (e.g. `path/to/file.swift -typecheck` for
415-
`bin/swift-frontend`).
416-
* Optionally set a custom working directory in the _Options_ pane.
417-
* Follow the previous steps to create more targets and schemes per your line
418-
of work.
375+
where `<build dir>` is the path to the build directory e.g
376+
`../build/Ninja-RelWithDebInfoAssert`. This will create a `Swift.xcodeproj`
377+
in the parent directory (next to the `build` directory).
378+
379+
`generate-xcode` directly invokes `swift-xcodegen`, which is a tool designed
380+
specifically to generate Xcode projects for the Swift repo (as well as a
381+
couple of adjacent repos such as LLVM and Clang). It supports a number of
382+
different options, you can run `utils/generate-xcode --help` to see them. For
383+
more information, see [the documentation for `swift-xcodegen`](/utils/swift-xcodegen/README.md).
419384

420385
#### Regenerating the Xcode project
421386

@@ -426,15 +391,6 @@ multiple `update-checkout` rounds, the resulting divergence is likely to begin
426391
affecting your editing experience. To fix this, regenerate the project by
427392
running the invocation from the <a href="#generate-xcode">first step</a>.
428393

429-
#### Troubleshooting editing issues in Xcode
430-
431-
* If a syntax highlighting or code action issue does not resolve itself after
432-
regenerating the Xcode project, select a scheme that covers the affected area
433-
and try *Product > Analyze*.
434-
* Xcode has been seen to sometimes get stuck on indexing after switching back
435-
and forth between distant branches. To sort things out, close the workspace
436-
and delete the _Index_ directory from its derived data.
437-
438394
### Other IDEs setup
439395

440396
You can also use other editors and IDEs to work on Swift.
@@ -658,12 +614,11 @@ printed to stderr. It will likely look something like:
658614
on. If you are new to LLDB, check out the [official LLDB documentation][] and
659615
[nesono's LLDB cheat sheet][].
660616
- Using LLDB within Xcode:
661-
Select the current scheme 'swift-frontend' → Edit Scheme → Run phase →
662-
Arguments tab. Under "Arguments Passed on Launch", copy-paste the `<args>`
663-
and make sure that "Expand Variables Based On" is set to swift-frontend.
664-
Close the scheme editor. If you now run the compiler
665-
(<kbd>⌘</kbd>+<kbd>R</kbd> or Product → Run), you will be able to use the
666-
Xcode debugger.
617+
Select the current scheme 'swift-frontend' → Edit Scheme → Run → Arguments
618+
tab. Under "Arguments Passed on Launch", copy-paste the `<args>` and make sure
619+
that "Expand Variables Based On" is set to swift-frontend. Close the scheme
620+
editor. If you now run the compiler (<kbd>⌘</kbd>+<kbd>R</kbd> or
621+
Product → Run), you will be able to use the Xcode debugger.
667622
668623
Xcode also has the ability to attach to and debug Swift processes launched
669624
elsewhere. Under Debug → Attach to Process by PID or name..., you can enter

test/lit.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ config.substitutions.append( ('%use_just_built_liblto', use_just_built_liblto) )
240240
config.substitutions.append( ('%llvm_libs_dir', llvm_libs_dir) )
241241
config.substitutions.append( ('%llvm_plugin_ext', llvm_plugin_ext) )
242242

243+
# Allow tests to restore the original environment if they need to.
244+
config.substitutions.append( ('%original_path_env', config.environment['PATH']) )
245+
243246
def append_to_env_path(directory):
244247
config.environment['PATH'] = \
245248
os.path.pathsep.join((directory, config.environment['PATH']))

utils/generate-xcode

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/zsh
2+
exec "$0:A:h/swift-xcodegen/swift-xcodegen" "$@"

utils/swift-xcodegen/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
.swiftpm

utils/swift-xcodegen/Package.resolved

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

utils/swift-xcodegen/Package.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// swift-tools-version: 5.8
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
import class Foundation.ProcessInfo
6+
7+
let package = Package(
8+
name: "swift-xcodegen",
9+
platforms: [.macOS(.v13)],
10+
targets: [
11+
.target(name: "Xcodeproj", exclude: ["README.md"]),
12+
.target(
13+
name: "SwiftXcodeGen",
14+
dependencies: [
15+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
16+
.product(name: "SwiftOptions", package: "swift-driver"),
17+
"Xcodeproj"
18+
],
19+
swiftSettings: [
20+
.enableExperimentalFeature("StrictConcurrency")
21+
]
22+
),
23+
.executableTarget(
24+
name: "swift-xcodegen",
25+
dependencies: [
26+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
27+
"SwiftXcodeGen"
28+
],
29+
swiftSettings: [
30+
.enableExperimentalFeature("StrictConcurrency")
31+
]
32+
),
33+
.testTarget(
34+
name: "SwiftXcodeGenTest",
35+
dependencies: ["SwiftXcodeGen"]
36+
)
37+
]
38+
)
39+
40+
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
41+
package.dependencies += [
42+
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.4.0"),
43+
.package(url: "https://github.com/swiftlang/swift-driver", branch: "main"),
44+
]
45+
} else {
46+
package.dependencies += [
47+
.package(path: "../../../swift-argument-parser"),
48+
.package(path: "../../../swift-driver"),
49+
]
50+
}

utils/swift-xcodegen/README.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# swift-xcodegen
2+
3+
A script for generating an Xcode project for the Swift repo, that sits on top of an existing Ninja build. This has a few advantages over CMake's Xcode generator (using `build-script --xcode`):
4+
5+
- Fast to regenerate (less than a second)
6+
- Native Swift targets for ASTGen/SwiftCompilerSources + Standard Library
7+
- Better file organization (by path rather than by target)
8+
- Much fewer targets, easier to manage
9+
10+
This script is primarily focussed on providing a good editor experience for working on the Swift project; it is not designed to produce compiled products or run tests, that should be done with `ninja` and `build-script`. It can however be used to [debug executables produced by the Ninja build](#debugging).
11+
12+
## Running
13+
14+
Run as:
15+
16+
```
17+
./swift-xcodegen <path to Ninja build directory>
18+
```
19+
20+
An Xcode project will be created in the grandparent directory (i.e `build/../Swift.xcodeproj`). Projects for LLVM, LLDB, and Clang may also be created by passing `--llvm`, `--lldb`, and `--clang` respectively. Workspaces of useful combinations will also be created (e.g Swift+LLVM, Clang+LLVM).
21+
22+
An `ALL` meta-target is created that depends on all the targets in the given project or workspace. A scheme for this target is automatically generated too (and automatic scheme generation is disabled). You can manually add individual schemes for targets you're interested in. Note however that Clang targets do not currently have dependency information.
23+
24+
## Debugging
25+
26+
By default, schemes are added for executable products, which can be used for debugging in Xcode. These use `ninja` to build the product before running. If using a separate build for debugging, you can specify it with `--runnable-build-dir`.
27+
28+
## Standard library targets
29+
30+
By default, C/C++ standard library + runtime files are added to the project. Swift targets may be added by passing `--stdlib-swift`, which adds a target for the core standard library as well as auxiliary libraries (e.g CxxStdlib, Backtracing, Concurrency). This requires using Xcode with an up-to-date development snapshot, since the standard library expects to be built using the just-built compiler.
31+
32+
## Command usage
33+
34+
```
35+
USAGE: swift-xcodegen [<options>] <build-dir>
36+
37+
ARGUMENTS:
38+
<build-dir> The path to the Ninja build directory to generate for
39+
40+
LLVM PROJECTS:
41+
--clang/--no-clang Generate an xcodeproj for Clang (default: --no-clang)
42+
--clang-tools-extra/--no-clang-tools-extra
43+
When generating a project for Clang, whether to include clang-tools-extra (default: --clang-tools-extra)
44+
--lldb/--no-lldb Generate an xcodeproj for LLDB (default: --no-lldb)
45+
--llvm/--no-llvm Generate an xcodeproj for LLVM (default: --no-llvm)
46+
47+
SWIFT TARGETS:
48+
--swift-targets/--no-swift-targets
49+
Generate targets for Swift files, e.g ASTGen, SwiftCompilerSources. Note
50+
this by default excludes the standard library, see '--stdlib-swift'. (default: --swift-targets)
51+
--swift-dependencies/--no-swift-dependencies
52+
When generating Swift targets, add dependencies (e.g swift-syntax) to the
53+
generated project. This makes build times slower, but improves syntax
54+
highlighting for targets that depend on them. (default: --swift-dependencies)
55+
56+
RUNNABLE TARGETS:
57+
--runnable-build-dir <runnable-build-dir>
58+
If specified, runnable targets will use this build directory. Useful for
59+
configurations where a separate debug build directory is used.
60+
--runnable-targets/--no-runnable-targets
61+
Whether to add runnable targets for e.g swift-frontend. This is useful
62+
for debugging in Xcode. (default: --runnable-targets)
63+
--build-runnable-targets/--no-build-runnable-targets
64+
If runnable targets are enabled, whether to add a build action for them.
65+
If false, they will be added as freestanding schemes. (default: --build-runnable-targets)
66+
67+
PROJECT CONFIGURATION:
68+
--compiler-libs/--no-compiler-libs
69+
Generate targets for compiler libraries (default: --compiler-libs)
70+
--compiler-tools/--no-compiler-tools
71+
Generate targets for compiler tools (default: --compiler-tools)
72+
--docs/--no-docs Add doc groups to the generated projects (default: --docs)
73+
--stdlib, --stdlib-cxx/--no-stdlib, --no-stdlib-cxx
74+
Generate a target for C/C++ files in the standard library (default: --stdlib)
75+
--stdlib-swift/--no-stdlib-swift
76+
Generate targets for Swift files in the standard library. This requires
77+
using Xcode with with a main development snapshot (and as such is disabled
78+
by default). (default: --no-stdlib-swift)
79+
--test-folders/--no-test-folders
80+
Add folder references for test files (default: --test-folders)
81+
--unittests/--no-unittests
82+
Generate a target for the unittests (default: --unittests)
83+
--infer-args/--no-infer-args
84+
Whether to infer build arguments for files that don't have any, based
85+
on the build arguments of surrounding files. This is mainly useful for
86+
files that aren't built in the default config, but are still useful to
87+
edit (e.g sourcekitdAPI-InProc.cpp). (default: --infer-args)
88+
89+
MISC:
90+
--project-root-dir <project-root-dir>
91+
The project root directory, which is the parent directory of the Swift repo.
92+
By default this is inferred from the build directory path.
93+
--output-dir <output-dir>
94+
The output directory to write the Xcode project to. Defaults to the project
95+
root directory.
96+
--log-level <log-level> The log level verbosity (default: info) (values: debug, info, note, warning, error)
97+
--parallel/--no-parallel
98+
Parallelize generation of projects (default: --parallel)
99+
-q, --quiet Quiet output; equivalent to --log-level warning
100+
101+
OPTIONS:
102+
-h, --help Show help information.
103+
```
104+
105+
## TODO
106+
107+
- [ ] Add support for mixed Swift + Clang targets
108+
- [ ] More tests

0 commit comments

Comments
 (0)