0

我正在将用 C 编写的中型(10,000 行左右)程序集成到 C++ 程序中。我创建了一个新类,BWAGenome作为 C 代码的接口,因此对 C 函数的任何访问都被封装。我正在用g++编译器编译所有东西。.o 文件都是正确生成的,但是当我尝试将它们链接到最终的可执行文件中时,编译器会抱怨它找不到符号。这是我收到的错误消息:

Undefined symbols:
BWAGenome::BWTRestoreBWT(char const*)", referenced from:
  BWAGenome::BWAGenome(char const*)in BWAGenome.o
"BWAGenome::GetMatches(unsigned int, int, bwt_t*, bwt_t*, bwt_t*, bntseq_t*, bntseq_t*)", referenced from:
  BWAGenome::getMatches(unsigned int, int)in BWAGenome.o

这些函数都在我制作的C++类中。它们将函数包装在 C 代码中,但我完全不明白符号是如何未定义的。

关于代码的一些细节以及我到目前为止所做的事情:

  • 一切都是用 编译的g++,所以如果我理解正确,我不需要extern "C" {};包含我包含的 c 头文件。
  • 所有代码都可以单独正确编译。该错误仅在链接期间发生。
  • 我在某处听说可能需要从静态函数调用 C 代码,所以我尝试将每个对 C 函数的调用包装在静态类方法中并调用它。

关于如何解决这个问题的任何想法?


编辑:添加了 BWTRestoreBWT 和 GetMatches 的定义和声明

//definition in BWAGenome.h
static bwt_t * BWTRestoreBWT(const char *fn);

//declaration in BWAGenome.cpp
static bwt_t * BWTRestoreBWT(const char *fn) {
    return bwt_restore_bwt(fn);
    //bwt_restore_bwt is a function in the C code that I am attempting to integrate
}

第二次编辑:经过深思熟虑后,我意识到这个问题与我认为的大部分问题无关。有关详细信息,请参阅我的答案。

4

7 回答 7

2

我注意到它正在寻找BWAGenome::BWTRestoreBWTand BWAGenome::GetMatches。这些是它正在寻找的成员函数,而不是根命名空间全局自由函数。

尝试将调用更改BWTRestoreBWT为对 C 函数的调用,以便::BWTRestoreBWT在代码中调用,看看会发生什么。对调用执行相同的操作GetMatches

告诉你需要从静态 C++ 函数调用 C 函数的人是完全错误的。这将迫使您将标准库包装在 C++ 静态函数中,这很愚蠢。

于 2009-12-12T07:08:37.893 回答
2

尝试使用 nm 程序获取程序中定义和引用的符号的输出:

nm file.o | grep BWTRestoreBWT

您应该看到带有 T 或 U 的符号。T 表示名称已定义,后者表示符号未定义但已调用。为了链接,对于每个 U 必须有对应的 T。

确保您的函数没有内联限定符,除非它们在头文件中定义。

于 2009-12-12T08:05:53.160 回答
2

我对这个问题想得越多,看起来你在类声明中声明的函数越多,但你没有对应的函数定义。

例如,此示例编译得很好,但会产生与您看到的相同的链接器错误:

typedef unsigned int bwt_t;
typedef unsigned int bntseq_t;

class BWAGenome {
public:
    BWAGenome( char const* name);

    void BWTRestoreBWT( char const* name);

    void GetMatches( unsigned int, int, int, bwt_t*, bwt_t*, bwt_t*, bntseq_t*, bntseq_t*);
    void getMatches( unsigned int, int);

};

BWAGenome::BWAGenome( char const* name) 
{
    BWTRestoreBWT( name);
}

void BWAGenome::getMatches( unsigned int x, int y)
{
    GetMatches( x, y, 0,0,0,0,0,0);
}

int main()
{
    return 0;
}

函数BWTRestoreBWT()GetMatches()应该是被包装的 C 函数的一部分class BWAGenome还是它们?如果是后者,则表明您将这些函数的标头包含在错误的位置(事实上,它们确实可能需要extern "C"添加链接规范)。


针对问题中的新信息进行编辑:


在您编辑的问题中,您说:

//definition in BWAGenome.h
static bwt_t * BWTRestoreBWT(const char *fn);

//declaration in BWAGenome.cpp
static bwt_t * BWTRestoreBWT(const char *fn) {
    return bwt_restore_bwt(fn);
    //bwt_restore_bwt is a function in the C code that I am attempting to integrate
}

由于您原始问题中的错误,我只能假设BWTRestoreBWT()in的声明BWAGenome.h是 inside of class BWAGenome,如下所示:

class BWAGenome {
    // etc...

    static bwt_t * BWTRestoreBWT(const char *fn);

    // etc...
};

这意味着 thatBWTRestoreBWT()是其中的成员,class BWAGenome()因此其定义应如下所示(注意BWAGenome::范围运算符):

//declaration in BWAGenome.cpp
static bwt_t * BWAGenome::BWTRestoreBWT(const char *fn) {
    return bwt_restore_bwt(fn);
    //bwt_restore_bwt is a function in the C code that I am attempting to integrate
}

或者您可以将声明移到BWTRestoreBWT()外部class BWAGenome(更正式地称为“命名空间范围”)。

那应该可以解决您当前的链接器错误。如果您现在收到有关名称类似于bwt_restore_bwtnot being found 的错误,那么您将知道您也需要 extern "C"为 C 函数执行此操作。

于 2009-12-12T08:07:13.000 回答
1

您是否告诉链接器在哪里可以找到包含该BWAGenome::BWTRestoreBWT函数的库/对象?由于您单独编译所有内容,因此您必须明确链接输出 .o 文件。

可能导致此链接错误的两个原因是

  1. 有一个搜索名称的定义,但您没有将其提供给链接器
  2. 您提供给链接器的目标文件不包含该方法 - 即您没有实现它(或认为您实现了它,但给实现一个“错误”的名称)
于 2009-12-12T08:17:20.877 回答
1

如果您对非类成员函数使用 static 关键字,则该函数将具有本地链接,这意味着它不会在您的编译单元(即 .cpp 文件)之外可见。您要么必须获取它的静态关键字,要么将函数体放入您的包含文件中。

在类成员函数的上下文中,静态具有不同的含义。在这种情况下,静态允许在不实例化类对象的情况下调用函数。

于 2009-12-13T00:22:24.887 回答
0

你检查过你真的声明了相同形状的函数吗?

它正在寻找BWAGenome::BWTRestoreBWT(char const*),但也许您已经BWAGenome::BWTRestoreBWT(char *)(没有const)声明了?

于 2009-12-12T06:49:12.397 回答
0

错误在于我将目标文件链接在一起的顺序。我需要先链接 C 代码,然后是我创建的 BWAGenome 类来调用它。链接器找不到 C 代码符号,因为它们尚未链接。感谢您的所有帮助。我想我让一些人感到沮丧,但无论如何谢谢。

于 2009-12-17T05:22:55.403 回答