본문 바로가기

Tuist

[Tuist] Build Configuration설정하기

 

 

안녕하세요✋ 주니오스입니다.

 

 

최근 학습중인 Tuist글을 작성해 보겠습니다.

 

 

Build Setting을 xcconfig파일을 사용하여 설정해보도록 하겠습니다.

 

 

Build Setting

 

빌드세팅이랑 프로젝트에서 특정 타겟을 빌드할 때 사용되는 명세입니다.

 

 

빌드세팅은 크게 2가지가 있습니다. 프로젝트는 빌드세팅을 가질 수있고 타겟도 빌드세팅을 가질 수 있습니다.

 

 

프로젝트 타겟들이 공통으로 가질 세팅의 경우 프로젝트 빌드세팅으로 선언하고 타겟 맞춤형 세팅을 설정하는 경우는 타겟의 빌드 세팅을 수정하면 됩니다.

 

 

적용 단계(Level)

여러 곳에서 빌드세팅을 해도 결국 하나의 결과만이 적용(resolve)됩니다.

 

아래사진은 타겟의 빌드세팅 페이지 입니다.

 

Build Setting in Target

 

타겟(빌드세팅) / 타겟(xcconfig) / 프로젝트(빌드세팅) / 프로젝트(xcconfig) / 기본값 

 

 

가장 왼쪽에 있는 값이 최종적으로 빌드세팅에 사용되게 되고 사진과 같이 초록색 배경을 가지게됩니다.

(빌드세팅의 Level을 누를 시 해당 사진처럼 표시됩니다. 🤗)

 

 

타겟(빌드세팅), 프로젝트(빌드세팅) 의 경우 xcproj파일 내부에 존재하는 세팅 값입니다. 

 

 

xcproj파일의 경우 다소 불안정한 파일이며 해당 파일에 세팅을 저장하는 것보다는 문서화하여 저장하는 것이 좋습니다.

 

 

여기서 말하는 문서화 파일이 xcconfig파일입니다.

 

 

자, 그럼 이제부터 Tuist에서 xcconfig파일을 불러오고 타겟과 프로젝트에 적용시켜 보겠습니다.

 

 

빌드세팅이 선택되는 구조

 

아래그림을 보시면 전체적인 흐름을 파악할 수 있습니다!

 

전체적인 구조

 

 

프로젝트는 스킴이라는 것을 통해서 빌드할 타겟과 Configuration을 선택합니다.

 

Configuration은 Debug, Release, QA등을 의미합니다.

 

프로젝트가 선택한 스킴의 Configuration을 타겟은 사용하게 됩니다.

 

이때 타겟은 특정 Configuration에 대해 사용할 xcconfig파일을 지정할 수 있습니다.

 

기존의 Xcode프로젝트 세팅을 통해 해당 동작이 가능함을 알 수 있습니다.

 

Xcode 프로젝트 세팅

 

Device_Debug라는 Configuration이 선택될 경우 특정 타겟이 사용할 xcconfig파일을 지정할 수 있습니다.

 

자 그럼 해당 설정을 Tuist로 해보겠습니다!

 

 

Tuist를 활용한 Configuration 불러오기

 

먼저, xcconfig파일들을 생성하고 프로젝트에 포함합니다.

 

├── ProjectBase
│   ├── ProjectBase-Development.xcconfig    // DevelopmentBase
│   ├── ProjectBase-PROD.xcconfig           // PRODBase
│   ├── ProjectBase-QA.xcconfig             // QABase
│   └── ProjectBase-Test.xcconfig           // TestBase
│
├── Projects
│   ├── Project-Development.xcconfig      // Development
│   ├── Project-PROD.xcconfig		  // Product
│   ├── Project-QA.xcconfig	          // QA
│   └── Project-Test.xcconfig             // Test
├── iOS-Demo.xcconfig		          // Demo앱용
├── iOS-Framework.xcconfig	          // Framework용
└── iOS-Tests.xcconfig		          // Test(unitTest, uiTest)

 

 

저는 목적에 따라 총 11개의 파일을 생성하였습니다.

 

 

파일을 생성한 이후 파일의 경로를 플러그인을 사용하여 정의하였습니다.

(Tuist Plugin에 대한 이해가 있으셔야 합니다..!😓)

 

