본문 바로가기
SW/Linux (Kernel)

Linux From Scratch 개발 노트 5 - 임시 시스템 구축(libstdc++,binutils, gcc)

by FastBench 2024. 8. 30.
반응형

 

참고 

github : https://github.com/NuttyJamie/LinuxFromScratch-for-Korean

 

GitHub - NuttyJamie/LinuxFromScratch-for-Korean: Korean translation of the LFS project.

Korean translation of the LFS project. Contribute to NuttyJamie/LinuxFromScratch-for-Korean development by creating an account on GitHub.

github.com

html 문서 : https://rawcdn.githack.com/NuttyJamie/LinuxFromScratch-for-Korean/88bdabae8abf2fad511b497b0dc676e6ac95b965/9.1/BOOK/HTML/index.html

 

Linux From Scratch

 

rawcdn.githack.com

 

libstdc++ from gcc-9.2.0

Libstdc++은 표준 C++ 라이브러리이다.

libstdc++ 은 C++ 코드를 컴파일할 때 필요하지만(GCC의 일부는 C++로 쓰여졌다), gcc-1단계를 빌드할 때는 설치를 미룰 수 밖에 없었다.  libstdc++ 을 컴파일 하기 위해서는 glibc가 필요했기 때문이다.

 

정리하면,,

libstdc++을 컴파일하기 위해서는 glibc가 필요하므로, glibc를 먼저 컴파일하고 설치한 후, libstdc++을 포함한 나머지 GCC를 빌드했습니다. 따라서 glibc가 설치되기 전에는 GCC의 일부(즉, libstdc++ 관련 부분)를 컴파일하지 않았었다.

 

cd $LFS/sources/gcc-9.2.0
mkdir build
cd build

../libstdc++-v3/configure           \
    --host=$LFS_TGT                 \
    --prefix=/tools                 \
    --disable-multilib              \
    --disable-nls                   \
    --disable-libstdcxx-threads     \
    --disable-libstdcxx-pch         \
    --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/9.2.0

Configure 옵션들의 의미:

--host=...

/usr/bin에 있는 컴파일러 대신 방금 만든 크로스 컴파일러를 사용하도록 지시한다.

--disable-libstdcxx-threads

GCC 1단계가 스레드를 지원하지 않기 때문에 C++ 스레드 라이브러리도 지원되지 않는다.

--disable-libstdcxx-pch

이 단계에서 필요하지 않은 사전 컴파일된 include 파일의 설치를 방지한다.

--with-gxx-include-dir=/tools/$LFS_TGT/include/c++/9.2.0

C++ 컴파일러가 표준 include 파일을 검색하는 위치이다. 일반적으로는 이 정보가 최상위 디렉토리로부터 Libstdc++ configure 옵션으로 자동 전달된다. 때문에 우리는 이 주소를 명시적으로 입력해야 한다.

make
make install

 

 

Binutils 2단계

Binutils 패키지는 링커, 어셈블러 및 객체 파일을 처리하기 위한 기타 도구를 포함한다.

cd $LFS/binutils-2.3.4
mkdir build
cd build

CC=$LFS_TGT-gcc                \
AR=$LFS_TGT-ar                 \
RANLIB=$LFS_TGT-ranlib         \
../configure                   \
    --prefix=/tools            \
    --disable-nls              \
    --disable-werror           \
    --with-lib-path=/tools/lib \
    --with-sysroot

 

새 Configure 옵션들의 의미:

CC=$LFS_TGT-gcc AR=$LFS_TGT-ar RANLIB=$LFS_TGT-ranlib

이것은 실사용할 Binutils의 네이티브 빌드이기 때문에, 이 옵션을 설정하여 빌드 시스템으로 하여금 호스트 시스템이 아닌 크로스 컴파일러(x86_64-lfs-linux-gnu) 와 관련 도구들을 사용하게끔 한다.

--with-lib-path=/tools/lib

Binutils를 컴파일하는 동안 라이브러리 검색 경로를 지정하도록 configure 스크립트에 지시해서 /tools/lib가 링커에 전달되도록 한다. 이렇게 해서 링커가 호스트의 라이브러리 디렉토리를 검색하는 것을 방지할 수 있다.

--with-sysroot

