XCode 4.x iOS Device와 Simulator용 Static Lib 통합해서 Universal Lib로 만들기

 제가 만들고 있는 Framework Static Lib를 기존에는 Simulator용으로만 빌드해서 사용했었습니다. 링크의 포스팅에도 언급했고 팀 프로그래머들이 Framework Lib 가져다 쓸 연동 시점도 다가오고 있어서 Device용 Static Lib도 만들어서 사용을 해야합니다. 해서 이번 포스팅에서는 Simulator와 Device용 Static Lib를 하나로 통합해서 사용하는 것을 정리해보겠습니다.

 먼저 간단하게 App과 외부 Static Lib Project간에 Build Target Lib가 맞지않아 생기는 에러와 해결 시 불편한 점 때문에 왜 굳이 Universal Lib로 통합을 해야하는지 짚고 넘어가보도록 하겠습니다.

 위와 같이 Simulator과 iPhone Device용 Static Lib가 만들어져있을때,

 App에서는 Device를 선택해서 빌드를 하는데 기존에 Static Lib를 추가한게 Simulator용이었다면 아래와 같은 에러가 나올 것입니다.


Undefined symbols for architecture armv7:
  "xxxxx", referenced from:
      xxxxx in xxxxx.o
      xxxxx in xxxxx.o
...
...
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)


 반대로 App은 Simulator이고 Static Lib가 Device용이어도 같은 에러가 발생합니다.

 이에 대한 해결은 당연하게도 App과 Static Lib가 같은 Bulid Target에 매칭되게 해서 Build를 하는 것입니다. 즉, Device용을 빌드할 때는 Static Lib도 Device용 Lib를 가져다써야하는거죠. Simulator로 테스트 할 땐 Simulator용 Static Lib를 넣었다가 Device로 바뀌면 Device용으로 갈아치워주고를 Build Target이 바뀔때마다 이리 해야한다는게 함정.

 그렇다고 Xcode에는 Win32개발처럼 #pragma comment( lib, "xxx.lib" ) 이게 되는지도 의문이고 Build Setting에서 추가 종속 Lib설정 같은것도 안보이는 것 같습니다.

 궁극적인 해결책인지는 모르겠지만 한가지가 있는데 libtool이라는 것을 이용해서 Universal Lib라고 Device와 Simulator용 Static Lib를 하나로 묶어서 사용하는 방법이 있네요. 이제부터 이것에 대해 정리를 해볼께요. 본격적으로 시작하기 전에 Static Lib Project는 이미 만들어져 있다고 가정하고 진행합니다.

Debug Static Lib를 Device용과 Simulator용으로 빌드 하신후 해당 lib.a가 있는 디렉토리의 한단계 위로 가셔서 Go2Shell을 실행합니다.

 libtool -static Debug-iphoneos/libFramework.a Debug-iphonesimulator/libFramework.a -o libFrameworkiOSDebug.a

 그리고 위와 같이 터미널에서 입력해줍니다. Debug용 Device lib와 Simulator lib를 libFrameworkiOSDebug.a 하나로 묶어주는 명령어입니다. 각자의 환경에 맞게 입력하시면 되겠습니다.

-bash: libtool: command not found

 만약 위와같이 libtool을 못 찾는다고 한다면 링크를 참고하시기 바랍니다.

 이제 finder에서보면 Universal Static Lib가 생성된 걸 확인할 수 있습니다.

 이제 기존에 추가했던 반쪽짜리 Static Lib는 삭제하시고 만들어진 Lib파일을 개발중인 App의 Frameworks 폴더에 끌어다 놓습니다. 그리고 Device나 Simulator 바꿔가면서해도 빌드 후 실행 가능할 것입니다.

 빌드시마다 매번 libtool을 타이핑해서 실행할 수 없으니 Universal용 Built Target을 따로 만들어 거기에 Built Script를 추가해서 처리해보도록 하겠습니다.

 먼저 Project -> TARGETS -> Add Target을 클릭합니다.

 iOS -> Other -> Aggregate를 선택합니다.

 Aggregate Target이 추가되었습니다.

 
 Targets -> Build Phases -> Add Build Phase를 클릭 후 Add Run Script를 선택합니다. 그리고 아래의 스크립트를 기입합니다. 여기서도 물론 각 개발 환경에 맞게 기입하시면 됩니다.


UNIVERSAL_LIB=libFrameworkUniversal.a
UNIVERSAL_DIR=${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-universal

if [ ! -d "${UNIVERSAL_DIR}" ]
then
    mkdir ${UNIVERSAL_DIR}
fi

rm -rf ${UNIVERSAL_DIR}/${UNIVERSAL_LIB}

libtool -static "${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-iphoneos/libFramework.a" "${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-iphonesimulator/libFramework.a" -o "${UNIVERSAL_DIR}/${UNIVERSAL_LIB}"

 간단히 설명드리면 Debug냐 Release냐에 따른 설정에 따라 Universal Dir에 통합 lib를 만드는 것입니다.

 이제 Scheme를 Aggregate Target으로 선택해서 Build하시면 됩니다. 물론 스크립트가 필요로하는 Device와 Simulator용 lib가 먼저 빌드되어 있어야겠죠.

 Universal Static Lib가 빌드되었습니다.

 Build시 Script부분에서 이런저런 Error가 발생할 수 있습니다. No such file or directory 같은 것말이죠. 디렉토리 참조 부분을 잘 수정해서 다시 시도해보시기 바랍니다.

댓글

이 블로그의 인기 게시물

'xxx.exe' 프로그램을 시작할 수 없습니다. 지정된 파일을 찾을 수 없습니다.

goorm IDE에서 node.js 프로젝트로 Hello World Simple Server 만들어 띄워보기

애드센스 수익을 웨스턴 유니온으로 수표대신 현금으로 지급 받아보자.