3.2. 툴체인

3.2.1. 배경

툴체인이란 여러 다른 컴포넌트로 이루어져 있다. 가장 중요한 것은 gcc 컴파일러 자체다. 또 gcc를 사 하기 위해 필요한 binutils도 포함된다. binutils는 바이너리를 다루는데 사용된다. 이 둘로 C 라이브러리 를 사용하는 것을 제외한 나머지 대부분과 커널을 컴파일 할 수 있다. 보통은 컴파일러를 컴파일하는 경우 부트스트랩에 관계된 문제 때문에 툴체인을 만드는 것이 간단치 않다.

이 장에서는 툴체인을 어떻게 만드는지 알아본다. 툴체인 만들기로 시간을 낭비하기 싫거나 시도 하기 싫다면 이미 만들어진 것을 사용해도 좋다.

경험에 의하면 혼자 만드는 툴체인의 경우 조심하지 않으면 나중에 사용할 때 어떤 형태의 이상한 결과 를 만들어낼지 모르기 때문에 검증된 이미 만들어진 툴체인을 사용하는 것이 좋다고 감히 말할 수 있다. 또 만들어보면 알겠지만 상당한 노력과 주의를 기울여야하기 때문에 이미 만들어진 것을 사용하는게 좋을 것이다.

그러나 한번 쯤은 경험으로라도 컴파일러를 만들고 이 것으로 프로그램을 만들어 사용해보기 바란다.

ARM 프로세서에 관한 툴체인은 http://www.arm.linux. org.uk 혹은 http://www.armlinux.org에서 찾기 바란다.

3.2.2. 미리 만들어진 툴체인

Native Compile

ARM 상에서 도는 Native 컴파일러의 안정화 버전 바이너리는 아래 사이에서 얻을 수 있다.

arm.linux.org.uk 버전

공식 ARM 리눅스 사이트에서 배포하는 것이다.

Embedian - 필자는 데비안을 사용하지 않기 때문에 실제 이 툴이 어떤지는 잘 모른다.

Embedian 버전은 gcc 2.95.2, binutils 2.9.5.0.37과 glibc 2.1.3을 포함한다. 인스톨은 간단해 데비안 시스템을 사용하면 apt를 사용해 쉽게 설치할 수 있다. 그러나 /usr/bin에 설치되므로 이미 시스템에 깔린 것에 엎어 쓰지 않도록 주의를 요한다.

LART

LART 타르볼은 아래와 같은 것을 포함한다.

  1. gcc 2.95.2

  2. binutils 2.9.5.0.22

  3. glibc 2.1.2

설치는 아래와 같이 한다.

mkdir /data
mkdir /data/lart
cd /data/lart
bzip2 -dc somewhere/arm-linux-cross.tar.bz2 | tar xvf -

그리고 /data/lart/cross/bin을 path에 추가해준다. C와 C++ 컴파일러는 arm-linux-gcc와 arm-linux-g++와 같이 명령을 사용해 실행할 수 있다.

Compaq - Itsy인가 하는 프로젝트에 있는데 사용해 보진 않았다.

컴팩 크로스 툴체인은 다음과 같은 것을 포함한다.

  1. gcc 2.95.2

  2. binutils 2.9.5.0.22

  3. glibc 2.1.2 with international crypt library

이 툴체인은 호스트는 i386, 타겟은 armv4l이다.

설치는 아래와 같이 한다. 이 툴체인은 반드시 /skiff/local에 설치되야한다. 그리고 아래와 같이 심볼릭 링크를 만들어줘야한다.

ln -s /usr/src/linux/include/asm /skiff/local/arm-linux/include/asm
ln -s /usr/src/linux/include/linux /skiff/local/arm-linux/include/linux

3.2.3. 툴체인 만들기

우선 크로스 컴파일러를 만들어보자. root로 시작하는 것이 좋겠다. 혹은 적어도 설치할 땐 root로 할 필요가 있다. binutils와 gcc를 다음 사이트에서 다운 받는다.

인텔 SA1100 Assabet 보드에 관한 리눅스 개발 사이트를 참조하면 보다 자세한 사항을 알 수 있다. 인텔 사이트.