public struct XCConfig {
    private struct Path {
        static var framework: ProjectDescription.Path { .relativeToRoot("Configs/iOS-Framework.xcconfig") }
        static var demo: ProjectDescription.Path { .relativeToRoot("Configs/iOS-Demo.xcconfig") }
        static var tests: ProjectDescription.Path { .relativeToRoot("Configs/iOS-Tests.xcconfig") }
        static func project(_ config: String) -> ProjectDescription.Path { .relativeToRoot("Configs/Projects/Project-\(config).xcconfig") }
        static func projectBase(_ config: String) -> ProjectDescription.Path { .relativeToRoot("Configs/Projects/ProjectBase-\(config).xcconfig") }
    }
    
    public static let framework: [Configuration] = [
        .debug(name: "Development", xcconfig: Path.framework),
        .debug(name: "Test", xcconfig: Path.framework),
        .release(name: "QA", xcconfig: Path.framework),
        .release(name: "PROD", xcconfig: Path.framework),
    ]
    
    public static let tests: [Configuration] = [
        .debug(name: "Development", xcconfig: Path.tests),
        .debug(name: "Test", xcconfig: Path.tests),
        .release(name: "QA", xcconfig: Path.tests),
        .release(name: "PROD", xcconfig: Path.tests),
    ]
    public static let demo: [Configuration] = [
        .debug(name: "Development", xcconfig: Path.demo),
        .debug(name: "Test", xcconfig: Path.demo),
        .release(name: "QA", xcconfig: Path.demo),
        .release(name: "PROD", xcconfig: Path.demo),
    ]
    public static let project: [Configuration] = [
        .debug(name: "Development", xcconfig: Path.project("Development")),
        .debug(name: "Test", xcconfig: Path.project("Test")),
        .release(name: "QA", xcconfig: Path.project("QA")),
        .release(name: "PROD", xcconfig: Path.project("PROD")),
    ]
}

 

 

자 이렇게 xcconfig파일을 불러오는 과정은 끝냈습니다.

 

이제 특정 configuration을 타겟과 프로젝에 작용시켜주면 됩니다.

 

Scheme

해당 과정에 앞서 스킴에 좀더 자세히 말하자면

 

스킴은 프로젝트가 보유하며 빌드될 타겟과 빌드시 사용될 Configuration을 지정합니다.

 

다수의 스킴이 존재할 수 있지만 오직 하나의 스킴이 Active상태인 이유가 바로 그것이지요!

 

활성화된 TuistTestWorkSpace-Dev 스킴

 

스킴은 빌드될 타겟을 지정하고 아래사진과 같이 특정 타겟이 목적에 따라 빌드될 시 사용될 Configuration을 선택할 수 있습니다. 

 

스킴 디테일

 

따라서 특정 프로젝트를 빌드해 최종적으로 프로덕트를 만들고 싶다면,

 

스킴이 있어야 하며 스킴이 빌드세팅에 사용할 Configuration 필요합니다.

 

빌드세팅은 특정 Configuration이 사용하는 xcconfig파일로 구체화 됩니다.

 

Configuration설정

 

Settings타입 인스턴스 생성매서드에 Configuration배열을 전달할 수 있습니다.

import ConfigPlugin		// 플러그인 임포트

...

let target = Target(
	
    ...
    
    settings: .settings(base: settings, configurations: XCConfig.project)
)

...

 

XCConfig.project는 아래사진과 같이 Configuration배열입니다.

 

아래 사진과 같이 저는 총 4개의 Configuration을 만들것입니다.

 

XCConfig.project

 

그 후 해당 타겟을 포함하는 프로젝트에는 XCConfig.projectBase를 전달합니다.

 

앞서 구조도에서 보신 것같이 프로젝트는

 

프로젝트 내부 타겟들이 사용할 Configuration이 가질 기본적인 xcconfig파일을 지정할 수 있습니다.

 

타겟이 특정 Configuration에 대해 별도의 xcconfig파일을 가지지 않는다면, 프로젝의 xcconfig파일이 사용되는 것이지요! 😎

 

Project(
    name: name,
    organizationName: Environment.workspaceName,
    packages: packages,
    
    ✋✋✋✋✋✋
    settings: .settings(configurations: XCConfig.projectBase),
    targets: projectTargets,
    schemes: scheme
)

 

타겟의 빌드세팅에 들어가시면 아래와 같은 계층을 볼 수 있습니다.

 

타겟(빌드세팅) / 타겟(xcconfig) / 프로젝트(빌드세팅) / 프로젝트(xcconfig) / 기본값 

 

 

