Building an Open Source Universal Binary
OSXDEV
Mac OS X는 시스템의 안정성과 튼튼함에 도움을 주는 많은 오픈소스 프로젝트를 포함하고 있다. 애플이 PowerPC와 Intel 아키텍처에서 실행할 수 있는 것들을 제공해주기도 하지만, 때로는 직접 기능을 추가하거나, 성능 조절을 하여 직접 빌드해야할 필요가 생길 수도 있다. 또한, 하나의 바이너리 파일을 배포하는 것이 각각의 아키텍처가 무엇인지 알아봐야 하는 것보다 더 좋을때가 있다. 하나의 파일에 PowerPC와 Intel 아키텍처의 코드를 모두 포함하고 있는 Universal Binary를 이용하여 프로젝트를 빌드하면 이러한 목적을 달성할 수 있다.
OpenSSL은 이러한 오픈소스 프로젝트의 하나이다. 이것은 Secure Sockets Layer (v2 and v3)와 Transport Layer Security (v1)의 구현을 제공하고, Mac OS X v10.0 부터 Darwin에 포함되어 있다. 이 문서는 Xcode(Xcode 2.2.1을 사용한다)를 이용하여 make 빌드 기반의 OpenSSL을 Universal Binary로 구축하는 방법에 대해 설명한다. 이 두종류의 라이브러리와 테스트 어플리케이션을 빌드하고 제대로 실행하기 위해 필요한것이 무엇인지 살펴볼것이다. 여러분의 프로젝트나 다른 오픈소스 어플리케이션을 Mac OS X로 포팅하는데 좋은 시작점이 될 것이다.
여러분은 이 문서를 위해 작성된 .DMG 파일(100KB)로된 Xcode 프로젝트를 다운로드 받을 수 있다.
목차 |
[편집] OpenSSL 프로젝트
OpenSSL은 오픈소스 버젼의 Secure Sockets Layer 라이브러리이다. 여러분은 https: //로 시작하는 URL에 접속할때 웹 브라우저 윈도우의 구석에 나타는 자물쇠 모양의 아이콘을 본적이 있을 것이다. SSL은 이것을 작동시키는 기반 구조이다.
openssl 명렁어 맨페이지는 OpenSSL 라이브러리의 기능에 대해 개략적인 설명을 제공한다.
- RSA, DH, DSA 키 파라메터의 생성
- X.509 증명서와, CSR, CRL의 생성
- 메세지 요약(Message Digests)의 계산
- Ciphers을 이용한 암호화와 해독
- SSL/TLS 클라이언트와 Server 테스트
- S/MIME 서명 또는 암호화된 메일 다루기
OpenSSL 프로젝트는 꽤 복잡한 편이다, 그러나 이 문서를 보며 핵심 라이브러리를 생성하는데 소스코드를 변경할 필요는 없다. 여기서 Xcode를 이용하여 PowerPC와 Intel 아키텍처 모두를 위한 프로젝트를 어떻게 빌드하는가에 대해 촛점을 둘 것이다. PowerPC 매킨토시에서 Universal Binary를 빌드하고 PowerPC 와 Intel기반의 매킨토시 모두에서 테스트를 할 것이다. Intel기반의 맥이 있다면 Intel기반 매킨토시에서 빌드하여, 양쪽에서 테스트할 수도 있을 것이다. 만약 다양한 아키텍처, 오픈소스 프로젝트에 대한 개념이 생소하다면 이 문서는 좋은 시작점이 될 것이다.
[편집] OpenSSL 프로젝트 구조
첫째로 압축된 OpenSSL 소스파일을을 다운받아 압축을 해제한다. openssl-0.9.8a.tar.gz 파일을 클릭하면 압축이 해제된다. 이 문서는 0.9.8a 버젼을 다루고 있다. 그림 1은 OpenSSL의 최상위 폴더에서의 구조를 보여주고 있다. 이 문서에서는 crypto와 ssl 폴더와 이 폴더의 소스코드로 부터 빌드되는 라이브러리에 대해서 다루기로 한다. 프로젝트 설정값을 결정하는데 최상위 makefile("Makefile")을 이용하기로 한다.
대부분의 오픈소스 프로젝트는 makefile을 이용하여 빌드 과정을 제어한다. makefile은 포함될 소스 파일, 사용될 빌드 옵션, 최종 바이너리의 형태와 같은 컴파일러와 링커의 지시 플래그를 설정한다. makefile에 관한 내용은 이 문서의 끝에 소개된 몇몇 ADC 문서에서 다루고 있다.
최상위 makefile을 보면 플랫폼 종속적인 설정들은 포함되어 있지 않다. 필요한 상세한 설정들은 config 쉘 스크립트를 실행함으로써 채워진다. config는 시스템을 분석하여 적절한 makefile을 생성해낸다. 만약 config의 작동을 변경하고 싶다면 프로젝트 빌드에 관한 플래그와 함께 스크립트를 실행하면 된다. Xcode 프로젝트를 시작하기 전에 config 스크립트를 실행한다. 이것은 아무런 문제도 되지 않으며, 빌드 시스템이 어떻게 make 파일을 위한 설정을 하는지 이해하는데 도움이 된다.
목록 1은 OpenSSL 프로젝트의 루트 폴더로부터 생성된 makefile의 일부분을 포함하고 있다. 첫번째 줄의 주석은 이 파일이 Configure로 부터 생성되었다는 것을 알려준다.
목록 1: 최상위 Makefile
### Generated automatically from Makefile.org by Configure. ## ## Makefile for OpenSSL ## VERSION=0.9.8a MAJOR=0 MINOR=9.8 PLATFORM=darwin-ppc-cc OPTIONS= no-gmp no-krb5 no-mdc2 no-rc5 no-shared no-zlib no-zlib-dynamic CONFIGURE_ARGS=darwin-ppc-cc SHLIB_TARGET=darwin-shared CC= cc CFLAG= -DOPENSSL_THREADS -D_REENTRANT -O3 -DB_ENDIAN AR=ar $(ARFLAGS) r RANLIB= /usr/bin/ranlib DIRS= crypto ssl engines apps test tools LIBS= libcrypto.a libssl.a BUILD_CMD= if [ -d "$$dir" ]; then \ ( cd $$dir && echo "making $$target in $$dir..." && \ $(CLEARENV) && $(MAKE) -e $(BUILDENV) TOP=.. DIR=$$dir $$target \ ) || exit 1; \ fi build_all: build_libs build_apps build_tests build_tools build_libs: build_crypto build_ssl build_engines build_crypto: @dir=crypto; target=all; $(BUILD_CMD) build_ssl: @dir=ssl; target=all; $(BUILD_CMD) build_engines: @dir=engines; target=all; $(BUILD_CMD)
우리가 관심있게 보아야 할 부분은 타켓 설정과 build_libs, 그리고 CC 변수의 값이다. 나중에 Intel용 라이브러리를 빌드할때, CC 설정을 변경하게 된다.
[편집] 빌드 순서 간단히 살펴보기
전반전인 빌드 순서는 다음과 같다. PowerPC 라이브러리를 빌드한다, Intel 라이브러리를 빌드한다, 두개를 하나의 라이브러리로 묶는다. OpenSSL은 몇가지 테스트 어플리케이션을 포함하고 있으며, 이것들은 마지막 과정에서 빌드된다. 아래에 상세한 과정이 나와있다. 각각의 라이브러리를(crypto와 ssl) 각각의 아키텍처에 빌드하는 점에 주의하자.
1. PPC로 빌드: PowerPC 라이브러리를 만듬
- 바이너리를 깨끗이 정리함
- 아키텍처 고유한 빌드 환경 설정 (여기서는, PPC)
- 라이브러리를 보관할 임시 폴더 생성
- PPC 버젼의 라이브러리 생성
- 임시 폴더에 PPC용 라이브러리를 복사
2. i386으로 빌드: Intel 아키텍처 라이브러리를 만듬
- 바이너리를 깨끗이 정리함
- 인텔 아키텍처 빌드 환경 설정
- 인텔 버젼의 라이브러리 생성
- 임시 폴더에 인텔용 라이브러리를 복사
3. Universal Binary 생성
- 유니버설 crypto 라이브러리를 만들기 위해 lipo를 사용
- 유니버설 ssl 라이브러리를 만들기 위해 lipo를 사용
- 유니버설 라이브러리를 루트 폴더에 복사. 이 과정은 중요한데, OpenSSL에 포함된 테스트 어플리케이션이 빌드된 라이브러리를 루트 폴더에서 찾기때문이다.
4. 테스트 어플리케이션 생성
- ranlib를 실행하여 각각의 라이브러리의 목차를 재빌드
- 아키텍처 고유한 빌드 환경 설정
- PPC 버젼의 테스트 어플리케이션 생성
이러한 일반적인 과정은 다른 오픈소스 프로젝트에서 사용될 수도 있다. 빌드 과정을 수행하기 위해 쉘스크립트를 사용할 것이다.
[편집] Xcode Project 만들기
지금까지 OpenSSL 소스 구조와 빌드 과정에 대해 간단히 살펴보았다. 이제 Xcode 프로젝트를 만들 차례다. 완성된 Xcode 프로젝트를 다운받고 싶으면, 이 문서의 마지막에 있는 "참고 자료"에 있는 링크를 이용하길 바란다. 첫번째 과정은 새로운 프로젝트를 생성하는 것이다. Xcode에서 File > New Project를 선택한다. 그 다음으로 그림 2와 같이 Assistant 다이얼로그에서 "Empty Project"를 선택한다.
그림 3과 같이 프로젝트 이름을 "OpenSSL"로 하고, 디렉토리는 OpenSSL 소스 폴더로 설정한다. Xcode는 기본적으로 타켓이름으로 서브폴더를 생성하는 것에 주의하자. 빌드 스크립트가 프로젝트의 최상위 폴더에서 실행되는 것을 가정하고 있기때문에, 여기서는 이런 특성은 바람직하지 않다.

