6.25. GCC-9.2.0

GCC 패키지는 C, C++ 컴파일러가 들어있는 GNU 컴파일러 컬렉션을 포함하고 있다.

예상 빌드 시간: 88 SBU (테스트 포함)
필요 디스크 공간: 4.2 GB

6.25.1. GCC 설치

x86_64에서 빌드하고 있다면, 64비트 라이브러리의 기본 디렉토리 이름을 lib로 변경하라:

case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
  ;;
esac

Gcc 2단계에서처럼, Glibc-2.31에서 언급된 문제를 수정한다:

sed -e '1161 s|^|//|' \
    -i libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc

GCC 문서는 전용 빌드 디렉토리에 GCC를 구축할 것을 권장한다:

mkdir -v build
cd       build

GCC 컴파일을 준비한다:

SED=sed                               \
../configure --prefix=/usr            \
             --enable-languages=c,c++ \
             --disable-multilib       \
             --disable-bootstrap      \
             --with-system-zlib

다른 언어의 경우는 아직 사용할 수 없는 몇 가지 전제 조건이 필요하다는 점을 참고하라. GCC에서 지원되는 모든 언어를 빌드하는 방법은 BLFS 책을 참고하라.

Configure 매개 변수들의 의미:

SED=sed

/tools/bin/sed로 경로가 하드코딩되는 것을 막는다.

--with-system-zlib

GCC가 자체적으로 갖는 내부 Zlib 라이브러리 대신 시스템에 설치된 Zlib 라이브러리에 링크되도록 설정한다.

패키지를 컴파일한다:

make
[중요]

중요

이 절의 GCC 테스트 스위트는 매우 중요하다. 어떤 상황에서도 건너뛰지 않도록 하라.

GCC 테스트 스위트 중의 한 테스트 세트는 스택을 많이 차지하는 것으로 알려져 있으므로 테스트를 실행하기 전에 스택 크기를 늘린다:

ulimit -s 32768

권한 없는 유저로 결과를 테스트하되 오류 발생 시 중단하지 않도록 하라:

chown -Rv nobody . 
su nobody -s /bin/bash -c "PATH=$PATH make -k check"

테스트 스위트 결과에 대한 요약을 확인하려면 다음을 실행하라:

../contrib/test_summary

요약만을 보려면, 위 결과를 grep -A7 Summ로 파이핑하라.

결과는 http://www.linuxfromscratch.org/lfs/build-logs/9.1/https://gcc.gnu.org/ml/gcc-testresults/에 있는 결과와 비교할 수 있다.

get_time과 관련된 6개의 테스트가 실패하는 것으로 알려져 있다. 이것들은 명백히 en_HK 로케일과 관련이 있다.

experimental/net에서 lookup.cc와 reverse.cc라는 두 테스트는 /etc/hosts와 iana-etc가 필요해서 LFS chroot 환경에서 실패하는 것으로 알려져 있다.

pr57193.c와 pr90178.c라는 두 가지 테스트가 실패하는 것으로 알려져 있다.

예기치 못한 실패가 더 있을 수도 있다. GCC 개발자들은 보통 이런 문제들을 알고 있지만 아직 해결하지 못했다. 위의 URL의 테스트 결과와 크게 다르지 않는 한, 계속 진행해도 무방하다.

패키지를 설치하고 필요하지않은 디렉토리를 삭제한다:

make install
rm -rf /usr/lib/gcc/$(gcc -dumpmachine)/9.2.0/include-fixed/bits/

GCC 빌드 디렉토리는 현재 nobody가 소유하며 설치된 헤더 디렉토리(와 그 내용)의 소유권은 불명확할 것이다. 소유권을 root 유저 및 그룹으로 변경하라:

chown -v -R root:root \
    /usr/lib/gcc/*linux-gnu/9.2.0/include{,-fixed}

"역사적인" 이유로 FHS에서 요구하는 심볼릭 링크를 생성한다.

ln -sv ../usr/bin/cpp /lib

많은 패키지들은 cc라는 이름으로 C 컴파일러를 호출한다. 이러한 패키지들에 대해 올바르게 동작할 수 있도록 심볼릭 링크를 생성하라:

ln -sv gcc /usr/bin/cc

링크 시간 최적화(Link Time Optimization, LTO)를 사용하여 프로그램을 빌드할 수 있도록 호환성 심볼릭 링크를 추가하라:

install -v -dm755 /usr/lib/bfd-plugins
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/9.2.0/liblto_plugin.so \
        /usr/lib/bfd-plugins/

이제 우리의 최종 툴체인(toolchain)이 자리를 잡았으니 컴파일과 링크가 예상대로 잘 될 수 있도록 다시 한 번 확인하는 것이 중요하다. 따라서 앞 장에서 했던 것과 같은 온전성 검사를 수행한다:

echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'

마지막 명령의 출력은(플랫폼에 따른 동적 링커 이름의 차이는 무관) 다음과 같으며 오류가 없어야 한다:

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

이제 올바른 시작 파일을 사용하도록 설정되었는지 확인하라:

grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log

이 명령의 출력은 다음과 같아야 한다:

/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crtn.o succeeded

당신의 시스템 아키텍쳐에 따라 위의 내용은 약간 다를 수 있는데, 대개 /usr/lib/gcc 다음에 나오는 디렉토리 이름이 차이난다. 여기서 중요하게 봐야 할 것은 gcc/usr/lib 디렉토리에서 crt*.o 파일 3개를 모두 찾아내었는지다.

컴파일러가 올바른 헤더 파일을 검색하는지 확인하라:

grep -B4 '^ /usr/include' dummy.log

이 명령은 다음과 같은 결과를 출력해야 한다:

#include <...> search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include-fixed
 /usr/include

다시 말하지만, 당신의 대상 트리플렛 뒤의 디렉토리 이름은 아키텍쳐에 따라 위와 다를 수 있다.

그 다음, 새 링커가 올바른 검색 경로와 함께 사용되고 있는지 확인하라:

grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'

'-linux-gnu' 요소가 있는 경로에 대한 참조는 무시해도 되지만, 나머지 결과는 다음과 같아야 한다:

SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");

32비트 시스템에서는 디렉토리 몇 개가 다른 것을 볼 수 있다. 예를 들어, i686 시스템에서는 출력이 다음과 같다:

SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");

다음으로 올바른 libc를 사용하고 있는지 확인하라:

grep "/lib.*/libc.so.6 " dummy.log

