Xcode4에서 범용으로 쓸 수 있는 library만들기.

개발하다보면 Common Module 혹은 Common Library 등.. 이런 뉘앙스의 이름으로 불리는 녀석들이 있다.
개발하는데 공통적으로 쓰이는 것들을 모아놓은 녀석들을 지칭하는 말인데,
cocoa에서는 이렇게 안부르고 static library라고 부른다.

iPhone, iPad의 경우 시뮬레이터가 있다보니 시뮬레이터(simulator)용, 디바이스(device)용 이렇개 2가지를 만들어서 상황에 맞게 사용을 해야 하는데, 이게 참 번거로운 일이다.

생각해보라.
시뮬레이터로 테스트 할땐 시뮬레이터용 라이브러리를 넣고
디바이스에서 테스트 할땐 시뮬레이터용 라이브러리를 삭제하고, 디바이스용 라이브러리를 넣고
다시 시뮬레이터로 테스트 할땐 디바이스용 라이브러리를 지우고, 시뮬레이터용 라이브러리 넣고.
지금 TAd(SK T에서 제공하는 광고)가 이렇게 구현되어 있다.

하지만, 다행스럽게도 라이브러리를 하나로 합칠 수 있다.
lipo를 이용하면 되는데, 잠시 후에 언급하겠다.

1. 라이브러리로 만들 프로젝트 생성

라이브러리로 만들 프로젝트를 새로 만든다. 이때 타입은 Cocoa Touch Static Library이다.
iOS > Framework & Library > Cocoa Touch Static Library

 

 

 

 

 

Library라는 이름으로 프로젝트를 생성했고, 공통으로 쓰이는 모듈을 모아놓은 파일을 프로젝트에 추가를 한다.
Common.h, Common.m 파일을 추가했다.

 

 

 

2. 시뮬레이터용(simulator) Target 만들기.

새로운 Target을 추가를 하는데, Target의 타입 또한 Cocoa Touch Static Library이다.

 

 

 

 

 

 

 
시뮬레이터용 라이브러리이므로, Target이름은 Library-Simulator로 하겠다. (네이밍은 본인 마음대로)

 

 

 

 

 
그리고 파일을 Build Phases에 추가를 해야 한다.
헤더(.h) 파일은 Copy Headers에, 소스(.m)파일은 Compile Sources에 드래그&드랍(Drag&Drop)으로 추가를 한다.
Header는 Public, Private, Project 이렇게 3가지 타입을 가지고 있다. 목적에 맞는곳에 넣으면 되며, 기본값은 Project이다.

 

 

 

 
그리고 마지막으로 Scheme 타입에 Build Configuration을 Release로 변경한다.
Product > Edit Scheme

 

 

 

3. 디바이스용(device) Target 만들기.

2. 시뮬레이터용(simulator) Target 만들기.와 똑같은 작업의 반복이다. 이름만 다른것으로 바꿔주면 된다.
Library-Device라고 하겠다.

 

 

 

4. Targets 합치기.

위에서 언급했던대로, 지금 만든 2개의 Target을 하나로 합치는 Target을 만든다.
이번에도 Add Target을 하는데, Aggregate로 만든다.
Other > Aggregate

 

 
이름은 Library-iOS4.0 으로 하겠다.
이번에도 마찬가지로 Edit Scheme에서 Build Configuration을 Release로 변경한다.

 

 
Run Script를 추가를 한다.
Add Build Phases > Add Run Script

 

 

 

 

 
그리고 나서 lipo를 이용한 두 Target을 Merge하는 구문을 넣는다.

 

rm -rf ${BUILT_PRODUCTS_DIR}/libLibrary-ios4.0.a
lipo -create “${BUILT_PRODUCTS_DIR}/../${BUILD_STYLE}-iphonesimulator/libLibrary-Simulator.a” \
“${BUILT_PRODUCTS_DIR}/libLibrary-Device.a” -output \
“${BUILT_PRODUCTS_DIR}/libLibrary-ios4.0.a”

 

보시다시피 sh 명령어이다. 파일명은 본인의 상황에 맞게 수정하면 된다.
위 명령어를 보면 대충 파악 되겠지만, 두개의 .a를 하나의 .a로 Merge해주는 명령어다.
지금은 빌드를 안했기 때문에 libLibrary-simulator.a와 libLibrary-device.a가 없다.
여기서 주의할점은, 빌드를 하면 lib이 접두어로 붙게 된다. 그러므로 .a 파일명에 접두어로 lib을 붙이는걸 잊지말자.

 

 

 

5. 빌드하기

자, 이제 세팅은 완료가 되었다. 각각의 Target을 Build해주면 된다.

 

 
먼저, Library-simulator 빌드!

 

 

 
이젠 Library-Device 빌드!

 


Library-simulator.a, Library-device.a 파일 모두 생성되었다.

 

 

 

 

 

마지막으로 Library-iOS4.0 빌드!

 

 

 
이제 만들어진 libLibrary-iOS4.0.a를 사용하면 되는데, 이 녀석의 위치는
libLibray-Device.a를 우클릭해서 Show in Finder로 보면 Finder가 열리는데, 그 위치에 있다.

 

 

 

 
이제 libLibrary-ios4.0.a와 Common.h 파일을 작업중인 프로젝트에 넣어서 사용하면 끝!

만약. libLibrary-ios.4.0 빌드를 실패했다면 십중팔구 파일을 lipo에서 파일을 못찾아서 나는 에러이다.
아래 4가지 항목을 체크해보면 해결 될 것이다.

  • 만들어놓은 Target들의 Build Configuration이 Release로 되어 있는지
  • Library-simulator는 Simulator로 빌드했는지
  • Library-device는 device로 빌드했는지
  • Library-ios는 device로 빌드했는지

아이폰 앱개발시 코드는 문제 없는데 이유를 알 수 없는 에러가 날때..

– 증상

앱 개발중 sqlite부분을 구현중이었습니다.

어느순간부터 컴파일시 이유를 알 수 없는 에러가 뜨더군요.

ld: warning: in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib/libsqlite3.0.dylib, missing required architecture i386 in file
ld: warning: in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib/libSystem.dylib, missing required architecture i386 in file
ld: in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib/libobjc.A.dylib, missing required architecture i386 in file
collect2: ld returned 1 exit status
Command /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 failed with exit code 1

 

(결론만 알고 싶은분은 아래로 스크롤 퀵다운 하세요 ㅎㅎ)

 

 

하소연잡소리

어느라인에서 에러가 났는지 트래킹도 안해주더군요..

이때 직감했습니다.. “지금시각 새벽3시.. 오늘 잠 다잤다.”

 

sqlite붙이면서 작성했던 코드.. 메쏘드 하나씩 주석으로 처리를 했는데도.. 여전히 저 에러는 뜨더군요.

그래서 코드자체를 지워봤는데도.. 여전히 뜨는겁니다.

혹시나 싶어 초창기때 떠논 스냅샷으로 했는데도 뜨더군요.

이때 직감했습니다.. “지금시각 새벽 3시 30분.. 오늘 잠 다잤다.”

 

 

맥부기와서 “gcc-4.2 failed with exit code 1″로 검색을 해봅니다.

질문글들은 있는데.. 대부분 무플.. 그나마 있는 답변은 저랑 케이스가 안맞더군요.

 

구글에서 검색했습니다.

역시 건질거 없습니다.

 

포기하고 잘까하다가..

시뮬레이터 버전을 바꿔봅니다.

역시 변하는거 없습니다.

 

침착하게 맘먹고.. 에러코드를 찬찬히 봅니다.

그랬더니 눈에 안보이던 에러코드가 보입니다.

d: warning: in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib/libsqlite3.0.dylib, missing required architecture i386 in file
ld: warning: in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib/libSystem.dylib, missing required architecture i386 in file
ld: in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib/libobjc.A.dylib, missing required architecture i386 in file

이번에 추가한 libsqlite3.0.dylib는 링크파일이어서 못찾나? 했는데…

libSystem.dylib랑 libobj.cd.A.dylib은 기존에 있던것들인데 missing이라고 하는게 의심스럽더군요.

이때 직감했습니다.. “오늘밤 잘 수 있겠구나..”

 

다시 맥부기로와서

“missing required architecture i386 in file” 검색합니다.

와우!!! 검색결과가 없답니다….

 

구글로 가서 검색을 합니다.

그중 뭔가 냄새가 나는글을 포착.. 링크에 링크를 타다보니.. stackoverflow.com에 저와 동일한 증상에 대한 질문이 있고 답글이 있더군요. (제가 RoR하는데 종종 stackoverflow.com에서 도움받았는데.. stackoverflow.com최고!!)

거기에 나와있는 해결책대로하니..

젠장……… 잘됩니다 ㅠ,.ㅠ

지쟈스.. 감사합니다. ㅠ,.ㅠ

이거 안되면

#1 일단 걍 잔다

#2 아침에 SDK새로깐다.

#3 그래도 안되면 다….다…다….다시 짠다.

 

자.. 저의 재미없는 하소연을 읽느라 지루하셨죠~?

이제 그 마법의 비법을 소개해드리겠습니다.

 

 

– 해결책

#1 문제가 있는 프로젝트의 프로젝트코드를 textmate나 textedit같은 text editor로 열어제낍니다.

예) example.xcodeproj

전 textmate로 열었습니다.

 

#2 textmate로 열면 3개의 파일이 나타나는데 그 중 project.pbxproj를 오픈합니다.

 

 

#3 그리고 FRAMEWORK_SEARCH_PATHS 혹은 LIBRARY_SEARCH_PATHS의 경로를 상황에 맞게 적절하게 수정해줍니다.

저같은 경우 이렇게 되어 있더군요.

LIBRARY_SEARCH_PATHS = (
“$(inherited)”,
“\”$(DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/lib\””,
“\”$(DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/lib\””,
);

네.. 그렇습니다 문제는 여기 있었던겁니다.

외부 프레임웤 파일을 추가할때(libsqlite3)이 경로도 변경이 된 것이죠… -ㅅ-; 버그죠. (전 스노우 레오파드입니다.)

벅차오르는 분노와.. 해결할 수 있다는 기쁨과 희망이 오묘하게 교차하는 순간이었습니다. ㅎㅎ

전 아래와 같이 수정해주었습니다.

LIBRARY_SEARCH_PATHS = (
“$(inherited)”,
“\”$(DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/System/Library/Frameworks\””,
“\”$(DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks\””,
);

 

 

이렇게 수정후 컴파일하니.. 시뮬레이터 잘 뜹니다.

네.. 제가 짠 sqlite부분은 문제가 없었던 것이었습니다.!!! (역시 난 틀리지 않았어!! ㅎㅎ)

정말로 기쁘더군요..

저의 기쁜 마음을 알아주는건지.. 창밖은 서서히 밝아오고..-ㅅ-

 

문제를 해결한 기쁜마음이 있을때 이렇게 써놓아야지.. 안그러고 자고나면 귀차니즘으로 안쓸걸 알기에..

이렇게 앞뒤문맥따위 예쁘게 무시해버린 글을 휘갈겨놓습니다.

 

참고링크: http://stackoverflow.com/questions/1456185/build-error-missing-required-architecture-i386-in-file/1467238#1467238