왼쪽에 위치할수록 우선순위가 높은 설정입니다. 

 

가장 우선순위가 높은것은 타겟(TuistTestWorkspace)자체 세팅(Settings)입니다. 타겟의 xcconfig가 바로 다음 우선순위입니다.

 

(타겟이름에 workspace가들어있는데 혼동 없으시길 바라겠습니다, 다음부턴 작명을좀..😓)

 

마지막으로 주입한 Configuration파일들을 사용하기 위해 스킴을 생성후 프로젝트에 선언해주겠습니다.

 

앱에 사용될 스킴을 아래 코드처럼 생성해넣고 간편하게 호출하여 스킴을 주입할 수 있습니다.

 

스킴들이 특정 Configuration을 가지는 것을 아래 코드로 확인할 수 있습니다.

 

static let appSchemes: [Scheme] = [
    // PROD API, debug scheme
    .init(
        name: "\(projectName)-DEV",
        shared: true,
        buildAction: .buildAction(targets: ["\(TargetName)"]),
        runAction: .runAction(configuration: "Development"),
        archiveAction: .archiveAction(configuration: "Development"),
        profileAction: .profileAction(configuration: "Development"),
        analyzeAction: .analyzeAction(configuration: "Development")
    ),
    // Test API, debug scheme
    .init(
        name: "\(projectName)-Test",
        shared: true,
        buildAction: .buildAction(targets: ["\(TargetName)"]),
        runAction: .runAction(configuration: "Test"),
        archiveAction: .archiveAction(configuration: "Test"),
        profileAction: .profileAction(configuration: "Test"),
        analyzeAction: .analyzeAction(configuration: "Test")
    ),
    // Test API, release scheme
    .init(
        name: "\(projectName)-QA",
        shared: true,
        buildAction: .buildAction(targets: ["\(TargetName)"]),
        runAction: .runAction(configuration: "QA"),
        archiveAction: .archiveAction(configuration: "QA"),
        profileAction: .profileAction(configuration: "QA"),
        analyzeAction: .analyzeAction(configuration: "QA")
    ),
    // PROD API, release scheme
    .init(
        name: "\(projectName)-PROD",
        shared: true,
        buildAction: .buildAction(targets: ["\(TargetName)"]),
        runAction: .runAction(configuration: "PROD"),
        archiveAction: .archiveAction(configuration: "PROD"),
        profileAction: .profileAction(configuration: "PROD"),
        analyzeAction: .analyzeAction(configuration: "PROD")
    ),
]

 

스킴들은 또한 빌드될 타겟을 지정합니다.

 

Tuist에서 빌드될 타겟은 buildAction매개변수로 지정할 수 있습니다.

buildAction: .buildAction(targets: ["\(TargetName)"]),

 

빌드시 사용될 Configuration을 선택합니다.

 

마지막으로 xcconfig파일들에 아래 텍스트를 추가하여 선택된 스킴의 Configuration마다 해당 옵션이 적용되는 지 확인해 봅시다.

 

아래 텍스트의 [config=] 부분은 현재 사용중인 Configuration이 일치하는 Configuration인 경우만 해당 옵션을 사용함을 의미합니다.

 

// Project-Development.xcconfig
OTHER_SWIFT_FLAGS[config=Development][sdk=*] = -DDevelopment

// Project-PROD.xcconfig
OTHER_SWIFT_FLAGS[config=PROD][sdk=*] = -DPROD

// Project-QA.xcconfig
OTHER_SWIFT_FLAGS[config=QA][sdk=*] = -DQA

// Project-Test.xcconfig
OTHER_SWIFT_FLAGS[config=Test][sdk=*] = -DTest

 

타겟 세팅에 따로 입력한 값이 없기에 xcconfig파일의 값이 잘적용(resolve)된 것을 확인할 수 있습니다.

 

빌드세팅 창

 

Run할때 스킴을 변경해 가며도 확인해 보겠습니다.

 

main

 

 

~ -Dev Sceme사용시 Flag가 올바르게 변경됨을 확인할 수 있었습니다.

 

실행결과

 

 

다음에는 Tuist를 사용하여 의존성 역전 구조를 만드는 방법을 포스팅 해보겠습니다.

 

감사합니다 ~!! ✋

'Tuist' 카테고리의 다른 글

[Xcode] 프로젝트 모듈화 개념 정리(with Tuist)  (1) 2023.11.13