5.2. 툴체인 기술 노트

이 절에서는 전체 빌드 방법에 대한 몇 가지 해석과 기술적 세부 사항을 설명한다. 이 절의 모든 것을 당장 이해할 필요는 없다. 이 정보들의 대부분은 실제 빌드를 하고 나서야 더 명확해질 것이다. 이 절은 진행 중에 언제든지 참고하라.

5장의 전반적인 목표는 앞서 언급한 호스트 시스템으로부터 분리할 수 있는 도구들을 포함하는 임시 공간을 구축하는 것이다. chroot를 사용함으로써, 나머지 장에 있는 명령들이 이 환경에 포함되어 대상 LFS 시스템을 깨끗하고 문제없이 구축할 수 있다. 빌드 절차는 새로운 독자를 위해 위험을 최소화하고 동시에 가장 교육적인 가치들을 제공하도록 설계되었다.

[참고]

참고

계속 진행하기 전에, 작업 중인 플랫폼의 명칭, 흔히 대상 트리플렛(target triplet)이라 칭하는 것을 알고 있어야 한다. 대상 트리플렛의 명칭을 구하는 간단한 방법은 많은 패키지의 소스와 함께 제공되는 config.guess 스크립트를 실행하는 것이다. Binutils 소스를 압축 해제하고 이 스크립트를 실행하라: ./config.guess 그리고 출력 결과를 기록하라. 예를 들어 32비트 인텔 프로세서의 경우 출력은 i686-pc-linux-gnu가 된다. 64비트 시스템에서는 x86_64-pc-linux-gnu일 것이다.

추가로 흔히 동적 로더(Binutils의 일부인 표준 링커 ld와 혼동하지 말라)라 불리는, 플랫폼의 동적 링커의 이름도 알고 있어야 한다. Glibc가 제공하는 동적 링커는 프로그램이 필요로 하는 공유 라이브러리를 찾아 불러오고, 실행할 프로그램을 준비한 후 실행한다. 32비트 인텔 시스템의 동적 링커 이름은 ld-linux.so.2(64비트 시스템의 경우 ld-linux-x86-64.so.2)일 것이다. 동적 링커의 이름을 알아내는 확실한 방법은 호스트 시스템에서 아무 바이너리나 검사하는 것이다: readelf -l <바이너리의 이름> | grep interpreter 을 실행하고 출력 결과를 기록하라. 모든 플랫폼을 다루는 신뢰할만한 레퍼런스는 Glibc 소스 트리의 최상위에 있는 shlib-versions 파일에 있다.

5장의 빌드 방법 작동 방식에 대한 몇 가지 핵심 기술적 요점:

GCC와 Glibc의 configure를 실행하면 어셈블러와 링커에서 다양한 기능 테스트를 거쳐 어떤 소프트웨어 기능을 활성화할지 결정하기 때문에 (어셈블러와 링커들이 포함된) Binutils를 먼저 설치한다. 이것은 보기보다 중요하다. 잘못 설정된 GCC나 Glibc는 툴체인의 미묘한 고장으로 이어질 수 있으며, 이러면 그 영향이 전체 시스템 빌드가 끝날 때까지 나타나지 않을 수 있다. 보통 테스트 스위트 실패는 이미 너무 많은 작업을 수행한 채로 뒤늦게 알아채기 전에 이 오류를 알려준다.

Binutils는 어셈블러와 링커를 /tools/bin/tools/$LFS_TGT/bin 두 위치에 설치한다. 한 위치의 도구는 다른 위치에 있는 도구로의 하드링크이다. 링커는 라이브러리 검색 순서가 중요하다. 자세한 정보는 ld--verbose 플래그를 붙여 실행하면 얻을 수 있다. 예를 들어 ld --verbose | grep SEARCH는 현재 검색 경로와 그 순서를 보여준다. 더미 프로그램을 컴파일하고 링커에 --verbose 옵션을 전달하면 어떤 파일들이 ld에 의해 링크되었는지 알 수 있다. 예를 들어 gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded은 링크 중에 성공적으로 열린 모든 파일들을 보여줄 것이다.

다음으로 설치될 패키지는 GCC이다. configure 실행 중에 볼 수 있는 예시이다:

checking what assembler to use... /tools/i686-lfs-linux-gnu/bin/as
checking what linker to use... /tools/i686-lfs-linux-gnu/bin/ld

이것은 위에 언급한 이유때문에 중요하다. 이는 또한 GCC의 configure 스크립트가 어떤 도구를 사용할지 찾느라 PATH 디렉토리를 검색하지 않는다는 것을 알 수 있다. 단, gcc 자체의 실제 작동 중에는 반드시 동일한 검색 경로가 사용되는 것은 아니다. gcc가 어떤 표준 링커를 사용할지 알아보려면 gcc -print-prog-name=ld를 실행하라.

더미 프로그램을 컴파일하면서 gcc-v 명령줄 옵션을 전달하면 자세한 정보를 얻을 수 있다. 예를 들어 gcc -v dummy.cgcc에 포함된 검색 경로 및 순서, 전처리기, 검파일, 어셈블리 단계에 대한 자세한 정보를 표시한다.

다음으로 설치될 것은 순수한 리눅스 API 헤더이다. 이를 통해 표준 C 라이브러리(Glibc)가 리눅스 커널에서 제공할 기능들과 상호 작용할 수 있다.

다음으로 설치될 패키지는 Glibc이다. Glibc 빌드에 있어 가장 중요한 것은 컴파일러, 바이너리 도구, 커널 헤더들이다. Glibc는 항상 configure 스크립트에 전달되는 --host 매개 변수에 관련된 컴파일러를 사용하기 때문에, 컴파일러는 대게 문제가 되지 않는다; 이 책의 컴파일러는 i686-lfs-linux-gnu-gcc이다. 바이너리 도구와 커널 헤더들의 경우는 조금 더 복잡하다. 그러니 위험을 무릅쓰지 말고 올바른 선택을 하려면 사용 가능한 configure 설정을 사용하라. configure 실행을 마친 뒤, glibc-build 디렉토리에서 config.make 파일을 열어 모든 중요한 세부사항을 확인하라. CC="i686-lfs-gnu-gcc"로 어떤 바이너리 도구들을 사용할지 지정하고 -nostdinc-isystem 플래그로 컴파일러의 include 탐색 경로를 정한다. 이 항목들로부터 Glibc 패키지의 중요한 점을 알 수 있다. Glibc 패키지는 빌드 환경에 있어서 매우 독립적이고 일반적으로 툴체인 기본값에 의존하지 않는다.

새로 빌드된 Binutils 2단계에서는 --with-lib-path configure 옵션을 활용하여 ld의 라이브러리 탐색 경로를 지정할 수 있다.

GCC의 재구축을 위해서는 새로운 동적 링커를 사용하도록 소스도 수정해야 한다. 그렇게 하지 않으면 GCC 프로그램 안에 호스트 시스템의 /lib 디렉토리에 있는 동적 링커의 이름이 포함되어 호스트에서 독립하려는 목표를 달성할 수 없다. 이 때부터 핵심 툴체인은 독립적으로 작동할 수 있게 된다. 나머지 5장 패키지는 모두 /tools의 새로운 Glibc를 기반으로 구축된다.

6장에서 chroot 환경에 들어가면, 위에서 언급한대로 독립적으로 작동할 수 있는 덕에 Glibc 패키지가 가장 먼저 설치된다. 이 Glibc가 /usr에 설치되고 나면 툴체인 기본값을 신속히 바꾸고 나머지 목표 LFS 시스템 구축을 진행할 것이다.