🔥 Swift 패키지 매니저에서 모듈 별칭 사용하기

561자
7분

Swift 패키지 매니저(이하 SPM)에서는 서로 다른 패키지에서 동일한 이름의 모듈을 사용할 때 충돌이 발생할 수 있습니다. 이러한 모듈 이름 충돌을 해결하기 위해 SPM은 모듈 별칭(Module Aliasing) 기능을 제공합니다. 이 글에서는 모듈 별칭(Module Aliasing)을 사용하는 방법과 예제를 통해 자세히 살펴보겠습니다.

사용 시나리오

모듈 별칭(Module Aliasing)을 사용하는 상황을 다음과 같은 시나리오를 통해 알아봅시다.

예제 1

App 프로젝트는 swift-draw 패키지에서 Utils 모듈을 가져옵니다. 그런데 App은 또 다른 패키지인 swift-game에 의존하고 싶고, 해당 패키지에서도 Utils 모듈을 제공합니다.

 App
   |— Module Utils (from package 'swift-draw')
   |— Module Utils (from package 'swift-game')
text

swift-game 패키지의 매니페스트 파일은 다음과 같습니다.

{
    name: "swift-game",
    products: [
        .library(name: "Utils", targets: ["Utils"]),
    ],
    targets: [
        .target(name: "Utils", dependencies: [])
    ]
}
 
swift

swift-draw 패키지의 매니페스트 파일은 다음과 같습니다.

{
    name: "swift-draw",
    products: [
        .library(name: "Utils", targets: ["Utils"]),
    ],
    targets: [
        .target(name: "Utils", dependencies: [])
    ]
}
 
swift

swift-drawswift-game 패키지 모두 Utils라는 동일한 이름의 모듈을 제공하므로 충돌이 발생합니다. 이를 해결하기 위해 moduleAliases 매개변수를 사용하여 모듈 이름을 구분할 수 있습니다.

App 프로젝트의 매니페스트 파일에서 다음과 같이 moduleAliases를 설정합니다.

    targets: [
        .executableTarget(
            name: "App",
            dependencies: [
                .product(name: "Utils",
                         package: "swift-draw"),
                .product(name: "Utils",
                         package: "swift-game",
                         moduleAliases: ["Utils": "GameUtils"]),
            ])
    ]
 
swift

moduleAliases 매개변수의 값은 딕셔너리 형태로, 충돌하는 원래 모듈 이름을 키로, 사용자 정의 고유한 새 이름을 값으로 지정합니다. 여기서는 swift-game 패키지의 Utils 모듈을 GameUtils로 이름을 변경했습니다. 이렇게 하면 swift-game 패키지의 바이너리 이름은 GameUtils.swiftmodule이 됩니다. swift-game 패키지에서는 소스 코드나 매니페스트 파일을 변경할 필요가 없습니다.

별칭이 지정된 모듈을 사용하려면 App 프로젝트에서 새로운 이름인 import GameUtils를 참조해야 합니다. 기존의 import Utils 문은 예상대로 swift-draw 패키지의 Utils 모듈을 계속 참조합니다.

의존성 제품 이름이 중복되더라도, 즉 Utils라는 동일한 이름을 가지더라도 모듈 별칭(Module Aliasing)을 사용하면 허용됩니다. 단, 동일한 제품 이름의 파일이 여러 개 생성되지 않아야 합니다. 이는 모든 제품이 자동 라이브러리 유형이거나, 최대 하나만 정적 라이브러리, 동적 라이브러리, 실행 파일 또는 제품 이름으로 파일이나 디렉토리를 생성하는 다른 유형이어야 함을 의미합니다.

예제 2

App 프로젝트는 swift-draw 패키지에서 Utils 모듈을 가져옵니다. 그리고 swift-game 패키지에 의존하고 해당 패키지에서 제공하는 Game 모듈을 가져오고 싶습니다. Game 모듈은 동일한 패키지 내의 Utils 모듈을 가져옵니다.

App
  |— Module Utils (from package 'swift-draw')
  |— Module Game (from package 'swift-game')
       |— Module Utils (from package 'swift-game')
text

swift-game 패키지의 매니페스트 파일은 다음과 같습니다.

{
    name: "swift-game",
    products: [
        .library(name: "Game", targets: ["Game"]),
    ],
    targets: [
        .target(name: "Game", dependencies: ["Utils"])
        .target(name: "Utils", dependencies: [])
    ]
}
 
swift

예제 1과 유사하게 두 패키지 모두 Utils라는 동일한 이름의 모듈을 포함하므로 충돌이 발생합니다. App 프로젝트에서 swift-game 패키지의 Utils 모듈을 직접 가져오지 않더라도 충돌하는 모듈의 이름을 구분해야 합니다.

다음과 같이 moduleAliases를 사용할 수 있습니다.

App 프로젝트의 매니페스트 파일:

    targets: [
        .executableTarget(
            name: "App",
            dependencies: [
                .product(name: "Utils",
                         package: "swift-draw"),
                .product(name: "Game",
                         package: "swift-game",
                         moduleAliases: ["Utils": "GameUtils"]),
            ])
    ]
 
swift

swift-game 패키지의 Utils 모듈은 GameUtils로 이름이 변경되고, Game 모듈의 소스 파일에서 Utils에 대한 모든 참조는 GameUtils로 컴파일됩니다. 예제 1과 마찬가지로 swift-game 패키지에서 소스 코드나 매니페스트 파일을 변경할 필요가 없습니다.

더 많은 별칭을 정의해야 하는 경우 쉼표로 구분하여 추가할 수 있습니다.

    moduleAliases: ["Utils": "GameUtils", "Logging": "GameLogging"]),
 
swift

이렇게 모듈 별칭(Module Aliasing)을 사용하면 서로 다른 패키지에서 동일한 이름의 모듈을 사용할 때 발생하는 충돌을 해결할 수 있습니다. 모듈 이름을 별칭으로 지정하여 구분함으로써 원활하게 패키지를 관리할 수 있게 됩니다.

모듈 별칭(Module Aliasing)은 SPM의 강력한 기능 중 하나로, 패키지 간의 모듈 이름 충돌 문제를 우아하게 해결해 줍니다. 이 기능을 활용하여 프로젝트에서 다양한 패키지를 원활하게 통합하고 관리할 수 있습니다. 코드의 가독성과 유지 보수성을 높이는 데에도 도움이 될 것입니다.