ARM 네이티브 툴체인 만들기

buildroot로 만든 라즈베리 파이의 파일 시스템에서 파이썬으로 만들어진 데모를 돌리기위해(pip로 설치하는 모듈이 C 코드를 빌드하기때문) 툴체인 빌드에 끝까지 성공하여 과정을 기록. (참고: 구버전 buildroot는 타겟 파일 시스템에서 실행되는 컴파일러를 지원 한것으로 보인다. 아쉬운 부분.)

커널 버전은 x.y.z 중 x.y까지만 동일, glibc 버전은 타겟 시스템의 glibc 버전 2.30과 동일하게 사용했다. 대상 시스템보다 높은 버전의 glibc를 사용하여 툴체인을 만들었다면 bison, python등에서 공유 라이브러리 libc.so.6 참조에서 문제가 발생한다. (또는 glibc의 버전이 동일해도 configure 옵션에 따라서 다른 문제가 발생할수도 있다.) 만약 취미삼아 최신 glibc를 써보고싶다면 대상 시스템에서 원하는 버전의 glibc를 --prefix=/usr로 빌드 후 설치하여 업데이트 할 수 있겠지만 특별히 의미도 없고 추천할 수 없다.

참고사이트
gcc configure: https://gcc.gnu.org/install/configure.html
multiarch path: https://wiki.debian.org/Multiarch/LibraryPathOverview
build cross compiler: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/
build cross compiler: https://gts3.org/2017/cross-kernel.html
crosstool-ng: https://github.com/crosstool-ng/crosstool-ng
compiler options for raspberry pi: https://gist.github.com/fm4dd/c663217935dc17f0fc73c9c81b0aa845
mode arm, thumb: http://recipes.egloos.com/5651064

첫번째 단계: ARM 크로스 컴파일러 생성

소스코드 및 작업 디렉토리는 ~/crossdev/work, 크로스 컴파일러는 ~/crossdev/cross-gcc, ARM 컴파일러는 ~/crossdev/arm-gcc, 프로세서는 라즈베리파이 3+이상인 cortex53(armv8-a)를 기준으로 하였다. 또한 크로스 컴파일러 만들 때 옵션을 보면 gcc나 glibc의 threads관련 옵션을 disable하는 스크립트들이 있던데… gcc 10.2.0 + glibc 2.30에서 발생하는 버그인지 이것을 disable하면 glibc를 make all 할 때 참조 오류가 발생하여 threads를 enable 하였다.

환경변수

export ARM=~/crosstool/arm-gcc
export CROSS=~/crosstool/cross-gcc
export LIB=~/crosstool/cross-lib
export WORK=~/crosstool/work
export CHOST=arm-pc-linux-gnueabihf
export PATH=$CROSS/bin:$PATH
export MINKER=3.2.0

패키지 다운로드 주소 (~/crosstool/work에 다운 후 압축을 푼다)

binutils: http://mirror.kakao.com/gnu/binutils/binutils-2.35.1.tar.xz
glibc: http://mirror.kakao.com/gnu/glibc/glibc-2.30.tar.xz
gcc: http://mirror.kakao.com/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.xz
gmp: http://mirror.kakao.com/gnu/gmp/gmp-6.2.1.tar.xz
mpfr: http://mirror.kakao.com/gnu/mpfr/mpfr-4.1.0.tar.xz
mpc: http://mirror.kakao.com/gnu/mpc/mpc-1.2.1.tar.gz
kernel: https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.180.tar.xz

툴체인 빌드

