[OS]/Embedded

[펌] 크로스 컴파일러 툴 체인

하늘을닮은호수M 2005. 6. 16. 13:22
반응형

크로스 컴파일러 툴 체인


1. 크로스 컴파일러란?

대부분의 프로그래머들은 PC라는 동일한 환경에서 프로그램을 작성하실 겁니다.

PC에서 프로그램을 짜고 컴파일 하고, 실행 화일을 PC에서 수행 합니다.
이렇게 동일한 환경에서 동작 되는 컴파일러와 이 컴파일러에서 생성된 실행 화일을 동일한 환경에서 수행 한다면 이때의 컴파일러를 네이티브( native ) 컴파일러라고 합니다.
이와 반대로 컴파일러가 동작하는 시스템과 컴파일러에 의해서 생성된 실행 화일이 동작하는 시스템이 다를 때 이 컴파일러를 크로스(cross) 컴파일러라고 합니다.

여러분이 임베디드 시스템에 동작하는 프로그램을 작성한다면 당연히 크로스 컴파일러 환경을 구축해야 합니다. 개발 환경은 PC일것이고 실행 화일이 동작하는 시스템은 다른 CPU 구성을 갖는 임베디드 시스템일 것이기 때문입니다. 그렇다고 모든 임베디드 시스템에 동작하는 프로그램들이 크로스 컴파일 환경을 필요로 하는 것은 아닙니다. PC와 같은 구조를 갖는 임베디드 리눅스 시스템을 만든다면 PC의 네이티브 컴파일러에서 만들어진 실행 화일이 그대로 수행될 수 있기 때문입니다.
하지만 임베디드 시스템 대부분이 저렴한 가격대를 요구하거나, 또는 특수한 기능을 수행하는 구조를 가지기 때문에 이런 경우는 조금 드믄 편입니다. 그래도 개발 프로세스를 빠르게 진행하기 위해서 익숙한 PC 구조를 사용하는 경우도 요즘은 많아 지는 추세인 것 같습니다.

어찌되었든 크로스 컴파일 환경에서의 개발은 윈도우 개발자 입장에서 보면 매우 열악한 개발 환경이 됩니다. 돈이 많은 회사야 좋은 개발 툴을 사서 이런 열악한 환경을 일부 개선하기는 하지만 그래도 열악하기는 마찬가지 입니다. 가장 큰 이유는 컴파일이 끝난 후 실행 화일을 즉시 시험하지 못하기 때문입니다. 그 외에도 개발하기 위해서 손가락이 무척 바빠지는 것도 한 요인입니다. 단순하게 마우스 클릭 한번으로 수행되는 GUI 컴파일러에 익순한 분들이 타자를 치는 것은 무척 힘든 것입니다.
그래도 리눅스에서 크로스 컴파일러를 사용하는 것에는 이유가 있읍니다.


2. 리눅스와 gcc

지금은 많은 분들이 임베디드 시스템 개발에 리눅스를 사용되고 있다는 것을 알고 있습니다.
하지만 그 이유가 리눅스 커널을 임베디드 시스템에 탑제하기 때문이라고 알고 계신다면 잘못 알고 계신 겁니다. 임베디드 시스템 개발 환경으로 리눅스를 사용하는 근본적인 이유는 gcc라는 막강한 컴파일러가 있기 때문입니다.

리눅스만 사용하시는 분이라면 리눅스 프로그램 개발을 위해서 당연히 gcc라는 컴파일러를 사용합니다. 그래서 gcc라는 것이 그냥 리눅스용 컴파일러라고 알고 있습니다. 하지만 gcc는 그렇게 단순한 컴파일러가 아닙니다. 또한 gcc는 그냥 i386 프로세서에서 동작하는 실행 화일을 만들어 내는 컴파일러도 아닙니다. 현재 존재 하는 컴파일러 중에서 가장 많은 프로세서를 지원하는 컴파일러가 바로 gcc입니다.

gcc 컴파일러의 패케지는 이미 전세계에 동작되는 대부분의 프로세서를 지원하기 위한 준비를 갖추고 있습니다. 더구나 공짜입니다. !!!
하지만 여러분은 이런 gcc가 어떻게 다른 CPU를 지원하게 할 수 있는지에 대해서는 모를 겁니다. 그냥 gcc 명령을 치면 i386 코드가 생성되기 때문입니다.


3. 크로스 컴파일러와 gcc 소스 패키지

