案例背景
由于我们使用的 OS 版本比较低,系统最高 OpenSSL 库版本是 openssl-1.0.1e
, 而 OpenSSL 在 1.1.0 之前默认是非线程安全的,因此,会导致 axel 偶现 crash。
因此,解决这个问题就变成了升级 OpenSSL 以及使用静态库(因为升级生产环境所有机器的 OpenSSL 库不现实)。
configure help guide
在我们编译出了静态的 LibreSSL 库之后,就要想办法怎么让 axel 使用私有目录的 LibreSSL 库。首先想到的就是 help 指引:
$ ./configure --help
Usage: ./configure [OPTION]... [VAR=VALUE]...
--with-ssl=[openssl/wolfssl]
Which TLS/SSL implementation to use, default: openssl
SSL_PREFIX installation prefix of the TLS/SSL library
SSL_CFLAGS C compiler flags for SSL, overriding pkg-config
SSL_LIBS linker flags for SSL, overriding pkg-config
由于 LibreSSL 是 OpenSSL 的 fork, 因此,本质上它也是 OpenSSL, 我们通过 SSL_PREFIX
来指定库路径:
./configure --prefix=/USER/.local SSL_PREFIX=/USER/.local && make && make install
make 阶段报错:
/USER/.local/lib/libcrypto.a(libcrypto_la-a_string.o): In function `ASN1_STRING_get0_data':
/USER/test/axel/libressl-3.9.1/crypto/asn1/a_string.c:238: multiple definition of `ASN1_STRING_get0_data'
lib/ASN1_STRING_get0_data.o:/USER/test/axel/axel-2.17.13/lib/ASN1_STRING_get0_data.c:24: first defined here
可以看到 ASN1_STRING_get0_data
重复定义,而从 configure 阶段的输出可以看到 check ASN1_STRING_get0_data
的结果为 no:
checking for openssl... yes
checking for ASN1_STRING_get0_data... no
为什么函数在 LibreSSL 中有定义且能链接到,而 check 结果却为 no, 事情到这里就陷入僵局了。
config.log
查看 configure 脚本发现,check 函数的过程是编译+链接,说变要么编译出错,要么链接出错,要是能查看编译和链接的详细参数就迎刃而解了。果不其然,有个 config.log 文件记录了 configure 阶段的详细日志:
onfigure:9062: checking for ASN1_STRING_get0_data
configure:9062: gcc -o conftest -g -O2 conftest.c -L/USER/.local/lib -lssl -lcrypto >&5
/USER/.local/lib/libcrypto.a(libcrypto_la-err.o): In function `ERR_load_ERR_strings':
/USER/test/axel/libressl-3.9.1/crypto/err/err.c:672: undefined reference to `pthread_once'
/USER/.local/lib/libcrypto.a(libcrypto_la-crypto_init.o): In function `OPENSSL_init_crypto':
/USER/test/axel/libressl-3.9.1/crypto/crypto_init.c:60: undefined reference to `pthread_once'
/USER/.local/lib/libcrypto.a(libcrypto_la-conf_sap.o): In function `OpenSSL_config':
/USER/test/axel/libressl-3.9.1/crypto/conf/conf_sap.c:116: undefined reference to `pthread_once'
/USER/.local/lib/libcrypto.a(libcrypto_la-conf_sap.o): In function `OpenSSL_no_config':
/USER/test/axel/libressl-3.9.1/crypto/conf/conf_sap.c:136: undefined reference to `pthread_once'
/USER/test/axel/libressl-3.9.1/crypto/conf/conf_sap.c:136: undefined reference to `pthread_once'
/USER/.local/lib/libcrypto.a(libcrypto_la-err_all.o):/USER/test/axel/libressl-3.9.1/crypto/err/err_all.c:152: more undefined references to `pthread_once' follow
collect2: error: ld returned 1 exit status
我们发现,原来是链接时没有指定 pthread 库导致的。
pkg-config
从 config.log 可以看出,axel 依赖 libssl 和 libcrypto, 我们查看二者的依赖:
$ cat .local/lib/pkgconfig/libcrypto.pc
#libcrypto pkg-config source file
prefix=/data/francishe/.local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: LibreSSL-libcrypto
Description: LibreSSL cryptography library
Version: 3.9.1
Libs: -L${libdir} -lcrypto
Libs.private: -lresolv -lpthread
Cflags: -I${includedir}
libcrypto 确实依赖 pthread 库,修改 configure 参数为 ./configure --prefix=/USER/.local SSL_PREFIX=/USER/.local LIBS=-lpthread
问题解决。