binutils
cd $WORK
cd binutils-2.35.1
mkdir stage1 && cd stage1
../configure --target=$CHOST --prefix=$CROSS --enable-ld=yes --enable-gold=no --disable-plugins --disable-lto --disable-gdb --with-arch=armv8-a --with-fpu=neon-fp-armv8 --with-float=hard
make
make install-strip
kernel headers
cd $WORK
cd linux-4.19.180
make ARCH=arm INSTALL_HDR_PATH=$CROSS/$CHOST headers_install
gmp
cd $WORK
cd gmp-6.2.1
mkdir stage1 && cd stage1
../configure --prefix=$LIB --disable-shared --enable-static
make
make install-strip
mpfr
cd $WORK
cd mpfr-4.1.0
mkdir stage1 && cd stage1
../configure --prefix=$LIB --disable-shared --enable-static --with-gmp=$LIB
make
make install-strip
mpc
cd $WORK
cd mpc-1.2.1
mkdir stage1 && cd stage1
../configure --prefix=$LIB --disable-shared --enable-static --with-gmp=$LIB --with-mpfr=$LIB
make
make install-strip
gcc (initial)
cd $WORK
cd gcc-10.2.0
mkdir stage1 && cd stage1
../configure --target=$CHOST --prefix=$CROSS --enable-languages=c,c++ --enable-__cxa_atexit --enable-clocale=gnu --enable-long-long --enable-threads=posix --enable-tls --with-abi=aapcs-linux --with-cpu=cortex-a53 --with-fpu=neon-fp-armv8 --with-float=hard --with-mode=arm --with-gmp=$LIB --with-mpfr=$LIB --with-mpc=$LIB --without-included-gettext --disable-lto --disable-plugin --disable-bootstrap --disable-multiarch --disable-multilib --disable-libgomp --disable-libmudflap --disable-libssp --disable-vtable-verify --disable-libvtv --disable-systemtap --disable-libquadmath --disable-libsanitizer --with-cloog=no --with-ppl=no --with-isl=no
make all-gcc
make install-strip-gcc
glibc (startfile, libc.so, stubs.h)
cd $WORK
cd glibc-2.30
mkdir stage1 && cd stage1
../configure --host=$CHOST --target=$CHOST --prefix=$CROSS/$CHOST --enable-kernel=$MINKER --with-arch=armv8-a --with-fpu=neon-fp-armv8 --with-float=hard --with-headers=$CROSS/$CHOST/include --without-cvs --without-gd --with-__thread --with-nptl --with-tls --disable-werror --disable-profile --disable-crypt --disable-sanity-checks libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes
make install-bootstrap-headers=yes install-headers
make csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o $CROSS/$CHOST/lib
$CHOST-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $CROSS/$CHOST/lib/libc.so
touch $CROSS/$CHOST/include/gnu/stubs.h
gcc (libgcc)
cd $WORK
cd gcc-10.2.0
cd stage1
make all-target-libgcc
make install-strip-target-libgcc
glibc (final)
cd $WORK
cd glibc-2.30
cd stage1
make
make install INSTALL_PROGRAM="install -s --strip-program=$CHOST-strip"
gcc (final)
cd $WORK
cd gcc-10.2.0
cd stage1
make
make install-strip
gmp
cd $WORK
cd gmp-6.2.1
mkdir stage2 && cd stage2
../configure --host=$CHOST --prefix=$CROSS/$CHOST --disable-shared --enable-static
make
make install-strip
mpfr
cd $WORK
cd mpfr-4.1.0
mkdir stage2 && cd stage2
../configure --host=$CHOST --prefix=$CROSS/$CHOST --disable-shared --enable-static --with-gmp=$CROSS/$CHOST
make
make install-strip
mpc
cd $WORK
cd mpc-1.2.1
mkdir stage2 && cd stage2
../configure --host=$CHOST --prefix=$CROSS/$CHOST --disable-shared --enable-static --with-gmp=$CROSS/$CHOST --with-mpfr=$CROSS/$CHOST
make
make install-strip

두번째 단계: ARM 네이티브 컴파일러 생성

kernel header와 glibc는 sysroot에만 설치되어야한다. binutils, gcc와 동일한 디렉토리에 설치되어 binutils가 빌드되면 툴체인이 설치된 경로와 prefix가 다를경우 libc.so.6 등 라이브러리를 링커에서 참조하지 못한다. 참고로 두번째 단계에서 빌드되는 gcc는 첫번째 단계의 마지막에 stage2로 빌드한 gmp, mpfr, mpc를 참조하여 사용하게된다.

