【发布时间】: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