gcc에서 i386 이외의 실행 화일을 만들기 위해서는 리눅스에 이미 설치된 gcc란 컴파일러는 소용이 없습니다. 몇 가지 옵션만 바꾸어서 gcc 수행한다고 i386 이외의 프로세서를 지원하는 코드가 생성되는 것은 아닙니다. 애초에 다른 프로세서에서 동작 될 수 있는 실행 파일을 만들 수 있겠끔 gcc를 만들어야 하는 것입니다. 그렇다고 기존에 i386에서 동작하는 gcc를 아예 다른 프로세서에서 동작하는 실행 파일을 만드는 gcc로 바꾸어 버리면 문제가 됩니다. 그 뒤로는 i386에 동작하는 어떤 프로그램도 만들 수 없기 때문입니다.
그래서 보통은 gcc의 이름을 조금 바꿉니다. 예를 들어 arm 계열의 프로세서에서 동작하는 실행 프로그램을 만들기 위해서 사용하는 gcc는 arm-linux-gcc라는 이름을 가집니다.
이름이 다른 이 두 컴파일러는 전혀 다른 컴파일러가 아닌 똑같은 gcc인 것입니다. 단지 gcc는 i386 프로세서에서 수행되는 코드를 만들어 내는 컴파일러이고 arm-linux-gcc라는 것은 arm 프로세서에서 동작되는 코드를 만들어 내는 컴파일러 일 뿐입니다.

관행적으로 네이티브용 컴파일러가 보통 gcc가 되고 크로스 컴파일러는 gcc 앞에 접두사를 붙입니다. 만약 알파 프로세서 동작하는 gcc에서 i386 계열의 실행 코드를 만드는 크로스 컴파일러는 i386-linux-gcc가 될 것입니다. (확인하지 않았습니다. ^^ )
어찌되었든 둘 다 동일하게 gcc란 패키지에서 파생한 컴파일러인 것입니다.

자.... 제가 자꾸 gcc 패키지라는 말을 쓰고 있습니다. 이 gcc 패키지라는 것이 무엇일까요? 윈도우에서 델파이라는 개발 툴을 구매해서 설치하면 단순하게 델파이 컴파일러만 설치되는 것이 아닙니다. 개발하기 위한 이것저것들이 설치 됩니다. 이와 동일한 개념으로 gcc 패키지란 컴파일을 하기 위한 이런 저런 것을 모두 담은 것을 말 하는 것입니다.
윈도우에서와 달리 리눅스에서는 패키지들이 소스로 구성되어 있습니다. 그래서 이런 것을 gcc를 예를 들면 gcc 소스 패키지 라고 말합니다.

또 여러분이 착각하는 것중 하나가 gcc가 단순하게 c 컴파일러라고 알고 있는데 정확하게 이야기 하면 c 컴파일러가 아닙니다. c++ 소스를 컴파일 할 때 도 역시 gcc 를 사용합니다. 어셈블러를 컴파일 할 때 도 gcc를 사용할 수 있습니다. 그래서 gcc 소스 패키지에는 c 이외의 몇 가지 컴파일러들이 더 들어 있습니다.
어찌되었든 gcc 소스 패키지란 gcc 컴파일러를 만들 수 있는 소스로 구성된 것을 말 합니다. 이 gcc 소스 패키지를 이용하여 원하는 프로세스 지원 크로스(또는 네이티브) 컴파일러를 만드는 것입니다.

그런데 아주 모순 된 것 중 하나는 gcc를 만들기 위해서는 gcc가 필요하다는 점입니다. 왜냐하면 gcc 소스 패키지이기 때문입니다. 하지만 이점은 여기에서 문제 삼지 않으려 합니다. 여러분의 리눅스에는 당연히 gcc 컴파일러가 이미 설치되어 있기 때문입니다.


4. gcc의 짝꿍들

gcc 는 컴파일러입니다. 당연히 소스를 컴파일 할 수 있습니다. 그런데 gcc만 가지고 있어서는 아무런 일도 못합니다.
왜냐구요? 그 이유를 알고 싶으시다면 kelp/임베디드강좌/이규명에 holelee 님이 쓰신 gcc 이야기 시리즈를 읽어 보시기 바랍니다.
그래서 gcc 이외에 필요한 프로그램과 데이터(?)들이 있습니다. 이런 것을 모두 모은 것을 크로스 컴파일러 툴 체인이라고 합니다. 컴파일러 툴이라면 될 텐데 굳이 체인이라고 붙인 이유는 제 개인적인 생각으로는 각 패키지간에 서로 의존적이기 때문일 것으로 추측합니다.

