g ++在visual studio很开心的时候给出了错误 - 未定义的引用

时间:2011-03-04 09:19:05

标签: c++ visual-studio-2010 g++ cross-compiling

我有一些在Visual Studio上运行良好的代码,我现在正在尝试在g ++上编译它。它在一堆地方给了我'SomeClass :: someMethod()const'的未定义引用。

最常见的是,情况如下:

for (const SomeListNode *node = owner->some_list; node != 0; node = node->getNext())

在这种情况下,我得到'对SomeListNode :: getNext()const'的未定义引用。明确包含此类的头文件。为什么这在g ++中不合法?

修改详情

我正在使用makefile构建:

CC=g++
CFLAGS=-c -Wall -DDEBUG -g
LDFLAGS=
SOURCES=main.cpp SomeList.cpp SomeListNode.cpp Location.cpp OutputControl.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=theprogram

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
    $(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:     $(CC)$(CFLAGS)$< -o $ @

最初列出的代码行位于OutputControl.cpp。它正在指向SomeListNode并迭代它。 getNext()返回指向另一个SomeListNode的指针。

也可能需要注意的是,这只发生在静态函数中。

6 个答案:

答案 0 :(得分:2)

您只能在const限定对象上调用const限定方法。如果getNext()不是const,那么您应该使用SomeListNode *node而不是const SomeListNode *node

答案 1 :(得分:1)

未定义的引用是链接器错误,它们与头部包含无关。您必须确保已将这些函数的定义编译到某个目标文件中,并将目标文件传递给链接器。

请注意,如果要编译静态库,则链接器命令行中库的顺序会影响结果。特别是,如果库依赖于其他库,则依赖项应出现在命令行之前所有依赖于库。

无论如何,将每个目标文件分别编译成.o或库并使用nm来提取每个翻译单元中定义的符号列表,这些符号应该告诉您定义是否已编译如果您正在编译静态库,将帮助您确定顺序。

答案 2 :(得分:1)

我建议您在makefile中设置依赖项,以便依赖于其他对象的对象以正确的顺序生成。还要设置一个删除.o文件的干净目标。在这个运行之后,使干净,并使。

这是我能用你给我们的信息来思考的最佳建议。

答案 3 :(得分:0)

将所有.cpp文件传递给g ++编译命令。

g++ -g -Wall -o myapp File1.cpp File2.cpp File3.cpp

编辑:

如果您正在使用静态库,则应在g ++命令行上添加 last

链接器按顺序处理传递的文件,当遇到静态库时,它会搜索到目前为止未定义的符号。您可以使用--whole-archive

更改此设置

答案 4 :(得分:0)

我建议使用nm工具找出您遇到的符号。它可能看起来像这样:

// foo.h
class Foo{
    public:
        void bar();
};

// foo.cpp
#include "foo.h"
void Foo::bar()
{
}

// bar.cpp
#include "foo.h"
void baz()
{
    Foo f;
    f.bar();
}

> nm foo.o
00000000 T _ZN3Foo3barEv

> nm bar.o
00000000 T _Z3bazv
         U _ZN3Foo3barEv
         U __gxx_personality_v0

在这里你可以看到,bar.o使用了未定义的_ZN3Foo3barEv符号(和__gxx_personality_v0,但这是一个编译器细节),标记为U。此符号在foo.o中定义,我们将其标记为T。要从受损名称中获取c ++名称,可以使用c++filt

> c++filt _ZN3Foo3barEv
Foo::bar()

> c++filt _Z3bazv
baz()

要调试您的问题,请检查SomeList.o和OutputControl.o文件并查找SomeListNode :: getNext实例。可能有很多输出,因此您可能希望使用nm file.o | grep 'SomeListNode.*getNext'过滤输出。每个U标记SomeListNode::getNext符号形式的OutputControl.o文件必须在SomeList.o文件中具有完全匹配。

修改:已发布的Makefile的调整后答案。

答案 5 :(得分:0)

Visual Studio和g ++之间的一个区别是它们如何处理模板。在Visual Studio中,如果您在模板中定义一个函数,但从未在任何地方使用它,VS将不会对其进行类型检查或生成任何代码。在g ++中它会进行类型检查(如果有任何问题,它会给你错误。)