2020年11月6日 星期五

[Linux] 使用 uClibc-ng 製作 x86_64 開發測試環境,以編譯 curl / libcurl 為例 @ Ubuntu 20.04

由於硬體要限縮資源,這時會把常見的 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

收工!

沒有留言:

張貼留言