이 툴 체인의 목록은 다음과 같습니다.
binutils - 어셈블러, 링커 그리고 라이브러리 관련 실행 화일들 모음
kernel - 리눅스 커널 ( 헤더 파일 때문에 필요함 )
gcc - 컴파일러
glibc - 라이브러리 및 헤더화일
추가적으로
gdb - 디버거 ( 이놈은 그냥 옵션으로 생각하시면 됩니다. ^^ )
가 있읍니다.

4.1 gcc의 3.0 대의 속설(?)

많은 분들은 gcc의 3.0 대에 문제가 있다고 알고 있어서 이 버전을 회피하시면서 예전 버전을 고집하시는 경향이 있습니다. 그런데 이 부분은 오해랍니다. 문제가 되는 버전은 gcc 3.0 입니다. 당연히 문제가 발생했으니 해당 버전을 고쳤겠지요 그래서 3.1 대 이후라면 별 문제는 없습니다.
크로스 컴파일을 하시는 분이라면 최근 프로세스를 쓰기 위해서는 예전 버전으로는 한계가 있습니다. 최신 버전을 쓰셔야 지원되는 프로세스가 있습니다. 넘 겁먹지 마시고 3.0대를 쓰시기 바랍니다.

4.2 binutils

바이너리 유틸 이라고 합니다. 포함되는 내용은 다음과 같죠...

addr2line – 실행 파일의 어드레스에 대한 소스 화일명과 라인 넘버를 표현해주는 프로그램입니다.
ar - 라이브러리를 관리하는 프로그램입니다.
as - 어셈블러입니다.
c++filt - 잘 모르겠습니다. ^^
gasp - 어셈블러 매크로 해석기입니다.
ld - 링커입니다.
nm - 오브젝트안의 심볼릭을 표시해 주는 프로그램입니다.
objcopy - 오브젝트 화일을 컨버팅 해주는 프로그램입니다.
objdump - 오브젝트 화일의 정보를 표시해 줍니다.
ranlib - 라이브러리의 인덱스 화일을 생성합니다.
readelf - elf 포맷의 화일 헤더 정보를 해석해 줍니다.
size - 오브젝트 화일의 섹션 크기와 포함된 오브젝트의 총 크기를 표시해 줍니다.
strings - 프로그램 내부에 사용되는 초기화 문자열들을 골라 표시해 줍니다.
strip - 오브젝트나 실행화일의 정보를 선택적으로 제거해 줍니다.

4.3 kernel

크로스 컴파일러를 만들 때 사용되는 데이터 타입이나 시스템 콜을 참조하기 위해서 필요한 헤더 파일을 참조하기 때문에 툴 체인에 들어 갑니다. 엄밀히 말하면 kernel의 헤더 파일만 필요합니다.

4.4 gcc

패키지가 일반적으로 지원하는 것은 각 언어별로 지원합니다. 다음은 크로스 컴파일러로 쓰는 대표적인 것 들입니다.
gcc, cpp, g++, c++, gccbug, gcov
설명을 굳이 달지 않는 이유는 저는 gcc 이외에는 거의 쓰지 않기 때문에 뭐 하는 놈들인지 잘 몰라서 입니다. 이해해 주세요...

4.5 glibc

커널을 컴파일 하거나 부트 로더를 컴파일 할 때는 필요 없습니다. 하지만 응용프로그램을 사용한다면 당연히 이것이 있어야 합니다. 여러분들 중에서 glibc와 newlib 를 혼동하시는 분들이 있습니다.
glibc 는 GNU 라이브러리 입니다. 크기가 매우 커집니다.
newlib는 glibc가 매우 크기 때문에 꼭 필요한 놈들만 골라서 추려놓은 것이죠 그래서 크기가 매우 작습니다.
특별한 경우가 아니라면 저는 newlib를 별로 추천하지 않습니다. 가끔 리눅스용 프로그램을 임베디드 제품에 포팅 하다보면 없는 함수가 있어서 곤란을 겪기 때문입니다.
램이나 플래쉬 시스템이 16M 이상이고 여유가 있다면 가급적 glibc를 쓰시기를 권유합니다.

4.6 gdb

이놈은 디버거죠.. 즉 프로그램을 디버깅 할때 유용한 도구 입니다. 하지만 윈도우 디버거를 사용하시던 분이라면 매우 불편함을 느끼실 겁니다. 하지만 없는 것 보다는 있는 것이 좋습니다. printf 만 가지고 디버깅 하시면 매우 힘들기 때문입니다. 더구나 익숙해지면 의외로 막강한 기능에 놀라시게 됩니다. 이 놈을 굳이 툴 체인에 포함시키지 않는 것은 상호 연관관계가 별로 없어서 입니다.

반응형