<meta charset="utf-8">

크로스 컴파일러 만들기

크로스 컴파일

임베디드 시스템에서 실행할 소스를 컴파일 하는 일은 해당 시스템에서도 얼마든지 가능하지만,
임베디드 시스템의 특성상 컴파일 속도가 매우 느리므로 성능이 좋은 PC에서 대신 컴파일하여 올리는 것이 일반적입니다.

이처럼 타겟(Target) 시스템에서 실행 될 소스를 호스트(Host)에서 대신 컴파일 하는 경우,
이러한 컴파일 과정을 크로스 컴파일(Cross Compile)이라고 합니다.
그리고 크로스 컴파일 과정을 실행해주는 툴을 크로스 컴파일러(Cross Compiler)라고 부릅니다.
또한 특정한 소스를 크로스 컴파일하기 위해서는 크로스 컴파일러 외에도 링커와 각종 라이브러리등 여러 가지 것들이 필요한데
이러한 것들을 한데 묶어서 툴체인(Toolchain)이라고 부릅니다.

p.s. 컴파일 하는 호스트와 타겟이 같을 경우(일반적으로 진행하는 컴파일과정)에는 이러한 과정을 Native Compile 이라고 부릅니다.

툴체인 빌드하기

이제부터 툴체인을 만들어 보도록 하겠습니다.

아래 과정은 사용되는 타겟 시스템의 사양에 따라 달라질 수 있으며, 해당 타겟 시스템 제작사에 자세한 내용을 문의하시기 바랍니다.
이 문서는 ARMv6를 타겟 시스템으로 하는 문서입니다.

README

이 문서를 그대로 따라하신다고 해도 환경에 따라서 수 많은 오류가 발생할 수 있습니다.
적어도 저희가 경험했던 오류들은 방지할 수 있도록 여러가지 옵션과 라이브러리들을 추가적으로 설치하도록 작성하였지만,
사용자에 따라서 새로운 에러가 나올 수도 있습니다. 그 부분에 대해서는 여러분들이 직접 구글링을 통해 문제를 해결하실 수 있을 것입니다.
처음에는 매우 귀찮은 작업일 수도 있지만, 이로인해 학습되는 부분이 많으니 스스로 에러를 해결하실 수 있기를 바랍니다.
툴체인 빌드는 인내심과의 싸움입니다. 여러분들도 인내심을 가지고 마지막 과정까지 빌드해 보시길 바랍니다.

:!: 모든 작업은 될 수 있으면 root 계정에서 작업해주세요.
:!: 작업 디렉토리의 전체 경로에서 한글 및 띄어쓰기가 없도록 해 주세요.1)
:!: 중간에 오류가 났다면, 해당 패키지의 디렉토리를 지우고 처음부터 다시 시작하여 오류를 수정하는 것을 권장합니다.

필요한 패키지

툴체인을 빌드하는 데 필요한 패키지들은 아래와 같습니다.

이름버전다운로드 주소
Ubuntu Linux64bithttp://www.ubuntu.com/
binutils2.20.1(r7)ftp://ftp.gnu.org/gnu/binutils/
gcc4.4.3(r7)http://mirrors-us.seosue.com/gcc/releases/gcc-4.4.3/
glibc2.11.2http://ftp.gnu.org/gnu/glibc/
glibc-ports2.11
linux kernel2.6.35http://www.kernel.org/pub/linux/kernel/v2.6/

위의 버전에 맞게 해당 패키지를 다운로드받고 적절한 위치에 압축을 풀어주시기 바랍니다.
확장자가 .tar.gz로 끝나는 경우엔

tar xvfz 파일명.tar.gz

확장자가 .tar.bz2로 끝나는 경우엔

tar xvfj 파일명.tar.bz2

명령어를 이용해 주시면 됩니다.

Ubuntu Linux의 경우 이미 10.04버전 이상의 64bit Ubuntu Linux를 사용하고 계신다면 따로 설치하실 필요가 없습니다.
64bit 버전의 Ubuntu Linux를 사용하는 이유는 Chromium OS를 빌드하는 OS와 환경을 맞추어 주기 위해서입니다.

기타 필요한 각 패키지에 대한 설명은 아래와 같습니다.

크로스 컴파일 툴체인을 만드는 과정은 아래와 같습니다.

  1. 크로스 컴파일할 타겟 시스템을 지정합니다.
    1. 이 문서에서는 armv6, 즉 arm-generic-linux-gnueabi가 타겟 시스템입니다.
  2. 원하는 gcc 버전에 맞는 각각의 패키지 버전 조합을 찾아냅니다.
  3. binutils를 컴파일합니다. (기존 호스트 시스템에 존재하는 gcc를 이용)
  4. 최소 기능의 gcc를 컴파일합니다. (Stage 1 GCC)
  5. 타겟 시스템에 맞는 커널 소스에서 필요한 헤더 파일을 복사합니다.
  6. Stage 1 GCC와 위에서 복사한 헤더파일들을 이용하여 glibc를 컴파일합니다.
  7. 완전한 기능의 gcc를 컴파일합니다. (Stage 2 GCC)