kernel headers (sysroot)
cd $WORK
cd linux-4.19.180
make ARCH=arm INSTALL_HDR_PATH=$ARM/$CHOST/sysroot/usr headers_install
glibc (sysroot)
cd $WORK
cd glibc-2.30
mkdir stage2 && cd stage2
../configure --host=$CHOST --target=$CHOST --prefix=/usr --enable-obsolete-rpc --enable-profile --enable-kernel=$MINKER --with-__thread --with-nptl --with-tls --with-arch=armv8-a --with-fpu=neon-fp-armv8 --with-float=hard --with-headers=$ARM/$CHOST/sysroot/usr/include --without-cvs --without-gd --disable-werror --disable-crypt --disable-sanity-checks
make
make install DESTDIR=$ARM/$CHOST/sysroot INSTALL_PROGRAM="install -s --strip-program=$CHOST-strip"
binutils
cd $WORK
cd binutils-2.35.1
mkdir stage2 && cd stage2
../configure --host=$CHOST --prefix=$ARM --enable-ld=yes --enable-gold=no --enable-poison-system-directories --with-arch=armv8-a --with-fpu=neon-fp-armv8 --with-float=hard --with-build-sysroot=$ARM/$CHOST/sysroot --disable-lto --disable-sim --disable-gdb --disable-plugins --disable-werror
make
make install-strip
gcc
cd $WORK
cd gcc-10.2.0
mkdir stage2 && cd stage2
../configure --host=$CHOST --target=$CHOST --prefix=$ARM --enable-languages=c,c++ --enable-threads=posix --enable-tls --enable-__cxa_atexit --enable-clocale=gnu --enable-long-long --with-abi=aapcs-linux --with-cpu=cortex-a53 --with-fpu=neon-fp-armv8 --with-float=hard --with-mode=arm --with-sysroot=$ARM/$CHOST/sysroot --disable-lto --disable-plugin --disable-bootstrap --disable-multiarch --disable-multilib --disable-libgomp --disable-libmudflap --disable-libssp --disable-vtable-verify --disable-libvtv --disable-libquadmath --disable-libsanitizer --with-isl=no --with-ppl=no --with-cloog=no
make
make install-strip

여기까지 타겟 보드에서 네이티브 툴체인을 만들기위한 컴파일 환경 빌드 끝. make install로 설치하면 바이너리에 용량 큰 디버깅 정보가 함께 복사되므로 make install-strip으로 설치. glibc는 install-strip이 없고, 대신 make install INSTALL_PROGRAM=’install -s’ 이렇게 실행하면 디버깅 정보가 지워진다. 단지 시스템 기본 strip 명령은 ARM 바이너리를 지원하지 않으므로 –strip-program 옵션으로 arm 타겟의 strip 명령을 추가로 지정하였으며 install-strip이 없는 python은 CC=”$CHOST-gcc -s”로 디버깅 정보를 gcc에서 넣지 않도록 하였다.

세번째 단계: 타겟 시스템에서 네이티브 툴체인 빌드

위에서 빌드된 ~/crosstool/arm-gcc를 타겟 파일시스템으로 복사한다. 경로는 /opt/bootstrap-gcc로 하였다. 이 툴체인은 대상 시스템에서 온전히 사용하기 무리가 있고 어차피 다시 빌드해야하기때문에 경로를 따로 잡았다. 툴체인의 sysroot 디렉토리에 커널 헤더와 glibc를 따로 설치하는 이유는 gcc 빌드 시 타겟 시스템의 /usr/include, /usr/lib에 시스템 헤더와 라이브러리가 없을경우 몇가지 편법을 써야하기 때문이다. (만약 위험성을 감수하고 prefix를 /usr로 지정하여 설치한다면 sysroot를 안써도 된다.)

직접 빌드한 프로그램이 실행되지 않고 기존 타겟 보드에 설치된 파일이 실행된다면 hash -r 명령을 실행 후 다시 시도하면 된다.

환경변수

export CHOST=arm-pc-linux-gnueabihf
export PREFIX=/opt/arm-gcc
export WORK=/opt/crosstool
export SYSROOT=$PREFIX/sysroot
export PATH=$PREFIX/ccache:/opt/bootstrap-gcc/bin:$PREFIX/sbin:$PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$PREFIX/lib
export GCC_VERSION=10.2.0
export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
export LANG=C

패키지 다운로드 주소 (/opt/crosstool에 다운 후 압축을 푼다)

binutils: http://mirror.kakao.com/gnu/binutils/binutils-2.35.1.tar.xz
glibc: http://mirror.kakao.com/gnu/glibc/glibc-2.30.tar.xz
gcc: http://mirror.kakao.com/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.xz
gmp: http://mirror.kakao.com/gnu/gmp/gmp-6.2.1.tar.xz
mpfr: http://mirror.kakao.com/gnu/mpfr/mpfr-4.1.0.tar.xz
mpc: http://mirror.kakao.com/gnu/mpc/mpc-1.2.1.tar.gz
kernel: https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.180.tar.xz
make: http://mirror.kakao.com/gnu/make/make-4.3.tar.gz
m4: http://mirror.kakao.com/gnu/m4/m4-1.4.18.tar.xz
gawk: http://mirror.kakao.com/gnu/gawk/gawk-5.1.0.tar.xz
grep: http://mirror.kakao.com/gnu/grep/grep-3.5.tar.xz
bison: http://mirror.kakao.com/gnu/bison/bison-3.7.3.tar.xz
zlib: https://www.zlib.net/fossils/zlib-1.2.11.tar.gz
libffi: https://github.com/libffi/libffi/releases/download/v3.3/libffi-3.3.tar.gz
python3: https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tar.xz
pkgconf: https://distfiles.dereferenced.org/pkgconf/pkgconf-1.6.3.tar.xz

