xcode-select와 DEVELOPER_DIR: 어느 쪽이 정석일까?
Expo 앱을 iOS 시뮬레이터에 띄우려고 도구부터 점검했는데, 결과가 앞뒤가 안 맞았습니다.
$ xcodebuild -version
xcodebuild: error: ...
$ swift --version
Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3)Swift 컴파일러는 6.3.3 이 멀쩡히 답하는데 xcodebuild 는 없다고 합니다. 시뮬레이터 목록을 뽑으려 하니 더 이상했습니다.
$ xcrun simctl list devices
xcrun: error: unable to find utility "simctl", not a developer tool or in PATH/Applications/Xcode.app 은 자리에 그대로 있었습니다. 버전을 직접 읽어 보니 26.6, 빌드 17F113 이었습니다.
Xcode 를 안 보고 있던 활성 개발자 디렉터리
원인은 한 줄로 나왔습니다.
$ xcode-select -p
/Library/Developer/CommandLineToolsmacOS 에는 "지금 활성인 개발자 디렉터리" 라는 전역 설정이 하나 있고, xcrun 과 xcodebuild 는 전부 그 값을 보고 도구를 찾습니다. 그 값이 Command Line Tools 를 가리키고 있었습니다. CLT 에도 clang, swift, git 은 들어 있습니다. 그래서 컴파일러는 답했습니다. 반면 simctl, xcodebuild, 시뮬레이터 런타임은 Xcode.app 안에만 있습니다. 그래서 그쪽만 통째로 없었습니다.
Xcode 를 안 깐 것도 아니고 깨진 것도 아니었습니다. 가리키는 곳이 틀렸을 뿐입니다. 보통 Xcode 를 먼저 깔고 나중에 CLT 를 따로 설치하면 이 상태가 됩니다.
전역 설정을 피하려던 처음 판단
고치는 방법이 둘이라는 건 금방 알았습니다.
# 1. 전역 전환
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
# 2. 명령 단위 우회
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer npx expo run:ios저는 2번을 골랐습니다. sudo 가 붙는 게 마음에 걸렸고, 전역 설정을 바꾸면 다른 프로젝트에도 영향이 간다는 게 부담스러웠습니다. 부작용이 작은 쪽이 안전하다고 생각했습니다.
고르고 나서 뒤늦게 의문이 들었습니다. 부작용이 작다는 것과 옳다는 것은 다른 이야기입니다.
거꾸로 읽고 있던 "영향이 간다"
다시 보니 제 판단의 전제가 틀렸습니다.
전역 전환이 다른 프로젝트에 영향을 주는 건 맞습니다. 그런데 그 영향이 정상 방향입니다. 지금 상태에서는 이 머신의 어떤 프로젝트도 시뮬레이터를 못 씁니다. Flutter 를 깔아도, 다른 회사 앱을 클론해도 똑같이 simctl 을 못 찾습니다. 전환은 그걸 고치는 것이지 망가뜨리는 게 아닙니다.
제가 "부작용" 이라고 부른 것은 사실 "복구" 였습니다. 지키려던 상태가 애초에 정상이 아니었는데, 건드리지 않는 쪽을 보수적이라고 착각했습니다.
여기에 더해 우회는 비용이 계속 듭니다. DEVELOPER_DIR 은 환경변수라서 그 명령, 그 셸, 그 서브프로세스에만 붙습니다. 다음에 터미널을 새로 열고 npx expo run:ios 를 치면 그대로 실패합니다. Xcode 를 GUI 로 열어 쓰는 순간에도 안 따라갑니다. 그리고 실패했을 때 나오는 메시지는 방금 제가 본 그 "not a developer tool" 이라, 원인을 다시 처음부터 찾게 됩니다.
정석은 도구들이 전제하는 쪽
결정적인 근거는 생태계 쪽에 있었습니다. Expo, React Native, Flutter, Fastlane 문서가 하나같이 xcode-select -p 가 Xcode 를 가리킨다고 가정하고 쓰여 있습니다. 뭔가 안 될 때 그 도구들이 뱉는 안내문도 전부 xcode-select -s 를 실행하라고 합니다. 우회로 굴러가는 환경은 그 안내문과 계속 어긋납니다.
DEVELOPER_DIR 이 쓸모없다는 뜻은 아닙니다. 정당한 자리가 따로 있습니다.
xcode-select -s |
DEVELOPER_DIR |
|
|---|---|---|
| 적용 범위 | 머신 전체, 영구 | 그 명령 하나 |
| 권한 | sudo 필요 |
불필요 |
| 쓰는 자리 | 평소 개발 머신의 기본 상태 | Xcode 여러 버전 중 하나를 고정할 때, CI 처럼 전역 상태를 안 건드리는 게 원칙인 환경 |
우선순위는 DEVELOPER_DIR 이 높습니다. 그래서 CI 에서 Xcode 16 과 26 을 오가며 빌드할 때는 이쪽이 정확한 도구입니다. 제 경우는 Xcode 가 한 벌뿐이었으니 해당이 없었습니다. 예외 상황용 도구를 기본 상태에 쓰려 했던 셈입니다.
전환한 뒤
한 줄로 끝났습니다.
$ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
$ xcodebuild -version
Xcode 26.6
Build version 17F113시뮬레이터는 11대가 잡혔고 iOS 26.5 런타임도 그때서야 보였습니다. CocoaPods 를 brew install cocoapods 로 1.17.0 을 깔고 npx expo prebuild --platform ios 를 돌리니 ios/ 생성과 Pod 설치까지 한 번에 지나갔습니다.
참고로 이 앱은 MapLibre 를 쓰는 터라 Expo Go 로는 아예 안 뜹니다. 네이티브 모듈이 들어간 앱은 dev client 를 직접 빌드해야 하고, 그래서 시뮬레이터가 없으면 화면을 볼 방법 자체가 없었습니다. xcode-select 한 줄이 막고 있던 게 그것이었습니다.
한 줄로 끝나는 원복
전역 설정이라 겁이 났던 것치고 원복은 간단합니다.
sudo xcode-select -s /Library/Developer/CommandLineToolsxcode-select 가 하는 일은 /var/db/xcode_select_link 심볼릭 링크를 바꾸는 것뿐입니다. 되돌릴 수 없는 변경을 피하려는 신중함은 좋지만, 그 변경이 실제로 되돌릴 수 있는지부터 확인했어야 했습니다. 저는 그걸 안 보고 우회부터 골랐습니다.
한 가지는 아직 확인 못 했습니다. Xcode 를 여러 버전 깔아 두고 프로젝트마다 다른 버전을 써야 하는 상황이라면 전역 전환만으로는 부족할 텐데, 그때 .envrc 같은 걸로 디렉터리 단위 DEVELOPER_DIR 을 거는 게 실제로 편한지는 안 써 봐서 모르겠습니다.
함께 읽기
- 새 맥북 개발 환경 세팅: git clone이 가져오지 않는 것들맥북을 새로 받고 하던 프로젝트를 이어서 하려 했습니다. 리포를 클론하고 npm install 을 돌린 다음 개발 서버를 띄웠는데, 브라우저에 이게 떴습니다.
- colima 자동 기동: brew services가 10초마다 재실행되는 이유개발기에 도커를 새로 깔 일이 생겼습니다. 컨테이너 하나만 돌리면 되는 일이라 가볍게 끝날 줄 알았는데, 설치 자체는 5분이었고 그 뒤에 두 가지를 더 고쳐야 했습니다. 하나는 깃 저장소가 더러워진 것이고, 하나는 코어 하나의 2.8%가 계속 타고 있던 것입니다.
- 드라이런과 멱등성: 사고를 막는 시점의 차이배포 스크립트에 안전장치를 넣는다고 할 때 두 가지가 자주 같이 나옵니다.
- prisma generate 를 어디서 돌릴까: postinstall 과 도커 빌드 캐시새 맥에 프로젝트들을 하나씩 세우는 중이었습니다. 클론하고, 의존성을 깔고, 개발 서버를 띄우면 이 화면이 떴습니다.
- 환경변수로 둔 CLI 기본값: 비대화형 셸에서 사라지는 이유문서를 저장하는 CLI를 하나 만들었습니다. 저장할 때마다 그 문서가 어디로 떨어졌는지 찾는 일이 반복돼서, 새 문서는 인박스로 가도록 기본값을 정했습니다. 터미널에서 쳐 보니 의도한 자리에 들어갔습니다.