서두

Swift Apple 사에서 개발 된 완전히 새로운 프로그래밍 언어이다. WWDC 2014에서 번개처럼 나타난 이 프로그래밍 언어는 순식간에 전세계 모바일 앱 개발자의 주목을 끌었다.

 

Swift는 충격적인 등장 이었기 때문에 갑자기 나타난 기술인 것처럼 볼 수도 있지만, 개발이 시작된 것은 2010 년이었다고 한다. 또한 Swift가 태어난 것은 Apple이 갑자기 새로운 영역에 내 디딘 것이 아니라 오랜 컴파일러 관련 기술 개발에 크게 노력해온 결과이라고 필자는 생각하고 있다.

 

본 문서는 Apple의 컴파일러 관련 기술을 돌아보며 Swift에 어떻게 연결되는지를 설명한다.

 

 

Objective-C와 컴파일러

Apple Steve Jobs의 복귀 이후 BSD 기반의 OS X​​ Intel 아키텍처로의 전환 등 매우 대담한 기술적인 전환을 많이 하였고 성공시켜 왔다. 개발자들은 Apple의 방향성에 추종하면 마냥 좋았다. 그러나 새로운 프로그래밍 언어를 만드는 등의 전환은 Swift가 처음이다. Apple은 왜 새로운 프로그래밍 언어를 만들었을까? Swift에 이르는 길은 Apple의 컴파일러 기술을 돌아보는 것으로 끈을 풀 수 있다.

 

 

Objective-C 2.0에서 Modern Objective-C

Apple WWDC 2006에서 기존의 Objective-C에 큰 변화가 추가 된 Objective-C 2.0을 발표했다. 이 업데이트는 모던 Objective-C 프로그래밍을 지원하는 속성과 클래스 확장, fast enumeration 등이 추가 되었다. 이 때 추가 된 기능은 모두 현재의 Objective-C의 인기에 필수적인 요소이지만, 현재 남아 있지 않는 것이 한가지 있다. 바로 가비지 컬렉션이다.

 

Objective-C는 메모리 관리에 참조 카운트 방식을 채용하고 있다. 특히 iOS 4 이전 정도부터 iOS 앱 개발을 시작한 분들 중에는 경험을 한 사람은 많을 것이다. 그러나 2006 년 시점에서 Objective-C 가비지 컬렉션이 있었는데, iOS 앱 개발에 메모리 관리가 고통인지 의문에 드지않나? 가비지 컬렉션은 OS X 만 지원으로 iOS에서 지원 될 수 없었다. 따라서 iOS 앱 개발에서 메모리 관리는 프로그래머의 책임으로 오랫동안 골치 아픈 문제 중 하나였다.

 

그런 불우한 환경에도 한줄기 광명이 있다. ARC(Automatic Reference Counting) Static Analyzer의 등장이다. ARC는 컴파일 시에 참조 횟수를 증감하는 코드를 자동으로 채운다. Static Analyzer를 사용하면 정적으로 잠재적 인 메모리 누수를 자동으로 감지 할 수 있다. 이러한 기능의 등장은 Apple이 개발한 새로운 C/C++ / Objective-C 컴파일러 인 Clang이 크게 관여하고 있다.

 

기존 Objective-C 컴파일러는 GCC를 이용하고 있었지만, 확장이 어렵기 때문에 Apple Clang을 개발했다. Clang을 내포한 Xcode 4.2의 출시로 프로그래머의 부담은 크게 경감된다. 종래는 프로그래머가 세심하게 메모리 관리를 구현하고 있던 것이 자동으로 관리되도록 대체되어, 메모리 누수 유무 검사는 Leaks (메모리 누수 탐지기) 등을 실행하는 응용 프로그램에 연결하여 실제로 동작하면서 측정함으로써 메모리 누수를 감지하고 있던 것이 자동으로 검사 할 수 있게 되었다. 예를 들면 ARC는 구현에 따라서는 메모리 누수 또는 Static Analyzer에서 찾을 수 없는 메모리 누수가 존재하기 때문에 완벽한 것은 아니지만, 프로그래머의 부담이 크게 줄어든 것은 부인할 수 없는 사실이다.

 

Clang 도입이 가져온 것은 메모리 관리의 부담 경감에 국한되지 않는다. C/C++에 대한 Apple의 독자 확장인 Blocks(클로져와 비슷한 것)이나 Objective-C Modern syntax Apple은 최근 몇 년 WWDC에서 매번 이라고 해도 좋을 정도로 Objective-C에 여러 업데이트를 추가했다. 이 정도까지 Objective-C 자체를 업데이트 할 수 있었던 이유는 스스로 컴파일러를 개발하고 있었기 때문이다. Objective-C 2.0 에서 Modern Objective-C으로의 크게 진화할 수 있었던 주인공이 Clang 인 것은 분명한 사실이다.

 

 

Clang에서 Apple이 목표로 한 것

Clang을 말할 때 뗄래야 뗄 수 없는 관계에 있는 것이 백엔드인 LLVM이다. LLVM은 컴파일과 링크 시 런타임 등 모든 지점에서 프로그램을 최적화 할 수 있는 컴파일러 기반이다. 현재 최신 버전 인 Xcode 6.3.2 컴파일러 프론트엔드에 Clang, 백엔드에 LLVM 조합이 사용되고 있지만, LLVM이 채택 된 당초는 프론트엔드는 GCC가 사용 되고 있었다.

 

