英文:
"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 # 可选的
然后我得到了以下输出:
$ 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开发,所以有点困惑。
经过大量阅读和搜索,我决定将编译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目录中。
所有这些都没有起作用,现在我被困在了这样一个错误中:
$ 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,没有旧版本。
谢谢!
英文:
I am trying to make use of a library, https://github.com/go-steem/rpc, that makes use of some C code, which references a library.
The C library can be found here, https://github.com/bitcoin-core/secp256k1
I followed the steps to get that installed
$ ./autogen.sh
$ ./configure
$ make
$ ./tests
$ sudo make install # optional
And have this output;
$ 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'
I try to run the upvote example from that Go library, go-steem/rpc/examples/upvote/ and get the following output;
$ go run main.go
# github.com/go-steem/rpc/transactions
../../transactions/signing.c:5:10: fatal error: 'secp256k1.h' file not found
Already it feels as though the wheels are falling off...
Please bear with me as I do not develop in C, so I get a bit hack-y.
After much reading, and googling I decide to copy the files from the 'include' directory where I compiled libsecp256k1 into the same directory as the error is originating from.
You can see the files are not there;
$ 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
and after the copy;
$ 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
Now I get a new error;
$ 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)
This has me reading and googling some more,
Finally I get even more hack-y and change transactions.go;
// #cgo LDFLAGS: -lsecp256k1
// #include <stdlib.h>
// #include "signing.h"
import "C"
becomes
// #cgo LDFLAGS: -L/usr/local/lib
// #include <stdlib.h>
// #include "signing.h"
import "C"
which fails, output on that later
I also try;
// #cgo LDFLAGS: -L/usr/local/lib -I/usr/local/include
// #include <stdlib.h>
// #include "signing.h"
import "C"
and copy the .h files into the /usr/local/include directory.
None of this works and now I am stuck with an error like this
$ 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)
At this point I really have no idea how to continue.
As you can see I am not experienced in C at all and have no idea how to test if the library libsecp256k1
is even installed properly!
This is where I ended up, but it's highly likely I took a wrong turn early in my journey, I would appreciate any help given as I have been struggling with this for a few nights already now
Not sure whats needed so here some env variables
$ 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"
Version is go version go1.8.3 darwin/amd64 with no old versions lying around.
Thanks!
答案1
得分: 1
你的问题有两个方面:
libsecp256k1
包配置不正确- 你的 C 编译器没有在
/usr/local
目录中搜索已安装的头文件和库
修复 libsecp256k1
配置不正确的问题
当涉及到链接 C 库时出现 "undefined symbols" 问题有时会指向配置不正确的包(指的是 Autotools 包或 CMake 包,而不是 Go 包)。运行 ./configure --help
,我看到有一个名为 --enable-module-recovery
的选项。根据类似 <code>_secp256k1_ecdsa_sign_<strong>recoverable</strong></code>
和 <code>_secp256k1_ecdsa_<strong>recover</strong></code>
的名称,你需要在配置时添加该选项,意味着你应该执行以下命令,而不是简单地执行 ./configure
:
./configure --enable-module-recovery
C 编译器是否损坏?
由于 secp256k1.h
头文件在 /usr/local/include
中找不到,尽管在执行 sudo make install
后该头文件肯定存在,这意味着你的编译器没有在 /usr/local
中搜索。
除非在链接的问题中有任何修复方法,否则你可以通过修改 Go 包的源代码来解决该问题,以添加/修改处理 import "C"
语句时使用的 CFLAGS
和 LDFLAGS
,如下所示:
// #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
将包含头文件,/usr/local/lib
将包含库。这意味着你需要在命令行中导出PKG_CONFIG_PATH
,例如export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
。当未设置PKG_CONFIG_PATH
时,默认设置包括/usr/lib/pkgconfig
和/usr/share/pkgconfig
,在 Linux 上按照此顺序指定为其他可能使用的包的后备,尽管在这种情况下可能不是必需的。默认路径集在 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"
// 或者只需使用 pkg-config 并导出包含以下路径的 PKG_CONFIG_PATH 环境变量:
// /opt/libsecp256k1/lib/pkgconfig
// /opt/libsecp256k1/share/pkgconfig
// /usr/lib/pkgconfig
// /usr/share/pkgconfig
你还需要修改 upvote 目录中提供的 Makefile,以设置构建的二进制文件的运行时路径,否则将找不到 libsecp256k1.0.dylib
:
# 如果你复制并粘贴此内容,请将 `go build` 前面的空格替换为一个水平制表符,否则 `make` 将失败。
#
# 请注意,“ldflags” 是针对 Go 链接器(go tool link)而不是系统链接器(ld)指定的。
build:
go build -ldflags="-r /opt/libsecp256k1/lib"
有关使用 cgo 的更多信息,请参考以下资源:
英文:
Your problem is twofold:
- Improperly configured
libsecp256k1
package - Your C compiler not searching
/usr/local
directories for installed headers/libs
Fixing the improperly libsecp256k1 configured package
Your "undefined symbols" issue when it comes to linking C libraries sometimes points to an improperly configured package (in the sense of an Autotools package or a CMake package, not a Go package). Running ./configure --help
, I see there is an option named --enable-module-recovery
. Judging by names like <code>secp256k1_ecdsa_sign<strong>recoverable</strong></code> and <code>secp256k1_ecdsa<strong>recover</strong></code>, you need to add that option when configuring, meaning instead of executing the simpler ./configure
, you should execute this:
./configure --enable-module-recovery
Is the C compiler broken?
Since the secp256k1.h
header file isn't found in /usr/local/include
, despite the fact that the header file most definitely exists after sudo make install
is finished, it means your compiler doesn't search /usr/local
.
Barring any fixes in the linked question, you can work around the issue by altering the source of the Go package as needed to add/modify the CFLAGS
and LDFLAGS
used when dealing with import "C"
statements like this:
// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -L/usr/local/lib -lsecp256k1
// #include <secp256k1.h>
import "C"
If you have pkg-config
installed, you can use that instead of setting CFLAGS
and LDFLAGS
manually:
- Export the
PKG_CONFIG_PATH
environment variable with a custom set of paths. Because no prefix (i.e. directory serving as the install root) was specified,/usr/local
is assumed, meaning/usr/local/include
will contain headers and/usr/local/lib
will contain libraries. This means you need to exportPKG_CONFIG_PATH
on your command line as inexport PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
. The default setting ofPKG_CONFIG_PATH
when unset includes/usr/lib/pkgconfig
and/usr/share/pkgconfig
in that order on Linux and are specified as a fallback for other packages that might be used, though it may not be necessary in this case. The default set of paths may differ on OS X, so consult yourpkg-config
man page for reference. - Use
// #cgo pkg-config: libsecp256k1
, andCFLAGS
andLDFLAGS
will be set as necessary without you needing to do anything to them. Since not all systems havepkg-config
installed, relying on this is perhaps a bad idea if you want a package to remain portable. Then again, I think it'd be preferable to the mess you dealt with sincepkg-config
simply wouldn't be found. - Change to the upvote directory and type
make
to build a working upvote binary.
Additional customization
Custom prefix
If you use something other than /usr/local
as your prefix (e.g. ./configure --enable-module-recovery --prefix=/opt/libsecp256k1
), then you'll need to adjust some things accordingly:
// #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
You'll also need to modify the provided Makefile in the upvote directory to set the runtime path of the binary that gets built, else libsecp256k1.0.dylib
will not be found:
# 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"
For more information about working with cgo, check out the following resources:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论