 |
|
크로스 컴파일
크로스 컴파일이란 무엇일까?
크로스 컴파일에서는 다른 머신에서 동작하는 코드를 개발하기 위해 시스템에서 어떤 다른 컴파일러를 사용한다. 크로스 컴파일은 평범한 유닉스 사용자들에겐 상대적인 드문 경우다. 기본적으로 평범한 시스템에서는 시스템에서 설치된 컴파일러를 기본적으로 사용하기 때문이다. 그렇지만 크로스 컴파일은 임베디드 시스템을 타킷으로 할 때는 꽤 일반적이다(상대적으로). 심지어 호스트와 타킷이 같은 아키텍처일 때라도 컴파일러 간에는 분리가 필수적이다. 라이브러리도 다른 버전일 수도 있고, 다른 컴파일러 옵션으로 만들어진 라이브러리일 수도 있기 때문에 호스트 컴파일러를 써서 컴파일된 것들이 구동에 실패할 수도 있거나 타깃 시스템에서 예측과는 다르게 동작할 수도 있다.
크로스 컴파일 도구 얻기
이론적으로 크로스 컴파일러를 스스로 빌드하는 것도 가능하지만 상당히 비현실적이다. 필요한 일련의 부트스트랩 단계들은 어려울 수 있으며 엄청난 시간이 드는 작업이다. 그리고 상당히 최소화한 컴파일러를 만드는 작업이 종종 요구되는데 이는 부분적으로는 라이브러리를 설정하고 빌드하는 데 사용되고, 그러고 나서 또 컴파일러를 재빌드하는 데 사용되는 것들을 또 재빌드하고... 이런 식이다. 다양한 아키텍처의 조합이 가능한 수많은 상용 크로스 컴파일러 소스를 이용할 수 있을 뿐 아니라 자유롭게 쓸 수 있는 크로스 컴파일러 툴킷도 몇 가지 나와 있다.
crosstool-ng에 대한 소개
Dan Kegel의 crosstool(자세한 내용은 참고자료 참조)에는 여러 시스템의 툴체인을 자동으로 빌드할 수 있도록 하는 다양한 전문 기술과 몇 가지 특수화된 패치를 모아두었다. crosstool은 그간 업데이트가 되지 않고 있다가 이 작업 동안 crosstool-ng 프로젝트가 새롭게 이뤄지고 있다. 이 튜토리얼에서는 2008년 5월에 출시된 crosstool-ng 버전 1.1.0을 사용했다. 배포 사이트(참고자료 참조)에서 다운로드하기 바란다.
crosstool-ng 설치
crosstool-ng는 configure 스크립트를 갖고 있다. 설정하려면 --prefix에 위치를 명시하고 스크립트를 실행하면 끝난다. 예를 들면 이렇다.
$ ./configure --prefix=$HOME/7800/ctng
설정이 끝나면 make를 사용해 빌드하고 make install한다. 빌드 과정에서 crosstool-ng 빌드 스크립트에 명기된 디렉터리 하에 7800 작업 디렉터리 내에 ctng 디렉터리를 생성한다. 경로에 ctng/bin 하위 디렉터리를 추가한다.
$ PATH=$PATH:$HOME/7800/ctng/bin
crosstool-ng 설정
crosstool-ng는 리눅스 커널이 사용하는 것과 비슷하게 .config 파일을 사용한다. crosstool-ng를 사용하기 위해 타깃과 일치하는 설정 파일을 생성할 필요가 있다. crosstool-ng 빌드를 위해 작업 디렉터리를 만들자.
$ mkdir toolchain-build
$ cd toolchain-build
이제 기본 설정을 복사한다. 하나씩 crosstool-ng를 설정하는 것도 가능하지만 여기서는 우연히도 예제 설정 파일 하나가 타깃에 딱 들어맞았다고 하자.
$ cp ../ctng/lib/ct-ng-1.1.0/samples/arm-unknown-linux-uclibc/* .
마지막으로 crosstool.config 파일의 이름을 바꾼다.
$ mv crosstool.config .config
이 작업은 TS-7800에서 사용되는 모델인 armv5te 프로세서를 타깃으로 하는 설정 파일을 복사하는 작업이다. uClibc로 빌드하는데 uClibc는 임베디드 시스템에 맞춰진 libc의 변종이다. 그런데 설정 파일이 수정해줘야 할 게 하나 있다.
설정 경로 수정
crosstool-ng 빌드에 대한 기본 타깃 디렉터리는 $HOME/x-tools/$TARGET이다. 예를 들어 이 빌드에서라면 x-tools/arm-unknown-linux-uclibc가 된다는 뜻이다. 타깃이 많다면 유용하긴 하지만 딱 하나 뿐이라면 그렇게 유용하지는 않다. .config를 열어 CT_PREFIX_DIR을 ${HOME}/7800/toolchain으로 수정하자.
툴체인 빌드
툴체인을 빌드하기 위해 build 인수를 주고 ct-ng 스크립트를 구동한다. 성능을 개선하려면, 특히 다중 코어 시스템이라면 build.#처럼 작업 개수를 명시하고 싶을 수도 있다. 예를 들어 다음 명령은 네 개의 작업으로 빌드한다.
$ ct-ng build.4
호스트 시스템의 사정에 따라 빌드 작업은 꽤 오래 걸릴지도 모른다. 완료되면 툴체인은 $HOME/7800/toolchain에 설치된다. 디렉터리와 디렉터리에 들어가 있는 파일들은 읽기 전용으로 되어 있을 것이다. 지우거나 옮기고 싶다면 chmod u+w를 쓰기 바란다. ct-ng 스크립트에는 이외에도 help 같은 다른 인수를 줄 수 있다. ct-ng는 표준 make 유틸리티용 스크립트이며, 결과적으로 --help를 주면 나오는 출력은 그저 표준 make의 도움말이다. crosstool-ng의 도움말을 보려면 ct-ng help를 사용하기 바란다.
전에 이런 트릭을 본 적이 없다면 간단 명료하게 설명하겠다. 현대 유닉스 시스템은 실행 파일을 해석할 때 첫 번째 줄이 #!로 시작하면 스크립트라고 인식한다. 구체적으로 말해 줄의 나머지에 이름 붙은 프로그램의 스크립트라고 본다. 예를 들어 많은 셸 스크립트들은 #!/bin/sh로 시작한다. 파일의 이름은 프로그램에 전달된다. 동작할 스크립트의 첫 번째 인수로 취급되기에 이 정도면 충분하다. 반면 make는 자동으로 뭘 할 수가 없기 때문에 여러분이 내용을 -f 플래그를 사용해 파일로 건네줘 동작할 수 있게끔 해줘야 한다. ct-ng의 첫 번째 줄을 보면 #!/usr/bin/make -rf다. -r 플래그는 make의 내장된 기본 규칙을 수행하지 않으며, -r 플래그는 make에게 이후에 나올 이름이 Makefile이라고 붙은 파일이 아닌 대신 사용할 파일 이름임을 알려준다. 결과적으로 셸 문법 대신에 make 문법을 사용하는 실행 스크립트다.
툴체인 사용
처음 시작하는 사람들이라면 컴파일러를 담고 있는 디렉터리에 경로를 추가하자.
$ PATH=~/7800/toolchain/bin:$PATH
경로에 넣었다면 이제 프로그램을 컴파일할 수 있다.
$ arm-unknown-linux-uclibc-gcc -o hello hello.c
$ file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for
GNU/Linux 2.4.17, dynamically linked (uses shared libs), not stripped
라이브러리는 어디에 있을까?
바이너리를 링크하기 위해 툴체인에 의해 사용되는 라이브러리는 toolchain 디렉터리 밑의 arm-unknown-linux-uclibc/sys-root에 저장되어 있다. 이 디렉터리는 궁극적으로 루트 파일 시스템의 토대를 형성하고 있으며 커널이 만들어지고 나면 파일 시스템에 대한 내용을 다룰 때 다룰 주제다.
커널 구성
벤더가 제공하는 커널 배포 트리는 이미 크로스 컴파일용으로 설정되어 있다. 아주 간단한 경우(이번 경우), 리눅스 커널 크로스 컴파일을 위해 여러분이 해야 할 거라곤 최상위 레벨 Makefile에서 CROSS_COMPILE 변수를 설정하는 것뿐이다. 이 접두어는 빌드 동안 사용되는 다양한 프로그램(gcc, as, ld)의 이름에 적용된다. 예를 들어 CROSS_COMPILE을 arm-으로 설정하면 컴파일 시 경로에서 arm-gcc라는 프로그램을 찾으려고 시도할 것이다. 그렇다면 우리의 경우라면 arm-unknown-linux-uclibc이다. 경로 설정에 의존하고 싶지 않다면 다음 예처럼 전체 경로를 명시할 수도 있다.
CROSS_COMPILE ?= $(HOME)/7800/toolchain/bin/arm-unknown-linux-uclibc-
|