【问题标题】:Unsdefined reference to library class members errors from caller program调用程序中对库类成员错误的未定义引用
【发布时间】:2011-04-05 18:30:26
【问题描述】:

以下添加的其他问题,2011 年 4 月 11 日

我正在开发一组跨平台的共享库 DLL/Sos 和 C++ 中的测试程序,尽管我必须能够支持 C。这些库将仅作为目标代码发布,但测试程序将发布带有源代码,因此我们的客户可以获得示例代码。出于这个原因,我正在设计要在运行时加载的库,即使用 dlopen()/LoadLibraryA() 进行动态链接。

我在 Umbutu 10.04 上使用 g++ 4.4.3-4,在 Vista/64(32 位模式)上使用 VC++ 2008。

在 Windows 上似乎一切正常(现在)。但是,当我在 Linux 上编译时,我遇到了一些我无法弄清楚的错误。

测试器和库有几个类,用几个 .cpp 和 .h 编码。除了主要入口点之外,库中的类和大部分内容都位于命名空间 DISCOVER_NS 中。

这是项目的简要概述:

首先,承认,我已经缩短了一堆名称,以便代码更具可读性。

discover.cpp

  • 使用指向它的指针创建一个类对象,称为 DiscoverObject 类型的 MainObject。

  • 有一个外部“C”函数将MainObject作为void*返回给调用者程序。

  • DiscoverObject 有几种方法,并实例化在单独的 cpp 和 .h 中找到的其他类。一种特殊的方法名为 Hello(),它可以满足您的期望,它会打印一条“hello”测试消息。


tester.cpp

  • 获取库的句柄

  • 获取指向返回 MainObject 的函数的函数指针。

  • 执行函数(指针)并将返回的地址从 void* 转换为 DISCOVER_NS::DiscoverObject* aDiscoverObject。

  • 运行发现对象->Hello()。


我编译:

CC = @g++

gflags = -g3

cflags = -fPIC -Wall -pedantic

lib_linkflags := -shared -fPIC -lstdc++ -lrt -lpthread -rdynamic

tester_linkflags := -ldl -lpthread

定义 = -D_linux_ -D_DEBUG -D_IPC_ARCH_INTEL=1 -D_THREAD_SAFE


现在,当我编译时出现以下错误: *Tester.cpp:142: 未定义引用 `Discover_NS::DiscoverObject::hello()'*

我还从 discover.so 中得到了一堆其他未定义的引用错误,例如: *discover.so: 未定义引用 `Discover_NS::DeviceList::~DeviceList()*


我尝试在 SO extern "C" 中制作几乎所有内容。没有区别。

我尝试将语句放入 discover.cpp,如下所示: extern void Discover_NS::OtherClass::method( args ); 但这给了我关于“类外声明不是定义”的错误。


我知道查看代码会有所帮助,但我需要时间整理一些小东西来发布。

谁能提供解决这个问题的想法?

谢谢,

韦斯

Dmitry 的解决方案并不是解决问题的全部,而是解决方案中的必要元素。在检查我的 makefile 后,我发现了一些无意中重复的行,我删除了它们,还有两个“错别字”,我将 -o 编码到编译步骤中的路径错误。破碎的步骤编译了logger.cpp和RemException.cpp:

./common/logger.o : ./common/logger.cpp
    $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  
        -I ./EdgeIO  -I ./Discover   
        -o ./common/Debug/logger.o   <+++++++++ path to .o was wrong
        ./common/logger.cpp   2>&1  | tee ./RemKonTester/logger.ERR

然后我发现了真正的错误。我完全错过了我没有在 Discover 目录中编译所有 .cpp 的事实!。删除所有 nit-pics 花了好一个小时,但现在她从 makefile 编译出来就好了。

原始问题的新版本:现在我知道它可以通过 makefile 工作,我如何让 Eclipse 做与 makefile 相同的事情?

谢谢德米特里。

韦斯

好吧,我的问题还在。

我的代码已根据 Dmitry (@Dmitry) 的建议进行编译。只是,它们似乎导致了一个单独的问题。我希望我的库在运行时动态链接到他的主测试程序。将 -l Discover -l EdgeIO 添加到链接可以编译所有内容,但它给了我静态链接。

仅供参考,未使用的“pi”是所以 SO 在其中有一个浮点数,因此将使用浮点支持进行编译。如果调用者想要使用浮点数,则需要。有人有更好的方法来强制 g++ 编译包含浮点数吗?

在修复了 Dmitry 帮助我找到的许多错误之后,我现在得到了以下输出:

make
./Discover/dllmain.cpp: In function ‘void InitalizeLibraryServices()’:
./Discover/dllmain.cpp:175: warning: unused variable ‘pi’


./EdgeIO/dllMain.cpp: In function ‘void InitalizeLibraryServices()’:
./EdgeIO/dllMain.cpp:158: warning: unused variable ‘pi’


linking RemKonTester
    gflags = -g3
    tstlinkflags = -ldl  -lpthread 
    defines =  -D__linux__   -D_DEBUG   -D_IPC_ARCH_INTEL=1   -D_THREAD_SAFE

./RemKonTester/Debug/RemKonTester.o: In function `main':
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:81: undefined 
    reference to `RemKon_EdgeIO::EdgeIoObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:111: undefined 
    reference to `RemKon_Discover::DiscoverObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:116: undefined 
    reference to `RemKon_Discover::DiscoverObject::SetLogLevel(unsigned int)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:117: undefined 
    reference to `RemKon_Discover::DiscoverObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:118: undefined 
    reference to `RemKon_Discover::DiscoverObject::LocalIpAddress(int)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:122: undefined 
    reference to `RemKon_Discover::DiscoverObject::RegisterCallback(bool(*)
    (void*), void*)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:123: undefined 
    reference to `RemKon_Discover::DiscoverObject::Search()'

collect2: ld returned 1 exit status

我从 Eclipse 中得到相同的错误消息。

RemKonTester.cpp 包括声明这些项目的所有 .h。我已经尝试使用声明 extern "C" 而不是。

希望得到帮助,

韦斯

【问题讨论】:

  • 你能发布 g++ 的实际输出吗?通常问题出在给g++的参数顺序上
  • 再次,它不是很清楚 g++ 到底是什么 :) 尝试make -n 查看 make 执行的实际 g++ 命令并将它们发布在这里。还要检查nm lib_your_lib.so|grep some_symbol_in_you_lib 预期的符号实际上是否在库中

标签: c++ cross-platform shared-libraries undefined-reference


【解决方案1】:

你的问题好像是-l&lt;library&gt;的位置:

$(CC)  $(gflags)  $(tstlinkflags) $(defines)      -L ./Debug    -ldiscover   
        -ledgeio -o ./Debug/RemKonTester  ./RemKonTester/Debug/RemKonTester.o  
        ./RemKonTester/Debug/logger.o  ./RemKonTester/Debug/libraryClass.o   
        2>&1  | tee ./RemKonTester/make.ERR

它们应该在目标文件之后,因为链接器会在它们在命令行遇到它们并搜索未定义的符号时加载它们。

请参阅man ld(特别是-l 选项)了解更多信息:

-l 名称规范

...

链接器只会在命令行中指定的位置搜索存档一次。如果档案定义了一个 在命令行存档之前出现的某些对象中未定义的符号,链接器将包括 档案中的适当文件。但是,稍后在命令行中出现的对象中的未定义符号不会导致 再次搜索存档的链接器。

这应该适合你:

$(CC) $(gflags) $(tstlinkflags) $(defines) -L ./Debug -o ./Debug/RemKonTester ./RemKonTester/Debug/RemKonTester.o ./RemKonTester/Debug/logger.o 。 /RemKonTester/Debug/libraryClass.o -ldiscover -ledgeio 2>&1 | tee ./RemKonTester/make.ERR

附:请注意,在 StackOverflow 中有一个用于编辑问题的选项,将附加信息作为答案发布不是一个好习惯。