Objective-C는 매우 동적인 것이 특징인 언어 중 하나이다. 예를 들어, 실행 시에는 모든 객체는 id 형으로 되기 때문에 실행 시 클래스를 확장하거나 구현을 대체 하는 등 인터프리터 언어처럼 행동 할 수 있다. 물론 메소드의 실행에 관해서도 마찬가지이다. NSObject performSelector: 메서드 등에서는 현저하게 그 특징을 간파 할 수 있다. 이렇게 Objective-C는 동적 기능에 의해 매우 유연하게 프로그램을 작성할 수 있다.

 

하지만 동적 특징은 좋은 것만 있지 않다. 일반적으로 컴파일러 언어는 런타임 비용을 낮추기 위하여 실행 코드를 최적화한다. 그러나 Objective-C에서는 런타임에 많은 것이 정해지기 때문에 컴파일 시 최적화를 실시하기 어렵다는 단점이 있었다. iPhone으로 기세를 되찾았던 Apple에 있어서, 모바일에서의 경험 향상은 가장 큰 과제 중 하나이다. 가능한 한 애플리케이션에 최적화를 하고, 경험을 향상시키고 싶은 싶은 것이 본심이다.

 

LLVM이 제공하는 유연한 최적화는 Objective-C에 있어 매우 편리한 것이었다. 그러나 처음에는 프런트엔드에 사용하던 GCC는 거대한 소프트웨어임으로 족쇄가 되어 Apple이 요구하는 속도로 Objective-C의 성능을 향상하는 것이 어려워졌다.

 

그래서 Apple C/C++ / Objective-C를위한 LLVM 프론트엔드인 Clang을 개발했다. Apple이 단기간에 Objective-C를 대폭 업데이트 할 수 있던 것은 Clang을 개발함으로써 스스로 주도권을 가질 수 있게 된 것이 가장 컸다.

 

Apple 스스로 컴파일러를 개발하는 것은 프로그램 고급 최적화를 하기 위해서도 Objective-C를 더 빨리 진화시키기 위해 필수적인 것이었다. 하드웨어의 기능을 향상시키는 것은 말할 것도 없지만, 그 위에서 동작하는 소프트웨어에 대해서도 기초 기술에서부터 갈고 닦아서 iPhone이 높은 사용자 경험을 지켜 왔다고도 말할 수 있다. LLVM Clang Apple의 제품을 뒷받침하는 중요한 역할을 담당하고 있던 것이었다.

 

 

LLVM Swift

LLVM Clang으로 커밋이 어떻게 Swift으로 이어질까? Apple LLVM Clang에 의해 만들어 낸 환경을 Swift에서도 다시 시도했던 것은 아니다. 사실 Swift Objective-C와 같이 LLVM에서 작동하는 것이다. 왜 이런 일이 가능할까? 비밀은 LLVM의 구조에 있다.

 

LLVM은 다음과 같이 소스 코드를 기계어로 변환 실행한다.

  소스 코드 -> 프런트엔드 -> LLVM Optimizer -> 백엔드 -> 기계어

 

간단하게 설명하면 Clang GCC 등의 프론트엔드가 소스 코드를 받아 최적화를 실시하고 백엔드에 보내어 결국 기계어로 변환되어 실행된다. 여기에서 프런트엔드와 LLVM Optimizer, LLVM Optimizer와 백엔드 간에 각각 LLVM IR(Intermediate Representation) 형식으로 전달된다. 지금까지 감이 좋은 사람은 알아차렸겠지만 프런트엔드만 다른 언어로 대응하면 다른 언어도 LLVM에서 움질 일 수 있도록 설계되어 있다. 사실 GCC에서 컴파일 한 Ada Fortran과 같은 언어를 LLVM에서 작동 할 수 있다(LLVM 프로젝트의 DragonEgg를 참조). , Swift LLVM의 새로운 프론트엔드로 구현되어 있다는 것이다.

 

공식적으로 자세하게 소개 되어있는 것은 아니지만, 컴파일러 옵션 등에서 다음과 같이 LLVM IR로 컴파일 되는 것을 알 수 있다.

  소스 코드 -> Swift AST -> SIL -> LLVM IR

 

소스 코드는 먼저 Swift Abstract Syntax Tree (AST)로 변환된다. 다음 Swift Intermediate Language(SIL)로 변환되어 Swift를 위한 최적화를 실시한 후 LLVM IR로 변환 된 LLVM Optimizer에 보내진다. 또한, 이러한 중간 상태는 Swift 컴파일러에서 직접 검색 할 수도 있다. 컴파일러의 도움말(xcrun swiftc -help )을 보면 출력 방법을 알 수 있기 때문에 흥미 있다면 꼭 시험해 봐라.

 

이렇게 Swift에서도 LLVM 기술은 깊이 관련되어 있다. Swift Objective-C와 공존 할 수 있고 C를 직접 사용 할 수 있지만, 이렇게 할 수 있는 것은 공통 기반으로 LLVM이 있기 때문에이다. 그 덕분에 Objective-C 프로그래머는 조금만 공부하면 Swift를 잘 다룰 수 있고, Swift으로의 전환을 매우 완만하게 할 수 있다. 이것이 바로 Apple의 기술 선택이 매우 잘 빠져 있다는 것을 나타내는 좋은 예라고 할 수 있다.

 

 

 

출처: http://codezine.jp/article/detail/8768

 

저작자 표시
신고
by 흥배 2015.07.20 08:00
| 1 |