/ 블로그 / Swift 6.4 duplic
ENGINEERING_BLOG · 2026.09.08

Swift 6.4 duplicate module name: 2026 원격 Mac CI 수정

Swift 6.4로 바꾼 뒤 원격 Mac CI에서 duplicate module name이 처음 발생했다면, 안정 툴체인이 통과했다는 사실과 새 노드가 실패했다는 사실을 먼저 보존해야 합니다.

가장 빠른 해결 순서는 노드를 재구축하거나 전체 캐시를 지우는 것이 아닙니다. 같은 의존성 검색에서 두 개의 같은 이름 Clang module 선언이 보였는지 확인하고, module.modulemap의 출처와 검색 경로를 추적한 뒤 중복 선언 제거, 의존성 업그레이드 또는 자체 모듈 이름 변경을 선택해야 합니다.

이번 주 권장 일정: 오늘은 실패 로그와 활동 툴체인을 고정하고, 다음 작업일에는 모듈 선언과 검색 경로를 비교하십시오. 서드파티 SDK를 당장 고칠 수 없다면 생산 CI는 안정 버전에 두고 Swift 6.4를 별도 검증선으로 운영하십시오.

이 글은 Objective-C, C/C++ 또는 바이너리 SDK를 포함한 Swift 프로젝트를 관리하는 개발자를 위한 글입니다. 원격 Mac 빌드 노드와 의존성 캐시를 담당하는 DevOps 엔지니어, 그리고 업그레이드 보류 여부를 결정하는 플랫폼 책임자에게도 해당합니다.

SECTION 01 먼저 실패 경계를 고정해야 합니다

duplicate module name은 일반적인 import 실패와 같은 문제가 아닙니다. module not found는 모듈을 찾지 못한 상태이고, redefinition은 선언 내부가 겹친 상태일 수 있습니다. 링크 단계의 라이브러리 오류라면 모듈 검색보다 뒤에서 발생합니다.

따라서 최종 종료 코드만 보고 원인을 정하면 안 됩니다. 다음 항목을 성공한 빌드와 실패한 빌드에서 함께 보존하십시오.

  • 활동 중인 Xcode와 Swift 툴체인
  • 전체 빌드 명령과 주요 환경 변수
  • Package.resolved 또는 동일한 의존성 잠금 상태
  • SDK 선택 결과와 헤더 검색 경로
  • 첫 번째 유효한 진단 메시지
  • 실패한 작업의 실제 모듈 로딩 경로

Apple은 Xcode 27 베타 6의 시스템 요구 사항 페이지에서 Swift 6.4가 포함된 구성을 안내하고 있습니다. Xcode 27 릴리스 노트에는 새 Swift dependency scanner가 한 번의 스캔에서 도달 가능한 Clang module 이름의 유일성을 요구한다는 내용이 확인됩니다. 이는 현재 베타 계열의 동작 근거이지, 이후 정식 버전의 영구적인 동작을 보장하는 문장은 아닙니다. Xcode 27 릴리스 노트Xcode 시스템 요구 사항을 배포 전에 다시 확인하십시오.

SECTION 02 충돌이 저장소 안에 있는 경우

가장 먼저 확인할 곳은 프로젝트가 직접 관리하는 module.modulemap입니다. 다음처럼 저장소와 의존성 디렉터리를 별도로 조사하십시오.

find <REPOSITORY_ROOT> -name module.modulemap -print
find <DEPENDENCY_ROOT> -name module.modulemap -print
grep -R "module <MODULE_NAME>" <REPOSITORY_ROOT> <DEPENDENCY_ROOT>

파일 이름만 보고 지우면 안 됩니다. 같은 모듈 이름을 가진 선언의 다음 내용을 대조해야 합니다.

  • 모듈 이름
  • umbrella 또는 공개 헤더 진입점
  • 실제 헤더가 있는 디렉터리
  • framework module인지 일반 module인지
  • 해당 경로를 추가한 패키지나 빌드 타깃

Swift Package Manager의 시스템 라이브러리 의존성 문서는 모듈 맵을 패키지와 연결하는 방식을 설명합니다. 공식 module map 문서를 기준으로 패키지 선언과 실제 파일의 관계를 확인하십시오.

자체 모듈과 패키지 모듈이 같은 이름을 사용한다면 우선순위는 명확합니다. 두 선언을 하나로 합칠 수 있으면 공개 헤더 진입점을 통합하고, 서로 다른 구성요소라면 자체 모듈 이름을 바꾸는 편이 안전합니다. 무작위 디렉터리를 삭제하는 방식은 다음 노드나 개발자 컴퓨터에서 같은 오류를 다시 만들 수 있습니다.

SECTION 03 외부 SDK와 검색 경로를 분리해 확인합니다

서드파티 소스, XCFramework, Swift Package, 수동으로 넣은 SDK가 각각 모듈 맵을 제공할 수 있습니다. 이때 충돌은 두 종류로 나뉩니다.