선택사항
coreutils: https://ftp.gnu.org/gnu/coreutils/coreutils-8.31.tar.xz
lz4: https://github.com/lz4/lz4/archive/v1.9.3.tar.gz
zstd: https://github.com/facebook/zstd/releases/download/v1.4.5/zstd-1.4.5.tar.gz
curl: https://github.com/curl/curl/releases/download/curl-7_74_0/curl-7.74.0.tar.xz
expat: https://github.com/libexpat/libexpat/releases/download/R_2_2_10/expat-2.2.10.tar.xz
libarchive: https://www.libarchive.org/downloads/libarchive-3.5.1.tar.xz
jsoncpp: https://github.com/open-source-parsers/jsoncpp/archive/1.9.4.tar.gz
rhash: https://sourceforge.net/projects/rhash/files/rhash/1.3.6/rhash-1.3.6-src.tar.gz
libuv: https://github.com/libuv/libuv/archive/v1.40.0.tar.gz
re2c: https://github.com/skvadrik/re2c/releases/download/2.0.3/re2c-2.0.3.tar.xz
perl: https://www.cpan.org/src/5.0/perl-5.30.3.tar.gz
openssl: https://github.com/openssl/openssl/archive/OpenSSL_1_1_1j.tar.gz
ninja: https://github.com/ninja-build/ninja/archive/v1.10.1.tar.gz
cmake: https://cmake.org/files/v3.18/cmake-3.18.5.tar.gz
ccache: https://github.com/ccache/ccache/releases/download/v4.1/ccache-4.1.tar.xz
autoconf: http://mirror.kakao.com/gnu/autoconf/autoconf-2.69.tar.xz
automake: http://mirror.kakao.com/gnu/automake/automake-1.16.2.tar.xz
libtool: http://mirror.kakao.com/gnu/libtool/libtool-2.4.6.tar.xz

코드 패치 (컴파일 시 오류가 발생하는 파일과 수정 되어야 할 내용)

m4 (1.4.18)
자세한 내용 (glibc 2.28이상에서 발생하는 빌드오류 수정)
https://github.com/openembedded/openembedded-core/blob/master/meta/recipes-devtools/m4/m4/m4-1.4.18-glibc-change-work-around.patch

패치파일 사용 (--dry-run에서 문제없으면 다음 명령을 실행)
cd $WORK
wget https://src.fedoraproject.org/rpms/m4/raw/814d592134fad36df757f9a61422d164ea2c6c9b/f/m4-1.4.18-glibc-change-work-around.patch
patch -p0 --dry-run < m4-1.4.18-glibc-change-work-around.patch
patch -p0 < m4-1.4.18-glibc-change-work-around.patch

직접 패치
파일: lib/freadahead.c
변경내용: 28번째 줄
변경 전: #if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
변경 후: #if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1

파일: lib/fseeko.c
변경내용: 50번째 줄
변경 전: #if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
변경 후: #if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1

파일: lib/stdio-impl.h
변경내용: 21번째 줄에 추가
추가내용:
#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN
# define _IO_IN_BACKUP 0x100
#endif

툴체인 빌드
BusyBox로 실행되는 명령들은 최소한의 옵션만 지원한다. gawk, grep 등이 BusyBox명령이 아니라면 해당 패키지는 패스해도 상관없다. 라즈베리 파이 3+처럼 메모리가 1기가라면 binutils(gold를 enable 하였을 경우)나 gcc 빌드 시 병렬 빌드를 하지않거나 가상 메모리를 1기가 이상 넉넉하게 잡아줘야 메모리 부족으로 빌드 중 문제가 생기지않는다. 또한 split 등 명령이 없다면 coreutils를 빌드하면 된다.

참고
파이썬 install 시 make altinstall로 설치하면 python3.8을 python3으로 심볼릭 링크를 생성하지 않게된다. 또한 bash 쉘에서 실행파일 경로를 캐시하여 시스템에 설치된 BusyBox로 명령이 실행된다면 hash -r 명령을 실행하면 명령어 캐시가 지워져 PATH 로 설정된 경로의 순서상의 명령어를 올바르게 실행할 수 있다.

