Hive Hive
Sign in

Strange directory structure

GitHub issue · Open

Metadata
Source
tuist/tuist #7636
Updated
Jun 11, 2026
Domains
Generated projects
Details

What happened?

I have a monorepo project, and the directory organization structure of the project is roughly as follows:

.
├── Components
│ ├── General
│ ├── App1
│ │ └── SDK
│ │ ├── SDK.xcodeproj
│ │ ├── Project.swift
│ │ ├── Resouce
│ │ │ ├── Resource.bundle
│ │ │ ├── image.png
│ │ │ ├── music.mp3
│ │ │ └── file.plist
│ │ └── Sources
│ │ ├── AAXXSDK
│ │ │ ├── include
│ │ │ │ ├── Define.h
│ │ │ │ └── ErrorCode.h
│ │ │ └── libs
│ │ │ ├── libyyy.a
│ │ │ └── libxxx.a
│ │ └── SDK.framework
│ └── App2
├── Monerepo.xcworkspace
├── Projects
│ ├── App1
│ │ ├── Project.swift
│ │ └── App1.xcodeproj
│ └── App2
│ ├── Project.swift
│ └── App2.xcodeproj
├── Tuist
├── Tuist.swift
└── Workspace.swift

SDK is a non-standard library provided by a third party, namely SDK.framework. It depends on AAXXSDK, as shown in the directory structure, it contains multiple .a and header files.

When I use Tuist to generate a project for App1 based on this directory structure, the final project directory structure is roughly as follows:

Monorepo.xcworkspace
├── Components
│ └── App1
│ └── SDK.xcodeproj
│ ├── Frameworks
│ ├── Products
│ └── Project
│ ├── Derived
│ ├── Sources
│ │ └── AAXXSDK
│ │ └── include
│ │ ├── Define.h
│ │ └── ErrorCode.h
│ └── Resouce
│ ├── Resource.bundle
│ ├── image.png
│ ├── music.mp3
│ └── file.plist
├── Projects
│ └── App1.xcodeproj
│ ├── Project
│ │ ├── Components
│ │ │ └── App1
│ │ │ └── SDK
│ │ │ └── Sources
│ │ │ ├── AAXXSDK
│ │ │ │ └── libs
│ │ │ │ ├── libyyy.a
│ │ │ │ └── libxxx.a
│ │ │ └── SDK.framework
│ │ ├── Derived
│ │ └── App1
│ ├── Products
│ │ ├── SDK
│ │ └── App1
│ ├── Frameworks
│ └── Pods
└── Pods.xcodeproj
└── Podfile

The directory structure looks strange: the AAXXSDK part is split into two different .xcodeproj, the header files and resource content are in the component project, and the binary package is in the main project.

This strange directory makes it difficult for developers to find related content. I hope that the content related to SDK in the main project can be moved to SDK.xcodeproj

How do we reproduce it?

tuist-issue.zip

I have packaged a sample demo. After unzipping it, run rake generate:appone in the root directory to generate the project.

Error log

There is no error log, and the project can be built normally, but the generated one is very strange.

macOS version

15.5 (24F74)

Tuist version

4.50.2

Xcode version

16.3 (16E140)

Comments
D
dosubot[bot] Jun 4, 2025

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

The directory structure you’re seeing is a result of how Tuist organizes dependencies and project files during generation. Tuist treats each project’s dependencies as explicit and modular, and the way you declare dependencies in each Project.swift determines where headers, resources, and binaries end up in the generated .xcodeproj files.

In your case, the split of AAXXSDK (headers/resources in SDK.xcodeproj, binaries in App1.xcodeproj) is likely due to how the dependencies are declared in the Project.swift files for App1 and SDK. If App1 declares a dependency directly on the SDK binaries (like .framework or .a files), Tuist will include those in App1.xcodeproj, even if the headers and resources are part of SDK.xcodeproj. This is consistent with Tuist’s approach: each project only includes what it needs for its targets, and dependencies are not automatically grouped together unless you explicitly model them that way in your manifests.

To ensure all SDK-related content (headers, resources, binaries) appears only in SDK.xcodeproj, you should:

  1. In SDK/Project.swift, declare all SDK-related files (headers, resources, binaries) as part of the SDK target.
  2. In Projects/App1/Project.swift, depend on the SDK target from SDK.xcodeproj using a .project dependency, not by referencing the binaries directly.
  3. Avoid declaring the SDK binaries as direct dependencies in App1’s Project.swift. Instead, only depend on the SDK target.

This way, Tuist will keep all SDK content in SDK.xcodeproj, and App1.xcodeproj will reference SDK.xcodeproj as a dependency, not duplicate or split its contents.

For reference, see how Tuist handles dependencies and project structure in the documentation:
Tuist dependencies guide

If you adjust your Project.swift files accordingly and regenerate, you should see a more intuitive grouping of SDK-related files. If you need a concrete example or run into issues with the manifest syntax, let me know the relevant parts of your Project.swift files and I can help you adjust them.

To reply, just mention @dosu.


Docs are dead. Just use Dosu.

Leave Feedback Ask Dosu about tuist Share Dosu with your team

R
rakuyoMo Jun 4, 2025

@dosu You may not have read the demo in the compressed file. In the demo, Projects/App1/Project.swift does not reference any files in SDK, it just depends on SDK, everything is just like what you said, but the final generated project structure is very confusing.

D
dosubot[bot] Jun 5, 2025

Thank you for clarifying. Based on the available information and a review of similar Tuist project setups, your Project.swift for App1 does not directly reference SDK binaries, and you are using a .project dependency as recommended. However, the confusing directory structure—where headers/resources are in SDK.xcodeproj but binaries (.a, .framework) appear in App1.xcodeproj—stems from how Tuist currently handles binary and resource propagation across project boundaries.

Tuist’s project generation logic is designed so that only the files explicitly declared in a target’s sources, resources, and headers are included in that target’s project. When you declare a dependency on a target in another project (e.g., SDK), only the build product (the framework or library output) is linked in the dependent project (App1), not the sources or resources themselves. However, if your SDK target is not set up to encapsulate all the binary artifacts (like .a files or .frameworks) as part of its own build product, Tuist may end up copying or referencing those binaries in the consuming project’s structure, leading to the split you’re seeing.

This behavior is a result of Tuist’s explicit dependency model and how it maps targets and their outputs into the generated Xcode projects. It does not automatically “group” all related files under the SDK.xcodeproj unless the SDK target itself is configured to own and output all those files as part of its build product. If the SDK target only references headers/resources and not the actual binaries, Tuist will resolve the binaries at the point of consumption (App1), which is why they appear in App1.xcodeproj.

To address this, ensure that in your SDK/Project.swift, the SDK target’s sources, resources, and headers include all relevant files (including .a, .framework, and headers), and that the target’s product type matches what you want to expose (e.g., .framework or .staticFramework). App1 should only depend on the SDK target via .project, not reference any SDK files directly. This setup should keep all SDK-related content within SDK.xcodeproj, and App1.xcodeproj will only link against the SDK’s build product.

This is a known limitation of how Tuist currently models and generates projects with prebuilt or third-party SDKs and is not unique to your setup. If you need more granular control, you may need to adjust the SDK target’s configuration to ensure it fully encapsulates all SDK artifacts.

If you have a specific snippet from your SDK/Project.swift and App1/Project.swift, sharing those would help confirm if there’s a manifest-level tweak that could improve the structure. Otherwise, this behavior is consistent with Tuist’s current dependency and project generation model.

To reply, just mention @dosu.


Share context across your team and agents. Try Dosu.

Leave Feedback Learn about tuist with Dosu Add Dosu to your team