fabric 国密库相关编译问题

背景

在区块链中采用国密加密算法,涉及到c代码编译成动态库供golang调用的问题。要满足linux下可运行,Darwin下可运行。linux下的相关编译已经在另一篇博文上记录过,已经可以运行。这里主要总结mac下的相关问题。

问题

符号表未定义问题

Undefined symbols for architecture x86_64:
  "_BIO_ctrl", referenced from:
      _LoadSM2PrivKeyFromFile in smcryptokit.o
      _LoadSM2CertFromFile in smcryptokit.o
  "_BIO_free", referenced from:
      _LoadSM2PrivKeyFromFile in smcryptokit.o
      _LoadSM2PrivKeyFromBytes in smcryptokit.o
      _LoadSM2CertFromFile in smcryptokit.o
  "_BIO_new", referenced from:
      _LoadSM2PrivKeyFromFile in smcryptokit.o
      _LoadSM2CertFromFile in smcryptokit.o
  "_BIO_new_mem_buf", referenced from:
      _LoadSM2PrivKeyFromBytes in smcryptokit.o
  "_BIO_s_file", referenced from:
      _LoadSM2PrivKeyFromFile in smcryptokit.o
      _LoadSM2CertFromFile in smcryptokit.o
  "_BIO_snprintf", referenced from:
      _SM2_gen_key in sm2_key.o
      _sm2_do_verify in sm2_sign.o
      _sm2_sign_setup in sm2_sign.o
      _sm2_do_sign in sm2_sign.o
      _SM2_sign_ex in sm2_sign.o
      _SM2_verify in sm2_sign.o
      _LoadSM2PrivKeyFromFile in smcryptokit.o
      ...
      
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
cp: .build/libs/libsmcryptokit.dylib: No such file or directory
make: *** [libs] Error 1

排查

一般来讲,这类问题基本上是因为一些库未加载到导致,需要指定链接库的路径。但是开始的时候还是走了些弯路,但是排查思路主要有:

1、编译器下划线修饰符

注意到编译器加了下划线修饰符,-fleading-underscore该选项强制写入目标文件的每个符号均以下划线开始。选项 -fno-leading-underscore 将抑制增加下划线字符。但是在Linux上是没有下划线的,当时就怀疑是不是因为加了下划线导致符号未定义,但是mac下编译器是clang无此选项,后来想了下,加不加下划线应该不影响,于是就寻求其他解决方法。

2、指定动态库

因为发现主要是缺少openssl的相关函数,于是到系统库目录去查找相关库的符号表。

nm /usr/local/lib/libssl.dylib
                 U _ASN1_INTEGER_get
                 U _ASN1_INTEGER_set
                 U _ASN1_const_check_infinite_end
                 U _ASN1_dup
                 U _ASN1_get_object
                 U _ASN1_object_size
                 U _ASN1_put_object
                 U _BIO_callback_ctrl
                 U _BIO_clear_flags
                 U _BIO_copy_next_retry
                 U _BIO_ctrl
                 U _BIO_dump_indent
                 U _BIO_f_buffer
0000000000000b40 T _BIO_f_ssl
                 U _BIO_find_type
                 U _BIO_free
                 U _BIO_free_all
                 U _BIO_get_retry_reason
                 U _BIO_int_ctrl
                 U _BIO_method_type
                 U _BIO_new
0000000000000b50 T _BIO_new_buffer_ssl_connect
0000000000000c50 T _BIO_new_ssl

发现动态库里是有该符号的,那么我们基本可确定问题所在:没有链接到动态库导致。

原因

没有链接到动态库导致

解决

1、指定动态链接库路径: DYLD_LIBRARY_PATH

添加环境变量 export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/usr/local/lib:/usr/lib
但是Mac上较新的系统会有保护操作不让操作:

New versions of OS X enable system integrity protection per default. Meaning that setting the DYLD_LIBRARY_PATH and LD_LIBRARY_PATH will have no effects.

I had this issue before in another context, but it looks like it’s a common issue on other Node modules as well: oracle/node-oracledb#231

Here is a guide to turn of SIP: http://osxdaily.com/2015/10/05/disable-rootless-system-integrity-protection-mac-os-x/
发现还是挺麻烦的,而且不太适用项目开发,于是有了下面方法

2、把系统库放到指定目录,生成链接库时显示指定

例如:

gcc -fPIC -shared -current_version 1.0 -compatibility_version 1.0 -fvisibility=hidden \
			librarys/libssl.dylib librarys/libltdl.dylib librarys/libcrypto.dylib \
			librarys/libcrypto.38.dylib ./libs/sm/sm2/sm2_key.o  -o ./libs/libsmcryptokit.dylib

这样这个符号未定义的问题就得到了解决。

其他问题

1、dyld: Library not loaded: .build/libs/libsmcryptokit.dylib Reason: image not found
解决:把生成的动态库放到/usr/local/lib/下。
2、

dyld: Library not loaded: .build/libs/libsmcryptokit.dylib
  Referenced from: ./release/darwin-amd64/bin/cryptogen
  Reason: Incompatible library version: cryptogen requires version 1.0.0 or later, but libsmcryptokit.dylib provides version 0.0.0
generateArtifacts.sh: line 47: 91974 Abort trap: 6   $CRYPTOGEN generate --config=$CRYPTO_CONFIG

解决:在生成动态库时添加相关版本信息选项:
-current_version 1.0 -compatibility_version 1.0

3、编译告警 ld: warning: directory not found for option '-L
解决:go在调用c库时,指定了一些库文件,有些库文件是不存在的,去除多余的即可。

// #cgo LDFLAGS: -I../../include -I./ -L../../librarys -lsmcryptokit -lcrypto
// #include "../../include/sm/smcryptokit.h"

4、找不到系统头文件:

file included from sm/sm3/sm3.go:4:
In file included from ./../../include/sm/smcryptokit.h:4: fatal error: 'openssl/des.h' file not found

解决:依赖系统openssl头文件,确保系统安装的openssl include文件放到系统库下。
1、重装openssl;
2、如果系统自带openssl,确保openssl/include文件放到系统库里,例如:放到/usr/local/include下:

cp -r  /usr/local/opt/openssl/include/openssl  /usr/local/include/.

总结

这样的话国密库在Darwin也可以编译成功,在Mac上也可以调试fabric相关的代码。

你可能感兴趣的:(区块链,fabric)