xcrun xcodeproj로 .xcodeproj를 커맨드라인에서 편집하기 (Xcode 27.2)
요약
Xcode 27.2에 포함된 `xcrun xcodeproj` 도구는 커맨드라인에서 Xcode 프로젝트 파일(.xcodeproj)을 생성하고 편집할 수 있게 합니다. 이 도구는 JSON 기반의 새로운 `project.xcproj` 형식을 지원하며, 기존 pbxproj 형식도 처리 가능합니다. 이를 통해 서드파티 라이브러리 없이 다양한 프로젝트 관리 작업을 수행할 수 있습니다.
핵심 포인트
- Xcode 27.2에 포함된 공식 커맨드라인 도구입니다.
- 프로젝트 생성부터 패키지 의존성까지 다룰 수 있습니다.
- JSON 기반의 `project.xcproj` 형식을 중심으로 동작합니다.
- 서드파티 라이브러리 사용 없이 프로젝트 관리가 가능해졌습니다.
서론
Xcode 27.2에는 xcrun xcodeproj라는 커맨드라인 도구가 포함되어 있습니다. Beta 2 시점에서는 setting, target, group의 세 가지 하위 명령어만 있었지만, Beta 3에서는 init, config, pkg 등이 추가되면서 프로젝트 생성부터 패키지 의존성 관리까지 가능해졌습니다.
$ xcrun xcodeproj --help
OVERVIEW: Inspect and modify Xcode project files (.xcodeproj) from the command line.
...
이 도구는 Xcode 프로젝트 파일(.xcodeproj 번들 내부의 project.xcproj 또는 project.pbxproj)을 커맨드라인에서 생성 및 편집하는, Xcode가 제공하는 도구입니다. 이전에는 CocoaPods의 xcodeproj gem이나 tuist/XcodeProj와 같은 서드파티 라이브러리를 사용해 수행하던 많은 작업을 추가 설치 없이 할 수 있습니다.
Xcode 27.2에서는 프로젝트 파일의 새로운 형식으로 JSON 기반의 project.xcproj가 도입되었습니다. xcrun xcodeproj는 JSON 형식과 기존의 project.pbxproj를 모두 처리할 수 있으며, init으로 생성하는 프로젝트 파일은 JSON 형식을 따릅니다. JSON 형식 자체와 Beta 2에서의 xcodeproj의 모습은 이전 기사 「Xcode의 프로젝트 설정을 JSON으로 만들기」에서 소개했습니다.
본 기사에서는 JSON 형식을 중심으로, Beta 3의 모든 하위 명령어를 실행하여 확인한 동작 방식과 주의가 필요한 동작을 정리합니다. pbxproj 형식은 JSON 형식으로 마이그레이션할 수 없는 경우의 선택지로 다룹니다.
위치 정보
본체는 Xcode.app/Contents/Developer/usr/bin/xcodeproj에 있는 arm64 Mach-O 바이너리입니다. Xcode 27.0 및 Xcode 27.1 RC(27A9275)에는 포함되어 있지 않습니다.
2026년 10월 15일 기준으로 Apple의 공식 문서는 없습니다. Xcode 27.2의 릴리스 노트, 프로젝트 형식 마이그레이션 가이드 「Updating your Xcode project configuration file format」, Xcode command-line tool reference 어느 곳에도 기재되어 있지 않으며 man 페이지도 없습니다. 본 기사의 내용은 도구의 --help와 실제로 실행한 결과를 기반으로 합니다.
$ DEVELOPER_DIR=/Applications/Xcode-27.2.0-Beta.3.app/Contents/Developer xcrun --find xcodeproj
/Applications/Xcode-27.2.0-Beta.3.app/Contents/Developer/usr/bin/xcodeproj
기능
하위 명령어는 6가지 그룹으로 나뉩니다.
| 하위 명령어 | 역할 |
|---|---|
init | 빈 프로젝트 생성 (JSON 형식) |
setting | 빌드 설정의 get / list / set / set-multi / unset |
target | 타겟 목록/추가/삭제, 의존성, 빌드 페이즈 조작 |
group | 그룹 트리 조작, 파일 참조 추가, 타겟에 include / exclude |
config | 빌드 구성에 연결되는 xcconfig의 set / unset |
pkg | Swift Package 의존성 추가/삭제, 제품 또는 플러그인 링크 |
도움말 초반부에 나와 있듯이, 다루는 것은 프로젝트 파일(project.xcproj / project.pbxproj)만입니다.
.xcworkspace, 스킴, .xcconfig의 내용은 변경하지 않습니다. 프로젝트는 다음 순서로 결정됩니다.
-P/--project로 지정한 경로 - 환경 변수XCODEPROJ_PROJECT
현재 디렉터리에 있는 유일한 .xcodeproj
명령어 체계의 전체 개요
xcodeproj
├── init <path>
├── setting get | list | set | set-multi | unset
...
CLI 도구 프로젝트를 새로 생성하기
init 명령어를 사용하여 프로젝트를 생성하고, xcodebuild로 빌드할 수 있는 상태까지의 절차입니다.
init으로 JSON 형식의 프로젝트 파일 만들기
$ mkdir -p Demo/Sources
$ echo 'print("Hello from xcrun xcodeproj")' > Demo/Sources/main.swift
$ xcrun xcodeproj init Demo.xcodeproj
...
init 명령어는 .xcodeproj 번들을 만들고, 그 안에 JSON 형식의 프로젝트 파일 project.xcproj를 작성합니다. pbxproj 형식으로 생성하는 옵션은 없습니다. 내용은 다음과 같습니다.
{
"default-configuration": "Release",
"configurations": [
...
이것은 끝에 쉼표가 붙은 JSON5 형태의 형식입니다. xcodeproj로 편집한 후의 파일은 xcprojformatter의 출력과 일치했습니다 (다만, init 직후의 파일만은 끝에 개행이 없는 점이 다릅니다).
타겟(Target), 동기화 그룹(Sync Group), 빌드 설정 추가하기
$ xcrun xcodeproj setting set SDKROOT macosx
$ xcrun xcodeproj setting set SWIFT_VERSION 6.0
$ xcrun xcodeproj target add Demo --product-type tool
...
--filesystem-path를 붙이면 Xcode 16에서 도입된 filesystem-synchronized group(폴더 동기화 그룹)을 만들 수 있습니다. 이후부터는 폴더에 파일을 놓기만 하면 빌드 대상에 포함됩니다.
$ xcodebuild -target Demo build SYMROOT=$PWD/build
...
** BUILD SUCCEEDED **
...
완성된 project.xcproj는 다음과 같습니다.
"files": [
{
"kind": "group",
...
id는 남아 있지만, 설정은 계층 구조로 표현되며 타겟이나 빌드 페이즈는 이름으로 참조됩니다. pbxproj에서는 이러한 참조가 24자리 ID로 표현됩니다.
이 프로젝트는 Xcode 27.0의 xcodebuild에서도 빌드가 가능했으며, Xcode 27.1 RC의 xcodebuild -list에서도 읽을 수 있었습니다. Apple의 설명에 따르면, JSON 형식을 다룰 수 있는 것은 Xcode 27 이후 버전입니다.
Swift Package 링크하기
$ xcrun xcodeproj target phase add frameworks --target Demo
$ xcrun xcodeproj pkg add-local Packages/Greeting --product Greeting --target Demo
Added local package 'Greeting' (Packages/Greeting).
...
원격 패키지 추가는 pkg add <url>을 사용합니다. 버전 요구사항은 --from, --up-to-next-minor, --exact, --range-min과 --range-max, --branch, --revision 중 하나를 지정합니다.
$ xcrun xcodeproj pkg add https://github.com/apple/swift-argument-parser --from 1.5.0
Added remote package 'swift-argument-parser' (https://github.com/apple/swift-argument-parser).
Requirement: up to next major version from 1.5.0
앱(App) 등에 임베딩되는 타겟의 경우, 동적 프레임워크 제품을 pkg link --embed로 "Embed & Sign"에 해당하도록 임베드할 수 있습니다 (이번 CLI 도구의 타겟에서는 사용할 수 없습니다). 빌드 툴 플러그인은 pkg link-plugin으로 연결합니다.
주의가 필요한 동작
1. 동기 그룹(Synchronized Group)을 include 하기 전에 Sources 페이즈(Sources Phase)가 필요
target add는 빌드 페이즈를 하나도 만들지 않습니다. 그 상태에서 동기 그룹을 include 하고 나중에 Sources 페이즈를 추가하면, 소스 코드가 전혀 컴파일되지 않는데 BUILD SUCCEEDED로 표시되고 결과물도 나오지 않습니다.
3가지 순서로 시도한 결과입니다.
| 단계 | 결과 |
|---|---|
phase add sources → group include | ✅ 컴파일되어 실행 가능 |
group include → phase add sources | ❌ BUILD SUCCEEDED이나 결과물 없음 |
Sources 페이즈 없이 group include | ❌ BUILD SUCCEEDED이나 결과물 없음 |
올바른 순서와 잘못된 순서로 만든 project.xcproj를 비교하면 원인을 알 수 있습니다. -는 페이즈를 먼저 추가한 경우, +는 include를 먼저 실행한 경우입니다.
- { "kind": "folder", "path": "Demo", "target-membership": [ "Demo" ] },
+ {
+ "kind": "folder",
...
include 시점에서 파일을 분배하는 페이즈가 없었기 때문에, main.swift가 membership exception (제외 파일)으로 기록되었습니다. 나중에 페이즈를 추가해도 제외는 그대로 남아 있습니다.
이미 이 상태라면, Sources 페이즈를 추가한 후 동기 그룹을 일단 exclude 했다가 다시 include 하면 제외가 사라지고 정상적으로 빌드됩니다.
$ xcrun xcodeproj group exclude --group /Demo --target Demo
Excluded filesystem-synchronized group '/Demo' from target 'Demo'.
$ xcrun xcodeproj group include --group /Demo --target Demo
...
파일 단위의 group include main.swift --group /Demo --target Demo로는 해결할 수 없었습니다. 동기 그룹에 지정할 수 있는 것은 바로 하위 파일 이름만 가능하며, Sources/main.swift와 같은 서브 폴더 내의 파일은 지정할 수 없기 때문입니다.
게다가 target add의 도움말에 나와 있듯이, 자동으로 들어가는 설정은 PRODUCT_NAME과 (일부 제품 유형의) GENERATE_INFOPLIST_FILE뿐입니다. SDKROOT나 SWIFT_VERSION도 포함되지 않습니다. Xcode의 새 프로젝트 템플릿과는 달리, 필요한 빌드 페이즈와 설정은 모두 직접 추가해야 합니다.
다음 순서로 실행하면, 동기 그룹 내 파일이 Sources 페이즈에 들어가는 것을 확인할 수 있었습니다.
xcrun xcodeproj target add MyTool --product-type tool
xcrun xcodeproj target phase add sources --target MyTool
xcrun xcodeproj target phase add frameworks --target MyTool # 패키지 링크 시
...
2. Frameworks 페이즈가 없으면 패키지를 링크할 수 없음
같은 이유로, Frameworks 페이즈가 없는 타겟에 pkg add-local --product ... --target ...
을 실행하면 오류가 발생합니다.
$ xcrun xcodeproj pkg add-local Packages/Greeting --product Greeting --target Demo
Error: Target 'Demo' has no Frameworks build phase to link a package product into (e.g. aggregate targets don't build or link anything).
이 실패 예시에서는 패키지 참조도 추가되지 않았습니다 (pkg list에 나타나지 않음). 링크만 실패하고 참조가 남아있는, 같은 일은 없었습니다.
3. 단일 값과 다중 값 설정에 따라 명령어가 나뉨
OTHER_LDFLAGS나 LD_RUNPATH_SEARCH_PATHS와 같은 다중 값 설정은 setting set으로는 작성할 수 없습니다.
$ xcrun xcodeproj setting set OTHER_LDFLAGS -- -lz
Error: 'OTHER_LDFLAGS' is a multi-valued build setting; use `setting set-multi` instead of `setting set`.
$ xcrun xcodeproj setting set-multi OTHER_LDFLAGS -- -lz -lsqlite3
...
-으로 시작하는 값은 옵션으로 해석되므로, 앞에 --를 붙입니다. 어떤 키가 다중 값인지((multi))는 setting set --help에 목록이 있습니다. setting get이나 setting list의 출력에도 (single)/(multi)가 붙습니다.
4. setting은 '순수 값'만 본다
setting get/list가 표시하는 것은 프로젝트 파일에 쓰여진 그대로의 값입니다. 매크로 전개, 상속, xcconfig의 내용은 반영되지 않습니다. 최종적인 값을 알고 싶을 때는, 여전히 xcodebuild -showBuildSettings를 사용합니다. xcconfig가 연결되어 있는 경우엔 (xcconfig: Debug.xcconfig)라는 주석이 붙기만 합니다.
기존 프로젝트 파일을 JSON 형식으로 변환하여 편집하기
기존 프로젝트 파일은 JSON 형식과 plist 형식으로 상호 변환할 수 있다는 것을 지난 기사에서 작성했습니다.
여기서는 iOS 앱(폴더 동기화 그룹 구성)의 프로젝트 복사본을 JSON 형식으로 변환하고, xcrun xcodeproj로 편집한 결과를 보여드립니다.
JSON 형식에서는 Debug/Release에 따라 값이 다른 설정은 다음과 같이 키에 접미사를 붙인 한 줄로 표현됩니다.
"DEBUG_INFORMATION_FORMAT[config=Debug]": "dwarf",
"DEBUG_INFORMATION_FORMAT[config=Release]": "dwarf-with-dsym",
setting set 도움말에 있는
첫 번째 쓰기 작업에서 Products 참조에 type이 추가되는 것 외에는, 설정 변경이 한 줄의 차이로 나타납니다.
관련 도구: xcprojformatter 및 apple/xcode-project-format
Xcode 27.2에는 project.xcproj를 표준 형식으로 정리하는 xcrun xcprojformatter도 포함되어 있습니다(사용법은 이전 기사를 참조하세요). JSON 형식을 읽고 쓰는 Swift 라이브러리 apple/xcode-project-format도 공개되어 있으며, xcprojformatter는 이를 기반으로 합니다. 2026년 10월 15일 시점에서는 이 리포지토리에 xcodeproj CLI가 포함되어 있지 않고, Xcode에 포함된 바이너리로만 제공됩니다.
pbxproj 형식 그대로 편집하는 경우
CocoaPods나 fastlane 등 JSON 형식에 대응하지 않는 도구를 사용해서 변환할 수 없는 경우에는 기존의 project.pbxproj를 그대로 편집할 수 있습니다. 변환 전과 동일한 프로젝트로 확인했습니다.
$ xcrun xcodeproj target list
Name Kind Product Type
AppleOS27Catalog native application
...
쓰기는 올바르게 수행되었습니다. 하지만 pbxproj에서는 이번 변경과 관련 없는 부분도 정규화됩니다.
- 58A3F6EA... /* AppleOS27Catalog.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; ...
+ 58A3F6EA... /* AppleOS27Catalog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; ...
...
git diff --stat는 3 insertions(+), 9 deletions(-)였습니다. 설정을 한 줄 추가했을 뿐인데도, 첫 번째 쓰기 작업에서는 변경하지 않은 부분의 차이가 포함됩니다. JSON 형식에서는 같은 작업을 수행해도 이전 절처럼 설정의 한 줄과 type의 추가만 있었습니다.
쓰기 전 검증
불일치한 프로젝트를 쓰지 않도록 검증이 내장되어 있습니다.
$ xcrun xcodeproj target add-dependency Helper Demo
Error: Target 'Helper' cannot depend on 'Demo' -- 'Demo' already (directly or transitively) depends on 'Helper', so this would create a dependency cycle.
$ xcrun xcodeproj target remove Helper
...
- 의존성 순환(전이적인 것도 포함), 중복된 의존성, 자체 의존성은 쓰기 전에 거부됩니다. - 다른 타겟에서 참조되는 타겟이나 파일은 삭제를 거부합니다(파일이나 그룹은
--force로 삭제할 수 있습니다). - 존재하지 않는 이름을 지정하면 유효한 후보 목록을 보여주는 도움말에는 다음에 실행할 명령어 안내가 포함되어 있습니다. 예를 들어target info의 도움말은 대상 이름을target list에서 확인하도록 안내하고 있습니다. 빌드 페이즈 번호가 저장된 ID가 아니라 그 시점에서의 위치라는 점도 도움말에 명시되어 있습니다.
Apple은 코딩 에이전트가 편집하기 쉽다는 점을 JSON 형식의 목표 중 하나로 언급하고 있습니다 (The Mac Observer).
기존 도구와의 관계
- CocoaPods xcodeproj gem / fastlane: 현재는 JSON 형식(
project.xcproj)을 지원하지 않습니다. fastlane의 버전 조작 액션 등은 변환된 프로젝트에서는 작동하지 않습니다 (CocoaPods/Xcodeproj#1052, fastlane/fastlane#30323). 이러한 도구를 사용하는 프로젝트는 대응 상황을 확인한 후 마이그레이션해야 합니다. - xcrun xcodeproj: 두 가지 형식을 모두 다룰 수 있으므로, CI 스크립트에서 빌드 설정을 수정하거나 패키지를 추가하는 용도로는 형식에 구애받지 않고 사용할 수 있습니다.
- XcodeGen / Tuist 등의 생성기(Generator): 프로젝트 전체를 선언적으로 생성하는 도구와 역할이 다릅니다.
xcrun xcodeproj는 기존 프로젝트를 명령적으로 조금씩 수정하는 도구입니다.
요약
- Xcode 27.2에 포함된 순정 CLI인
xcrun xcodeproj는 Beta 3에서 프로젝트 생성(init), xcconfig(config), Swift Package(pkg)까지 다룰 수 있게 되었습니다. init이 생성하는 프로젝트 파일은 JSON 형식의project.xcproj입니다. 기존의project.pbxproj는xcodebuild -convert-project xcproj로 JSON 형식으로 변환한 후 편집할 수 있으며, 변환할 수 없는 경우 pbxproj 상태 그대로도 편집 가능합니다. 타겟(target), 빌드 페이즈(build phase), 그룹(group), 빌드 설정(build setting), xcconfig, Swift Package를 모두 조작할 수 있습니다. 스킴(Scheme)과 워크스페이스(Workspace)는 제외됩니다.target add는 빌드 페이즈를 생성하지 않습니다. 동기 그룹을 포함하기 전에 Sources 페이즈를 추가하지 않으면 소스가 제외된 채로 조용히 빌드가 성공합니다 - CocoaPods (xcodeproj gem)를 사용 중인 경우 이름 충돌이 발생하므로,xcrun을 통해 호출해야 합니다.- 의존성 순환이나 참조 중인 타겟 삭제는 쓰기 전에 거부되며, 오류 메시지에는 유효한 후보나 다음 단계가 제시됩니다.
위의 모든 내용은 Xcode 27.2 Beta 3에서의 동작이며, 정식 출시까지 변경될 수 있습니다.
참고
- Xcode 프로젝트 설정을 JSON으로 만들기
- Updating your Xcode project configuration file format - Apple Developer Documentation
- apple/xcode-project-format
- Xcode 27.2 beta adds a JSON project format for Git and AI tools - The Mac Observer
- Support for Xcode 27.2's new JSON project format (.xcproj)? · CocoaPods/Xcodeproj#1052
- Xcode 27.2 JSON project format (.xcproj): support status for versioning actions? · fastlane/fastlane#30323
토론(Discussion)

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기