충돌 유형 확인할 대상 우선 선택할 수정
서로 다른 서드파티 구성요소가 같은 모듈 이름 사용 패키지의 module.modulemap, XCFramework 내부 헤더 호환 버전 확인 후 하나의 선언으로 통합하거나 공급자 수정본 적용
서드파티 구성요소가 시스템 모듈 이름 재사용 SDK 헤더, -I, -F, -Xcc 인자 시스템 경로를 덮는 검색 경로 제거, 의존성 격리
프로젝트 자체 모듈과 외부 모듈이 같은 이름 사용 타깃 설정, Bridging Header, 수동 헤더 디렉터리 자체 모듈 이름 변경 또는 중복 진입점 제거

Xcode의 Header Search Paths와 Framework Search Paths는 실제로 어떤 헤더와 프레임워크를 먼저 볼지 바꿀 수 있습니다. Xcode 빌드 설정 문서를 참고해 프로젝트 설정과 CI 스크립트의 값을 따로 기록하십시오.

원격 Mac CI에서는 로컬에 없는 경로가 추가되는 경우가 많습니다. Homebrew 경로, 전역 환경 변수, 셸 초기화 파일, 작업 디렉터리, 계정별 캐시가 모두 검색 결과에 영향을 줄 수 있습니다. 특히 빌드 스크립트가 특정 계정의 홈 디렉터리를 직접 참조하면, 다른 계정의 노드에서 별도의 SDK가 보일 수 있습니다.

다음 표처럼 로컬과 원격 환경을 나란히 비교하면 추측을 줄일 수 있습니다.

비교 항목 로컬에서 기록할 값 원격 Mac CI에서 기록할 값
툴체인 xcode-select -p, Swift 버전 동일 명령의 출력과 실행 계정
SDK 선택된 SDK 경로 빌드 로그의 SDK 경로
의존성 잠금 파일과 체크아웃 경로 잠금 파일, 캐시 경로, 체크아웃 경로
검색 경로 프로젝트 설정과 셸 변수 빌드 스크립트가 추가한 -I, -F, -Xcc
모듈 증거 모듈 진단 출력 실제로 읽힌 module.modulemap 경로

Swift와 Clang의 모듈 로딩 규칙은 Swift Clang 모듈 문서Clang 모듈 문서에서 확인할 수 있습니다. 단순히 같은 파일 이름을 가진 항목을 모두 삭제하지 말고, 진단 출력에서 실제로 로드된 파일을 기준으로 범위를 좁혀야 합니다.

SECTION 04 캐시 초기화보다 재현 조건을 먼저 고정합니다

DerivedData, Module Cache, 패키지 캐시는 서로 같은 저장소가 아닙니다. 오래된 모듈 결과가 남아 새 수정이 반영되지 않을 수 있지만, 현재 검색 경로에 두 선언이 계속 존재한다면 캐시 삭제만으로 해결되지 않습니다.

권장 순서는 다음과 같습니다.

  1. 새 작업 디렉터리에서 같은 커밋을 체크아웃합니다.
  2. 기존 캐시와 분리된 Module Cache 및 DerivedData 경로를 지정합니다.
  3. 같은 SDK와 같은 의존성 잠금 파일로 실패를 재현합니다.
  4. 모듈 로딩 진단을 켜고 실제 module.modulemap 경로를 저장합니다.
  5. 원인 파일이나 검색 경로를 한 곳만 수정합니다.
  6. 냉각 빌드와 증분 빌드를 각각 실행합니다.
  7. 같은 조건으로 반복해 오류가 다시 나타나는지 확인합니다.

전체 노드의 캐시를 비우는 방식은 병렬 작업을 방해하고, 다른 작업의 재빌드 비용을 만들 수 있습니다. 캐시를 지울 때는 대상 경로와 작업 점유 상태를 기록하고, 문제가 없으면 이전 캐시를 복원할 수 있도록 이름을 바꿔 보관하는 방식이 낫습니다.

조건별 복구 선택

  • 모듈 선언 하나가 프로젝트에 중복되어 있으면 중복 진입점을 제거하고 냉각 빌드부터 다시 실행합니다.
  • 서로 다른 자체 구성요소가 같은 이름을 쓰면 헤더 진입점을 합치거나 자체 모듈 이름을 변경합니다.
  • 서드파티 SDK가 원인이며 업데이트가 있으면 호환 수정본을 격리 환경에서 검증한 뒤 잠금 파일을 갱신합니다.
  • 서드파티 SDK를 수정할 수 없고 안정 빌드가 필요하면 생산 CI는 안정 툴체인에 유지하고 Swift 6.4 노드는 검증선으로 남깁니다.
  • 깨끗한 경로에서도 하나의 선언만 로드되고 반복 빌드가 통과하면 캐시를 단계적으로 되돌리되, 증분 빌드 결과를 함께 보존합니다.
  • 첫 진단이 링크 오류나 단순 모듈 누락이면 duplicate module name 절차를 중단하고 해당 오류의 검색 경로 또는 링크 설정을 따로 조사합니다.

SECTION 05 자주 묻는 확인 사항

구형 툴체인에서는 통과하던 프로젝트가 Swift 6.4에서만 실패하는 이유는 무엇인가요?