기본(존재하지 않는) sysroot 디렉토리 /tools/$LFS_TGT/sys-root를 정의한다. 링커의 명령줄에 명시된 다른 공유 객체에 필요한 공유 객체를 찾을 때 유용하다. 이러한 객체들은 <sysroot>/etc/ld.so.conf에 나열된 디렉토리에서 검색되고, 찾지 못하면, 링커 검색 경로로 검색된다. 만약 이 옵션이 설정되지 않으면, 호스트의 /etc/ld.so.conf가 사용되고, 그러면 프로그램이 호스트의 라이브러리에 연결될 수 있으며 이는 우리의 목적에 부합하지 않는다.

(이미 gcc 를 빌드할 때, sysroot 을 /mnt/lfs 로 주었는데.. 이를 사용한다는 뜻이다. $LFS_TGT-gcc -v 또는 $LFS_TGT-gcc -print-sysroot 을 통해 확인 할 수 있다.)

make
make install

 

다음 단계에서 링커 '재조정'을 하는데 이를 위한 준비를 한다.

make -C ld clean
make -C ld LIB_PATH=/usr/lib:/lib
cp -v ld/ld-new /tools/bin

Make 인자들의 의미:

-C ld clean

ld 하위 디렉토리에서 컴파일된 모든 파일을 제거한다.

-C ld LIB_PATH=/usr/lib:/lib

ld 하위 디렉토리의 모든 것을 재빌드한다. 명령줄에 LIB_PATH Makefile 변수를 지정하면 임시 도구의 기본값을 무시하고 올바른 최종 경로를 가리킬 수 있다. 이 변수의 값이 링커의 기본 라이브러리 검색 경로이다. 이 준비사항은 다음 장에서 쓰인다.

 

왜?

더보기

1. 링커의 "재조정" 과정 이해

LFS 프로젝트의 이 단계에서는 임시 도구 체인에서 사용하는 링커를 최종 시스템에서 사용할 링커로 조정하기 위한 준비 작업을 하고 있습니다. 이 작업은 새로운 시스템에서 링커가 올바르게 작동할 수 있도록 보장하기 위한 것입니다.

2. LIB_PATH=/usr/lib:/lib의 역할

이 LIB_PATH 설정은 다음 단계에서 수행될 링커의 "재조정" 작업에서 중요한 역할을 합니다.

  • 링커의 기본 경로 확인: 이 과정에서 링커는 기본 라이브러리 경로로 /usr/lib과 /lib을 사용하도록 설정됩니다. 이 경로는 최종 시스템이 완성된 후, 실제로 프로그램들이 참조하게 될 경로입니다.
  • 임시 설정: 여기서 /usr/lib:/lib 경로는 임시 설정일 뿐, 이 단계를 거친 후 LFS 시스템이 구축될 때까지는 아직 이 경로가 참조되지 않습니다. 실제로는 이 과정이 끝난 후, 시스템의 부트스트랩 단계에서 사용될 수 있는 링커를 준비하는 것이 목적입니다.
  • 링커의 최종 경로 설정: 이 설정이 중요한 이유는, LFS가 완성된 후 /tools 디렉터리가 사라지고 나면 최종적으로 시스템이 /usr/lib과 /lib 경로에서 라이브러리를 참조하게 된다는 것입니다. 이 경로들은 LFS 시스템이 완성된 후 실제로 사용될 경로들입니다.

3. 왜 크로스컴파일러의 경로가 아닌가?

여기서 중요한 점은, 이 LIB_PATH 설정이 실제로 사용되기 전에 LFS 시스템의 부트스트랩 과정이 끝난다는 점입니다. ld 링커의 "재조정" 과정이 완료된 후에는, 호스트 시스템의 /usr/lib과 /lib 경로 대신, LFS 시스템이 완성된 후 해당 시스템의 경로로 변경됩니다.

즉, 이 단계에서 설정된 /usr/lib:/lib 경로는 일시적으로 사용되며, 실제로는 이 경로가 최종 시스템의 라이브러리 경로로서 올바르게 작동하도록 링커를 조정하는 역할을 합니다.

결론

LIB_PATH를 /usr/lib:/lib으로 설정하는 것은 최종 LFS 시스템이 완성된 후 사용할 경로를 미리 설정하기 위한 것입니다. 이는 호스트 시스템의 경로를 그대로 사용하기 위한 것이 아니라, 새 시스템이 완성되었을 때 올바른 라이브러리 경로를 사용할 수 있도록 준비하기 위한 임시 설정입니다. 이후 시스템이 완성되면, 실제로는 이 경로들이 LFS 시스템의 일부로 작동하게 됩니다.

 

