Contents

Atachment
첨부 '2'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
iOS의 프로젝트가 커지다 보면 코드를 다수의 라이브러리들로 나누어야 한다. 불행이도 iOS에서는 동적 라이브러리가 지원되지 않기 때문에 iOS에서 라이브러리를 만든다면 정적인 라이브러리를 말한다. (비공식적인 방법도 있다고는 하지만 테스트는 해보지 않았다.)


Fat 타입

라이브러리를 만들때 Fat 타입으로 만들면 사용하지 쉽다. Fat 타입은 여러가지 CPU 아키텍쳐의 라이브러리가 한 파일에 포함되어 있는 파일이다.

$> file libcrypto.a 
libcrypto.a: Mach-O universal binary with 3 architectures
libcrypto.a (for architecture i386):    current ar archive random library
libcrypto.a (for architecture armv7):   current ar archive random library
libcrypto.a (for architecture cputype (12) cpusubtype (11)):    current ar archive random library
위에서 처럼 file 명령을 사용하면 원하는 라이브러리가 Fat 타입인지 확인할 수 있다. 위 예제를 보면libcrypto.a 파일에 i386, armv7, armv7s ( cputype (12) cpusubtype(11) 이라고 되어 있다. ) 가 지원됨을 할 수 있다. i386은 시뮬레이터에서 사용할 파일이고 armv7, armv7s는 실제 기기에 올라가는 앱을 만들때 사용된다.


Fat 타입 라이브러리 만들기

Fat 타입 라이브러리를 만들기 위해서는 i386, armv7, armv7s로 빌드된 라이브러리가 있어야 한다. 각각의 플랫폼 별로 라이브러리가 만들어져 있다면 다음 명령으로 하나의 Fat 파일을 만들 수 있다.

$> lipo -ouput libtest.a -create libtest_i386.a libtest_armv7.a libtest_armv7s.a
lipo 명령을 이용하게 되는 lipo파일로 여러타입으로 빌드된 라이브러리를 하나로 만들 수 있다. lipo 명령은 비단 라이브러리에만 적용되는 것 아니다. mac의 실행파일로 Fat 파일로 되어 있다. Mac에 인텔 CPU는 사용하기 전에는 Power PC를 사용했는데 앱을 개발하는 입장에서 각 CPU별로 따로 빌드해서 배포하는 것을 귀찮은 일이다. 이럴때 lipo를 이용해서 여러 타입의 바이너리를 하나로 합칠 수 있다.


쉬운 방법

Fat 타입 라이브러리를 만드는 과정은 lipo 명령을 이용해서 수동으로 만들 수도 있지만
Xcode만을 주로 사용한다면 Xcode에 쉘스트립트를 추가해서 Xcode 빌드시마다 Fat 라이브러리를 만들 수 있다.

figure01.png

그림 1. 스크립트 추가



그림 1과 같이 Static Library 프로젝트의 Build Phases에서 Add Run Script를 통해서 빌드 과정에서 필요한 스트립트를 추가할 수 있도록 한다.

다음 스크립트를 Run Script에 추가한다. ( 출처 : http://stackoverflow.com/questions/3520977)

#
# c.f. StackOverflow question/answer here: http://stackoverflow.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4
#
# Version 2.5
#
# Latest Change:
# - The "copy headers" section now respects the build setting for the location of the public headers
# 
# Purpose:
#   Create a static library for iPhone from within XCode
#   Because Apple staff DELIBERATELY broke Xcode to make this impossible from the GUI (Xcode 3.2.3 specifically states this in the Release notes!)
#   ...no, I don't understand why they did this!
#
# Author: Adam Martin - http://twitter.com/redglassesapps
# Based on: original script from Eonil (main changes: Eonil's script WILL NOT WORK in Xcode GUI - it WILL CRASH YOUR COMPUTER)
#

set -e
set -o pipefail

#################[ Tests: helps workaround any future bugs in Xcode ]########
#
DEBUG_THIS_SCRIPT="false"

if [ $DEBUG_THIS_SCRIPT = "true" ]
then
echo "########### TESTS #############"
echo "Use the following variables when debugging this script; note that they may change on recursions"
echo "BUILD_DIR = $BUILD_DIR"
echo "BUILD_ROOT = $BUILD_ROOT"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "BUILT_PRODUCTS_DIR = $BUILT_PRODUCTS_DIR"
echo "CONFIGURATION_TEMP_DIR = $CONFIGURATION_TEMP_DIR"
echo "TARGET_BUILD_DIR = $TARGET_BUILD_DIR"
fi

#####################[ part 1 ]##################
# First, work out the BASESDK version number (NB: Apple ought to report this, but they hide it)
#    (incidental: searching for substrings in sh is a nightmare! Sob)

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '.\{3\}$')

# Next, work out if we're in SIM or DEVICE

if [ ${PLATFORM_NAME} = "iphonesimulator" ]
then
OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}
else
OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}
fi

