【问题标题】:Linker cannot find symbols in library链接器在库中找不到符号
【发布时间】:2017-05-31 02:40:43
【问题描述】:

我使用 CMake 构建了一个 C 库。这是该库的 CMakeLists 文件:

cmake_minimum_required(VERSION 3.7)
project(sshserial)

set(CMAKE_C_STANDARD 99)

include_directories(BEFORE SYSTEM ${CMAKE_SOURCE_DIR}/common/include)
link_directories(${CMAKE_SOURCE_DIR}/common/lib)

set(SOURCE_FILES sshserial.c sshserial.h)
add_library(sshserial ${SOURCE_FILES})

TARGET_LINK_LIBRARIES(sshserial libssh.a)

我在 C++ 程序中使用这个库。这是程序的 CMakeLists 文件:

cmake_minimum_required(VERSION 3.7)
project(sshtest)

set(CMAKE_CXX_STANDARD 11)

include_directories(BEFORE SYSTEM ${CMAKE_SOURCE_DIR}/common/include)
link_directories(${CMAKE_SOURCE_DIR}/common/lib)

set(SOURCE_FILES main.cpp)
add_executable(sshtest ${SOURCE_FILES})

TARGET_LINK_LIBRARIES(sshtest libsshserial.a)

我已将库复制到正确的文件夹中。当我在库上运行 nm 时,我得到了这个:

$ nm libsshserial.a 

libsshserial.a(sshserial.c.o):
                 U ___error
                 U ___stack_chk_fail
                 U ___stack_chk_guard
                 U ___stderrp
                 U ___stdinp
0000000000000330 T _create_session
                 U _exit
                 U _fgets
                 U _fprintf
                 U _free
                 U _getpass
0000000000000490 T _read_from_session
                 U _ssh_channel_close
                 U _ssh_channel_free
                 U _ssh_channel_new
                 U _ssh_channel_open_session
                 U _ssh_channel_read
                 U _ssh_channel_request_exec
                 U _ssh_channel_send_eof
                 U _ssh_connect
                 U _ssh_disconnect
                 U _ssh_free
                 U _ssh_get_error
                 U _ssh_get_hexa
                 U _ssh_get_pubkey_hash
                 U _ssh_is_server_known
                 U _ssh_new
                 U _ssh_options_set
                 U _ssh_print_hexa
                 U _ssh_userauth_password
                 U _ssh_write_knownhost
                 U _strerror
                 U _strncasecmp
0000000000000000 T _verify_knownhost
                 U _write

当我尝试构建程序时,我得到这个链接器错误:

Undefined symbols for architecture x86_64:
  "create_session()", referenced from:
      _main in main.cpp.o
  "read_from_session(ssh_session_struct*)", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [sshtest] Error 1
make[2]: *** [CMakeFiles/sshtest.dir/all] Error 2
make[1]: *** [CMakeFiles/sshtest.dir/rule] Error 2
make: *** [sshtest] Error 2

我被困在这里已经有一段时间了,我确信我错过了一些微不足道的东西。我做错了什么?

附:我在 Mac 上

$ uname -a
Darwin XXXXXX 15.6.0 Darwin Kernel Version 15.6.0: Tue Apr 11 16:00:51 PDT 2017; root:xnu-3248.60.11.5.3~1/RELEASE_X86_64 x86_64

【问题讨论】:

  • 为什么不将测试项目设为库项目的子项目(在子文件夹中)?然后你可以做TARGET_LINK_LIBRARIES(sshtest sshserial) 和 CMake 设置 makefiles 以自动与库链接。
  • 另外,您确实在声明由 C++ 编译器编译的函数时使用extern "C"
  • @Someprogrammerdude :我现在可以试试,我会的。但后来我想在其他项目中使用 C 库,所以我猜这不是一个永久的解决方案。
  • @Someprogrammerdude : 该库是用 C 构建的
  • 是的,这很可能是问题所在。 C 和 C++ 在很多方面都不同,其中一个 C++ 使用name mangling,以支持重载等。这意味着非 C++ 库的函数声明需要以 extern "C" 为前缀或包围以禁止名称修改,因为 C 不会“修改”名称。

标签: c++ c cmake linker


【解决方案1】:

问题在于 C++ 使用了name mangling。为了抑制这种情况,您需要使用 extern "C" 声明 C 函数,但仅在由 C++ 编译器编译时。您可以使用 __cplusplus 宏来检查这一点,该宏在编译 C++ 时定义,但不是在编译 C 时。

在声明函数原型的头文件中,执行类似

#ifdef __cplusplus
// Being compiled by a C++ compiler, inhibit name mangling
extern "C" {
#endif

// All your function prototype declarations here

#ifdef __cplusplus
}  // End of extern "C"
#endif

【讨论】:

  • 正如我在帖子的 cmets 中指出的那样,该库是用 C 构建的,所以我不需要用 extern "C" 装饰导出的符号
  • @nakiya 如果您想使用 C++ 中的函数,那么您需要!故事结局!只需尝试
  • @nakiya 或者,如果它是第 3 方库,您可以将 #includeextern "C" {..} 括起来。
猜你喜欢
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多