make
cd $WORK
cd make-4.3
mkdir build
cd build
../configure --prefix=$PREFIX --enable-nls --disable-dependency-tracking
../build.sh
./make -j4
./make install-strip
m4
cd $WORK
cd m4-1.4.18
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
bison
cd $WORK
cd bison-3.7.3
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
gawk
cd $WORK
cd gawk-5.1.0
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
pkgconf
cd $WORK
cd pkgconf-1.6.3
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
ln -s pkgconf $PREFIX/bin/pkg-config
zlib
cd $WORK
cd zlib-1.2.11
mkdir build
cd build
CC="gcc -s" ../configure --prefix=$PREFIX
make -j4
make install
grep
cd $WORK
cd grep-3.5
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
perl (선택사항, 빌드옵션 참고)
cd $WORK
cd perl-5.30.3
mkdir build
cd build
../Configure -des -Dprefix=$PREFIX -Dmksymlinks -Dcc=gcc
make -j4
make install-strip
openssl (선택사항)
cd $WORK
cd openssl-OpenSSL_1_1_1j
mkdir build
cd build
CC="gcc -s" ../Configure --prefix=$PREFIX linux-armv4
make -j4
make install
libffi
cd $WORK
cd libffi-3.3
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
python
cd $WORK
cd Python-3.9.1
mkdir build
cd build
CC="gcc -s" ../configure --prefix=$PREFIX --enable-optimizations --with-system-ffi
make -j4
make install
python 링크 생성
ln -s python3 $PREFIX/bin/python
kernel header (sysroot)
cd $WORK
cd linux-4.19.180
make INSTALL_HDR_PATH=$SYSROOT/usr headers_install
glibc (sysroot)
cd $WORK
cd glibc-2.30
mkdir build-sysroot
cd build-sysroot
../configure --build=$CHOST --host=$CHOST --target=$CHOST --prefix=/usr --with-headers=$SYSROOT/usr/include --with-tls --with-__thread --enable-profile --disable-multi-arch --disable-multilib --disable-werror --without-cvs
make -j4
make install DESTDIR=$SYSROOT INSTALL_PROGRAM="install -s"
gmp
cd $WORK
cd gmp-6.2.1
mkdir build
cd build
../configure --prefix=$PREFIX --host=armcortexa53neon-pc-linux-gnueabihf
make -j4
make install-strip
mpfr
cd $WORK
cd mpfr-4.1.0
mkdir build
cd build
../configure --prefix=$PREFIX --with-gmp=$PREFIX
make -j4
make install-strip
mpc
cd $WORK
cd mpc-1.2.1
mkdir build
cd build
../configure --prefix=$PREFIX --with-gmp=$PREFIX --with-mpfr=$PREFIX
make -j4
make install-strip
binutils
cd $WORK
cd binutils-2.35.1
mkdir build
cd build
../configure --build=$CHOST --host=$CHOST --target=$CHOST --prefix=$PREFIX --enable-ld=yes --enable-gold=no --with-sysroot=$SYSROOT --disable-werror --disable-gdb --disable-libdecnumber --disable-readline --disable-sim --disable-libquadmath --disable-libquadmath-support --without-included-gettext --without-debuginfod
make -j4
make install-strip
gcc
cd $WORK
cd gcc-10.2.0
mkdir build
cd build
../configure --host=$CHOST --build=$CHOST --prefix=$PREFIX --enable-languages=c,c++,lto --enable-lto --enable-shared --enable-linker-build-id --without-included-gettext --enable-threads=posix --enable-nls --enable-clocale=gnu --enable-libsanitizer --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-c99 --enable-long-long --enable-checking=release --with-gmp=$PREFIX --with-mpfr=$PREFIX --with-mpc=$PREFIX --with-default-libstdcxx-abi=new --disable-multiarch --disable-libitm --disable-libquadmath --disable-libquadmath-support --disable-sjlj-exceptions --disable-werror --with-cpu=cortex-a53 --with-fpu=neon-fp-armv8 --with-float=hard --with-isl=no --with-cloog=no --with-ppl=no --with-sysroot=$SYSROOT
make -j4
make install-strip
binutils 링크 생성
for executable in addr2line ar as c++filt dwp elfedit gprof ld ld.bfd ld.gold nm objcopy objdump ranlib readelf size strings strip; do if test -f "$PREFIX/bin/$executable"; then ln -sf $executable $PREFIX/bin/$CHOST-$executable; fi; done
gcc 링크 생성(안해도 문제없지만 완전한 host prefix와 일부 복사된 바이너리의 용량을 줄이기 위함)
for executable in c++ cpp g++ gcc gcc-ar gcc-nm gcc-ranlib; do if test -f "$PREFIX/bin/$executable"; then ln -sf $executable $PREFIX/bin/$CHOST-$executable; fi; done
if test -f $CHOST-gcc-$GCC_VERSION; then ln -sf gcc $CHOST-gcc-$GCC_VERSION; fi
gcc include 링크
ln -s ../include $PREFIX/$CHOST/include