그림 3: OpenSSL 소스 폴더에 직접 프로젝트를 생성
다음 과정은 빌드 과정을 수행할 타켓을 추가하는 것이다. 프로젝트의 "Targets" 그룹에서 마우스 오른쪽을 클릭하고 Add > New Target을 선택한다. 그림 4와 같다.
그림 5처럼 타켓 타입으로 "Aggregate"를 선택한다.
그림 6처럼 타켓 이름을 "Build PPC" 로 한다.

그림 6: 새로운 타켓의 이름을 설정
다음으로 Build PPC 타겟에 빌드 단계(phase)를 추가한다. 이 단계는 빌드 환경설정을 위해 스크립트를 실행하고, PowerPC 라이브러리를 생성할 것이다. "Build PPC" 에서 마우스 오른쪽 버튼을 클릭하고 Add > New Build Phase > New Run Script Build Phase를 선택한다.

그림 7: 타켓에 Run Script Build Phase를 추가
Targets > Build PPC > Run Script에서 더블클릭을 하면, 그림 8과 같이 스크립트를 입력할 수 있는 다이알로그가 화면에 나타난다 (아래의 목록 2와 목록 3에 스크립트를 코드가 나와있다).

그림 8: Build PPC의 Run Script 다이얼로그
프로젝트는 i386 라이브러리, 유니버설 라이브러리, 테스트 어플리케이션을 위한 몇개의 추가적인 타켓을 필요로 한다. 그림 9를 보면 각각의 타켓의 타입이 "Aggregate"로 되어있다. 집합적(aggregate) 타켓은 다른 타켓에 의존적이다. 이러한 의존 관계가 나열된 순서대로 빌드 순서가 결정된다. 우리의 OpenSSL 프로젝트에서는 빌드 과정을 독립되고, 규칙적인 과정으로 나누기 위해 집합적 타켓을 사용하기로 한다.
"Build Universal" 타켓은 "Build PPC"와 "Build i386" 타켓 모두에 대한 의존성을 포함하고 있다. "Build Universal"을 더블클릭하면, 타켓 정보 다이얼로그가 표시된다. 아래에 있는 "+" 아이콘을 클릭하여 의존성을 추가한다. 타켓을 드래그 하여 추가할 수도 있다. 그림 10을 보자.

