最近因为工作需要处理一些 SVN 仓库,但我还是偏好 Git。早些年就知道 Git 提供了 git svn
可以桥接 SVN。但今天发现公司开发机上的 Git 没有把 git svn
编译进来,也就是会报错:
1 | $ git svn |
又因为开发机上我没有 root
权限,所以不得已只能自己从源码编译安装 Git。
基本操作
首先是下载、解包、configure
、make
一波流。
1 | $ wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.24.1.tar.gz |
但在链接阶段报错,提示 SSLv23_method
, SSL_library_init
, SSL_load_error_strings
, sk_num
, sk_value
, sk_pop_free
等符号不存在。
1 | imap-send.o: In function `verify_hostname': |
我第一反应是 OpenSSL 没安装,或是没有正确配置。但随即发现,早先在安装别的工具的时候,已经安装了 OpenSSL 1.1.1b;并且已经修改了 LD_PATH
和 LD_LIBRARY_PATH
两个环境变量,确保链接器能够正确找到相应的共享对象(动态链接库)。
排查问题
在确定 OpenSSL 已安装且能够被编译器、链接器正确找到之后,就只能去检查一下相应符号在共享对象中是否存在了。
SSLv23_method
, SSL_library_init
和 SSL_load_error_strings
显然属于 OpenSSL 当中的 libssl.so
。于是执行命令
1 | $ nm libssl.so | grep SSL_library_init |
返现返回均为空。这说明在 libssl.so
当中确实不存在这三个符号。sk_num
, sk_value
和 sk_pop_free
应当位于 libcrypto.so
当中,检查也有同样结果。
这就令人「满头大汉」了。难道是我下载 OpenSSL 的姿势不对?经过一番检索,在一个与 Git 无关的版本库的 commit log 中,发现了这么一段话:
1 | # https://cbi-dev.igbmc.fr/niveale/tap-formatter/commit/b67a118e7a438009e5d44d0701c21d030c92aa94 |
原来,OpenSSL 自 1.1.0 开始,修改了部分 API 的名称,导致部分符号名发生了变化。此时,大胆猜想:SSL_*
等三个未定义的符号也是因为类似原因导致的。小心求证如下:
- 首先,在
libssl.so
当中检索含有init
的符号,发现有名为OPENSSL_init_ssl
的符号。看名字,其作用应该与SSL_library_init
相近。 - 而后,在 Google 上检索
SSL_library_init OPENSSL_init_ssl
,发现果然,也是在 1.1.0 版本中,该 API 发生了修改;并且OPENSSL_init_ssl
包括了原先SSL_library_init
和SSL_load_error_strings
二者的功能。 - 最后,需要确定
SSLv23_method
的对应是什么。在 Google 上检索SSLv23_method deprecated
,发现在 OpenSSL 官方文档有提到,它已为TLS_method
所代替。
解决
于是检索 Git 代码中所有用到这些过时符号的代码,将他们分别修改为对应的新版本。之后编译、链接正常。最后,再顺手提交一个 patch。