【问题标题】:"Undefined symbols for architecture x86_64:" for library using cgo on macOS Sierra“架构 x86_64 的未定义符号:”用于在 macOS Sierra 上使用 cgo 的库
【发布时间】:2017-12-23 23:33:14
【问题描述】:

我正在尝试使用一个库 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 库 go-steem/rpc/examples/upvote/ 中运行 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 的“包含”目录中的文件复制到与错误来源相同的目录中。

可以看到文件不存在;

$ 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 版本 go1.8.3 darwin/amd64,没有旧版本。

谢谢!

【问题讨论】:

  • 我通过使用 ./configure --enable-module-recovery 设法让它在 Linux 上运行。由于我安装到了编译器标准搜索路径之外的目录,因此我还必须修改 transactions/signed_transaction.go 以修复 #cgo 行,以使事情正常工作,以及 upvote 示例目录中 Makefile 中的 ldflags。您可能需要这样做。然后您可以使用examples/upvote 目录中的make 来构建示例。我写了一个shell script to illustrate/automate things。在执行之前阅读 cmets。
  • 非常感谢!我按照您的步骤进行操作,并且成功了,非常感谢您的帮助。请将此添加为答案,以便我可以接受并至少以某种方式奖励您。
  • 很高兴它对您有所帮助。我已经发布了一个更详细的答案,关于正在发生的事情颠覆了对评论脚本的需求,但我留下了包含它的评论,因为它以后可能对其他人有用。

标签: c macos gcc go cgo


【解决方案1】:

你的问题是双重的:

  1. libsecp256k1 包配置不当
  2. 您的 C 编译器未在 /usr/local 目录中搜索已安装的头文件/库

修复不正确的 libsecp256k1 配置包

在链接 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 编译器坏了吗?

由于/usr/local/include中没有找到secp256k1.h头文件,尽管在sudo make install完成后头文件肯定存在,这意味着your compiler doesn't search /usr/local

除非在链接的问题中进行任何修复,否则您可以通过根据需要更改 Go 包的源来解决此问题,以添加/修改在处理 import "C" 语句时使用的 CFLAGSLDFLAGS,如下所示:

// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -L/usr/local/lib -lsecp256k1
// #include <secp256k1.h>
import "C"

如果您安装了pkg-config,您可以使用它来代替手动设置CFLAGSLDFLAGS

  1. 使用一组自定义路径导出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/pkgconfigPKG_CONFIG_PATH 的默认设置在未设置时包括在 Linux 上按此顺序排列的 /usr/lib/pkgconfig/usr/share/pkgconfig,并被指定为可能使用的其他包的后备,尽管在这种情况下可能没有必要。 OS X 上的默认路径集可能有所不同,因此请参阅您的 pkg-config 手册页以供参考。
  2. 使用// #cgo pkg-config: libsecp256k1CFLAGSLDFLAGS 将根据需要进行设置,您无需对它们进行任何操作。由于并非所有系统都安装了pkg-config,因此如果您希望软件包保持可移植性,那么依赖它可能不是一个好主意。再说一次,我认为这比你处理的烂摊子更可取,因为根本找不到 pkg-config
  3. 切换到 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 的更多信息,请查看以下资源:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 2017-08-21
    • 2017-05-18
    • 1970-01-01
    • 2020-12-10
    • 1970-01-01
    • 2015-03-09
    相关资源
    最近更新 更多