이곳에 따르면 include 경로에 sysroot를 사용하면 native only가 적용되지 않는지 $(prefix)/include를 포함하지 않는다. 하지만 cross only에 해당하는 $(tooldir)/include를 참고하는 이유를 모르겠다. 빌드하려면 시간도 너무걸리고(…)

여기까지 빌드되면 끝났다고 봐도된다. --with-gmp=$PREFIX와 같은 옵션을 주지않아도 라이브러리를 찾게되고 환경변수 PKG_CONFIG_ALLOW_SYSTEM_CFLAGS, PKG_CONFIG_ALLOW_SYSTEM_LIBS가 필요없으므로 unset으로 지워도 된다. 이제부터는 /opt/bootstrap-gcc 폴더를 지우거나 이름을 변경하여 해당 컴파일러가 사용되지 않도록 한다. 혹시 모르니 hash -r 을 실행하여 bash의 명령어 캐시도 제거한다. 아래 환경변수는 위 툴체인을 사용 시 최소한의 환경변수. (원한다면 PREFIX 환경변수를 export하지않고 PATH=/opt/arm-gcc/ccache:…:$PATH 이런식으로 사용해도 상관없다.)

export PREFIX=/opt/arm-gcc
export PATH=$PREFIX/ccache:$PREFIX/sbin:$PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$PREFIX/lib

아래부터는 취향에 따라, 또는 필요에 따라 설치.

참고: lz4, zstd에서 make 명령을 실행할 때 PREIFX환경변수가 없으면 make -C lib libzstd.pc PREFIX=/path 와 같이 PREFIX 값을 넘겨줘야 한다. (만약 값이 잘못되었을 경우 make clean으로 정리할 수 있다.)

meson
cd $WORK
python3 -m pip install meson==0.56.2
re2c
cd $WORK
cd re2c-2.0.3
mkdir build-src
cd build-src
../configure --prefix=$PREFIX
make -j4
make install-strip
ninja
cd $WORK
cd ninja-1.10.1
mkdir build
cd build
../configure.py --bootstrap
install -s ninja $PREFIX/bin
autoconf
cd $WORK
cd autoconf-2.69
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
automake
cd $WORK
cd automake-1.16.2
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
libtool
cd $WORK
cd libtool-2.4.6
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
lz4
cd $WORK
cd lz4-1.9.3
make -j4 CC="gcc -s"
make CC="gcc -s" install
zstd
cd $WORK
cd zstd-1.4.5
make -j4 -C lib libzstd libzstd.a libzstd.pc CC="gcc -s" CXX="g++ -s"
make -j4 -C contrib/pzstd CC="gcc -s" CXX="g++ -s"
make -j4 zstd CC="gcc -s" CXX="g++ -s" HAVE_LZ4=1
make -C lib install
make -C contrib/pzstd install
make -C programs install
curl
cd $WORK
cd curl-7.74.0
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
expat
cd $WORK
cd expat-2.2.10
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
libarchive
cd $WORK
cd libarchive-3.5.1
mkdir build
cd build
../configure --prefix=$PREFIX
make -j4
make install-strip
jsoncpp
cd $WORK
cd jsoncpp-1.9.4
mkdir build
cd build
meson configure --prefix=$PREFIX --strip
meson compile
meson install
rhash
cd $WORK
cd RHash-1.3.6
./configure --prefix=$PREFIX./configure --prefix=$PREFIX --disable-openssl-runtime --disable-static --enable-lib-shared --extra-cflags=-s --extra-ldflags=-s
make
make install install-pkg-config install-lib-so-link
make -C librhash install-headers
libuv
cd $WORK
cd libuv-1.40.0
./autogen.sh
mkdir build
cd build
../configure --prefix=$PREFIX --cc="gcc -s"
make -j4
make install-strip
cmake (system libs의존성: zstd, curl, )
cd $WORK
cd cmake-3.18.5
mkdir build
cd build
../configure --prefix=$PREFIX --parallel=4 --system-libs
make -j2
make install/strip
ccache (선택사항)
cd $WORK
cd ccache-4.1
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX ..
make -j4
make install/strip
mkdir $PREFIX/ccache
ln -s ../bin/ccache $PREFIX/ccache/c++
ln -s ../bin/ccache $PREFIX/ccache/g++
ln -s ../bin/ccache $PREFIX/ccache/gcc
ln -s ../bin/ccache $PREFIX/ccache/$HOST-c++
ln -s ../bin/ccache $PREFIX/ccache/$HOST-g++
ln -s ../bin/ccache $PREFIX/ccache/$HOST-gcc
ccache --set-config=cache_dir=$PREFIX/ccache/cache

