3

好的,这可能是非常基本的,但我找不到问题。我正在尝试使用 -lyajl 将我的 C++ 程序与 C 共享库(以 YAJL 命名)链接;链接器似乎找到了它(它不会为此抱怨)但找不到我在代码中使用的符号:

$> g++ test.c -lyajl

Undefined symbols for architecture x86_64:
  "yajl_tree_parse(char const*, char*, unsigned long)", referenced from:
      _main in ccEqsAaJ.o
  "yajl_tree_get(yajl_val_s*, char const**, yajl_type)", referenced from:
      _main in ccEqsAaJ.o
  "yajl_tree_free(yajl_val_s*)", referenced from:
      _main in ccEqsAaJ.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
$>

我制作了一个极简的 test.c 文件来隔离行为。好吧,非常奇怪的是 gcc 似乎完全可以使用代码(顺便说一下,test.c 只是 C 代码,这里没有 C++ 功能):

$> gcc test.c -lyajl
$>

gcc 在做什么,g++ 似乎无法做对?

4

2 回答 2

4

会不会是 libyajl.so 中的符号是 C 链接,但是您的代码(或您正在使用的头文件)没有声明它们extern "C"?在这种情况下,将代码编译为 C++ 会导致目标文件中出现名称损坏的符号,这与库中的(C 链接,未损坏的)符号不匹配。

解决方案是在头文件中编写如下内容:

#ifdef __cplusplus
// "__cplusplus" is defined whenever it's a C++ compiler,
// not a C compiler, that is doing the compiling.
extern "C" {
#endif

// Exchange "void" with the real return type for these functions
void yajl_tree_parse(char const*, char*, unsigned long);
void yajl_tree_get(yajl_val_s*, char const**, yajl_type);
void yajl_tree_free(yajl_val_s*);

#ifdef __cplusplus
}
#endif
于 2012-06-20T10:44:55.190 回答
3

如果extern "C"不能修复,试试这个。

我在尝试链接静态库 libyajl_s.a 时遇到了同样的问题。可以通过将 yajl 源代码编译成可执行文件来解决这个问题,但我确实需要静态库。在仔细检查 yajl 源代码后,您会看到源代码正在两个单独的文件夹中查找标题,例如

#include <api/yajl_tree.h>
#include <api/yajl_parse.h>
#include "yajl_parser.h"

链接器似乎将 yajl_tree_parse、yajl_tree_get 和 yajl_tree_free 解析为它们在 yajl_tree.h 中的原型,而不是它们在 yajl_tree.c 中的定义。换句话说 - 它们在生成的库中仍未定义。

解决方案是将所有标头从api文件夹移动到src文件夹并删除所有对<api/...>. 然后链接器正确地选择了 yajl_tree_xxx 函数定义。

于 2012-09-20T10:32:04.060 回答