GCC 2단계

첫 번째 GCC 빌드에서는 몇 가지 내부 시스템 헤더 파일이 설치되었다. 그 중 하나가 limits.h라는 파일인데, 이 파일은 보통 시스템의 limits.h 헤더 파일(즉, /tools/include/limits.h)을 포함한다. 그러나 GCC를 처음 빌드할 당시에는 /tools/include/limits.h가 존재하지 않았기 때문에, 그때 설치된 limits.h는 불완전한 상태였다. 쉽게 말해, 이 파일은 시스템 헤더의 모든 기능을 담고 있지 않고, 독립적으로 일부만 포함된 파일이었다는 것이다.

이런 상태는 임시로 libc를 빌드할 때는 문제가 없었다. 그 당시에는 아주 기본적인 기능만 필요했기 때문이다. 하지만 이제는 GCC를 제대로 빌드하기 위해 전체 내부 헤더가 필요하다. 그래서 이번에는 일반적인 상황에서 GCC 빌드 시스템이 수행하는 것과 동일한 명령을 사용해 내부 헤더의 완전한 버전을 만들어야 한다. 이를 통해 GCC가 모든 필요한 시스템 헤더를 올바르게 포함할 수 있게 되는 것이다.

cat gcc/limitx.h gcc/glimits.h gcc/limity.h > \
  `dirname $($LFS_TGT-gcc -print-libgcc-file-name)`/include-fixed/limits.h

 

이전에 했던 것 처럼, 동적 링커 위치와 lib 이름을 변경한다

for file in gcc/config/{linux,i386/linux{,64}}.h
do
  cp -uv $file{,.orig}
  sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&@g' \
      -e 's@/usr@/tools@g' $file.orig > $file
  echo '
#undef STANDARD_STARTFILE_PREFIX_1
#undef STANDARD_STARTFILE_PREFIX_2
#define STANDARD_STARTFILE_PREFIX_1 "/tools/lib/"
#define STANDARD_STARTFILE_PREFIX_2 ""' >> $file
  touch $file.orig
done
case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
  ;;
esac

 

이후 필요한 패키지를 준비한다

tar -xf ../mpfr-4.0.2.tar.xz
mv -v mpfr-4.0.2 mpfr
tar -xf ../gmp-6.2.0.tar.xz
mv -v gmp-6.2.0 gmp
tar -xf ../mpc-1.1.0.tar.gz
mv -v mpc-1.1.0 mpc

 

glibc-2.31 과의 호환성 문제를 해결한다.

sed -e '1161 s|^|//|' \
    -i libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
CC=$LFS_TGT-gcc                                    \
CXX=$LFS_TGT-g++                                   \
AR=$LFS_TGT-ar                                     \
RANLIB=$LFS_TGT-ranlib                             \
../configure                                       \
    --prefix=/tools                                \
    --with-local-prefix=/tools                     \
    --with-native-system-header-dir=/tools/include \
    --enable-languages=c,c++                       \
    --disable-libstdcxx-pch                        \
    --disable-multilib                             \
    --disable-bootstrap                            \
    --disable-libgomp

Configure 옵션들의 의미:

--enable-languages=c,c++

C와 C++ 컴파일러가 모두 빌드되도록 한다.

--disable-libstdcxx-pch

libstdc++를 위해 사전 컴파일된 헤더(PCH)를 빌드하지 않도록 한다. 디스크 공간을 많이 차지하며, 우리에게 쓸모가 없다.

--disable-bootstrap

네이티브 GCC 빌드는 "부트스트랩" 빌드가 기본값이다. 이것은 단순히 GCC를 컴파일하는 것이 아니라 여러번 컴파일한다. 1차 컴파일 결과를 활용해 2차 빌드를 한 뒤, 3차 컴파일을 한다. 두 번째와 세 번째 반복을 거쳐 제스스로 완전히 복제가 가능한 지 비교한다. 이를 통해 정확하게 컴파일됐는지의 여부도 알 수 있다. 그러나 LFS 빌드 과정은 매번 부트스트랩할 필요 없이 견고한 컴파일러를 제공할 것이다.

이후 아래의 명령어를 통해 잘 설치 되었는지 확인한다.

echo 'int main(){}' > dummy.c
cc dummy.c
readelf -l a.out | grep ': /tools'

 

[Requesting program interpreter: /tools/lib64/ld-linux-x86-64.so.2]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

댓글