echo "XCode has selected SDK: ${PLATFORM_NAME} with version: ${SDK_VERSION} (although back-targetting: ${IPHONEOS_DEPLOYMENT_TARGET})"
echo "...therefore, OTHER_SDK_TO_BUILD = ${OTHER_SDK_TO_BUILD}"
#
#####################[ end of part 1 ]##################

#####################[ part 2 ]##################
#
# IF this is the original invocation, invoke WHATEVER other builds are required
#
# Xcode is already building ONE target...
#
# ...but this is a LIBRARY, so Apple is wrong to set it to build just one.
# ...we need to build ALL targets
# ...we MUST NOT re-build the target that is ALREADY being built: Xcode WILL CRASH YOUR COMPUTER if you try this (infinite recursion!)
#
#
# So: build ONLY the missing platforms/configurations.

if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: I am NOT the root invocation, so I'm NOT going to recurse"
else
# CRITICAL:
# Prevent infinite recursion (Xcode sucks)
export ALREADYINVOKED="true"

echo "RECURSION: I am the root ... recursing all missing build targets NOW..."
echo "RECURSION: ...about to invoke: xcodebuild -configuration \"${CONFIGURATION}\" -project \"${PROJECT_NAME}.xcodeproj\" -target \"${TARGET_NAME}\" -sdk \"${OTHER_SDK_TO_BUILD}\" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO" BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" SYMROOT=\"${SYMROOT}\"

xcodebuild -configuration "${CONFIGURATION}" -project "${PROJECT_NAME}.xcodeproj" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"

ACTION="build"

#Merge all platform binaries as a fat binary for each configurations.

# Calculate where the (multiple) built files are coming from:
CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos
CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator

echo "Taking device build from: ${CURRENTCONFIG_DEVICE_DIR}"
echo "Taking simulator build from: ${CURRENTCONFIG_SIMULATOR_DIR}"

CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
echo "...I will output a universal build to: ${CREATING_UNIVERSAL_DIR}"

# ... remove the products of previous runs of this script
#      NB: this directory is ONLY created by this script - it should be safe to delete!

rm -rf "${CREATING_UNIVERSAL_DIR}"
mkdir "${CREATING_UNIVERSAL_DIR}"

#
echo "lipo: for current configuration (${CONFIGURATION}) creating output file: ${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}"
lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"

#########
#
# Added: StackOverflow suggestion to also copy "include" files
#    (untested, but should work OK)
#
echo "Fetching headers from ${PUBLIC_HEADERS_FOLDER_PATH}"
if [ -d "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}" ]
then
mkdir -p "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
# * needs to be outside the double quotes?
cp -r "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"* "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
fi
fi
설정이 끝났다면 terminal에서 다음 명령을 실행해서 빌드 해보자. ( xcodebuild 명령어 사용 )

$> xcodebuild test.xcodeproj build
이렇게 빌드를 하면 다음 경로에 Fat 라이브러리가 보인다.
build/Release-universal/
이제 이 라이브러리를 사용하면 시뮬레이터와 디바이스용으로 빌드할 때 같은 파일을 사용할 수 있다.


마무리

iOS 앱을 직접 개발을 한다면 static library를 작성할 일을 많지 않을 것이다. 대부분 소스 자체를 공유해서 쓰는 편이 문제가 더 적기 때문이다. 하지만 조금 큰 프로젝트라면 static library를 만들어야 할 때가 있다. 이럴때 사용하면 유용할 팁이다.


참고


[출처] http://10apps.tistory.com/123

?

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
933 System/OS [mac] Mac OS 패키지 매니저, HomeBrew file hooni 2015.01.03 1270
932 Develop [ios] binary를 C코드로 변환 file hooni 2015.01.03 1506
931 Develop [ios] APNS에 사용할 인증서 만들기 (KeyChain에 있는 인증서 Export) file hooni 2015.01.03 870
930 Develop [ios] iOS앱의 Xcode 빌드 과정 file hooni 2015.01.03 2237
» Develop [ios] Xcode를 사용해서 Static Library 만들기 (시뮬레이터 + 디바이스) file hooni 2015.01.03 3254
928 Develop [ios] Thread Loop 내에서 UI 업데이트 방법 hooni 2015.01.03 827
927 Develop [ios] UIView 계층구조 hooni 2015.01.03 1104
926 System/OS [linux] CentOS 에 APM 설치하기 hooni 2015.01.02 1669
925 Develop [ios] UIWebView를 이용한 로컬 HTML 파일 표시 file hooni 2015.01.02 1203
924 Develop [android] 안드로이드 동영상 스트리밍 예제 2 hooni 2015.01.02 4794
923 System/OS CentOS 에서 Cacti 설치하기 hooni 2015.01.02 1742
922 Develop [java] netty (비동기 이벤트 방식 네트워크 프레임워크) 사용법 #2 (client) hooni 2015.01.02 2017
Board Pagination Prev 1 ... 16 17 18 19 20 21 22 23 24 25 ... 98 Next
/ 98