여기까지가 현재 필요한 부분을 다 빌드한 내용. PC는 프로세서가 빠르니까 삽질도 금방이지만 arm에서는 뭔가 잘못 빌드하면 흠 좀… (이럴바엔 걍 젠투로 밀어버려도 될거같다.) 어느정도는 감이 잡혔으니 이제 64비트 시스템 구측해봐야겠다(?!).

참고용 스크립트
라이브러리 참조 경로 확인: gcc (옵션) -print-search-dirs | sed -e :a -e ‘s,[^/]*/..\/,,’ -e ta
헤더 참조 경로 확인: gcc (옵션) -Wp,-v 2>&1 | sed -e :a -e ‘s,[^/]*/..\/,,’ -e ta
일정 시간이 지난 파일 삭제(20분 이전부터 현재 시간까지) : find ./ -mmin -20 -exec rm -fv {} \;

64비트 arm(aarch64)이 대상일 경우

1. 환경변수 CHOST 변경 (export CHOST=aarch64-pc-linux-gnu)
2. linux의 HOST 값은 arm64로 변경
3. gcc의 configure에서 --with-abi는 lp64, --with-float, --with-mode, --with-fpu 옵션 제거
4. 타겟 보드에 gcc를 복사한 후 /opt/bootstrap-gcc/aarch64-pc-linux-gnueabihf/sysroot/usr 폴더로 이동, ln -s lib64 lib 명령을 실행하여 lib64를 lib로 링크
5. glibc (sysroot)를 빌드 후 /opt/arm-gcc/sysroot/usr 폴더로 이동 후 ln -s lib64 lib 명령을 실행하여 lib64를 lib로 링크
6. openssl을 빌드할 때 CC="gcc -s" ../Configure --prefix=$PREFIX linux-aarch64 으로 configure 실행
7. C++ 런타임 등 shared 파일을 찾지 못할경우 export LD_LIBRARY_PATH=/opt/arm-gcc/lib64:/opt/arm-gcc/lib 명령으로 로딩 경로를 지정
8. 타겟보드에서의 gcc configure 명령어 예: ../configure --prefix=/opt/arm-gcc --enable-static --host=$CHOST --build=$CHOST --with-sysroot=$SYSROOT --enable-__cxa_atexit --with-gnu-ld --disable-libssp --disable-multilib --disable-decimal-float --enable-plugins --enable-lto --with-gmp=$PREFIX --with-mpc=$PREFIX --with-mpfr=$PREFIX --without-zstd --disable-libquadmath --disable-libquadmath-support --enable-tls --enable-threads --without-isl --without-cloog --with-abi=lp64 --with-cpu=cortex-a53 --enable-languages=c --enable-shared --disable-libgomp

glibc 빌드 시 hang 걸리는 문제
참조: https://stackoverflow.com/a/77107152
make 4.4에서 발생하는 문제로 적당한 버전으로 make 4.3버전을 빌드하여 시스템 make대신 호출하면 해결 됨

m4-1.4.18-glibc-change-work-around.patch 파일 내용 백업

diff -up m4-1.4.18/lib/fflush.c.orig m4-1.4.18/lib/fflush.c
--- m4-1.4.18/lib/fflush.c.orig	2018-05-02 12:35:59.536851666 +0200
+++ m4-1.4.18/lib/fflush.c	2018-05-02 12:37:02.768958606 +0200
@@ -33,7 +33,7 @@
 #undef fflush
 
 
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
 
 /* Clear the stream's ungetc buffer, preserving the value of ftello (fp).  */
 static void
@@ -72,7 +72,7 @@ clear_ungetc_buffer (FILE *fp)
 
 #endif
 
-#if ! (defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */)
+#if ! (defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */)
 
 # if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT
 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */
@@ -148,7 +148,7 @@ rpl_fflush (FILE *stream)
   if (stream == NULL || ! freading (stream))
     return fflush (stream);
 
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
 
   clear_ungetc_buffer_preserving_position (stream);
 
