[Tuist] Version 4 / config / package / dependencies

2024. 3. 29. 16:11🍏/Xcode

Tuist config 설정.

공식문서의 개요를 보시면 

" Tuist는 공유 Config.swift 매니페스트를 통해 구성할 수 있습니다. 튜이스트가 실행되면 디렉토리를 탐색하여 Config.swift 파일이 포함된 튜이스트 디렉토리를 찾습니다. 구성 매니페스트 정의는 필수는 아니지만 저장소의 일부인 모든 프로젝트에서 일관된 동작을 보장하기 위해 권장됩니다. "

라고 적혀있습니다. 이 뜻은 config가 없어도 되지만 일관된 동작을 보장하려면 config를 작성하라고 권장하고 있습니다.

ProjectDescription 확인해서 해당 하는 인스턴스들이 어떤 역할을 하는지 간단하게 살펴보았습니다.

/// - Parameters:
///   - compatibleXcodeVersions: List of Xcode versions the project is compatible with.
///   - cloud: Cloud configuration.
///   - swiftVersion: The version of Swift that will be used by Tuist.
///   - plugins: A list of plugins to extend Tuist.
///   - generationOptions: List of options to use when generating the project.
import ProjectDescription

let config = Config(
    compatibleXcodeVersions: ["15.2"],
    swiftVersion: "5.4.0",
    generationOptions: .options(
        xcodeProjectName: "SomePrefix-\(.projectName)-SomeSuffix",
        organizationName: "Tuist",
        developmentRegion: "de"
    )
)

공식문서에 따르면 example로 상단의 코드를 주지만 .options의 생성자가 변경된 것인지 사용이 불가능합니다.

ProjectDescription을 까보면 .option 생성자 쪽에 이러한 인스턴스들이 들어가야 한다고 적혀있습니다. 인스턴스에 대해서 자세히 알고싶으시면 아래 더 보기를 눌러주세요.

더보기

 resolveDependenciesWithSystemScm

  • Bool 타입으로, true로 설정할 경우 Xcode는 시스템에 정의된 계정(예: git)을 사용하여 패키지 매니저 의존성을 해결합니다. 기본적으로 Xcode는 내부적으로 정의된 계정을 사용하지만, 이 옵션을 사용하면 시스템 수준의 SCM(소프트웨어 구성 관리) 설정을 사용하게 합니다.

disablePackageVersionLocking

  • Bool 타입으로, true로 설정할 경우 Swift 패키지의 버전 잠금을 비활성화합니다. 이는 프로젝트 생성 속도를 높일 수 있지만, 패키지 선언에서 버전이 명시적으로 잠기지 않았을 경우 위험을 증가시킬 수 있습니다.

clonedSourcePackagesDirPath

  • ProjectDescription.Path? 타입으로, 패키지 의존성을 해결할 때 사용할 사용자 정의 디렉토리를 설정할 수 있습니다. 이 경로는 xcodebuild 명령어에 -clonedSourcePackagesDirPath 인자로 전달됩니다.

staticSideEffectsWarningTargets

  • ProjectDescription.Config.GenerationOptions.StaticSideEffectsWarningTargets 타입으로, Tuist가 정적 라이브러리나 프레임워크의 중복 의존성으로 인한 부작용을 검사할 대상을 구성할 수 있습니다. 예를 들어, 여러 개의 그래프 분기가 동일한 정적 라이브러리를 전이적 의존성으로 포함하는 경우 경고를 발생시킬 수 있습니다.

enforceExplicitDependencies

  • Bool 타입으로, true로 설정할 경우 생성된 프로젝트는 빌드 설정과 빌드 경로를 수정하여 암시적 의존성을 가진 프로젝트가 모든 의존성이 명시적으로 선언될 때까지 빌드되지 않도록 합니다.
        /// When passed, Xcode will resolve its Package Manager dependencies using the system-defined
        /// accounts (for example, git) instead of the Xcode-defined accounts
        public var resolveDependenciesWithSystemScm: Bool

        /// Disables locking Swift packages. This can speed up generation but does increase risk if packages are not locked
        /// in their declarations.
        public var disablePackageVersionLocking: Bool

        /// Allows setting a custom directory to be used when resolving package dependencies
        /// This path is passed to `xcodebuild` via the `-clonedSourcePackagesDirPath` argument
        public var clonedSourcePackagesDirPath: ProjectDescription.Path?

        /// Allows configuring which targets Tuist checks for potential side effects due multiple branches of the graph
        /// including the same static library of framework as a transitive dependency.
        public var staticSideEffectsWarningTargets: ProjectDescription.Config.GenerationOptions.StaticSideEffectsWarningTargets

        /// The generated project has build settings and build paths modified in such a way that projects with implicit
        /// dependencies won't build until all dependencies are declared explicitly.
        public let enforceExplicitDependencies: Bool

        public static func options(resolveDependenciesWithSystemScm: Bool = false, disablePackageVersionLocking: Bool = false, clonedSourcePackagesDirPath: ProjectDescription.Path? = nil, staticSideEffectsWarningTargets: ProjectDescription.Config.GenerationOptions.StaticSideEffectsWarningTargets = .all, enforceExplicitDependencies: Bool = false) -> ProjectDescription.Config.GenerationOptions

그래서 결론적으로 제 프로젝트에는 

//
//  Config.swift
//  Packages
//
//  Created by Chan on 3/29/24.
//

