Wes*_*ler 3 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
define = -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
Run Code Online (Sandbox Code Playgroud)
然后我发现了真正的错误.我完全错过了我没有在Discover目录中编译所有.cpp的事实.花了一个小时才把所有的图片都删除了,但现在她从makefile中编译就好了.
原始问题的新版本:我知道它可以通过makefile工作,我如何让Eclipse与makefile做同样的事情?
谢谢德米特里.
韦斯
我有我的代码编译与Dmitry(@Dmitry)的建议.只是,它们似乎造成了一个单独的问题.我希望我的库在运行时动态链接到主测试程序.将-l Discover -l EdgeIO添加到链接会获得编译的所有内容,但它会为我提供静态链接.
仅供参考,未使用的"pi"是SO,因此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
Run Code Online (Sandbox Code Playgroud)
我从Eclipse获得了同样的错误消息.
RemKonTester.cpp包含声明这些项的所有.h.我用声明extern"C"尝试过它们而不是.
希望得到帮助,
韦斯
你的问题似乎是-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
Run Code Online (Sandbox Code Playgroud)
它们应该位于目标文件之后,因为链接器在命令行遇到它们时会加载它们并搜索未定义的符号.
有关详细信息,请参阅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>&1 | tee ./RemKonTester/make.ERR
PS请注意,在StackOverflow中有一个编辑问题的选项,发布附加信息作为答案不是一个好习惯.