그림 10: Build Universal 타겟의 의존관계
[편집] 빌드 스크립트 추가하기
목록 2와 목록3은 PowerPC와 i386 라이브러리를 빌드하는 스크립트를 보여준다. 이 스크립트들은 이 문서에서 다운로드를 제공하는 프로젝트에 포함되어 있다. 각각의 스크립트는 기대되는 아키텍처에 맞는 빌드 환경을 설정하고, 라이브러리를 빌드하고, 라이브러리를 아키텍처에 맞는 빌드 폴더에 이동해준다.
목록 2: Build PPC 스크립트
# shell script goes here BUILD_ARCH=build/ppc ./config make build_libs mkdir -p $BUILD_ARCH mv *.a $BUILD_ARCH echo "Done" exit 0
목록 3: Build i386 스크립트
# shell script goes here ARCH_DIR=build/i386 make clean ./Configure 386 darwin-i386-cc make build_libs "CC=cc -arch i386" mkdir -p $ARCH_DIR ls *.a > libnames.tmp mv *.a $ARCH_DIR exit 0
위의 두 스크립트 사이엔 약간의 차이점이 있다. 예를들면 Build PPC는 빌드 과정에서 첫번째 타켓이기 때문에(정리할 빌드 결과물이 없다) make clean 을 수행하지 않는다. 그러나 어떤 이유로 타켓을 여러번 실행해야 한다면, make clean을 Build PPC 스크립트에 넣는 것이 편리할 수도 있다.
또한 Build i386 스크립트는 생성된 파일들의 이름을 libnames.tmp 파일에 쓴다. 이 파일은 유니버설 바이너리를 만들기 위해 Run lipo 스크립트를 실행할때 사용된다.
[편집] lipo를 사용한 유니버설 바이너리의 생성
lipo 툴은 유니버설 바이너리를 다루기 위해 사용한다. lipo를 사용하여 crypto와 ssl 각각의 라이브러리의 PowerPC와 Intel용 라이브러리를 합쳐서 각각의 유니버설 바이너리를 얻게될 것이다. 목록 4에의 Run lipo 스크립트는 반복하면서 build 폴더 하위의 각각의 폴더들(build/ppc와 build/i386)에서 각각의 라이브러리 이름을 읽어온다.
Listing 4: Run lipo 스크립트
# shell script goes here for lib in `cat libnames.tmp`; do lipo -create build/*/$lib -output $lib done exit 0
스크립트를 수행한후에 라이브러리에 관한 내용을 확인할 수 있다. file 명령어는 그 파일의 아키텍처 정보를 출력해준다. lipo -info 도 같은 역할을 수행한다. 목록 5는 이 명령어들을 실행한 결과를 보여준다.
목록 5: file과 lipo 명령어를 통해 얻은 정보
Mertz:/Volumes/Tiger/Users/asd/openssl-0.9.8a asd$ file * libcrypto.a: Mach-O fat file with 2 architectures libcrypto.a (for architecture ppc): current ar archive libcrypto.a (for architecture i386): current ar archive random library libssl.a: Mach-O fat file with 2 architectures libssl.a (for architecture ppc): current ar archive libssl.a (for architecture i386): current ar archive random library Mertz:/Volumes/Tiger/Users/asd/openssl-0.9.8a asd$ lipo -info * Architectures in the fat file: libcrypto.a a
이제 라이브러리가 작동하는지를 어떻게 확인할 것인가? 이 질문에 대답하기 위해서 몇가지 테스트 어플리케이션을 빌드해보자.
[편집] 라이브러리 테스트
OpenSSL은 많은 테스트 파일을 포함하고 있다. 이것들은 대개 라이브러리의 특정한 부분을 실험해보는 하나의 main 함수로 이루어진 것들이다. 목록 5는 테스트 어플리케이션을 빌드하기 위한 스크립트이다. 첫번째로 나오는 ranlib 명렁어는 libcrypto와 libssl 라이브러리의 목록에 있는 심볼들을 갱신한다. 이 작업은 정적 라이브러리를 다른 아키텍처의 머신에 복사할때나 심지어 같은 아키텍처의 머신에서 다른 폴더에 복사할때 필요하다. 이러한 시나리오에서 어플리케이션을 링크하기 전에 라이브러리의 심볼 테이블을 재빌드 해야한다. 그렇지않으면 라이브러리가 갱신되지 않았다는 링커 에러가 발생한다. ranlib의 맨 페이지에서 자세한 정보를 확인할 수 있다.
목록 5: Build Tests 스크립트
ranlib *.a ./config make build_tests
목록 6은 castTest를 실행항 결과를 보여준다.
목록 6: Cast Test 어플리케이션 실행
Mertz:/Volumes/Tiger/Users/asd/OpenSSL/test/castTest; exit In main() checkpoint 0 In main() checkpoint 0.5 In main() checkpoint 1 In main() checkpoint 2 In main() checkpoint 4 In main() checkpoint 0.5 In main() checkpoint 1 In main() checkpoint 2 In main() checkpoint 4 In main() checkpoint 0.5 In main() checkpoint 1 In main() checkpoint 2 In main() checkpoint 4 ecb cast5 ok In main() checkpoint 2 This test will take some time....123456789ABCDEF ok
이 테스트 어플리케이션은 라이브러리와 친숙해지고 사용법을 익혀, OpenSSL을 여러분의 어플리케이션에서 사용하는데 도움을 준다.
/test/Makefile의 LIBCRYPTO와 LIBSSL을 목록 7에 보이는 것처럼 고쳐야 할 수도 있다. 그렇게 하지 않으면 테스트 어플리케이션을 빌드하는동안 정의되지 않은 심볼에 대한 링커 에러가 발생할 수도 있다. 만약 전체 프로젝트를 하나의 머신에서 다른 머신으로 복사하게되면, 오직 이 과정만 한번 실행해주면 된다. 그렇지 않으면 양쪽의 머신에서 이 변경을 적용하였는지 확인해야 한다.
목록 7: test/Makefile에서 라이브러리 참조 변경
# Change these lines: LIBCRYPTO= -L.. -lcrypto LIBSSL= -L.. -lssl # to LIBCRYPTO= ../libcrypto.a LIBSSL= ../liblssl.a
[편집] Intel 환경에서 테스트
Intel기반의 맥을 갖고 있다면, 다음에서 논의될 내용을 위해 빌드된 라이브러리를 포함한 전체 프로젝트를 복사할 수 있다. 그렇지 않다면 테스트를 위해 친구나 학교에 여러분의 테스트를 위해 도와달라고 설득한다거나 하는 등의 창조적인 방법을 생각해 보라. 이것은 분명 오픈소스 커뮤니티의 정신에 부합된 것이다!
그림 11은 테스트 플랫폼으로 쓰일 인텔기반 맥의 "이 매킨토시에 대하여" 화면이다.
인텔기반 맥에서 똑같은 테스트 어플리케이션을 빌드하고 실행해볼 것이다. 목록 8을 보면 실행결과가 PowerPC에서와 같다는 것을 확인할 수 있다. 대단하지 않은가!
Listing 8: Intel에서 실행한 Cast Test
Twenty-Something:~ asd$ /Users/asd/OpenSSL/test/castTest; exit In main() checkpoint 0 In main() checkpoint 0.5 In main() checkpoint 1 In main() checkpoint 2 In main() checkpoint 4 In CAST_decrypt() In main() checkpoint 0.5 In main() checkpoint 1 In main() checkpoint 2 In main() checkpoint 4 In CAST_decrypt() In main() checkpoint 0.5 In main() checkpoint 1 In main() checkpoint 2 In main() checkpoint 4 In CAST_decrypt() ecb cast5 ok In main() checkpoint 2 This test will take some time....123456789ABCDEF ok
[편집] 참고 자료
이 문서에 다루는 내용을 통해, 다른 오픈소스 프로젝트를 유니버설 바이너리 아키텍처로 이주(migrate)할 수 있다. 아래의 자료들은 더 정확한 정보를 찾는데 도움이 될 것이다.
The ADC Developer Transition Resource Center should be your first stop for information on creating Universal Binaries. Here you will find a number of resources such as:
- ADC Developer Transition Resource Center 는 유니버설 바이너리를 만드는 정보를 얻기위해 여러분이 처음으로 들려야 할 곳이다. 여기서 다음과 같은 다양한 자료를 얻을 수 있다.
- 참조할 문서에 추가하여, WWDC 2005 컨퍼런스 세션 003 "Extending Your Application to Run on an Intel-based Macintosh (인텔기반 매킨토시에서 실행가능하게 어플리케이션을 확장하기)" 을 보기 바란다. 온라인 ADC 계정으로 로그인하여 WWDC 세션이라고 써있는 섹션으로 이동하여 세션 동영상을 보거나 슬라이드를 다운로드 할 수 있다.
- 이 문서를 위해 작성된 Xcode 프로젝트를 다운로드 할 수 있다. 이 프로젝트는 Xcode 2.2.1을 필요로 한다.
- OpenSSL 프로젝트 사이트.
- DarwinPorts 문서 페이지.
원문 : http://developer.apple.com/opensource/buildingopensourceuniversal.html
번역 : sunil










