라이브러리나 프레임워크의 인터페이스를 표현하는 코드 배포 단위
Swift 타겟은 여러 개의 Swift 파일을 가지고 있고 이 파일들이 모여서 모듈을 표현한다.
Swift 파일의 인터페이스는 접근 제어자를 통해서 표현된다.
모듈은 다른 모듈을 import할 수 있고, 프로젝트 전체적으로 비순환 모듈 그래프가 만들어지게 된다.
Swift 컴파일러는 외부 인터페이스들을 모아서 .swiftinterface 파일에 모아놓게 된다.
Objective-C나 C계열 언어에서는 Swift와 다르게 모듈의 인터페이스는 수동으로 작성된다.
헤더와 모듈맵으로 구성된다.
모듈맵이 알려주는 것
framework module UIKit {
umbrella header "UIKit.h"
export *
}
모듈 이름으로 import하거나 모듈에 포함된 헤더를 include하면 모듈을 사용하는 것이다.
import SwiftUI // Swift 모듈
import ResearchKit // Objective-C 모듈
#import "ORKActiveStepTimer.h" // 프로젝트 자체의 헤더
#import "ORKHelpers_Internal.h"
@import UIKit; // UIKit 모듈 import
#include <mach/mach.h> // SDK의 헤더 include. Clang이 module import로 바꿔줌
#include <mach/mach_time.h>
모듈은 인터페이스 파싱을 여러 소스파일에서 공유할 수 있게 해준다.
그러려면 컴파일러가 모듈을 찾고 컴파일 해야 한다.
컴파일러가 import 구문을 만나면 import가 어떤 모듈을 가리키는지 발견하고 해당 모듈의 컴파일 된 형태를 알야아 한다.
이 모듈을 빌드하는 부분에서 Xcode 16에서 달라지는 부분이 있다.
이렇게 암시적으로 빌드하는 모듈이 포함된 Swift, C, Objective-C 코드가 포함된 경우 종종 오래 걸리는 작업들이 생기게 된다.
빌드 시스템이 컴파일을 시작하면 여러 컴파일러 프로세스가 암시적으로 모듈을 찾아서 빌드가 안된경우는 빌드를 하거나 이미 존재하면 있는 걸 쓰게 된다.
이 때 한 컴파일러가 암시적으로 모듈을 찾아서 빌드하고 있으면 해당 모듈이 필요한 다른 컴파일러는 작업이 블록되게 된다.
이 작업은 빌드 과정에서 수없이 일어날 수 있다.
Xcode 16에서는 이를 명시적으로 하게 바뀌었다.
이를 위해서 Xcode는 컴파일 작업을 3단계로 나눈다.
이 모든 작업은 타임라인에 명시적으로 남는다.
모듈을 알게되면 아직 돌아갈 준비가 안된 작업이 대기상태로 레인을 채우지 않고 필요한 모듈이 준비되어야만 실제 작업을 시작하게 된다.
빌드시스템이 이를 알게 되면 가능한 실행 레인을 효율적으로 쓸 수 있게 된다.
명시적으로 모듈을 빌드했을 때의 장점