그리고 위의 과정을 거치면서 생성되는 파일들을 tarball 형태로 배포할 수 있도록 별도의 위치에도 저장할 것입니다.

binutils 컴파일

Configure

binutils 디렉터리에서 아래의 명령어를 실행합니다.

./configure --target=arm-generic-linux-gnueabi \
            --prefix=/opt \
            --program-prefix=arm-generic-linux-gnueabi- \
            --disable-nls --with-abi=aapcs-linux
  • --target
    • 만들 대상을 적어주는 부분입니다. 저 이름은 마음대로 정할 수 있는 것이 아니라 규칙이 존재합니다.
  • --prefix
    • 설치될 대상 폴더를 적어줍니다.
  • --program-prefix
    • 프로그램의 앞에 붙는 prefix를 적어줍니다.
    • ex) gcc라는 프로그램은 이 옵션을 사용하면 앞으로 arm-generic-linux-gnueabi-gcc 라는 이름을 가집니다.

Compile

configure가 문제없이 끝났다면, 다음 명령어를 차례대로 실행합니다.

make
make check
make install

문제없이 완료가 되었다면 binutils의 설치가 완료된 것입니다.
/opt 경로로 가 보시면 arm-generic-linux-gnueabi 디렉터리가 생성된 것을 확인하실 수 있습니다.

리눅스 커널 헤더 세팅

리눅스 커널 헤더가 필요한 이유는 시스템 의존적인 라이브러리를 빌드할 때, 리눅스 커널의 헤더 파일을 참조하기 때문입니다.
따라서 커널의 설정을 ARM으로 세팅한 후 진행해야 합니다.

리눅스 커널 디렉터리에서 아래 명령어를 실행합니다.

make ARCH=arm CROSS_COMPILE=arm-generic-linux-gnueabi- ezs3c6410_defconfig
make ARCH=arm CROSS_COMPILE=arm-generic-linux-gnueabi- zImage

컴파일이 되다가 에러가 날 것입니다. 아직 arm-generic-linux-gnueabi-gcc 가 설치되어 있지 않기 때문입니다.
우리는 여기서 진행 중에 include/linux/version.h가 만들어지는 것만 확인하면 됩니다.

마지막으로 아래 명령어들을 이용하여 필요한 헤더 파일들을 배포용 디렉터리로 복사합니다.

mkdir /opt/arm-generic-linux-gnueabi/sys-include
cp -dpR arch/arm/include/asm /opt/arm-generic-linux-gnueabi/sys-include/asm
cp -dpR include/asm-generic /opt/arm-generic-linux-gnueabi/sys-include/asm-generic
cp -dpR include/linux /opt/arm-generic-linux-gnueabi/sys-include/linux
cp -dpR arch/arm/mach-s3c64xx /opt/arm-generic-linux-gnueabi/sys-include/mach

GCC 빌드 stage 1

GCC의 빌드에 대해서는 GCC INSTALL 공식 문서를 읽어보시면 좋습니다.

gmp, mpfr, libmudflap, gawk 패키지 설치

GCC를 빌드하기 전에 설치해야 할 패키지가 있습니다.
gmp 패키지와 mpfr 패키지인데 이를 설치하지 않으면 에러가 발생하므로 설치를 반드시 해 줍니다.

패키지명버전다운로드 주소
gmp4.1.3ftp://ftp.gnu.org/gnu/gmp/gmp-4.1.3.tar.gz
mpfr2.3.2http://www.mpfr.org/mpfr-2.3.2/mpfr-2.3.2.tar.bz2
libmudflap-apt-get을 이용해 설치 가능
gawk-

위에서 필요한 패키지를 받았던 것과 같은 방법으로 다운로드 한 후 압축을 풀어줍니다.

gmp 디렉터리에서 아래 명령어를 실행해 gmp 패키지를 설치해줍니다.

apt-get install m4
./configure
make
make check
make install


mpfr 디렉터리에서 아래 명령어를 실행해 mpfr 패키지를 설치해줍니다.

./configure
make
make check
make install


그리고 아래 명령어를 실행하여 libmudflap 패키지도 설치해줍니다.

apt-get install libmudflap0


아래 명령어를 실행하여 gawk 패키지를 설치해줍니다. 그리고 호환을 위해 몇몇 파일을 바꾸어줍니다.

apt-get install gawk
rm /usr/bin/awk
rm /usr/bin/mawk
cp /usr/bin/gawk /usr/bin/awk
cp /usr/bin/gawk /usr/bin/mawk

Configure

