由於硬體要限縮資源,這時會把常見的 glibc 換成 uclibc 節省空間,而過程包括要建置 toolchain 等等。由於部分程式在 embedded linux 運作不如預期,大家擔心可能是 uclibc 產生的問題,就出現在 x86_64 運行 uclibc 作檢驗的念頭
實作上也是要建置 x86_64 的 toolchain 出來,此例就用 curl / libcurl 為例。此篇工作記錄參考 编译工具链制作-x86_64-linux-uclibc 文章,建議先拜讀這篇,裡頭編譯參數的項目都有說明,佛心啊。此處筆記是設法把開發環境都用最新環境,包括:
- Ubuntu 20.04.1 LTS server
- uClibc-ng-1.0.36
- binutils-2.35
- gcc-9.3.0
- mpfr-4.1.0
- mpc-1.2.1
- gmp-6.1.2
- linux-2.6.39
而後面編譯 curl 採用以下資源:
- tiny-curl-7.72.0
- zlib-1.2.11
- openssl-1.1.1h
採用 gcc-9.3.0 的主因是 ubuntu 20.04 預設 apt install gcc 就是 9.3 版。以下連續動作:
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.gz
$ wget https://ftp.gnu.org/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.gz
$ wget https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.bz2
$ wget https://ftp.gnu.org/gnu/mpc/mpc-1.2.1.tar.gz
$ wget https://ftp.gnu.org/gnu/mpfr/mpfr-4.1.0.tar.gz
$ wget http://ftp.ntu.edu.tw/linux/kernel/v2.6/linux-2.6.39.tar.gz
$ wget https://downloads.uclibc-ng.org/releases/1.0.36/uClibc-ng-1.0.36.tar.gz
並全在 user 家目錄解壓縮,解壓縮後把 open source 包都移到 resource 目錄中保存:
user@buildserver:~$ tree -L 1
.
├── binutils-2.35
├── gcc-9.3.0
├── gmp-6.1.2
├── linux-2.6.39
├── mpc-1.2.1
├── mpfr-4.1.0
├── resource
└── uClibc-ng-1.0.36
安裝一些工具:
$ sudo apt install make cmake gcc g++ libncurses-dev libncurses5-dev
$ gcc -v
...
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
$ g++ -v
...
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
$ make -v
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
$ cmake --version
cmake version 3.16.3
建置環境變數,預計都安裝在家目錄的 tarball 裡,此例就是 /home/user/tarball:
$ cat ~/uclibc-init.sh
export ARCH=x86
export TARGET=x86_64-linux-uclibc
export PREFIX=/home/user/tarball
export TARGET_PREFIX=$PREFIX/$TARGET
export PATH=$PREFIX/bin:$PATH
$ source ~/uclibc-init.sh
$ mkdir -p $TARGET_PREFIX
編譯 binutils 環境:
$ cd binutils-2.35 && mkdir -p $TARGET && cd $TARGET
$ ../configure \
--prefix=$PREFIX \
--with-lib-path=$PREFIX/lib:$PREFIX/lib64 \
--disable-multilib \
--disable-werror \
--disable-nls \
--enable-gold \
--target=$TARGET
$ make && make install
$ x86_64-linux-uclibc-ld --verbose | grep SEARCH
SEARCH_DIR("/home/user/tarball/x86_64-linux-uclibc/lib64"); SEARCH_DIR("/home/user/tarball/lib"); SEARCH_DIR("/home/user/tarball/lib64"); SEARCH_DIR("/home/user/tarball/x86_64-linux-uclibc/lib");
這邊增加 --enable-gold 用於 gcc-9.3 的編譯時會踩到的需求,通常就是缺一些 header files 就是要找找看躲在 binutils, uclibc 等等
安置 linux header files:
$ linux-2.6.39/
$ make ARCH=$ARCH INSTALL_HDR_PATH=$TARGET_PREFIX headers_install
編譯跨平台 gcc 工具:
$ cd gcc-9.3.0/
$ ln -s ../mpc-1.2.1/ mpc
$ ln -s ../mpfr-4.1.0/ mpfr
$ ln -s ../gmp-6.1.2/ gmp
$ mkdir -p $TARGET && cd $TARGET
$ ../configure \
--prefix=$PREFIX \
--with-sysroot=$PREFIX \
--with-local-prefix=$PREFIX \
--with-native-system-header-dir=/$TARGET/include \
--enable-languages=c,c++ \
--enable-linker-build-id \
--disable-multilib \
--disable-werror \
--without-headers \
--with-newlib \
--disable-shared \
--disable-nls \
--target=$TARGET
$ make all-gcc
$ make install-gcc安置 uclibc 相關檔案們(startfiles/headers):
$ cd uClibc-ng-1.0.36
$ make menuconfig
Target Architecture
--> x86_64
Target Architecture Features and Options
--> [*] Enable full C99 math library support
--> [*] Enable C99 Floating-point environment
--> Linux kernel header location (/home/user/tarball/x86_64-linux-uclibc/include)
General Library Settings
--> [*] Dynamic linker stand-alone mode support
--> Thread support (Native POSIX Threading (NPTL))
--> [*] utmpx based support for tracking login/logouts to/from the system
--> [*] utmp support (XPG2 compat, SVr4 compat)
--> [*] Enable SuSv3 LEGACY functions
--> [*] Enable SuSv3 LEGACY macros
--> [*] Enable SuSv4 or obsolescent functions
Advanced Library Settings
--> [*] Enable SVr4 deprecated functions
Networking Support
--> [*] IP version 6 support
--> [*] Use netlink to query interfaces
--> [*] Support the AI_ADDRCONFIG flag
--> [*] DNS resolver functions
String and Stdio Support
--> [*] Wide Charater Support
Big and Tall
--> [*] Support the wordexp() interface
Libray Installation Options
--> uClibc runtime library directory(/home/user/tarball/x86_64-linux-uclibc)
--> uClibc development envirment directory(/home/user/tarball/x86_64-linux-uclibc)
Development/debugging options
--> Cross-compiling toolchain prefix (x86_64-linux-uclibc-)
--> (-D__NR_setns -D__NR_syncfs) Extra CFLAGS
$ make startfiles
$ PREFIX="" make install_startfiles
$ PREFIX="" make install_headers
其中我開啟了不少項目都是後邊在編譯 gcc-9.3 和 curl 會用到的項目,像是缺 ifaddrs.h 而開啟 Support the AI_ADDRCONFIG flag 又相依要開啟 Use netlink to query interfaces 選項等等。過程常見的都是編譯期間缺 header files 而反覆在 uclibc 開啟資源,可以把缺的 header files 在 uclibc 中靠 find 或 grep 搜尋
繼續編譯跨平台 libgcc:
$ cd ~/gcc-9.3.0/$TARGET
$ make all-target-libgcc
$ make install-target-libgcc
編譯和安裝 uclibc :
$ cd ~/uClibc-ng-1.0.36/
$ make
$ PREFIX="" make install
最後一次 gcc 編譯:
$ cd ~/gcc-9.3.0/$TARGET
$ ../configure \
--prefix=$PREFIX \
--with-sysroot=/ \
--with-local-prefix=$PREFIX \
--with-native-system-header-dir=$TARGET_PREFIX/include \
--enable-languages=c,c++ \
--enable-linker-build-id \
--disable-libsanitizer \
--disable-multilib \
--disable-werror \
--disable-nls \
--target=$TARGET
$ make all
$ make install
如此,就可以有基本的環境運行了,例如編譯 main.c:
$ cat main.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello\n");
return 0;
}
$ x86_64-linux-uclibc-gcc main.c
$ ./a.out
-bash: ./a.out: No such file or directory
$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64-uClibc.so.0, BuildID[sha1]=c243334b7550adf7ef5342019c444d6762da738b, not stripped
$ ~/tarball/x86_64-linux-uclibc/lib/ld64-uClibc-1.0.36.so --library-path /home/user/tarball/x86_64-linux-uclibc/lib/:/home/user/tarball/x86_64-linux-uclibc/lib64:/home/user/tarball/lib ./a.out
Hello
緊接著編譯 curl 來用,因為他相依 openssl, libssh2, zlib ,所以過程要先把這些函示庫都編好:
$ wget https://zlib.net/zlib-1.2.11.tar.gz
$ tar -xvf zlib-1.2.11.tar.gz && cd ~/zlib-1.2.11
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-g++ ./configure --prefix=$PREFIX
$ make && make install
$ wget https://www.libssh2.org/download/libssh2-1.9.0.tar.gz
$ tar -xvf libssh2-1.9.0.tar.gz && cd libssh2-1.9.0
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-g++ ./configure --prefix=$PREFIX --host x86_64-linux-uclibc
$ make && make install
$ wget https://www.openssl.org/source/openssl-1.1.1h.tar.gz
$ tar -xvf openssl-1.1.1h.tar.gz && cd ~/openssl-1.1.1h
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-g++ ./config --prefix=$PREFIX -latomic no-threads no-shared no-rc5 enable-camellia enable-mdc2 no-tests no-fuzz-libfuzzer no-fuzz-afl zlib
$ make && make install
$ wget https://curl.haxx.se/tiny/tiny-curl-7.72.0.tar.gz
$ tar -xvf tiny-curl-7.72.0.tar.gz && cd tiny-curl-7.72.0
$ mkdir build && cd build
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-gc++ cmake .. -DCMAKE_PREFIX_PATH=~/tarball -DCMAKE_INSTALL_PREFIX=~/tarball
$ make && make install
$ /home/user/tarball/bin/curl
-bash: /home/user/tarball/bin/curl: No such file or directory
$ ~/tarball/x86_64-linux-uclibc/lib/ld64-uClibc-1.0.36.so --library-path /home/user/tarball/x86_64-linux-uclibc/lib/:/home/user/tarball/x86_64-linux-uclibc/lib64:/home/user/tarball/lib /home/user/tarball/bin/curl --version
curl 7.72.0 (Linux) libcurl/7.72.0 OpenSSL/1.1.1h zlib/1.2.11 libssh2/1.9.0
Release-Date: 2020-08-27
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS HTTPS-proxy IPv6 Largefile libz NTLM SSL UnixSockets
收工!