Generated projects
Tuist and XcodeGen produce the
.xcodeproj from a spec file, so the project is an artifact rather than something you edit. Everything
in the CLI works normally with them. build, run, test, archive, format and the rest neither
know nor care how the project got there.
Two things are different, and both exist to stop a generated project from lying to you.
Nothing to set up
Auto-discovery finds a generated .xcodeproj the same way it finds any other, searching upward to the
git root and then up to two levels down. A typical layout needs no configuration at all:
cd MyApp
sweetpad build
SweetPad recognizes the generator from the spec file sitting beside the .xcodeproj:
| Spec file | Generator |
|---|---|
project.yml, project.yaml, or project.json | XcodeGen |
Project.swift | Tuist |
The stale-spec warning
The failure mode that costs people an afternoon: you add a file to the spec, forget to regenerate, and the build fails with a compile error naming a symbol. The real cause is that the project has never heard of the file.
SweetPad compares the spec's modification time against the project's and says so up front:
$ sweetpad build
warning: project.yml is newer than SweetpadCIApp.xcodeproj — run 'xcodegen generate' so the build sees your latest file changes
building SweetpadCIApp (Debug) for platform=iOS Simulator,id=F92801F8-…
✓ Build succeeded (4.9s)
It's a warning rather than an error, and the build still runs, because an edited spec doesn't always change
what compiles. You get it once per command, so build --watch doesn't repeat it on every rebuild.
The comparison is against project.pbxproj specifically, not the .xcodeproj bundle around it. Xcode
writes user state inside that bundle constantly, and any of it would otherwise look like a fresh
generate, so the check would go quiet exactly when you need it.
Edits to the project are refused
The commands that mutate a project file (dependency add, dependency remove, dependency update,
and everything under pbxproj) stop before touching a generated project:
$ sweetpad pbxproj settings set SWIFT_VERSION=6.0
error: SweetpadCIApp.xcodeproj is generated by XcodeGen — this edit would be silently overwritten by the next `xcodegen generate`. Declare the change in project.yml instead, or pass --force to edit the generated project anyway (deliberate, ephemeral)
The edit would work. It would also vanish the next time anyone regenerates, probably on someone else's machine, probably without anyone noticing which change went missing. Declaring it in the spec is almost always what you actually want.
--force overrides the guard when you mean it: trying something out, reproducing a bug, scripting a
temporary change you're about to throw away:
sweetpad pbxproj settings set SWIFT_VERSION=6.0 --force
Treat anything you --force as ephemeral. It survives until the next xcodegen generate or
tuist generate and no longer.
Read-only commands are never affected. project info, settings show, dependency list, and
pbxproj settings show work on a generated project exactly as they do anywhere else.
Declaring the generator yourself
Detection needs the spec next to the .xcodeproj. When your layout puts it somewhere else, say so in
sweetpad.toml and the guard applies anyway:
# sweetpad.toml
generator = "tuist"
"xcodegen" and "tuist" are recognized by name and produce the messages above. Any other value
works too. The guard still fires, and the message names whatever tool you wrote.
An explicit generator wins over what's on disk, which is also how you turn the guard on for a
project generated by something SweetPad doesn't recognize.
Using the VS Code extension as well
The extension approaches the same problem from the other end: it can run xcodegen generate or
tuist generate for you, on a command or automatically when .swift files change. See its
Tuist and XcodeGen pages. Nothing here depends on it, and
the CLI's guards work whether or not the extension is installed.
The workflow
Nothing exotic: edit, regenerate, build.
$EDITOR project.yml
xcodegen generate
sweetpad build
If you find yourself reaching for sweetpad dependency add on a generated project, that's the moment
to add the package to the spec instead. The CLI's refusal is pointing at the right file.
Many generated-project repos gitignore the .xcodeproj entirely, since it can be rebuilt from the
spec. If yours does, the .pbxproj half of the
git merge drivers has nothing to do, though the Package.resolved half still earns its
keep.