이 명령의 출력은 다음과 같아야 한다:

attempt to open /lib/libc.so.6 succeeded

마지막으로 GCC가 올바른 동적 링커를 사용하는지 확인하라:

grep found dummy.log

이 명령의 출력은 다음과 같아야 한다(플랫폼에 따른 동적 링커 이름의 차이는 무관):

found ld-linux-x86-64.so.2 at /lib/ld-linux-x86-64.so.2

만약 출력이 위와 같이 나타나지 않거나 출력이 전혀 없다면, 무언가 심각하게 잘못된 것이다. 이전 단계를 조사하고 추적해서 문제가 어디에 있는지 파악하고 수정하라. 가장 유력한 원인은 spec 파일 조정에 이상이 생겼기 때문이다. 어떤 문제든 계속 진행하기 전에 해결해야 할 것이다.

모든 것이 올바르게 작동하면 테스트 파일을 정리하라:

rm -v dummy.c a.out dummy.log

마지막으로, 위치가 잘못된 파일을 이동하라:

mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib

6.25.2. GCC의 내용

설치된 프로그램들: c++, cc (gcc로 링크), cpp, g++, gcc, gcc-ar, gcc-nm, gcc-ranlib, gcov, gcov-dump, gcov-tool
설치된 라이브러리들: libasan.{a,so}, libatomic.{a,so}, libcc1.so, libgcc.a, libgcc_eh.a, libgcc_s.so, libgcov.a, libgomp.{a,so}, libitm.{a,so}, liblsan.{a,so}, liblto_plugin.so, libquadmath.{a,so}, libssp.{a,so}, libssp_nonshared.a, libstdc++.{a,so}, libstdc++fs.a, libsupc++.a, libtsan.{a,so}, libubsan.{a,so}
설치된 디렉토리들: /usr/include/c++, /usr/lib/gcc, /usr/libexec/gcc, /usr/share/gcc-9.2.0

요약

c++

C++ 컴파일러

cc

C 컴파일러

cpp

C 전처리기; 소스 파일에서 #include, #define 등의 유사한 구문들을 확장하기 위해 컴파일러에 의해 사용된다

g++

C++ 컴파일러

gcc

C 컴파일러

gcc-ar

명령줄에 플러그인을 추가하는 ar 래퍼(wrapper). 이 프로그램은 "링크 시간 최적화"를 추가하는 데만 사용되며 기본 빌드 옵션에서는 유용하지 않음

gcc-nm

명령줄에 플러그인을 추가하는 nm 래퍼. 이 프로그램은 "링크 시간 최적화"를 추가하는 데만 사용되며 기본 빌드 옵션에서는 유용하지 않음

gcc-ranlib

명령줄에 플러그인을 추가하는 ranlib 래퍼. 이 프로그램은 "링크 시간 최적화"를 추가하는 데만 사용되며 기본 빌드 옵션에서는 유용하지 않음

gcov

적용 범위 테스트 도구; 최적화의 영향이 가장 효과적인 지점을 파악하기 위해 프로그램을 분석하는데 사용됨

gcov-dump

오프라인 gcda 및 gcno 프로필 덤프 도구

gcov-tool

오프라인 gcda 프로필 처리 도구

libasan

Address Sanitizer 런타임 라이브러리

libatomic

GCC atomic 내장 런타임 라이브러리

libcc1

C 전처리 라이브러리

libgcc

gcc에 대한 런타임 라이브러리 포함

libgcov

이 라이브러리는 GCC의 프로파일링이 활성화될 때 프로그램에 링크된다.

libgomp

C/C++와 포트란에서 멀티 플랫폼 공유 메모리 병렬 프로그래밍을 위한 OpenMP API의 GNU 구현

liblsan

Leak Sanitizer 런타임 라이브러리

liblto_plugin

컴파일 단위 전체에 걸쳐 최적화를 수행할 수 있도록 하는 GCC의 링크 시간 최적화(Link Time Optimization, LTO) 플러그인

libquadmath

GCC Quad Precision 수학 라이브러리 API

libssp

GCC의 stack-smashing 보호 기능을 지원하는 루틴 포함

libstdc++

표준 C++ 라이브러리

libstdc++fs

ISO/IEC TS 18822:2015 파일 시스템 라이브러리

libsupc++

C++ 프로그래밍 언어 지원 루틴 제공

libtsan

The Thread Sanitizer 런타임 라이브러리

libubsan

The Undefined Behavior Sanitizer 런타임 라이브러리