Xcode를 이용해서 빌드를 하면 어떤 과정으로 컴파일이 될까? Xcode라는 자동화된 툴을 다루다보니 내부에서는 어떤 과정을 거쳐서 최종 패키지가 만들어지는 항상 궁금하다. 오늘은 Xcode의 생성과정에 대해서 알아 볼 것이다.
로그 파일 얻기
Xcode를 통해서 빌드를 하면 빌드 중에 생성되는 로그들이 저장된다. <그림1>은 Xcode를 통해서 생성된 로그를 볼 수 있는 방법을 보여주고 있다.
<그림1> Xcode Build 로그
화면에 보이는 로그에서 모든 모든 경로들이 절대경로로 되어 있고 command line 명령들이 길게 늘어져 있어서 실제로 보기에는 힘든 정보들이다.
필자가 일부 간략화한 내용을 가지고 보는 것이 좋을 것이다.
xcode-build-log.txt (첨부파일)
빌드과정
로그를 통해서 알아본 빌드과정을 정리해보도록 하자. 빌드 과정은 간략하게 총 15 단계를 거친다. 각 단계에 대해서 간략히 설명하면 다음과 같다.
정리
1. 빌드 과정중에 생성되는 디렉토리 설정을 한다.
- 명령어: ln -s
빌드 과정 중에 사용되는 임시 디렉토리 중에 빌드시에 사용되는 디렉토리( MyApp.build )와 최종 생성 앱을 저장하는 디렉토리를 심볼릭 링크로 연결한다.
2. INFO.PLIST를 INSTALL_PRODUCT에 변환 복사
- Xcode 내장 명령어: builtin-infoPlistUtility
앱의 설정 정보를 담고 있는 XXX-Info.plist 파일을 binary로 만들어 복사한다. 이때 사용되는 명령은 xcode 내장 명령을 사용하고 있다.
3. RESOURCERULES.PLIST를 변환 복사
- Xcode 내장 명령어: builtin-copy
ResourceRules.plist 파일을 복사한다. ResourceRulles.plist파일은 SDK에서 복사한다.
4. PCH 생성 ( 임시 파일로 생성 )
- 명령어: clang -x objective-c-header
compile 속도를 높이기 위한 기법인 PCH 파일을 생성한다. PCH파일은 프로젝트에서 자주 사용되는 header들을 미리 컴파일해서 사용하는 것으로 compile 과정 중에 cpp에 의해서 전처리 과정에서 시간이 많이 걸리는 문제를 해결하기 위한 방법으로 사용되는 기술이다.
5. 소스 컴파일
- 명령어: clang -x objective-c
.m, .c, .mm, .cc 등 소스 파일이 컴파일 되는 단게이다. 소스들을 컴파일해서 .o 파일로 만든다.
6. 링크
- 명령어: clang
5번 단계에서 컴파일이 되면 clang을 통해서 링크한다. 이렇게해서 최종 실행 파일이 만들어진다.
7. DEBUG SYMBOL 생성
- 명령어: dsymutil
앱을 디버깅하기 위한 디버깅 정보들이 들어 있다. 실행되는 바이너리에 해당하는 소스의 위치를 저장하고 있다. .dym 파일을 생성한다.
8. RESOURCE 복사
- xxx.string ( Xcode 내장 명령어: builtin-copyStrings)
- xxx.xib ( 명령어: ibtool)
- xxx.png ( 명령어: copypng)
프로그램 실행에 사용되는 리소스들을 .app에 복사한다. .app은 iOS에서 실행된 번들이다. 리소스의 타입에 따라서 복사가 된다. 복사가 되는 과정에서 png 이미 파일은 copypng 명령을 통해서 이미지 최적화가 되고 .xib파일을 .nib파일로 컴파일이 된다. .string파일로 binary파일로 컴파일되어 저장된다.
9. PROVISION 파일 추가
- 명령어: builtin-productPackagingUtility
앱이 단말에서 실행되도록 하기 위해서 provision파일을 .app에 복사한다.
10. APP 폴더 갱신
- 명령어: touch
app 폴더를 touch 명령으로 갱신한다. app 폴더는 iOS의 실행 번들로써 새로 업데이트 되었다는 것을 표시하기 위한 것으로 보인다.
11. 파일의 OWNER AND GROUP 설정
- 명령어: chown
.app 폴더의 owner와 그룹을 설정한다.
12. ENTITLEMENT. 파일 복사
- Xcode 내장 명령어: builtin-productPackagingUtitlity
iOS앱은 entitlement를 통해서 debug를 못하게 하거나 data protection 기능을 설정하게 된다. key chain을 사용할때로 이 entitlement 파일을 이용하게 된다. 이 단계에서 entitlement가 app폴더로 복사된다.
만약, 설정된 entitlement가 없다면 기본 파일이 설정된다. (/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/Entitlements.plist )
13. CODESIGN
- 명령어: codesign
이제 실행파일과 모든 리소스들이 복사가 되었다면 codesign 명령어를 통해서 코드 사인을 하게 된다. 이때 사용되는 파라미터로 entitlement와 코드 사인에 사용될 인증서 등이다.
14. VALIDATE
- 명령어: Validation
앞에서 앱을 만들었다면 이것을 검증하게 된다. 꼭 필요한 resource가 없거나 resource가 잘못되었을때 경고를 해준다.
15. 디버그 심볼 파일 갱신
- 명령어: touch
디버그 심볼 파일을 touch통해서 갱신한다.
사용된 툴
위에서 간단히 알아본 빌드과정에서 사용된 명령들을 다음과 같은 것들이 있다.
Xcode 3까지는 Xcode가 gcc나 llvm등의 빌드 명령어를 호출하는 수준이였는데 Xcode 4에서부터는 내부 명령로 처리하는 부분이 일부 존재한다. 이런 명령때문에 Xcode를 이용하지 않고 make만으로는 빌드가 어렵다.
- codesign
- Validation
- touch
- ln
- dsymutil
- ibtool
- copypng
- clang ( gcc 대체 )
- builtin-productPackagingUtitlity : provision 추가, entitlement 추가
- builtin-infoPlistUtility
- builtin-copy
- builtin-copyStrings
생성되는 파일들
컴파일 과정에서 생성되는 파일이 많이 있다. 그 중에 많이 보이는 파일들은 다음과 같다.
- .hmap:
- include path들을 찾기 위한 hash 파일
- .xcent:
- entitlement의 최종 버전
- .LinkFileList
- Link할 object 파일들
- .d
- dependencies 파일들 ( 먼저 컴파일이 되야하는 )
- .dia
- diagnositc 파일
- build-state.dat
- 빌드하는 과정 상태
위 파일들은 빌드 과정에서 만들어지는 파일들이다. 빌드 로그를 살펴보면 이 파일들이 만들어지는 명령들을 확인할 수 있다.
생성 파일 경로 : ~/Library/Developer/Xcode/DerivedData/${Project}-${TEMPNAME}/
|-- Build
| |-- Intermediates
| | |-- MyApp.build
| | | |-- Debug-iphoneos
| | | | `-- MyApp.build
| | | | |-- MyApp-all-target-headers.hmap
| | | | |-- MyApp-generated-files.hmap
| | | | |-- MyApp-own-target-headers.hmap
| | | | |-- MyApp-project-headers.hmap
| | | | |-- MyApp.dep
| | | | |-- MyApp.hmap
| | | | |-- MyApp.xcent
| | | | |-- MyApp~.dep
| | | | |-- Objects-normal
| | | | | `-- armv7
| | | | | |-- MyApp.LinkFileList
| | | | | |-- MyAppAppDelegate.d
| | | | | |-- MyAppAppDelegate.dia
| | | | | |-- MyAppAppDelegate.o
| | | | | |-- MyAppViewController.d
| | | | | |-- MyAppViewController.dia
| | | | | |-- MyAppViewController.o
| | | | | |-- NewViewController.d
| | | | | |-- NewViewController.dia
| | | | | |-- NewViewController.o
| | | | | |-- PluginExample.d
| | | | | |-- PluginExample.dia
| | | | | |-- PluginExample.o
| | | | | |-- main.d
| | | | | |-- main.dia
| | | | | `-- main.o
| | | | |-- build-state.dat
| | | | `-- build-state~.dat
| | | `-- Debug-iphonesimulator
| | `-- PrecompiledHeaders
| | |-- MyApp-Prefix-dnadxkwywgdnrcfkgyzunpkidzod
| | | |-- MyApp-Prefix.pch.d
| | | |-- MyApp-Prefix.pch.dia
| | | |-- MyApp-Prefix.pch.pth
| | | `-- MyApp-Prefix.pch.pth.hash-criteria
| `-- Products
| |-- Debug-iphoneos
| | |-- MyApp.app
| | | |-- Base.lproj
| | | | |-- MyAppViewController.nib
| | | | `-- MainWindow.nib
| | | |-- Default-568h@2x.png
| | | |-- Default-Landscape@2x~ipad.png
| | | |-- Default-Landscape~ipad.png
| | | |-- Default-Portrait@2x~ipad.png
| | | |-- Default-Portrait~ipad.png
| | | |-- Default.png
| | | |-- Default@2x.png
| | | |-- Entitlements.entitlements
| | | |-- FileViewerLibrary.ItemListView.nib
| | | |-- FileViewerLibrary.MainWindow.nib
| | | |-- FileViewerLibrary.bundle
| | | | |-- en.lproj
| | | | | `-- Localizable.strings
| | | | |-- images
| | | | | |-- Default.png
| | | | | |-- Default_width.PNG
| | | | | |-- GoPageIcon.png
| | | | | `-- x_red.png
| | | | `-- ko.lproj
| | | | `-- Localizable.strings
| | | |-- MyApp
| | | |-- MyAppViewController.nib
| | | |-- Info.plist
| | | |-- MainWindow-iPad.nib
| | | |-- MainWindow.nib
| | | |-- NewViewController~iPad.nib
| | | |-- NewViewController~iPhone.nib
| | | |-- PkgInfo
| | | |-- ResourceRules.plist
| | | |-- _CodeSignature
| | | | `-- CodeResources
| | | |-- apns-dev-cert.pem
| | | |-- apns-dev-key.pem
| | | |-- embedded.mobileprovision
| | | |-- en.lproj
| | | | |-- MyAppViewController.nib
| | | | |-- MyAppViewController.strings
| | | | |-- InfoPlist.strings
| | | | |-- Localizable.strings
| | | | |-- MainWindow.nib
| | | | `-- MainWindow.strings
| | | |-- icon.png
| | | |-- ko.lproj
| | | | `-- InfoPlist.strings
| | | `-- www
| | |-- MyApp.app.dSYM
| | | `-- Contents
| | | |-- Info.plist
| | | `-- Resources
| | | `-- DWARF
| | | `-- MyApp
| | `-- libMDHybridPlatform.a
| `-- Debug-iphonesimulator
|-- Index
| |-- Debug
| | |-- iphoneos6.0-armv7
| | | `-- MyApp.xcindex
| | | |-- db.xcindexdb
| | | |-- db.xcindexdb-shm
| | | |-- db.xcindexdb-wal
| | | |-- db.xcindexdb.strings-cmp
| | | |-- db.xcindexdb.strings-dir
| | | |-- db.xcindexdb.strings-file
| | | |-- db.xcindexdb.strings-res
| | | `-- db.xcindexdb.strings-sym
| |-- MyApp.hmap
| `-- PrecompiledHeaders
| |-- MyApp-Prefix-eexltsqbxftvslbqzbejwmcymksy_ast
| |-- MyApp-Prefix.pch.pth
| `-- MyApp-Prefix.pch.pth.hash-criteria
`-- Logs
|-- Build
`-- Debug
마무리
이 것으로 Xcode가 빌드하는 과정을 알아보았다. Xcode를 포함한 최근의 IDE들을 참 좋다. 모든 복잡한 작업들을 내부로 숨기고 개발자에게는 간단한 설정만으로 빌드가 자동으로 되도록 만들어준다. 참 좋은 세상이 되었다. 하지만 그러다 보니 IDE가 없으면 아무것도 못하는 문제도 생겼다. 순응하고 살면 편한 세상이 되었지만 왠지 반항하고 싶다. 모드가 왼쪽으로 갈때 오른쪽으로 가고 싶은 마음이랄까..
[출처] http://10apps.tistory.com/132No. | Category | Subject | Author | Date | Views |
---|---|---|---|---|---|
409 | Develop |
[c++] mfc로 만든 부엌 수납 시스템(2D기반 설계)
![]() |
hooni | 2013.04.23 | 7290 |
408 | Develop |
[c] 웹 메모장.. ㅋㅋ
![]() |
hooni | 2013.04.23 | 6851 |
407 | Develop | [java] RGB코드를 HEX코드로 변환하는 코드 ㅎㅎ | hooni | 2013.04.23 | 8031 |
406 | Develop | 라이브러리에 대한 설명 (static & dynamic library) | hooni | 2013.04.23 | 6969 |
405 | Develop | [c] 파일(File)의 연결과 연결 해제 (link, unlink, chown) | hooni | 2013.04.23 | 9558 |
404 | Develop | [js] 실행되는 디렉토리 확인하는 스크립트.. | hooni | 2013.04.23 | 6789 |
403 | Develop |
[c++] mfc 윈도우에서 ODBC 사용하여 MDB파일 읽기.. ㅋㅋ
![]() |
hooni | 2013.04.23 | 9150 |
402 | Develop | [c++] String Tokenizer (나중에 c 코드로 변경해서 사용할 것) | hooni | 2013.04.23 | 11731 |
401 | Develop |
[doc] mfc 매뉴얼 다운 받아서 완성하기.. ㅋㄷ
![]() |
hooni | 2013.04.23 | 7716 |
400 | Develop |
[c++] 채팅로봇 소스.. ㅋㄷㅋㄷ
![]() |
hooni | 2013.04.23 | 8906 |
399 | Develop | [c] 쓰레드에 대한 내용 퍼오기..ㅡㅡ; | hooni | 2013.04.23 | 8468 |
398 | Develop | [c++] mfc에서 윈도우 항상 위 속성 주기.. | hooni | 2013.04.23 | 11369 |