来自调用者程序的未定义的库类成员错误引用

时间:2011-04-05 18:30:26

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

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

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

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

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

测试人员和库有几个类,分别用.cpp和.h编写。除主入口点外,库中的类和大多数内容都在命名空间DISCOVER_NS中。

以下是该项目的简要草图:

首先,承认,我缩短了一堆名称,因此代码更具可读性。

discover.cpp

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

  • 有一个extern“C”函数,它将theMainObject作为void *返回给调用者程序。

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


tester.cpp

  • 获取库的句柄

  • 获取返回theMainObject的函数的函数指针。

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

  • 运行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外部“C”中制作几乎所有东西。没有区别。

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


我知道这会有助于查看代码,但我需要时间来解决一些小问题。

有人能提出解决这个烂摊子的想法吗?

谢谢,

韦斯

德米特里的解决方案并不是全部解决方案,但却是解决方案中的必要元素。在检查了我的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的事实。花了一个小时才把所有的图片都删除了,但现在她从makefile中编译就好了。

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

谢谢德米特里。

韦斯

嗯,我的问题仍然存在。

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

FYI,未使用的“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”尝试了它们而不是。

希望得到帮助,

韦斯

2 个答案:

答案 0 :(得分:5)

您的问题似乎是-l<library>

的位置
$(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 namespec

     

...

     

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

这应该适合你:

  

$(CC)$(gflags)$(tstlinkflags)$(定义)-L ./Debug -o ./Debug/RemKonTester ./RemKonTester/Debug/RemKonTester.o ./RemKonTester/Debug/logger.o。 /RemKonTester/Debug/libraryClass.o -ldiscover -ledgeio 2&gt;&amp; 1 | tee ./RemKonTester/make.ERR

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

答案 1 :(得分:0)

编辑:终于找到了“编辑”。做得更漂亮。 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

这是makefile。对不起,我不会说得那么好,所以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*

############################################

谢谢,

韦斯