【问题标题】:Clang and undefined symbols when building a library构建库时的 Clang 和未定义符号
【发布时间】:2014-10-14 19:12:31
【问题描述】:

我正在开发一个 C++ 框架,当我在 OSX 上使用 Clang 编译它时出现了一些问题。

首先,我正在使用其他一些库,例如 openssl,并且当我构建库时,clang 抱怨某些符号没有解决。它们不应该是:这些库将与最终的二进制文件链接,它不应该发生在中介上。

然后,还有一些方法和变量应该在“客户端”二进制文件中实现......使用 GCC,没有问题,但 Clang 也抱怨这些符号在编译期间无法解决。

怎么会?我该怎么办?

这是我的 CMakeLists.txt,以防万一:

cmake_minimum_required(VERSION 2.8)

project(crails_project)

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wno-deprecated-declarations -pedantic -DASYNC_SERVER -DSERVER_DEBUG -DUSE_MONGODB_SESSION_STORE")

find_package(cppnetlib REQUIRED)

include_directories(include /usr/local/include ${CPPNETLIB_INCLUDE_DIRS} .)

file(GLOB crails_core
     src/*.cpp)

file(GLOB crails_sql
     src/sql/*.cpp)

file(GLOB crails_mongodb
     src/mongodb/*.cpp)

add_library(crails-core    SHARED ${crails_core})
add_library(crails-sql     SHARED ${crails_sql})
add_library(crails-mongodb SHARED ${crails_mongodb})

这是崩溃的命令:

/usr/bin/c++  -std=c++0x -Wall -Wno-deprecated-declarations -pedantic -DASYNC_SERVER -DSERVER_DEBUG -DUSE_MONGODB_SESSION_STORE -dynamiclib -Wl,-headerpad_max_install_names   -o libcrails-core.dylib -install_name /Users/michael/Personal/crails/build/libcrails-core.dylib CMakeFiles/crails-core.dir/src/assets.cpp.o CMakeFiles/crails-core.dir/src/cgi2params.cpp.o CMakeFiles/crails-core.dir/src/cipher.cpp.o [...]

这是我得到的两种错误:

架构 x86_64 的未定义符号:

  "_BIO_ctrl", referenced from:
      Cipher::encode_base64(unsigned char*, unsigned int) const in cipher.cpp.o

第二个:

  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "vtable for boost::detail::thread_data_base", referenced from:
      boost::detail::thread_data_base::thread_data_base() in server.cpp.o

【问题讨论】:

  • 你得到的错误是什么?您是否尝试过进行详细构建,以查看正在使用哪些命令(和标志)(即生成一个 makefile,并使用VERBOSE=1 运行它)?
  • 感谢您的回答,我更新了帖子的更多细节!
  • 第一个错误使用-lcrypto

标签: c++ cmake clang


【解决方案1】:

我不建议启用全局动态查找:

-undefined dynamic_lookup 这会将所有未定义的符号标记为必须在运行时查找。

为特定符号解决问题的更安全的方法:

-Wl,-U,symbol_name,仅对给定符号这样做(注意:您必须在符号名称前加上下划线)

你也可以使用弱动态链接:

extern int SayHello() __attribute__((weak));

【讨论】:

  • 请注意,-undefined dynamic_lookup 是特定于 OSX 的。 Linux 共享库的行为就像-undefined dynamic_lookup 一直处于启用状态一样。我不确定 Windows。
【解决方案2】:

解决了! Clang 需要接收选项-undefined dynamic_lookup 以在编译库时忽略丢失的符号。

将此添加到 CMakeFile.txt 以产生预期的效果:

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
  set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS} -undefined dynamic_lookup")
endif()

【讨论】:

  • 这不是一个好的答案,根本不是一个真正的答案。如果您丢失了_open,因为它应该是open-undefined dynamic_lookup 不会解决任何问题。为什么clang将这些 _ 添加到没有导出的函数中?我看到应该存在的各种错误:_close、_write、_sleep。我是否需要链接一些我不知道的特殊 LLVM libc?有问题的函数在没有这个下划线废话的情况下使用,并且在 /lib/libc-2.27.so 中没有定义! ef 在哪里 llvm libc?
  • 这个答案的重点不是修复丢失的符号。我正在构建的库中预计会丢失这些符号。这个答案显示了如何使用 clang 实现这一目标。在您的情况下,我会说 _open、_write、_sleep 只是打开/写入/睡眠的错位形式。至于为什么它们在您的构建中丢失,这是另一个我不知道是否可以提供帮助的问题。
【解决方案3】:

根据其中一位评论者的说法,您必须使用 -lcrypto 来防止出现第一个错误。

第二个错误似乎是由于 clang 和 gcc 的 ABI 不兼容。使用 clang++ 和 libc++ 重建 boost。请参阅 SO 帖子 Is clang++ ABI same as g++?Why can't clang with libc++ in c++0x mode link this boost::program_options example?How to compile/link Boost with clang++/libc++?

如果您在使用其他库时遇到链接器问题,您还应该尝试使用 clang++ 重建那些。

编辑:

为了指示 OS X 链接器允许未解析的符号,您应该将 -undefined dynamic_lookup 添加到链接器选项中。另见 SO 帖子Error when making dynamic lib from .o

【讨论】:

  • 这实际上是我想知道的事情之一:为什么我应该使用 -lcrypto 或担心 ABI 兼容性?我不需要与 GCC 进行任何链接(这很好,因为在构建库时存在 should not 解决的符号)。有没有办法不用链接就可以用 Clang 编译库?在我的场景中,我应该在构建可执行文件时担心 ABI 兼容性,而不是之前。
  • Afaik clang 的行为不应有所不同。您确定在使用 g++ 编译时不链接这些库吗?您可能想使用“nm -C -u libcrails-core.dylib”来检查用 g++ 编译的库中是否有未定义的符号。
  • 好吧,我刚刚运行了nm -C -u /usr/lib/libcrails-core.so(g++ 构建已经在 Linux 上进行),它返回了 Clang 谈到的所有符号(以相同的顺序),以及更多(字符串、字符串流、 pthread 的东西)。
  • 您是否尝试在 Mac OS X 上使用 g++ 进行编译?我假设您遇到了同样的麻烦,并且您还需要将“-undefined dynamic_lookup”添加到链接器选项中。所以这不是一个clang问题......
  • 确实如此。那么为什么会这样呢?我是否应该检查操作系统,并在构建脚本在 OSX 上运行时始终添加此标志?
猜你喜欢
  • 1970-01-01
  • 2013-07-16
  • 2014-09-08
  • 1970-01-01
  • 2020-03-01
  • 2017-03-10
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
相关资源
最近更新 更多