받은 파일이 /devel/arm/assabet에 들었다고 가정하고 그 디렉토리에서 다음과 같은 절차를 사용해 컴파일러를 만든다.

  1. binutils

    %cd /devel/arm/assabet
    %tar xzf binutils-2.11.2.tar.gz
    %cd binutils-2.11.2
    %./configure --target=arm-linux --prefix=/usr/local/arm
    %make
    %make install

    configure할 때의 --target은 만들어질 binutils가 arm-linux용이란 것을 나타내고, --prefix는 만들어진 binutils가 설치될 디렉토리를 나타낸다.

    설치된 디렉토리의 리스트는 다음과 같이 될 것이다.
    drwxr-xr-x    4 root     root           16  2월 26 09:58 arm-linux
    drwxr-xr-x    2 root     root         4096  2월 26 09:58 bin
    drwxr-xr-x    2 root     root           48  2월 26 09:58 include
    drwxr-xr-x    2 root     root         4096  2월 26 09:58 lib
    drwxr-xr-x    3 root     root            8  2월 26 09:58 man
    drwxr-xr-x    2 root     root            1  2월 26 09:58 share

    정상적으로 만들어 졌으면 다음 절차에서 사용되게 하기 위해 path에 임시로 추가해 준다. bash를 사용한다고 가정했다.
    export PATH=/usr/local/arm/bin:$PATH

  2. gcc

    gcc를 만들기 위해선 리눅스 커널의 헤더 파일이 필요하다. 우선 커널 소스를 풀고 2개의 디렉토리를 링크해 준다. 사용된 커널은 원하는 버전을 받아 사용하기 바란다. 여기선 2.4.17을 사용했다.

    %cd /devel/arm/assabet
    %tar xvjf linux-2.4.17.tar.bz2
    %mv linux linux-2.4.17
    %cd /usr/local/arm/arm-linux
    %mkdir include
    %cd include
    %ln -s /devel/arm/assabet/linux-2.4.17/include/asm-arm asm
    %ln -s /devel/arm/assabet/linux-2.4.17/include/linux linux
    %ls asm
    %ls linux
    %cd /devel/arm/assabet
    %tar xzf gcc-2.95.3.tar.gz
    %cd gcc-2.95.3
    %./configure --target=arm-linux --prefix=/usr/local/arm
    %make LANGUAGES="c"

    make를 진행하는 중에 stdlib.h, unistd.h와 같은 몇 개의 파일이 없다고 에러가 날 것이다. ARM 리눅스 사이트에서 얻은 정보에 의하면, gcc/config/arm/t-linux란 파일을 수정하라고 되어있다.아래와 같이 수정한다.

    %cd gcc/config/arm
    %vi t-linux

    제일 위에 있는 줄을 찾아보면 'TARGET_LIBGCC2_CFLAGS='란 줄이 있을 것이다. 이 줄의 끝에 '-Dinhibit_libc -D__gthr_posix_h'를 추가해 준다. 그리고 configure를 실행할 때 --disable-threads를 추가해 주고 다시 configure과 make를 실행한다.

    %./configure --target=arm-linux --prefix=/usr/local/arm --disable-threads
    %make LANGUAGES="c"

    컴파일 후 에러가 나는 것 처럼 보이지만 에러 나도 필요한 파일은 만들어졌으므로 아래 명령으로 확인 한다. 만약 gcc/xgcc가 없다면 make가 제대로 되지 않은 것이다. 아래 명령의 출력은 'arm-linux'가된다.

    %./gcc/xgcc -dumpmachine
    arm-linux

    위와 같이 출력된다면 제대로 된 것이므로 인스톨한다.

    %make LANGUAGES="c" install

  3. glibc를 만드는 절차에선 커널의 version.h가 필요하다. version.h는 make dep를 하면 생성된다.

    %cd /devel/arm/assabet
    %cd linux-2.4.17
    %zcat ../patch-2.4.17-rmk5.gz | patch -p1

    patch까지 적용하고 나서 Makefile을 수정한다. /devel/arm/assabet/linux-2.4.17/Makefile을 열어 'ARCH := arm'으로 수정하고 'CROSS_COMPILE =/usr/local/arm/bin/arm-linux-'으로 수정한다.

    %make assabet_config
    %make config

    그냥 enter만 쳐서 일단 default setting으로 저장한다.

    %make dep
    %find -name "version.h"

    version.h가 include/linux에 없다면 에러!

    glibc가 설치될 디렉토리를 만들어 준다.

    %mkdir /usr/local/arm/glibc
    %mkdir /usr/local/arm/glibc/arm-linux-glibc
    %cd /devel/arm/assabet
    %tar xzf glibc-2.1.3.tar.gz
    %cd glibc-2.1.3
    %tar xzf ../glibc-linuxthreads-2.1.3.tar.gz
    %tar xzf ../glibc-crypt-2.1.tar.gz
    %CC=arm-linux-gcc ./configure arm-linux --build=i686-pc-linux-gnu \
    --prefix=/usr/local/arm/glibc/arm-linux-glibc --enable-add-ons \
    --with-headers=/devel/arm/assabet/linux-2.4.17/include
    %make
    %make install

    속도가 느린 호스트를 사용한다면 아마도 집에 퇴근하기 전에 make 실행해 놓고 집에 갔다 오면 에러가 나 있던지 제대로 컴파일이 되어 있던지 할 것이다. 전에 P-II 400MHz에서 약 1시간 걸린 기억이 있다. 현재 Athlon 1GHz에서 약 10분 걸린것 같다.

  4. c++

    c++ 컴파일러도 만들어보자.

    %cd /devel/arm/assabet
    %cd gcc-2.95.3
    %./configure --host=i686-pc-linux-gnu --target=arm-linux \
    --prefix=/usr/local/arm \
    --with-headers=/usr/local/arm/glibc/arm-linux-glibc/include \
    --with-libs=/usr/local/arm/glibc/arm-linux-glibc/lib
    %make LANGUAGES="c c++"
    %make LANGUAGES="c c++" install

  5. 테스트

    다 만들어진 컴파일러, 라이브러리를 테스트 해본다. 테스트 전에 /usr/local/arm/bin이 패스에 설정됐는지 확인. 없다면 넣어 주거나 아래 compiler 명령에서 적당히 path를 삽입해 줄것.

    %cat > hello.c
    /*
     * hello.c
     */
    #include <stdio.h>
    
    int main()
    {
    	printf("hello.\n");
    	return 0;
    }
    
    %arm-linux-gcc -o hello hello.c

    에러 없이 컴파일되고 hello가 만들어졌는지 확인할 것. 그리고 file 명령으로 만들어진 hello가 어떤 내용인지 확인해 본다. 아래 처럼 ELF이고 ARM용이면 OK.

    %file hello
    hello: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped

여기까지 툴체인을 만들어 봤다. 커널이 잘 돌아간다면 만든 툴체인은 잘 동작한다고 봐도 될것이다.