압축을 해제한 gcc 디렉터리에서 build라는 디렉토리를 생성한 후 그 안에서 작업을 진행합니다.

mkdir build
cd build

configure를 실행해줍니다.

../configure --target=arm-generic-linux-gnueabi \
             --prefix=/opt \
             --with-local-prefix=/opt/arm-generic-linux-gnueabi \
             --without-headers --with-newlib --disable-shared --disable-threads \
             --disable-libmudflap --disable-libssp --enable-languages=c 

Compile

Configure 과정이 이상 없이 끝나면 아래 명령어를 입력하여 컴파일을 진행합니다.

make all-gcc
make install-gcc
make all-target-libgcc
make install-target-libgcc

glibc 빌드

Configure

glibc-ports 패키지를 압축을 풀어서 나온 디렉터리를 glibc 패키지 디렉터리에 ports라는 이름으로 이동시킵니다.
그리고 glibc 패키지의 디렉터리 내에서 아래 명령어를 실행합니다.

mkdir build
cd build
echo "libc_cv_forced_unwind=yes" >> config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
ln -vs libgcc.a `arm-generic-linux-gnueabi-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'`


만일 마지막 ln 명령어에서

ln: creating symbolic link `/opt/lib/gcc/arm-generic-linux-gnueabi/4.4.3/libgcc_eh.a': File exists

에러가 발생한 경우

rm -f /opt/lib/gcc/arm-generic-linux-gnueabi/4.4.3/libgcc_eh.a

명령어로 이미 존재하는 파일을 제거해 주면 됩니다.

위의 준비가 모두 끝났으면 configure를 실행합니다.

CC=arm-generic-linux-gnueabi-gcc \
AR=arm-generic-linux-gnueabi-ar \
RANLIB=arm-generic-linux-gnueabi-ranlib \
../configure --target=arm-generic-linux-gnueabi \
             --prefix=/opt/arm-generic-linux-gnueabi \
             --host=arm-generic-linux-gnueabi \
             --with-headers=/opt/arm-generic-linux-gnueabi/sys-include/ \
             --cache-file=config.cache --enable-kernel=2.6.35 \
             --with-float=soft --with-fp --with-tls --with-__thread --without-gd \
             --with-abi=aapcs-linux --without-cvs --disable-profile --disable-debug \
             --enable-shared --enable-add-ons=ports,nptl

Compile

Configure가 정상적으로 완료되었으면 아래 명령어를 이용해 컴파일해줍니다.

make
make install

GCC Stage2

이제 마지막 최종 GCC를 빌드하는 일만 남았습니다.
이전에 압축을 풀어놨던 gcc 패키지 폴더를 지우고 다시 새롭게 압축을 풀어야 합니다.

Configure

새로 압축을 해제한 gcc 디렉터리에서 아래 명령어를 실행합니다.

mkdir build
cd build
 
../configure --prefix=/opt \
             --target=arm-generic-linux-gnueabi \
             --with-headers=/opt/arm-generic-linux-gnueabi/sys-include \
             --enable-languages=c,c++ \
             --enable-__cxa_atexit --enable-target-optspace \
             --with-gnu-ld --enable-shared --with-gmp=/usr/local --with-mpfr=/usr/local \
             --enable-c99 --enable-long-long --disable-nls --enable-threads \
             --disable-multilib --disable-decimal-float --with-arch=armv6 \
             --with-float=softfp --with-fpu=vfp --enable-symvers=gnu \
             --with-pkgversion=for_boriOS_Development_Team

Make

Configure가 정상적으로 완료되면 마지막으로 설치해줍니다.

make all
make install

배포를 위해 opt 디렉터리 압축하기

이제 크로스 컴파일에 필요한 툴체인이 모두 완성되었습니다.
위 과정을 모두 따라오셨다면 /opt 디렉터리에 툴체인이 설치되어 있을 것입니다.
배포를 위해선 /opt 디렉터리에 있는 파일들을 이용해야 합니다.

/opt 디렉터리의 모든 내용을 압축하시면 간단히 툴체인 tarball 파일이 생성됩니다.

cd /
tar cvfz armv6_toolchain.tar.gz ./opt

생성되는 tarball 파일은 추후에 컴파일 과정 없이 간단히 루트 디렉터리(/)에 압축을 해제하는 것만으로 툴체인을 이용 가능하게 해 줍니다.
tarball 파일이 생성되면 해당 파일을 안전한 곳에 옮겨두시면 됩니다.

수고하셨습니다. :) 드디어 툴체인 빌드가 끝났습니다.
툴체인이 만들어지는 과정을 잘 기억해 두시기 바랍니다.

참고 자료

1) pwd 명령어를 실행했을 때 한글 및 띄어쓰기가 있으면 에러가 발생할 가능성이 높습니다.


이 문서는 보리 OS 위키(http://wiki.borios.co.kr/)에서도 보실 수 있습니다.

</meta>