import ProjectDescription

let config = Config(
    compatibleXcodeVersions: ["15.2"],
    swiftVersion: "5.9.2",
    generationOptions: .options()
)

위와 같이 Config.swift 파일을 설정하였습니다. 

Package 설정입니다. Alamofire 20230329 기준 최신 버전인 5.9.0을 사용하기 위하여 .framework로 등록하여 사용합니다.
기본적으로는 deafult값은 .staticFramework입니다.

product types는 enum으로 정리되어 있는데, 어떤 타입들이 있는지 확인하시려면 아래의 더 보기를 클릭하세요.

더보기
/// Possible products types.
public enum Product : String, Codable, Equatable {

    /// An application.
    case app

    /// A static library.
    case staticLibrary

    /// A dynamic library.
    case dynamicLibrary

    /// A dynamic framework.
    case framework

    /// A static framework.
    case staticFramework

    /// A unit tests bundle.
    case unitTests

    /// A UI tests bundle.
    case uiTests

    /// A custom bundle. (currently only iOS resource bundles are supported).
    case bundle

    /// A command line tool (macOS platform only).
    case commandLineTool

    /// An appClip. (iOS platform only).
    case appClip

    /// An application extension.
    case appExtension

    /// A Watch application. (watchOS platform only) .
    case watch2App

    /// A Watch application extension. (watchOS platform only).
    case watch2Extension

    /// A TV Top Shelf Extension.
    case tvTopShelfExtension

    /// An iMessage extension. (iOS platform only)
    case messagesExtension

    /// A sticker pack extension.
    case stickerPackExtension

    /// An XPC. (macOS platform only).
    case xpc

    /// An system extension. (macOS platform only).
    case systemExtension

    /// An ExtensionKit extension.
    case extensionKitExtension

    /// A Swift Macro
    /// Although Apple doesn't officially support Swift Macro Xcode Project targets, we
    /// enable them by adding a command line tool target, a target dependency in
    /// the dependent targets, and the right build settings to use the macro executable.
    case macro

    /// Creates a new instance with the specified raw value.
    ///
    /// If there is no value of the type that corresponds with the specified raw
    /// value, this initializer returns `nil`. For example:
    ///
    ///     enum PaperSize: String {
    ///         case A4, A5, Letter, Legal
    ///     }
    ///
    ///     print(PaperSize(rawValue: "Legal"))
    ///     // Prints "Optional("PaperSize.Legal")"
    ///
    ///     print(PaperSize(rawValue: "Tabloid"))
    ///     // Prints "nil"
    ///
    /// - Parameter rawValue: The raw value to use for the new instance.
    public init?(rawValue: String)

    /// The raw type that can be used to represent all values of the conforming
    /// type.
    ///
    /// Every distinct value of the conforming type has a corresponding unique
    /// value of the `RawValue` type, but there may be values of the `RawValue`
    /// type that don't have a corresponding value of the conforming type.
    public typealias RawValue = String

    /// The corresponding value of the raw type.
    ///
    /// A new instance initialized with `rawValue` will be equivalent to this
    /// instance. For example:
    ///
    ///     enum PaperSize: String {
    ///         case A4, A5, Letter, Legal
    ///     }
    ///
    ///     let selectedSize = PaperSize.Letter
    ///     print(selectedSize.rawValue)
    ///     // Prints "Letter"
    ///
    ///     print(selectedSize == PaperSize(rawValue: selectedSize.rawValue)!)
    ///     // Prints "true"
    public var rawValue: String { get }
}

외부 의존성 설정

Package.swift

// swift-tools-version: 5.9
import PackageDescription

#if TUIST
import ProjectDescription

let packageSettings = PackageSettings(
    productTypes: ["Alamofire": .framework,]
)
#endif

let package = Package(
    name: "SwiftyProteins",
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire", from: "5.9.0"),
        // You can read more about dependencies here: https://docs.tuist.io/documentation/tuist/dependencies
    ]
)

저는 Alamofire를 Dynamic Framework로 등록을 시켰습니다. Libraries, frameworks, swiftpackages에 대해서 알고 싶으시다면 이 링크가 도움이 되실 겁니다. https://chanhhh.tistory.com/200

 

[Swift] Libraries, Frameworks, Swift Packages

swift packages에 대해서 정리하고 알아보던 도중 좋은 글이 있어서, 읽어보면서 정리해보려고 쓰는 글입니다. Module Swift의 코드 구성과 접근 제어 개념은 모듈을 기반으로 합니다. 이 뜻은 하나의

chanhhh.tistory.com


내부 의존성 설정

Package를 등록했으면 타겟이 해당 프레임워크를 사용할 수 있게, 프레임워크를 의존해야 합니다. 

Project에서 사용할 타겟의 dependencies에 .external(name: "<프레임워크이름>") 로 의존성 주입이 가능해집니다.

Project.swift 

dependencies: [
                .external(name: "Alamofire")
            ]

tuist generate를 통하여 해당 external이 원하는 타겟으로 들어와 진 것을 확인할 수 있습니다. 

만약 다른 타겟 혹은 프로젝트들을 의존하고 싶다면 아래와 같이 사용하여 의존할 수 있습니다.
target 으로 지정할 수도, path를 입력한 프로젝트로도 사용할 수 있습니다.

dependencies: [
                .target(name: "SwiftyProteins"),
                .project(target: "SwiftyProteins", path: "../SwiftProteins")
            ]