구형 툴체인에서는 같은 이름의 선언 중 하나만 선택되어 문제가 드러나지 않았을 수 있습니다. Swift 6.4 계열의 새 dependency scanner가 도달 가능한 모듈을 함께 확인하면서 충돌이 표면화될 가능성이 있습니다.

다만 이것만으로 원인을 확정하면 안 됩니다. 성공 빌드와 실패 빌드의 첫 진단, SDK, 검색 경로, 의존성 잠금 상태를 비교해야 합니다. Apple의 릴리스 노트는 현재 확인된 베타 동작의 근거로 사용하고, 정식 버전에 대한 단정은 피하십시오.

두 개의 같은 이름 module.modulemap이 어떤 의존성에서 왔는지 어떻게 찾나요?

저장소, 패키지 체크아웃 디렉터리, XCFramework 내부를 나누어 검색합니다. 같은 이름을 가진 파일을 찾은 뒤 모듈 맵 안의 헤더 진입점과 실제 경로를 비교하십시오.

그다음 컴파일러 모듈 진단을 사용해 현재 빌드가 실제로 읽은 파일을 확인합니다. 두 파일이 존재한다는 사실만으로 충돌을 확정하지 말고, 동일한 검색 범위에서 동시에 도달 가능한지까지 확인해야 합니다.

DerivedData를 지우면 Swift 모듈 이름 중복 오류가 해결되나요?

오래된 모듈 캐시가 잘못된 상태를 보존했다면 제한된 캐시 초기화가 결과를 바꿀 수 있습니다. 그러나 두 개의 선언이 현재 검색 경로에 있으면 다시 생성될 뿐입니다.

새 작업 디렉터리와 독립 캐시에서 먼저 같은 오류가 발생하는지 확인하십시오. 수정 뒤에는 냉각 빌드와 증분 빌드를 모두 실행해야 캐시가 오류를 숨긴 것인지 실제로 해결된 것인지 구분할 수 있습니다.

수정할 수 없는 서드파티 SDK가 원인이라면 CI를 되돌려야 하나요?

생산선이 즉시 필요하고 SDK를 수정할 수 없다면 안정 툴체인을 유지하는 편이 안전합니다. Swift 6.4를 생산에 강제로 올리기보다 같은 커밋, 잠금 파일, 빌드 인자를 사용하는 별도 검증 노드에서 계속 테스트하십시오.

상위 공급자가 호환 버전을 배포하면 격리 노드에서 먼저 검증하고, 반복 빌드와 의존성 변경 기록을 확인한 뒤 생산선 전환을 결정합니다. 임시 패치를 운영 저장소에 영구 반영하는 방식은 피해야 합니다.

SECTION 06 두 툴체인 검증으로 전환 시점을 결정합니다

안정 버전과 Swift 6.4를 비교할 때는 툴체인만 바꾸고 나머지 조건은 고정해야 합니다. 다음 항목이 하나라도 달라지면 결과 비교의 의미가 약해집니다.

  • 같은 커밋
  • 같은 Package.resolved
  • 같은 SDK와 빌드 인자
  • 같은 서드파티 바이너리
  • 독립된 캐시 경로
  • 동일한 서명과 환경 변수 조건

안정 버전은 통과하고 Swift 6.4만 실패한다면, 실패한 모듈의 출처와 검색 경로를 저장한 뒤 원인을 분리하십시오. 두 버전 모두 통과하지만 증분 빌드만 실패하면 캐시 또는 작업 순서를 별도로 조사해야 합니다. 두 버전 모두 같은 모듈 충돌을 보이면 Swift 업그레이드보다 프로젝트와 의존성 구조가 우선 원인일 수 있습니다.

2026년 9월 8일 기준으로 이번 판단은 Xcode 27 베타 계열의 공식 문서와 Swift 모듈 관련 문서를 바탕으로 합니다. Xcode 27의 후보 버전이나 정식 버전이 공개되거나, Swift 6.4가 독립 정식 릴리스로 바뀌거나, 주요 SDK가 호환 수정본을 배포하면 릴리스 노트와 실제 로그를 다시 대조해야 합니다.

현재 방식이 로컬 Mac 한 대의 수동 전환이라면 계정별 셸 설정, 공유 캐시, 숨은 SDK 경로가 재현성을 떨어뜨립니다. Mac 미니를 직접 운영하는 방식도 물리 장비와 유지 보수 부담, 노드 장애 시 복구 시간, 여러 툴체인 격리 문제를 함께 떠안게 됩니다. 생산선은 안정 버전에 두면서 Swift 6.4 검증 환경을 별도로 유지해야 한다면, VPSNIX의 원격 Mac 환경에서 이중 툴체인 배치와 노드 복구 조건을 먼저 확인하는 편이 더 현실적입니다. 원격 Mac 환경 안내이용 가능한 요금 구성을 비교한 뒤, 장기 고정 부하나 물리 포트가 필요한 경우에는 직접 구매가 더 적합한지까지 함께 판단하십시오. 자세한 접속과 운영 조건은 도움말 센터에서 확인할 수 있습니다.