【讨论】:

    【解决方案2】:

    EDITED:终于找到了“编辑器”。让它更漂亮。 wjm

    抱歉耽搁了。昨晚我不得不把一棵倒下的树从我的前院弄出来。

    注意:我更改了原始笔记中的一些名称以使其更短。这个答案已经说明了一切。


    g++ 输出...

    $ make
    ./EdgeIO/dllMain.cpp: In function ‘void InitalizeLibraryServices()’:
    ./EdgeIO/dllMain.cpp:158: warning: unused variable ‘pi’
    ./Discover/dllmain.cpp: In function ‘void InitalizeLibraryServices()’:
    ./Discover/dllmain.cpp:174: warning: unused variable ‘pi’
    ./RemKonTester/RemKonTester.cpp: In function ‘int main(int, char**)’:
    ./RemKonTester/RemKonTester.cpp:130: warning: ISO C++ forbids casting between     
    pointer-to-function and pointer-to-object
    ./RemKonTester/RemKonTester.cpp:152: warning: unused variable ‘searchResp’
    ./RemKonTester/libraryClass.cpp: In member function ‘int 
    library::AttachLibrary()’:
    ./RemKonTester/libraryClass.cpp:132: warning: ISO C++ forbids casting between 
    pointer-to-function and pointer-to-object
    ./RemKonTester/libraryClass.cpp:154: warning: ISO C++ forbids casting between 
    pointer-to-function and pointer-to-object
    ./RemKonTester/Debug/RemKonTester.o: In function `main': 
    /home/wmiller/Projects/Eclipse/
    ./RemKonTester/RemKonTester.cpp:142: undefined reference to 
    `RemKon_Discover::DiscoverObject::hello()'
    collect2: ld returned 1 exit status
    gflags = -g3
    tstlinkflags = -ldl  -lpthread
    defines =  -D__linux__   -D_DEBUG   -D_IPC_ARCH_INTEL=1   -D_THREAD_SAFE
    ./Debug/libdiscover.so: undefined reference to     
    `RemKon_Discover::RemKonDeviceList::~RemKonDeviceList()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::ClientPort(unsigned short)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::PayloadSize(unsigned int)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::Socket() const'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemKonDeviceList::Count() const'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemException::~RemException()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::UDPbinder()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::ListenTimeOut(int)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::ServerPort(unsigned short)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemKonDeviceList::Next()'
    ./Debug/libdiscover.so: undefined reference to `RemKon_Discover::Log(char 
    const*, ...)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::UDPlisten(unsigned char*, int*, sockaddr_in*, int*)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemException::RemException()'
    ./Debug/libdiscover.so: undefined reference to `RemKon_Discover::VerboseLogging()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::RegisterCallbackFunction(void (*)(void*, unsigned 
    char*, int), void*)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemKonDeviceList::First()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::TestData(unsigned int, unsigned int, unsigned char*, 
    unsigned int)'
    ./Debug/libdiscover.so: undefined reference to `RemKon_Discover::Logging()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::MessageLength(int)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::LocalIpAddress(int)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::UDPsend()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::DiscoverObject::LocalIpAddress() const'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::SetBroadcastMode()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::MakeMacAddressString(unsigned char*, char*)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemKonDeviceList::RemKonDeviceList()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemKonDeviceList::New()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::ActivateLogging(unsigned int)'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::RemSocket()'
    ./Debug/libdiscover.so: undefined reference to 
    `RemKon_Discover::RemSocket::Payload(unsigned int)'
    collect2: ld returned 1 exit status
    

    这是生成文件。抱歉,我的 make 说得不太好,所以 makefile 是功能性的,而不是漂亮的。

    CC = @g++
    gflags = -g3
    cflags = -fPIC -Wall -pedantic
    liblinkflags := -shared -fPIC -lstdc++ -lrt -lpthread -rdynamic
    tstlinkflags := -ldl  -lpthread
    defines = -D__linux__   -D_DEBUG   -D_IPC_ARCH_INTEL=1   -D_THREAD_SAFE
    
    
    all : clean edgeio discover tester
    
    
    ############################################
    
    edgeio : ./EdgeIO/dllMain.o ./EdgeIO/EdgeIO.o
    $(CC) $(gflags)  $(liblinkflags) $(defines)    -Wl,-soname,./Debug
        /libedgeio.so.1  -o ./Debug/libedgeio.so.1.0 ./EdgeIO/Debug/edgeio.o  
        ./EdgeIO/Debug/dllmain.o    2>&1  | tee ./EdgeIO/make.ERR
                @cd ./Debug; ln -sf libedgeio.so.1.0    libedgeio.so
            @cd ./Debug; ln -sf libedgeio.so.1.0    libedgeio.so.1
    
    ./EdgeIO/dllMain.o : ./EdgeIO/dllMain.cpp
            $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
        -I ./Discover   -o./EdgeIO/Debug/dllmain.o  ./EdgeIO/dllMain.cpp   2>&1  
        | tee ./EdgeIO/dllmain.ERR
    
    ./EdgeIO/EdgeIO.o : ./EdgeIO/EdgeIO.cpp
        $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
        -I ./Discover   -o./EdgeIO/Debug/edgeio.o  ./EdgeIO/EdgeIO.cpp     2>&1  | 
        tee ./EdgeIO/EdgeIO.ERR
    
    ############################################
    
    discover : ./Discover/Discover.o ./Discover/dllmain.o
        $(CC) $(gflags)  $(liblinkflags) $(defines)    -Wl,-soname,./Debug
            /libdiscover.so.1  -o ./Debug/libdiscover.so.1.0          ./Discover/Debug
            /Discover.o  ./Discover/Debug/dllmain.o    2>&1  | tee ./Discover/make.ERR
        @cd ./Debug; ln -sf libdiscover.so.1.0  libdiscover.so
        @cd ./Debug; ln -sf libdiscover.so.1.0  libdiscover.so.1
    
    ./Discover/Discover.o : ./Discover/Discover.cpp
        $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
        -I ./Discover   -o./Discover/Debug/Discover.o  ./Discover/Discover.cpp  
         2>&1  | tee ./Discover/Discover.ERR
    
    ./Discover/dllmain.o : ./Discover/dllmain.cpp
            $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
            -I ./Discover   -o./Discover/Debug/dllmain.o  ./Discover/dllmain.cpp   
            2>&1  | tee ./Discover/dllmain.ERR
    
    ############################################
    
    tester : ./RemKonTester/RemKonTester.o ./common/logger.o  ./RemKonTester
            /libraryClass.o    ./common/RemException.o
        $(CC)  $(gflags)  $(tstlinkflags) $(defines)       
            -L ./Debug -o ./Debug/RemKonTester  ./RemKonTester/Debug
            /RemKonTester.o  ./RemKonTester/Debug/logger.o  ./RemKonTester/Debug
            /libraryClass.o   2>&1  | tee ./RemKonTester/make.ERR
    
        @echo "gflags = $(gflags)"   2>&1  | tee ./RemKonTester/make.ERR
        @echo "tstlinkflags = $(tstlinkflags)"   2>&1  | tee ./RemKonTester/make.ERR
        @echo "defines =  $(defines)"   2>&1  | tee ./RemKonTester/make.ERR
    
        $(CC)  $(gflags)  $(tstlinkflags) $(defines)      -L ./Debug    -ldiscover   
            -ledgeio -o ./Debug/RemKonTester  ./RemKonTester/Debug/RemKonTester.o  
            ./RemKonTester/Debug/logger.o  ./RemKonTester/Debug/libraryClass.o   
            2>&1  | tee ./RemKonTester/make.ERR
    
    ./RemKonTester/RemKonTester.o : ./RemKonTester/RemKonTester.cpp
        $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
            -I ./Discover   -o ./RemKonTester/Debug/RemKonTester.o   ./RemKonTester
            /RemKonTester.cpp   2>&1  | tee ./RemKonTester/RemKonTester.ERR
    
    ./common/logger.o : ./common/logger.cpp
        $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
            -I ./Discover    -o ./RemKonTester/Debug/logger.o  ./common/logger.cpp
            2>&1  | tee ./RemKonTester/logger.ERR
    
    ./RemKonTester/libraryClass.o : ./RemKonTester/libraryClass.cpp
        $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
            -I ./Discover    -o ./RemKonTester/Debug/libraryClass.o 
            ./RemKonTester/libraryClass.cpp   2>&1  | tee ./RemKonTester
            /libraryClass.ERR
    
    ./common/RemException.o : ./common/RemException.cpp
        $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
            -I ./Discover    -o ./RemKonTester/Debug/RemException.o ./common
            /RemException.cpp   2>&1  | tee ./RemKonTester/RemException.ERR
    
    
    ############################################
    
    clean :
        @rm -f *.ERR
        @rm -f ./common/*.ERR
        @rm -f ./EdgeIO/*.ERR
        @rm -f ./Discover/*.ERR
        @rm -f ./RemKonTester/*.ERR
    
        @rm -f QEMACRO*
        @rm -f ./common/EdgeIO/QEMACRO*
        @rm -f ./EdgeIO/QEMACRO*
        @rm -f ./Discover/QEMACRO*
        @rm -f ./RemKonTester/QEMACRO*
    
        @rm -f ./Debug/*.o
        @rm -f ./common/Debug/*.o
        @rm -f ./EdgeIO/Debug/*.o
        @rm -f ./Discover/Debug/*.o
        @rm -f ./RemKonTester/Debug/*.o
    
        @rm -f ./Debug/*.log
        @rm -f ./common/Debug/*.log
        @rm -f ./EdgeIO/Debug/*.log
        @rm -f ./Discover/Debug/*.log
        @rm -f ./RemKonTester/Debug/*.log
    
        @rm -f ./Debug/*.so*
    
    ############################################
    

    谢谢,

    韦斯

    【讨论】:

      猜你喜欢
      • 2021-11-30
      • 1970-01-01
      • 2021-07-10
      相关资源
      最近更新 更多