Hive Hive
Sign in

SPM build tool plugins (e.g. SwiftLint) not emitted as PBXBuildToolPlugin/buildToolPlugins

GitHub issue · Open

Metadata
Source
tuist/tuist #9269
Updated
Sep 9, 2026
Details

What happened?

  1. Add a build-tool plugin package to the project packages (example in Tuist/Package.swift).
  2. Add the plugin as a target dependency, e.g.: .package(product: “SwiftLintBuildToolPlugin”, type: .plugin) and include it in a target dependency (.package(product: “…”, type: .plugin))
  3. Run tuist generate.
  4. Open the generated Xcode project and build a target that should use the plugin.
  5. Inspect generated project file *.xcodeproj/project.pbxproj.

How do we reproduce it?

  1. Add a build-tool plugin package to the project packages (example in Tuist/Package.swift).
  2. Add the plugin as a target dependency, e.g.: .package(product: “SwiftLintBuildToolPlugin”, type: .plugin) and include it in a target dependency (.package(product: “…”, type: .plugin))
  3. Run tuist generate.
  4. Open the generated Xcode project and build a target that should use the plugin.
  5. Inspect generated project file *.xcodeproj/project.pbxproj.

Error log

1) Target block shows a PBXTargetDependency referencing the plugin product:

<ANON_TARGET> /* PBXNativeTarget / = { isa = PBXNativeTarget; buildPhases = ( / Sources /, / Resources /, / Frameworks /, ); buildRules = ( ); dependencies = ( //, 0B69D60995D9AD7F00480AFF / PBXTargetDependency */, // plugin dependency entry ); name = “<ANON_TARGET>”; };

0B69D60995D9AD7F00480AFF /* PBXTargetDependency / = { isa = PBXTargetDependency; productRef = 5F9742E781E0E4A2DC0120DD / SwiftLintBuildToolPlugin */; };

2) Package product dependency exists:

5F9742E781E0E4A2DC0120DD /* SwiftLintBuildToolPlugin */ = { isa = XCSwiftPackageProductDependency; productName = “plugin:SwiftLintBuildToolPlugin”; … };

Expected but missing:

  • PBXBuildToolPlugin objects section mapping plugin product -> PBXBuildToolPlugin
  • buildToolPlugins = ( /* SwiftLintBuildToolPlugin */ ) entries inside the PBXNativeTarget block

Consequence: Xcode does not execute plugin (no plugin run printed in build logs; generated artifacts absent).

macOS version

25.2.0

Tuist version

4.131.1

Xcode version

26.2

Flights

Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.

New Flights are paused Configure model inference, GitHub, and a sandbox provider to start another Flight. Existing results remain available below.
No Flights yet

Start a Flight and preserve its objective, outcome, and session here.

Comments
L
linear[bot] Jan 28, 2026
D
dosubot[bot] Jan 28, 2026

Hi @losharik! I’m Dosu and I’m helping the tuist team.

Tuist does not currently support emitting SPM build tool plugins (like SwiftLint) as PBXBuildToolPlugin/buildToolPlugins in the generated Xcode project, which means Xcode won’t execute these plugins during the build. This is a known limitation—there’s an open issue tracking it (#6096), and a prototype PR (#7990) is in progress but not yet merged or complete. The current TargetGenerator only wires up standard dependencies and does not generate the PBX structures required for SPM build tool plugins, so what you’re seeing is expected behavior right now.

If you need plugin functionality immediately, you’ll need to use a manual workaround (like a custom script phase), or keep an eye on the referenced issue and PR for future support. For more details, see the Tuist documentation and the community discussion.

To reply, just mention @dosu.


Docs are dead. Just use Dosu.

Leave Feedback Ask Dosu about tuist Share Dosu with your team

P
pepicrft Jan 28, 2026

@losharik I’d also add to what Dosu said that you can install SwiftLint using Mise, and then invoke SwiftLint from a script build phase in your projects. At the end of the day, SwiftPM build tool plugins are a a convenient distribution and integration tool with slightly less convenient ways of achieveing the same thing. If ou are interested in taking the implementation yourself, we’d be happy to review the code, but we can’t prioritize this at the moment.

A
Austinate Sep 4, 2026

Hitting this too. Our case: an internal Swift package whose target uses swift-openapi-generator‘s OpenAPIGenerator build-tool plugin to generate its Client/Types/Servers sources at build time. It’s integrated via Tuist’s XcodeProj-based (.external()) package integration, so the plugin product resolves fine in the graph (shows up as a PBXTargetDependency), but no PBXBuildToolPlugin object or buildToolPlugins entry ever gets emitted, exactly like this issue describes. Xcode never runs the plugin, and the consuming target fails with “Cannot find type ‘Client’/‘Servers’ in scope.”

We’re weighing two workarounds: moving the package out of .external() into a Tuist-local target with a .pre script build phase that calls the generator’s CLI directly (thanks @marekfort for the pointer on a similar case in the community forum), or just running the generator once and committing the output, dropping the plugin dependency entirely - we already do this for another internal package unrelated to this migration. Both work, but neither feels as clean as native SwiftPM integration.

No pressure on timeline, just wanted to add a confirmed real-world case in case it helps gauge how common this is (this plus swift-openapi-generator, plus probably SwiftLint’s plugin per the issue title). Happy to share more repro details if it’d help.