6. Installing Basic System Software (2)
- 6.7. Linux-3.19 API Headers
- 6.8. Man-pages-3.79
- 6.9. Glibc-2.21
- 6.10. Adjusting the Toolchain
- 6.11. Zlib-1.2.8
- 6.12. File-5.22
- 6.13. Binutils-2.25
- 6.14. GMP-6.0.0a
- 6.15. MPFR-3.1.2
- 6.16. MPC-1.0.2
- 6.17. GCC-4.9.2
6.7. Linux-3.19 API Headers
시스템의C 라이브러리(LFS의Glibc)가 사용하는 API 를 위해서
리눅스 커널소스의 헤더파일을 사용해야한다.
- 커널 소스의 이전 작업 내용 삭제
$ make mrproper
- 헤더파일 추출
$ make INSTALL_HDR_PATH=dest headers_install
$ find dest/include \( -name .install -o -name ..install.cmd \) -delete
$ cp -rv dest/include/* /usr/include
6.8. Man-pages-3.79
- man page 설치
$ make install
6.9. Glibc-2.21
Glibc 는 아래의 일을 할 수 있는 기본 C 루틴을 제공.
allocating memory, searching directories, opening and closing files,
reading and writing files, string handling, pattern matching, arithmetic 등.
6.9.1. Installation of Glibc
- 패치 적용
$ patch -Np1 -i ../glibc-2.21-fhs-1.patch
FHS-compliant관련 이슈 패치임.
패치적용은 별거 아니고 해당 패키지에 필요한 패치들 source레벨로 그냥 적용하는것임.
- 32-bit arch에 영향을 주는 Regression 수정
$ sed -e '/ia32/s/^/1:/' \
-e '/SSE2/s/^1://' \
-i sysdeps/i386/i686/multiarch/mempcpy_chk.S
sed 유틸리티로 memcpy_chk.S 파일 내용 수정
- 빌드 디렉토리 생성
$ mkdir -v ../glibc-build
$ cd ../glibc-build
- Glibc confirue 설정 makefile 생성
$ ../glibc-2.21/configure \
--prefix=/usr \
--disable-profile \
--enable-kernel=2.6.32 \
--enable-obsolete-rpc
(에러 발생)
checking for nm... nm configure: error: *** These critical programs are missing or too old: gawk *** Check the INSTALL file for required versions.
(원인)
/tools 및에 gawk가 없었음.
5장에서 설치를 안했었다.
다시 lfs로 로그인 해서 /source/gawk 경로가서 5장대로 make ,make install하면됨.
(반드시 lfs계정으로 configure, make, make check까지만 수행)
그러나 5장 마지막에 /tools 의 권한을 root로 바꿨다.
lfs 로 로그인하면 make install에서 권한이 없어서 /tools 및으로 gawk바이너리를 복사를 못함.
그래서 make install만 jihuun계정으로 sudo로 해야함.
그런데 lfs계정으로는 sudo가 안돼서 jihuun계정에서 sudo로 make install함.(주의) tools밑의 temp유틸리티는 반드시 lfs계정으로 빌드해야함.
이유는 gawk를 빌드할때 lfs계정으로하면 PATH가 tools/bin이 우선이기때문에
tools/밑의 유틸리티를 이용해 빌드한다.
그렇지않으면 호스트 시스템의 유틸리티와 라이브러리를 사용해 빌드하기때문에
gawk를 분명/tools/bin/gawk으로 설치했는데도 자꾸 gawk가 없다고 나옴.
- ldd했을때 라이브러리 자체가/tools/lib 으로 이용.
lfs@jihuun:/mnt/lfs/sources/gawk-4.1.1$ ldd /tools/bin/gawk linux-vdso.so.1 (0x00007fffe8bfe000) libdl.so.2 => /tools/lib/libdl.so.2 (0x00007f624089b000) libm.so.6 => /tools/lib/libm.so.6 (0x00007f6240596000) libc.so.6 => /tools/lib/libc.so.6 (0x00007f62401f3000) /tools/lib64/ld-linux-x86-64.so.2 (0x00007f6240a9f000)
아닌듯 계정마다 공유라이브러리 위치는 달랐음.
- 패키지 빌드
$ make
- Test suite 실행
$ make check
이제부터 test suite실행을 반드시 해봐야한다.
아래와 같이 몇몇 failure가 발생하는데 관계없음.
공식 테스트 로그 확인FAIL: posix/tst-getaddrinfo4 FAIL: posix/tst-getaddrinfo5 Summary of test results: 2 FAIL 2183 PASS 199 XFAIL 3 XPASS Makefile:321: recipe for target 'tests' failed make[1]: *** [tests] Error 1 make[1]: Leaving directory '/sources/glibc-2.21' Makefile:9: recipe for target 'check' failed make: *** [check] Error 2
- 필요한 파일 생성
$ touch /etc/ld.so.conf
Glibc가 설치될때 위의 파일이 없으면 경고줌.
- 패키지 인스톨
$ make install
- nscd.conf 파일 생성
$ cp -v ../glibc-2.21/nscd/nscd.conf /etc/nscd.conf
$ mkdir -pv /var/cache/nscd
(찾아보기)
/etc/nscd.conf 의 역할?
- Locale 설정
mkdir -pv /usr/lib/locale
localedef -i cs_CZ -f UTF-8 cs_CZ.UTF-8
localedef -i de_DE -f ISO-8859-1 de_DE
localedef -i de_DE@euro -f ISO-8859-15 de_DE@euro
localedef -i de_DE -f UTF-8 de_DE.UTF-8
localedef -i en_GB -f UTF-8 en_GB.UTF-8
localedef -i en_HK -f ISO-8859-1 en_HK
localedef -i en_PH -f ISO-8859-1 en_PH
localedef -i en_US -f ISO-8859-1 en_US
localedef -i en_US -f UTF-8 en_US.UTF-8
localedef -i es_MX -f ISO-8859-1 es_MX
localedef -i fa_IR -f UTF-8 fa_IR
localedef -i fr_FR -f ISO-8859-1 fr_FR
localedef -i fr_FR@euro -f ISO-8859-15 fr_FR@euro
localedef -i fr_FR -f UTF-8 fr_FR.UTF-8
localedef -i it_IT -f ISO-8859-1 it_IT
localedef -i it_IT -f UTF-8 it_IT.UTF-8
localedef -i ja_JP -f EUC-JP ja_JP
localedef -i ru_RU -f KOI8-R ru_RU.KOI8-R
localedef -i ru_RU -f UTF-8 ru_RU.UTF-8
localedef -i tr_TR -f UTF-8 tr_TR.UTF-8
localedef -i zh_CN -f GB18030 zh_CN.GB18030
localedef 유틸리티로 각 locale이 설치됨.(찾아보기)
localedef 명령어
- 모든 locale설치
$ make localedata/install-locales
6.9.2. Configuring Glibc
- /etc/nsswitch.conf파일 생성
$ cat > /etc/nsswitch.conf << "EOF"
## Begin /etc/nsswitch.conf
passwd: files
group: files
shadow: files
hosts: files dns
networks: files
protocols: files
services: files
ethers: files
rpc: files
## End /etc/nsswitch.conf
EOF
(찾아보기)
/etc/nsswitch.conf 의 역할은?
- timezone데이터 설치
$ tar -xf ../tzdata2015a.tar.gz
$ ZONEINFO=/usr/share/zoneinfo
$ mkdir -pv $ZONEINFO/{posix,right}
$ for tz in etcetera southamerica northamerica europe africa antarctica \
asia australasia backward pacificnew systemv; do
zic -L /dev/null -d $ZONEINFO -y "sh yearistype.sh" ${tz}
zic -L /dev/null -d $ZONEINFO/posix -y "sh yearistype.sh" ${tz}
zic -L leapseconds -d $ZONEINFO/right -y "sh yearistype.sh" ${tz}
$ done
$ cp -v zone.tab zone1970.tab iso3166.tab $ZONEINFO
$ zic -d $ZONEINFO -p America/New_York
$ unset ZONEINFO
- local time zone설정
$ tzselect
대화식으로 시간 zone설정
Then create the /etc/localtime file by running:
- /etc/localtime파일 생성
$ cp -v /usr/share/zoneinfo/<xxx> /etc/localtime
는 설치된 이름으로 변경
(찾아보기)
/etc/localtime의 역할은?
6.9.3. Configuring the Dynamic Loader
(찾아보기)
dynamic loader 와 dymaic linker의 차이?
dynamic loader : 프로그램이 실행된 이후에 필요한 라이브러리나 바이너리를 메모리에 올려주는 역할?
dymaic linker: runtime에 필요한 공유라이브러리를 메모리에 올려주고 link해주는 운영체제의 한 기능?
static linker: 컴파일 타임에 라이브러리 포함?
다시조사..
- /etc/ld.so.conf 생성
$ cat > /etc/ld.so.conf << "EOF"
## Begin /etc/ld.so.conf
/usr/local/lib
/opt/lib
$ EOF
디폴트 dynamic loader는(/lib/ld-linux.so.2) /lib 그리고 /usr/lib 에서 찾는다.
그러나 만약 위의 두 경로가 아닌 다른곳에 라이브러리가 있다면,
/etc/ld.so.conf 에 적어줘야한다.
- 라이브러리 path추가
$ cat >> /etc/ld.so.conf << "EOF"
## Add an include directory
include /etc/ld.so.conf.d/*.conf
$ EOF
$ mkdir -pv /etc/ld.so.conf.d
6.9.4. Contents of Glibc
빌드 생성물 참고. 많음.
http://linuxfromscratch.org/lfs/view/stable/chapter06/glibc.html
6.10. Adjusting the Toolchain
C 라이브러리가 설치 되었으므로 이전에 임시로 사용했던(/tools) 라이브러리에서
새 경로로 path지정.
- linker 교체
$ mv -v /tools/bin/{ld,ld-old}
$ mv -v /tools/$(gcc -dumpmachine)/bin/{ld,ld-old}
$ mv -v /tools/bin/{ld-new,ld}
$ ln -sv /tools/bin/ld /tools/$(gcc -dumpmachine)/bin/ld
- 새 linker를 가리키도록 Gcc spec파일 수정
$ gcc -dumpspecs | sed -e 's@/tools@@g' \
-e '/\*startfile_prefix_spec:/{n;s@.*@/usr/lib/ @}' \
-e '/\*cpp:/{n;s@$@ -isystem /usr/include@}' > \
`dirname $(gcc --print-libgcc-file-name)`/specs
- 빌드 테스트로 dynamic linker 위치 확인
$ echo 'main(){}' > dummy.c
$ cc dummy.c -v -Wl,--verbose &> dummy.log
$ readelf -l a.out | grep ': /lib'
결과를 아래와 같아야함.
[Requesting program interpreter: /lib/ld-linux.so.2]
- Now make sure that we are setup to use the correct startfiles
$ grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log
결과는 아래와 같아야함.
/usr/lib/crt1.o succeeded /usr/lib/crti.o succeeded /usr/lib/crtn.o succeeded
- 컴파일러가 올바른 헤더파일을 찾는지 확인
$ grep -B1 '^ /usr/include' dummy.log
결과는 아래와 같아야함.
##include <...> search starts here: /usr/include
- 새로운 linker가 올바른 탐색 path에 존재하는지 확인
$ grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
결과는 아래와 같아야함.
SEARCH_DIR("/usr/lib") SEARCH_DIR("/lib");
- 올바른 libc를 사용하는지 확인
$ grep "/lib.*/libc.so.6 " dummy.log
결과는 아래와 같아야함.
attempt to open /lib/libc.so.6 succeeded
64비트 시스템에서는 /lib64/임.
- 마지막으로 gcc가 정확한 dynamic linker를 사용하는지 확인
$ grep found dummy.log
결과는 아래와 같아야함.
found ld-linux.so.2 at /lib/ld-linux.so.2
- 모두 정상이라면 아래파일 제거
$ rm -v dummy.c a.out dummy.log
6.11. Zlib-1.2.8
6.11.1. Installation of Zlib
몇 프로그램에서 사용하는 압축/해제 루틴을 포함함.
- Prepare Zlib for compilation
$ ./configure --prefix=/usr
--profix=/usr 로 변경되었다는 점 주의
- Compile the package
$ make
- To test the results
$ make check
- Install the package
$ make install
- 공유 라이브러리는 /lib으로 옮겨져야함.
$ mv -v /usr/lib/libz.so.* /lib
$ ln -sfv ../../lib/$(readlink /usr/lib/libz.so) /usr/lib/libz.so
그리고 결과 파일인 .so파일도 /usr/lib/으로 링크시킴.
(찾아보기)
/usr/lib /lib 차이?
6.11.2. Contents of Zlib
설치되는 라이브러리
libz.{a,so}
(찾아보기)
libz란?
Contains compression and decompression functions used by some programs
6.12. File-5.22
6.12.1. Installation of File
- Prepare File for compilation
$ ./configure --prefix=/usr
- Compile the package
$ make
- To test the results
$ make check
- Install the package
$ make install
6.12.2. Contents of File
Installed programs: file
Installed library: libmagic.so
6.13. Binutils-2.25
오브젝트 파일을 다루기위한 linker, assembler, other tool들을 포함.
Verify that the PTYs are working properly inside the chroot environment
by performing a simple test:
- chroot환경에서 PTY가 적절하게 동작하는지 확인
$ expect -c "spawn ls"
결과는 아래와 같아야 함.
spawn ls
만약 결과가 아래와 같이 나오면 안됨.
The system has no more ptys. Ask your system administrator to create more.
(찾아보기)
PTY란?
- 빌드 디렉토리 생성
$ mkdir -v ../binutils-build
$ cd ../binutils-build
- Prepare 빌드
$ ../binutils-2.25/configure --prefix=/usr \
--enable-shared \
--disable-werror
- 컴파일
$ make tooldir=/usr
- test suite
$ make -k check
- 패키지 설치
$ make tooldir=/usr install
(찾아보기)
여기서 설치한 링커랑 위에서 설치한 dynamic 링커랑 뭐가 다름?
dynamic loader?
6.14. GMP-6.0.0a
GMP패키지는 math라이브러리를 포함함.
- Prepare GMP for compilation:
$ ./configure --prefix=/usr \
--enable-cxx \
--docdir=/usr/share/doc/gmp-6.0.0a
The meaning of the new configure options:
- 컴파일, HTML documentation도 생성
$ make
$ make html
- Test suite
$ make check 2>&1 | tee gmp-check-log
- 아래 테스트가 통화하는지 확인
$ awk '/tests passed/{total+=$2} ; END{print total}' gmp-check-log
- 설치
$ make install
$ make install-html
6.15. MPFR-3.1.2
MPFR패키지는 functions for multiple precision math 를 포함.
6.15.1. Installation of MPFR
- 버그 패치 적용
$ patch -Np1 -i ../mpfr-3.1.2-upstream_fixes-3.patch
- Prepare MPFR for compilation
$ ./configure --prefix=/usr \
--enable-thread-safe \
--docdir=/usr/share/doc/mpfr-3.1.2
- 빌드
$ make
$ make html
- Test suite
$ make check
- 패키지 설치
$ make install
$ make install-html
$
6.16. MPC-1.0.2
복잡한 math function을 포함하는 패키지
6.16.1. Installation of MPC
- Prepare MPC for compilation
$ ./configure --prefix=/usr --docdir=/usr/share/doc/mpc-1.0.2
- 빌드
$ make
$ make html
- Test suite
$ make check
- 패키지 설치
$ make install
$ make install-html
6.17. GCC-4.9.2
gcc 패키지는 C, C++ 컴파일러를 포함하는 GNU 컴파일러 모음이다.
- 빌드 디렉토리 생성
$ mkdir -v ../gcc-build
$ cd ../gcc-build
(주의) chap4에서 만들었던 gcc-build/가 지워져있는지 확인
- gcc빌드 준비
$ SED=sed \
$ ../gcc-4.9.2/configure \
--prefix=/usr \
--enable-languages=c,c++ \
--disable-multilib \
--disable-bootstrap \
--with-system-zlib
- 빌드
$ make
- stack 사이즈 수정
$ ulimit -s 32768
gcc test suite는 스택을 많이 씀.
- Test suite 돌리기
$ make -k check
에러 발생
Makefile:2171: recipe for target 'do-check' failed make: *** [do-check] Error 2 make: Target 'check' not remade because of errors.
문제인가 해서 lfs공식 build-log확인해보니 결과가 비슷하게 나온듯.
http://www.linuxfromscratch.org/lfs/build-logs/7.7/i7-5820K/test-logs/082-gcc-4.9.2
일단 계속 진행.
시작할때부터 나오는 아래 에러로그도 정상임.make[3]: autogen: Command not found Makefile:176: recipe for target 'check' failed make[3]: *** [check] Error 127 make[3]: Leaving directory '/sources/gcc-build/fixincludes' Makefile:3416: recipe for target 'check-fixincludes' failed make[2]: *** [check-fixincludes] Error 2
아래와 같이 에러가 났지만 무시하고 계속진행
http://thread.gmane.org/gmane.linux.lfs.support/38010
=== g++ tests === Running target unix FAIL: g++.dg/asan/asan_test.C -O2 AddressSanitizer_HugeMallocTest Ident((char*)malloc(size))[-1] = 0 output pattern test XPASS: g++.dg/tls/thread_local-order2.C -std=c++11 execution test XPASS: g++.dg/tls/thread_local-order2.C -std=c++1y execution test === g++ Summary === # of expected passes 88500 # of unexpected failures 1 # of unexpected successes 2 # of expected failures 443 # of unsupported tests 3058
- 위의 테스트 로그는 다음으로 확인
$ ../gcc-4.9.2/contrib/test_summary
요약만 보려고하면 | grep -A7 Summ. 하면됨.
- Install the package
$ make install
- cpp의 심볼릭 링크를 /lib에 생성
$ ln -sv ../usr/bin/cpp /lib
- cc를 gcc로 심볼릭 링크
$ ln -sv gcc /usr/bin/cc
많은 패키지가 cc를 사용함.
- LTO로 빌드하기 위한 심볼록 링크
$ install -v -dm755 /usr/lib/bfd-plugins
$ ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/4.9.2/liblto_plugin.so /usr/lib/bfd-plugins/
Add a compatibility symlink to enable building programs with Link Time
Optimization (LTO)
- 정상 빌드 체크
$ echo 'main(){}' > dummy.c
$ cc dummy.c -v -Wl,--verbose &> dummy.log
$ readelf -l a.out | grep ': /lib'
결과가 아래와 같이 나와야함. 그런데 안나오는 경우
[Requesting program interpreter: /lib/ld-linux.so.2]$ readelf -l a.out
해보면 아래와 같이 나오는데 /lib64에 같은내용이 있으므로 정상인것이다.
(찾아보기)
readelf 명령어와 elf 파일구조 간단하게 파악해보기.
- readelf -l a.out
root:/sources/gcc-build# readelf -l a.out Elf file type is EXEC (Executable file) Entry point 0x4003a0 There are 8 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000001c0 0x00000000000001c0 R E 8 INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200 0x0000000000000022 0x0000000000000022 R 1 _[Requesting program interpreter: /tools/lib64/ld-linux-x86-64.so.2]_ LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x000000000000064c 0x000000000000064c R E 200000 LOAD 0x0000000000000650 0x0000000000600650 0x0000000000600650 0x0000000000000228 0x0000000000000230 RW 200000 DYNAMIC 0x0000000000000668 0x0000000000600668 0x0000000000600668 0x00000000000001d0 0x00000000000001d0 RW 8 NOTE 0x0000000000000224 0x0000000000400224 0x0000000000400224 0x0000000000000020 0x0000000000000020 R 4 GNU_EH_FRAME 0x0000000000000524 0x0000000000400524 0x0000000000400524 0x0000000000000034 0x0000000000000034 R 4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 10 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 04 .dynamic 05 .note.ABI-tag 06 .eh_frame_hdr 07
- 올바른 startfile을 사용하는지 확인
$ grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log
결과는 아래와 같아야함.
/usr/lib/gcc/i686-pc-linux-gnu/4.9.2/../../../crt1.o succeeded /usr/lib/gcc/i686-pc-linux-gnu/4.9.2/../../../crti.o succeeded /usr/lib/gcc/i686-pc-linux-gnu/4.9.2/../../../crtn.o succeeded
- 컴파일러가 올바른 헤더파일을 찾는지 확인
$ grep -B4 '^ /usr/include' dummy.log
- 새 링커가 올바른 path를 찾는지 확인
$ grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
결과는 아래와 같아야함. (x86_64기준)
SEARCH_DIR("/usr/x86_64-unknown-linux-gnu/lib64") SEARCH_DIR("/usr/local/lib64") SEARCH_DIR("/lib64") SEARCH_DIR("/usr/lib64") SEARCH_DIR("/usr/x86_64-unknown-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가 올바른 dynamic linker를 사용하는지 확인
$ grep found dummy.log
결과는 아래와 같아야함.
found ld-linux.so.2 at /lib/ld-linux.so.2
결과가 이렇게 안나오면 다음으로 진행할 의미없음. 다시돌아가서 찾기.
- 모두 정상이라면 아래파일 제거
$ rm -v dummy.c a.out dummy.log
- misplaced file이동
$ mkdir -pv /usr/share/gdb/auto-load/usr/lib
$ mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib