在区块链中采用国密加密算法,涉及到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
一般来讲,这类问题基本上是因为一些库未加载到导致,需要指定链接库的路径。但是开始的时候还是走了些弯路,但是排查思路主要有:
注意到编译器加了下划线修饰符,-fleading-underscore该选项强制写入目标文件的每个符号均以下划线开始。选项 -fno-leading-underscore 将抑制增加下划线字符。但是在Linux上是没有下划线的,当时就怀疑是不是因为加了下划线导致符号未定义,但是mac下编译器是clang无此选项,后来想了下,加不加下划线应该不影响,于是就寻求其他解决方法。
因为发现主要是缺少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
发现动态库里是有该符号的,那么我们基本可确定问题所在:没有链接到动态库导致。
没有链接到动态库导致
添加环境变量 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/
发现还是挺麻烦的,而且不太适用项目开发,于是有了下面方法
例如:
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相关的代码。