diff -up m4-1.4.18/lib/fpending.c.orig m4-1.4.18/lib/fpending.c
--- m4-1.4.18/lib/fpending.c.orig	2018-05-02 12:35:32.305806774 +0200
+++ m4-1.4.18/lib/fpending.c	2018-05-02 12:35:44.944827347 +0200
@@ -32,7 +32,7 @@ __fpending (FILE *fp)
   /* Most systems provide FILE as a struct and the necessary bitmask in
      <stdio.h>, because they need it for implementing getc() and putc() as
      fast macros.  */
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   return fp->_IO_write_ptr - fp->_IO_write_base;
 #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
   /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */
diff -up m4-1.4.18/lib/fpurge.c.orig m4-1.4.18/lib/fpurge.c
--- m4-1.4.18/lib/fpurge.c.orig	2018-05-02 12:38:13.586078669 +0200
+++ m4-1.4.18/lib/fpurge.c	2018-05-02 12:38:38.785121867 +0200
@@ -62,7 +62,7 @@ fpurge (FILE *fp)
   /* Most systems provide FILE as a struct and the necessary bitmask in
      <stdio.h>, because they need it for implementing getc() and putc() as
      fast macros.  */
-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   fp->_IO_read_end = fp->_IO_read_ptr;
   fp->_IO_write_ptr = fp->_IO_write_base;
   /* Avoid memory leak when there is an active ungetc buffer.  */
diff -up m4-1.4.18/lib/freadahead.c.orig m4-1.4.18/lib/freadahead.c
--- m4-1.4.18/lib/freadahead.c.orig	2016-12-31 14:54:41.000000000 +0100
+++ m4-1.4.18/lib/freadahead.c	2018-05-02 11:43:19.570336724 +0200
@@ -25,7 +25,7 @@
 size_t
 freadahead (FILE *fp)
 {
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   if (fp->_IO_write_ptr > fp->_IO_write_base)
     return 0;
   return (fp->_IO_read_end - fp->_IO_read_ptr)
diff -up m4-1.4.18/lib/freading.c.orig m4-1.4.18/lib/freading.c
--- m4-1.4.18/lib/freading.c.orig	2018-05-02 12:37:33.970011368 +0200
+++ m4-1.4.18/lib/freading.c	2018-05-02 12:37:59.393054359 +0200
@@ -31,7 +31,7 @@ freading (FILE *fp)
   /* Most systems provide FILE as a struct and the necessary bitmask in
      <stdio.h>, because they need it for implementing getc() and putc() as
      fast macros.  */
-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   return ((fp->_flags & _IO_NO_WRITES) != 0
           || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0
               && fp->_IO_read_base != NULL));
diff -up m4-1.4.18/lib/fseeko.c.orig m4-1.4.18/lib/fseeko.c
--- m4-1.4.18/lib/fseeko.c.orig	2018-05-02 11:44:17.947460233 +0200
+++ m4-1.4.18/lib/fseeko.c	2018-05-02 12:39:49.537216897 +0200
@@ -47,7 +47,7 @@ fseeko (FILE *fp, off_t offset, int when
 #endif
 
   /* These tests are based on fpurge.c.  */
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
   if (fp->_IO_read_end == fp->_IO_read_ptr
       && fp->_IO_write_ptr == fp->_IO_write_base
       && fp->_IO_save_base == NULL)
@@ -123,7 +123,7 @@ fseeko (FILE *fp, off_t offset, int when
           return -1;
         }
 
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
       fp->_flags &= ~_IO_EOF_SEEN;
       fp->_offset = pos;
 #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
diff -up m4-1.4.18/lib/stdio-impl.h.orig m4-1.4.18/lib/stdio-impl.h
--- m4-1.4.18/lib/stdio-impl.h.orig	2016-12-31 14:54:42.000000000 +0100
+++ m4-1.4.18/lib/stdio-impl.h	2018-05-02 11:43:19.570336724 +0200
@@ -18,6 +18,12 @@
    the same implementation of stdio extension API, except that some fields
    have different naming conventions, or their access requires some casts.  */
 
+/* Glibc 2.28 made _IO_IN_BACKUP private.  For now, work around this
+   problem by defining it ourselves.  FIXME: Do not rely on glibc
+   internals.  */
+#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN
+# define _IO_IN_BACKUP 0x100
+#endif
 
 /* BSD stdio derived implementations.  */

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

*
*

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.