PackageInfoMapper#
PackageInfoMapper is the core component in TuistLoader that translates Swift Package Manager manifest data (PackageInfo) into Tuist's ProjectDescription.Project representation. It lives at cli/Sources/TuistLoader/SwiftPackageManager/PackageInfoMapper.swift (~2,800 lines) and conforms to the PackageInfoMapping protocol .
Its two primary entry points are:
resolveExternalDependencies(...)β maps all resolved SPM packages into[String: [TargetDependency]]map(...)β maps a singlePackageInfointo aProjectDescription.Project?
Build Settings Generation#
The Settings.from(target:...) static method is the central routine for producing build settings for each generated target. It:
- Delegates SPM-to-Xcode flag translation to
SettingsMapper(mapSettings()returns a baseSettingsDictionary;settingsForBuildConfiguration(_:)layers in config-conditional overrides) - Emits
MODULEMAP_FILEwhen a generated module map path is available - Sets
DEFINES_MODULE = NOand appends-fmodule-name=<moduleName>toOTHER_CFLAGSfor.directory,.header, and.custommodule map cases - Appends prebuilt library flags (
OTHER_SWIFT_FLAGS -I,LIBRARY_SEARCH_PATHS,LD_RUNPATH_SEARCH_PATHS,OTHER_LDFLAGS -l) for prebuilt static library artifacts - Merges package base settings into the target's
baseSettingsDictionary, withPRODUCT_BUNDLE_IDENTIFIERexplicitly excluded to avoid clobbering sanitized per-target identifiers - Merges user-defined per-target overrides from
PackageSettings.targetSettings, with arrays unioned and scalars overriding
Module Map Generation#
Module map generation is delegated to SwiftPackageManagerModuleMapGenerator (injected into PackageInfoMapper at init time). Generated files are written into Derived/ModuleMaps/ for local packages . The generator's writeIfDifferent method preserves file modification times when content hasn't changed β a fix introduced in PR #11351 to stop Xcode from invalidating Swift compilation due to phantom mtime changes on module map files.
The downstream ModuleMapMapper (a graph mapper in TuistGenerator) propagates -Xcc -fmodule-map-file= flags and HEADER_SEARCH_PATHS across the dependency graph. Since PR #11797, it skips appending these flags to configurations that already contain $(inherited), preventing duplication in inheriting configurations.
Framework Search Paths & Response Files#
When a target has β₯20 precompiled framework search paths, FrameworkSearchPathsGraphMapper consolidates them into a response file at Derived/FrameworkSearchPaths/<Target>.resp . The response file is referenced via @file in OTHER_CFLAGS and OTHER_LDFLAGS, but OTHER_SWIFT_FLAGS receives -F flags directly . This was changed in PR #11023 to fix an Xcode 26 breakage where -Xcc @<resp> in OTHER_SWIFT_FLAGS caused ClangImporter to generate two -cc1 jobs, failing with "expected exactly one compiler job."
Trait-Conditional Settings#
When enabledTraits is non-empty, Settings.from(...) resolves trait conditions and appends matching names to SWIFT_ACTIVE_COMPILATION_CONDITIONS . Dependencies and prebuilts guarded by .when(traits:) conditions are excluded if none of their required traits appear in enabledTraits . PR #11370 fixed a prior gap where trait-conditional build settings were silently dropped because SettingsMapper didn't receive trait information.
Base Settings Propagation#
PackageSettings.baseSettings defines package-wide Xcode settings (e.g., deployment targets). These are merged into every generated target's base settings dictionary, with target-specific overrides taking final precedence . PR #11574 closed a gap where macro targets were excluded from this merge, causing build failures when MACOSX_DEPLOYMENT_TARGET was set at the package level.
Caching#
PR #11760 added SwiftPackageManagerGraphCache to serialize the fully-mapped DependenciesGraph to disk. The cache key hashes workspace-state.json, root manifest content, local package fingerprints, Swift/Tuist versions, and environment variables. The cache is invalidated if any recorded derived file (generated module map, XCFramework) is missing. This cuts ~2β4 s from tuist generate invocations when SPM dependencies are unchanged.
Key Related Files#
| File | Role |
|---|---|
PackageInfoMapper.swift | Core SPM β ProjectDescription translation |
SettingsMapper.swift | SPM build flags β Xcode SettingsDictionary |
SwiftPackageManagerModuleMapGenerator.swift | Generates .modulemap files for C-family targets |
ModuleMapMapper.swift | Graph mapper: propagates -fmodule-map-file flags across dep graph |
FrameworkSearchPathsGraphMapper.swift | Graph mapper: consolidates framework search paths into response files |