在使用了第三方库seetaface6,并且自定义类继承了库中的类。
链接时报错:
/usr/bin/ld: CMakeFiles/main.dir/main.cpp.o:(.data.rel.ro._ZTI7Handler[_ZTI7Handler]+0x10): undefined reference to `typeinfo for seeta::v3::QualityOfBrightness'
反复看了库的源代码和自己的代码,确认所有函数都定义了。
绝望之时看到有说是-fno-rtti选项的原因。
g++手册:
-fno-rtti
Disable generation of information about every class with virtual
functions for use by the C++ run-time type identification features
("dynamic_cast" and "typeid"). If you don't use those parts of the
language, you can save some space by using this flag. Note that
exception handling uses the same information, but G++ generates it as
needed. The "dynamic_cast" operator can still be used for casts that do
not require run-time type information, i.e. casts to "void *" or to
unambiguous base classes.
Mixing code compiled with -frtti with that compiled with -fno-rtti may
not work. For example, programs may fail to link if a class compiled
with -fno-rtti is used as a base for a class compiled with -frtti.
我们平时的代码编译时是-frtti,而如果其他库使用-fno-rtti,就可能在链接时出错。
当在编译我对代码时带上-fno-rtti,确实能通过了,但是这样有很大缺陷。
所以我选择将库重新编译,带上-frtti。然而这并没有奏效,我确信-frtti在库中已经启用。
又看到其中有个-fvidibility=hidden,当将它去掉之后,重新编译库,就解决了。具体原因请看手册介绍。
-fvisibility=[default|internal|hidden|protected]
Set the default ELF image symbol visibility to the specified
option---all symbols are marked with this unless overridden within the
code. Using this feature can very substantially improve linking and
load times of shared object libraries, produce more optimized code,
provide near-perfect API export and prevent symbol clashes. It is
strongly recommended that you use this in any shared objects you
distribute.
Despite the nomenclature, default always means public; i.e., available
to be linked against from outside the shared object. protected and
internal are pretty useless in real-world usage so the only other
commonly used option is hidden. The default if -fvisibility isn't
specified is default, i.e., make every symbol public.
A good explanation of the benefits offered by ensuring ELF symbols have
the correct visibility is given by "How To Write Shared Libraries" by
Ulrich Drepper (which can be found at
<https://www.akkadia.org/drepper/>)---however a superior solution made
possible by this option to marking things hidden when the default is
public is to make the default hidden and mark things public. This is
the norm with DLLs on Windows and with -fvisibility=hidden and
"__attribute__ ((visibility("default")))" instead of
"__declspec(dllexport)" you get almost identical semantics with
identical syntax. This is a great boon to those working with cross-
platform projects.
For those adding visibility support to existing code, you may find
"#pragma GCC visibility" of use. This works by you enclosing the
declarations you wish to set visibility for with (for example) "#pragma
GCC visibility push(hidden)" and "#pragma GCC visibility pop". Bear in
mind that symbol visibility should be viewed as part of the API
interface contract and thus all new code should always specify
visibility when it is not the default; i.e., declarations only for use
within the local DSO should always be marked explicitly as hidden as so
to avoid PLT indirection overheads---making this abundantly clear also
aids readability and self-documentation of the code. Note that due to
ISO C++ specification requirements, "operator new" and "operator delete"
must always be of default visibility.
Be aware that headers from outside your project, in particular system
headers and headers from any other library you use, may not be expecting
to be compiled with visibility other than the default. You may need to
explicitly say "#pragma GCC visibility push(default)" before including
any such headers.
"extern" declarations are not affected by -fvisibility, so a lot of code
can be recompiled with -fvisibility=hidden with no modifications.
However, this means that calls to "extern" functions with no explicit
visibility use the PLT, so it is more effective to use "__attribute
((visibility))" and/or "#pragma GCC visibility" to tell the compiler
which "extern" declarations should be treated as hidden.
Note that -fvisibility does affect C++ vague linkage entities. This
means that, for instance, an exception class that is be thrown between
DSOs must be explicitly marked with default visibility so that the
type_info nodes are unified between the DSOs.
An overview of these techniques, their benefits and how to use them is
at <http://gcc.gnu.org/wiki/Visibility>.
以下内容转自https://blog.csdn.net/ai2000ai/article/details/47152133
在项目中遇到了这样一个问题:C++文件编译都OK,但链接的时候报错:undefined reference to `typeinfo for xxx’。typeinfo是C++中的RTTI(RunTime Type Identification)机制中记录类型信息用的,dynamic_cast和typeid操作符会使用这些信息。
以”undefined reference to typeinfo”为关键字在网络上搜索,大多数都是说有虚函数定义了但是未实现导致的。但是我的代码显然不是这个情况。在我即将放弃的时候,终于在StackOverflow上发现有人提出,这种错误的原因也可能是混合使用了带RTTI信息和不带RTTI信息的代码导致的。对比检查,发现我的项目里的问题正是这个。最后用了一点dirty hack,解决了bug。下面就仔细分析一下”undefined reference to `typeinfo for xxx’“产生的原因。
虚函数未实现
产生”undefined reference to `typeinfo for xxx’“最常见的原因就是基类的虚函数未实现了。由于C++类的实现可以分布在多个源文件中,所以生成目标文件时,基类的虚函数没有定义是不会报错的。但是链接成可执行文件时,需要将虚函数的信息放进typeinfo中,这个时候虚函数未实现就会引发这个错误。
混用了no-RTTI代码和RTTI代码
我碰到的正是混用了no-RTTI和RTTI代码的情形。项目中我们自己写的程序必须开启RTTI,而我们使用的外部的一个库使用no-RTTI编译。我们在自己的代码中需要重载一个外部库中的带虚函数的类,结果链接的时候就出现了问题。外部库中的基类使用-fno-rtti选项编译,生成的代码没有typeinfo信息,而我们的代码使用-frtti选项编译,要求基类必须要有typeinfo信息。最后,我在编译系统中做了一些dirty hack,让那个派生类所在的源文件以-fno-rtti选项编译,解决了问题。
我遇到的问题类似,现在的项目中需要开启RTTI,链接的外部库是no-RTTI编译的,在现在的工程中重载外部库的带虚函数的类,连接的时候报错.原文说的dirty hack,是对单个文件加编译选项-fno-rtti 。因为我用的外部库是可以开启RTTI的,我用RTTI重新编译一次后,现在的工程不报错啦。

文章讲述了在使用seetaface6库时遇到的链接错误,该错误是由于项目代码启用RTTI而库未启用导致的。通过添加-fno-rtti编译选项解决当前问题,但作者认为这不是最佳方案。最终,通过去掉-fvisibility=hidden选项并重新编译库,成功解决了问题,这允许正确处理类型信息并避免了符号冲突。

9200

被折叠的 条评论
为什么被折叠?



