"Undefined symbols for architecture x86_64:" 用于在 macOS Sierra 上使用 cgo 的库
"Undefined symbols for architecture x86_64:" for library using cgo on macOS Sierra
我正在尝试使用一个库,https://github.com/go-steem/rpc,它使用了一些引用库的 C 代码。
C 库可以在这里找到,https://github.com/bitcoin-core/secp256k1
我按照步骤进行了安装
$ ./autogen.sh
$ ./configure
$ make
$ ./tests
$ sudo make install # optional
并有这个输出;
$ sudo make install
Password:
CC src/libsecp256k1_la-secp256k1.lo
CCLD libsecp256k1.la
CC src/tests-tests.o
CCLD tests
CC src/exhaustive_tests-tests_exhaustive.o
CCLD exhaustive_tests
build-aux/install-sh -c -d '/usr/local/lib'
/bin/sh ./libtool --mode=install /usr/bin/install -c libsecp256k1.la '/usr/local/lib'
libtool: install: /usr/bin/install -c .libs/libsecp256k1.0.dylib /usr/local/lib/libsecp256k1.0.dylib
libtool: install: (cd /usr/local/lib && { ln -s -f libsecp256k1.0.dylib libsecp256k1.dylib || { rm -f libsecp256k1.dylib && ln -s libsecp256k1.0.dylib libsecp256k1.dylib; }; })
libtool: install: /usr/bin/install -c .libs/libsecp256k1.lai /usr/local/lib/libsecp256k1.la
libtool: install: /usr/bin/install -c .libs/libsecp256k1.a /usr/local/lib/libsecp256k1.a
libtool: install: chmod 644 /usr/local/lib/libsecp256k1.a
libtool: install: /usr/bin/ranlib /usr/local/lib/libsecp256k1.a
build-aux/install-sh -c -d '/usr/local/include'
/usr/bin/install -c -m 644 include/secp256k1.h '/usr/local/include'
build-aux/install-sh -c -d '/usr/local/lib/pkgconfig'
/usr/bin/install -c -m 644 libsecp256k1.pc '/usr/local/lib/pkgconfig'
我尝试 运行 来自那个 Go 库的 upvote 示例,go-steem/rpc/examples/upvote/ 并获得以下输出;
$ go run main.go
# github.com/go-steem/rpc/transactions
../../transactions/signing.c:5:10: fatal error: 'secp256k1.h' file not found
已经感觉轮子掉下来了...
请多多包涵,因为我不是用 C 开发的,所以有点 hack-y。
经过大量阅读和谷歌搜索后,我决定将编译 libsecp256k1 的 'include' 目录中的文件复制到与错误源相同的目录中。
您可以看到文件不存在;
$ ls -la ../../transactions/
total 48
drwxr-xr-x 8 shaunmorrow staff 272 May 8 18:09 .
drwxr-xr-x 15 shaunmorrow staff 510 May 8 18:09 ..
-rw-r--r-- 1 shaunmorrow staff 256 Apr 27 17:53 chains.go
-rw-r--r-- 1 shaunmorrow staff 3731 May 8 18:09 signed_transaction.go
-rw-r--r-- 1 shaunmorrow staff 1849 May 8 18:09 signed_transaction_test.go
-rw-r--r-- 1 shaunmorrow staff 3075 Apr 27 17:53 signing.c
-rw-r--r-- 1 shaunmorrow staff 408 Apr 27 17:53 signing.h
-rw-r--r-- 1 shaunmorrow staff 1049 May 8 18:09 transactions.go
复制后;
$ ls -la ../../transactions/
total 128
drwxr-xr-x 11 shaunmorrow staff 374 Jul 18 19:08 .
drwxr-xr-x 15 shaunmorrow staff 510 May 8 18:09 ..
-rw-r--r-- 1 shaunmorrow staff 256 Apr 27 17:53 chains.go
-rw-r--r-- 1 shaunmorrow staff 27071 Jul 18 19:08 secp256k1.h
-rw-r--r-- 1 shaunmorrow staff 1014 Jul 18 19:08 secp256k1_ecdh.h
-rw-r--r-- 1 shaunmorrow staff 4700 Jul 18 19:08 secp256k1_recovery.h
-rw-r--r-- 1 shaunmorrow staff 3731 Jul 18 19:05 signed_transaction.go
-rw-r--r-- 1 shaunmorrow staff 1849 May 8 18:09 signed_transaction_test.go
-rw-r--r-- 1 shaunmorrow staff 3075 Apr 27 17:53 signing.c
-rw-r--r-- 1 shaunmorrow staff 408 Apr 27 17:53 signing.h
-rw-r--r-- 1 shaunmorrow staff 1049 May 8 18:09 transactions.go
现在我收到一个新错误;
$ go run main.go
# github.com/go-steem/rpc/transactions
ld: library not found for -lsecp256k1
clang: error: linker command failed with exit code 1 (use -v to see invocation)
这让我阅读和谷歌搜索更多,
最后我得到了更多的 hack-y 和改变 transactions.go;
// #cgo LDFLAGS: -lsecp256k1
// #include <stdlib.h>
// #include "signing.h"
import "C"
变成
// #cgo LDFLAGS: -L/usr/local/lib
// #include <stdlib.h>
// #include "signing.h"
import "C"
失败,稍后输出
我也试试;
// #cgo LDFLAGS: -L/usr/local/lib -I/usr/local/include
// #include <stdlib.h>
// #include "signing.h"
import "C"
并将 .h 文件复制到 /usr/local/include 目录中。
None 有效,现在我遇到了这样的错误
$ go run main.go
# github.com/go-steem/rpc/transactions
ld: library not found for -lsecp256k1
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ShaunsSePc-2:upvote shaunmorrow$ go run main.go
# github.com/go-steem/rpc/transactions
Undefined symbols for architecture x86_64:
"_secp256k1_context_create", referenced from:
_sign_transaction in signing.o
_verify_recoverable_signature in signing.o
"_secp256k1_context_destroy", referenced from:
_sign_transaction in signing.o
_verify_recoverable_signature in signing.o
"_secp256k1_ec_pubkey_serialize", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recover", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recoverable_signature_convert", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recoverable_signature_parse_compact", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recoverable_signature_serialize_compact", referenced from:
_sign_transaction in signing.o
"_secp256k1_ecdsa_sign_recoverable", referenced from:
_sign_transaction in signing.o
"_secp256k1_ecdsa_verify", referenced from:
_verify_recoverable_signature in signing.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
此时我真的不知道如何继续。
如您所见,我完全没有使用 C 语言的经验,也不知道如何测试库 libsecp256k1
是否安装正确!
这是我结束的地方,但很可能我在旅途的早期转错了方向,我将不胜感激任何帮助,因为我已经为此苦苦挣扎了几个晚上:(
不确定需要什么,所以这里有一些环境变量
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/shaunmorrow/Work/go/"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/86/hlqptn5101z5bcydjz05qy8m0000gn/T/go-build689438019=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
版本是 go version go1.8.3 darwin/amd64 没有旧版本。
谢谢!
你的问题是双重的:
- 配置不正确
libsecp256k1
包
- 您的 C 编译器未在
/usr/local
目录中搜索已安装的 headers/libs
修复不正确的 libsecp256k1 配置包
您的 "undefined symbols" 关于链接 C 库的问题有时指向配置不正确的包(在 Autotools 包或 CMake 包的意义上,而不是 Go 包)。 运行 ./configure --help
,我看到有一个名为 --enable-module-recovery
的选项。从名称判断 _secp256k1_ecdsa_sign_<strong>recoverable</strong>
和 _secp256k1_ecdsa_<strong>recover</strong>
,你需要在配置的时候加上那个选项,意思是不是执行更简单的./configure
,你应该执行这个:
./configure --enable-module-recovery
是不是C编译器坏了?
由于 secp256k1.h
header 文件未在 /usr/local/include
中找到,尽管 header 文件肯定存在于 sudo make install
之后完了,就是your compiler doesn't search /usr/local
.
除了链接问题中的任何修复,您可以通过根据需要将 Go 包的源更改为 add/modify 处理时使用的 CFLAGS
和 LDFLAGS
来解决此问题使用 import "C"
语句如下:
// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -L/usr/local/lib -lsecp256k1
// #include <secp256k1.h>
import "C"
如果您安装了 pkg-config
,您可以使用它来代替手动设置 CFLAGS
和 LDFLAGS
:
- 使用一组自定义路径导出
PKG_CONFIG_PATH
环境变量。因为没有指定前缀(即作为安装根目录的目录),所以假定 /usr/local
,这意味着 /usr/local/include
将包含 header,而 /usr/local/lib
将包含库。这意味着您需要像 export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
一样在命令行中导出 PKG_CONFIG_PATH
。未设置时 PKG_CONFIG_PATH
的默认设置在 Linux 上按顺序包括 /usr/lib/pkgconfig
和 /usr/share/pkgconfig
,并被指定为可能使用的其他包的回退,尽管它可能不会在这种情况下是必要的。 OS X 上的默认路径集可能有所不同,因此请查阅 pkg-config
手册页以供参考。
- 使用
// #cgo pkg-config: libsecp256k1
,CFLAGS
和LDFLAGS
将根据需要进行设置,您无需对它们进行任何操作。由于并非所有系统都安装了 pkg-config
,因此如果您希望软件包保持可移植性,依赖它可能不是一个好主意。再一次,我认为它比你处理的混乱更可取,因为 pkg-config
根本找不到。
- 切换到 upvote 目录并键入
make
以构建一个可用的 upvote 二进制文件。
额外的定制
自定义前缀
如果您使用 /usr/local
以外的前缀作为前缀(例如 ./configure --enable-module-recovery --prefix=/opt/libsecp256k1
),那么您需要相应地调整一些内容:
// #cgo CFLAGS: -I/opt/libsecp256k1/include
// #cgo LDFLAGS: -L/opt/libsecp256k1/lib -lsecp256k1
// #include "secp256k1.h"
import "C"
// or just use pkg-config and export the PKG_CONFIG_PATH environment
// variable containing the following paths:
// /opt/libsecp256k1/lib/pkgconfig
// /opt/libsecp256k1/share/pkgconfig
// /usr/lib/pkgconfig
// /usr/share/pkgconfig
您还需要修改 upvote 目录中提供的 Makefile 以设置生成的二进制文件的运行时路径,否则 libsecp256k1.0.dylib
将找不到:
# If you copy and paste this, replace the spaces in front of `go build`
# with a single horizontal tab character, else `make` will fail.
#
# Note that the "ldflags" specified are for the Go linker (go tool link),
# not the system's linker (ld).
build:
go build -ldflags="-r /opt/libsecp256k1/lib"
有关使用 cgo 的更多信息,请查看以下资源:
我正在尝试使用一个库,https://github.com/go-steem/rpc,它使用了一些引用库的 C 代码。
C 库可以在这里找到,https://github.com/bitcoin-core/secp256k1
我按照步骤进行了安装
$ ./autogen.sh
$ ./configure
$ make
$ ./tests
$ sudo make install # optional
并有这个输出;
$ sudo make install
Password:
CC src/libsecp256k1_la-secp256k1.lo
CCLD libsecp256k1.la
CC src/tests-tests.o
CCLD tests
CC src/exhaustive_tests-tests_exhaustive.o
CCLD exhaustive_tests
build-aux/install-sh -c -d '/usr/local/lib'
/bin/sh ./libtool --mode=install /usr/bin/install -c libsecp256k1.la '/usr/local/lib'
libtool: install: /usr/bin/install -c .libs/libsecp256k1.0.dylib /usr/local/lib/libsecp256k1.0.dylib
libtool: install: (cd /usr/local/lib && { ln -s -f libsecp256k1.0.dylib libsecp256k1.dylib || { rm -f libsecp256k1.dylib && ln -s libsecp256k1.0.dylib libsecp256k1.dylib; }; })
libtool: install: /usr/bin/install -c .libs/libsecp256k1.lai /usr/local/lib/libsecp256k1.la
libtool: install: /usr/bin/install -c .libs/libsecp256k1.a /usr/local/lib/libsecp256k1.a
libtool: install: chmod 644 /usr/local/lib/libsecp256k1.a
libtool: install: /usr/bin/ranlib /usr/local/lib/libsecp256k1.a
build-aux/install-sh -c -d '/usr/local/include'
/usr/bin/install -c -m 644 include/secp256k1.h '/usr/local/include'
build-aux/install-sh -c -d '/usr/local/lib/pkgconfig'
/usr/bin/install -c -m 644 libsecp256k1.pc '/usr/local/lib/pkgconfig'
我尝试 运行 来自那个 Go 库的 upvote 示例,go-steem/rpc/examples/upvote/ 并获得以下输出;
$ go run main.go
# github.com/go-steem/rpc/transactions
../../transactions/signing.c:5:10: fatal error: 'secp256k1.h' file not found
已经感觉轮子掉下来了...
请多多包涵,因为我不是用 C 开发的,所以有点 hack-y。
经过大量阅读和谷歌搜索后,我决定将编译 libsecp256k1 的 'include' 目录中的文件复制到与错误源相同的目录中。
您可以看到文件不存在;
$ ls -la ../../transactions/
total 48
drwxr-xr-x 8 shaunmorrow staff 272 May 8 18:09 .
drwxr-xr-x 15 shaunmorrow staff 510 May 8 18:09 ..
-rw-r--r-- 1 shaunmorrow staff 256 Apr 27 17:53 chains.go
-rw-r--r-- 1 shaunmorrow staff 3731 May 8 18:09 signed_transaction.go
-rw-r--r-- 1 shaunmorrow staff 1849 May 8 18:09 signed_transaction_test.go
-rw-r--r-- 1 shaunmorrow staff 3075 Apr 27 17:53 signing.c
-rw-r--r-- 1 shaunmorrow staff 408 Apr 27 17:53 signing.h
-rw-r--r-- 1 shaunmorrow staff 1049 May 8 18:09 transactions.go
复制后;
$ ls -la ../../transactions/
total 128
drwxr-xr-x 11 shaunmorrow staff 374 Jul 18 19:08 .
drwxr-xr-x 15 shaunmorrow staff 510 May 8 18:09 ..
-rw-r--r-- 1 shaunmorrow staff 256 Apr 27 17:53 chains.go
-rw-r--r-- 1 shaunmorrow staff 27071 Jul 18 19:08 secp256k1.h
-rw-r--r-- 1 shaunmorrow staff 1014 Jul 18 19:08 secp256k1_ecdh.h
-rw-r--r-- 1 shaunmorrow staff 4700 Jul 18 19:08 secp256k1_recovery.h
-rw-r--r-- 1 shaunmorrow staff 3731 Jul 18 19:05 signed_transaction.go
-rw-r--r-- 1 shaunmorrow staff 1849 May 8 18:09 signed_transaction_test.go
-rw-r--r-- 1 shaunmorrow staff 3075 Apr 27 17:53 signing.c
-rw-r--r-- 1 shaunmorrow staff 408 Apr 27 17:53 signing.h
-rw-r--r-- 1 shaunmorrow staff 1049 May 8 18:09 transactions.go
现在我收到一个新错误;
$ go run main.go
# github.com/go-steem/rpc/transactions
ld: library not found for -lsecp256k1
clang: error: linker command failed with exit code 1 (use -v to see invocation)
这让我阅读和谷歌搜索更多,
最后我得到了更多的 hack-y 和改变 transactions.go;
// #cgo LDFLAGS: -lsecp256k1
// #include <stdlib.h>
// #include "signing.h"
import "C"
变成
// #cgo LDFLAGS: -L/usr/local/lib
// #include <stdlib.h>
// #include "signing.h"
import "C"
失败,稍后输出
我也试试;
// #cgo LDFLAGS: -L/usr/local/lib -I/usr/local/include
// #include <stdlib.h>
// #include "signing.h"
import "C"
并将 .h 文件复制到 /usr/local/include 目录中。
None 有效,现在我遇到了这样的错误
$ go run main.go
# github.com/go-steem/rpc/transactions
ld: library not found for -lsecp256k1
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ShaunsSePc-2:upvote shaunmorrow$ go run main.go
# github.com/go-steem/rpc/transactions
Undefined symbols for architecture x86_64:
"_secp256k1_context_create", referenced from:
_sign_transaction in signing.o
_verify_recoverable_signature in signing.o
"_secp256k1_context_destroy", referenced from:
_sign_transaction in signing.o
_verify_recoverable_signature in signing.o
"_secp256k1_ec_pubkey_serialize", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recover", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recoverable_signature_convert", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recoverable_signature_parse_compact", referenced from:
_verify_recoverable_signature in signing.o
"_secp256k1_ecdsa_recoverable_signature_serialize_compact", referenced from:
_sign_transaction in signing.o
"_secp256k1_ecdsa_sign_recoverable", referenced from:
_sign_transaction in signing.o
"_secp256k1_ecdsa_verify", referenced from:
_verify_recoverable_signature in signing.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
此时我真的不知道如何继续。
如您所见,我完全没有使用 C 语言的经验,也不知道如何测试库 libsecp256k1
是否安装正确!
这是我结束的地方,但很可能我在旅途的早期转错了方向,我将不胜感激任何帮助,因为我已经为此苦苦挣扎了几个晚上:(
不确定需要什么,所以这里有一些环境变量
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/shaunmorrow/Work/go/"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/86/hlqptn5101z5bcydjz05qy8m0000gn/T/go-build689438019=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
版本是 go version go1.8.3 darwin/amd64 没有旧版本。
谢谢!
你的问题是双重的:
- 配置不正确
libsecp256k1
包 - 您的 C 编译器未在
/usr/local
目录中搜索已安装的 headers/libs
修复不正确的 libsecp256k1 配置包
您的 "undefined symbols" 关于链接 C 库的问题有时指向配置不正确的包(在 Autotools 包或 CMake 包的意义上,而不是 Go 包)。 运行 ./configure --help
,我看到有一个名为 --enable-module-recovery
的选项。从名称判断 _secp256k1_ecdsa_sign_<strong>recoverable</strong>
和 _secp256k1_ecdsa_<strong>recover</strong>
,你需要在配置的时候加上那个选项,意思是不是执行更简单的./configure
,你应该执行这个:
./configure --enable-module-recovery
是不是C编译器坏了?
由于 secp256k1.h
header 文件未在 /usr/local/include
中找到,尽管 header 文件肯定存在于 sudo make install
之后完了,就是your compiler doesn't search /usr/local
.
除了链接问题中的任何修复,您可以通过根据需要将 Go 包的源更改为 add/modify 处理时使用的 CFLAGS
和 LDFLAGS
来解决此问题使用 import "C"
语句如下:
// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -L/usr/local/lib -lsecp256k1
// #include <secp256k1.h>
import "C"
如果您安装了 pkg-config
,您可以使用它来代替手动设置 CFLAGS
和 LDFLAGS
:
- 使用一组自定义路径导出
PKG_CONFIG_PATH
环境变量。因为没有指定前缀(即作为安装根目录的目录),所以假定/usr/local
,这意味着/usr/local/include
将包含 header,而/usr/local/lib
将包含库。这意味着您需要像export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
一样在命令行中导出PKG_CONFIG_PATH
。未设置时PKG_CONFIG_PATH
的默认设置在 Linux 上按顺序包括/usr/lib/pkgconfig
和/usr/share/pkgconfig
,并被指定为可能使用的其他包的回退,尽管它可能不会在这种情况下是必要的。 OS X 上的默认路径集可能有所不同,因此请查阅pkg-config
手册页以供参考。 - 使用
// #cgo pkg-config: libsecp256k1
,CFLAGS
和LDFLAGS
将根据需要进行设置,您无需对它们进行任何操作。由于并非所有系统都安装了pkg-config
,因此如果您希望软件包保持可移植性,依赖它可能不是一个好主意。再一次,我认为它比你处理的混乱更可取,因为pkg-config
根本找不到。 - 切换到 upvote 目录并键入
make
以构建一个可用的 upvote 二进制文件。
额外的定制
自定义前缀
如果您使用 /usr/local
以外的前缀作为前缀(例如 ./configure --enable-module-recovery --prefix=/opt/libsecp256k1
),那么您需要相应地调整一些内容:
// #cgo CFLAGS: -I/opt/libsecp256k1/include
// #cgo LDFLAGS: -L/opt/libsecp256k1/lib -lsecp256k1
// #include "secp256k1.h"
import "C"
// or just use pkg-config and export the PKG_CONFIG_PATH environment
// variable containing the following paths:
// /opt/libsecp256k1/lib/pkgconfig
// /opt/libsecp256k1/share/pkgconfig
// /usr/lib/pkgconfig
// /usr/share/pkgconfig
您还需要修改 upvote 目录中提供的 Makefile 以设置生成的二进制文件的运行时路径,否则 libsecp256k1.0.dylib
将找不到:
# If you copy and paste this, replace the spaces in front of `go build`
# with a single horizontal tab character, else `make` will fail.
#
# Note that the "ldflags" specified are for the Go linker (go tool link),
# not the system's linker (ld).
build:
go build -ldflags="-r /opt/libsecp256k1/lib"
有关使用 cgo 的更多信息,请查看以下资源: