【问题标题】:Solaris' stdlib.h functions implemented by C++ libs?由 C++ 库实现的 Solaris 的 stdlib.h 函数?
【发布时间】:2020-09-17 21:17:06
【问题描述】:

我正在努力将开源工具移植到 Solaris。大多数事情都有效,cmake/pkg-config/等。在那里,找到了依赖关系,gmake 工作,编译器和链接器调用看起来都很好,并且很流行:

Undefined           first referenced
 symbol                 in file
std::qsort(void*, unsigned int, unsigned int, int (*)(const void*, const void*))      ...

这部分我不明白。乍一看,std::qsort 没有意义,它应该是 C 库的一部分,而不是 STL。所以我查看了 stdlib.h 并找到了一个列表,如 using std::sort; 和许多其他标准函数,如 freemallocatoi 等,在 C++ 上下文的情况下重定向。

Oracle 在那里做什么?为什么?如果他们像这样重定向它,我应该链接哪个库?或者为什么 CC 命令不像 GCC 那样自动将其拉入? 我尝试添加 -lstdc++ 但没有运气。

另外,普通的 libc 版本似乎在 (或 )中定义。直接包含其中一个标头是否合法,或者这会在链接时造成其他随机破坏吗?

编辑:

由于对构建系统的怪异有多种怀疑,这里基本上是来自 gmake 执行的链接调用:

/opt/developerstudio12.6/bin/CC -std=c++11 -xO3 -DNDEBUG <i.e. bunch of object files> -o ../systest  -L/opt/csw/lib/64 -lintl

我在那里看不到任何特别之处,我希望 CC 弄清楚要链接什么以获得强制性功能。

【问题讨论】:

  • 真正的问题是:你到底是如何构建这个的,以便标准库默认不链接到二进制文件?那是我不明白的部分,除非 cmake 在 Solaris 上被简单地破坏了。链接器应自动将您的应用程序与 C 和 C++ 运行时库链接。如果没有,那有些东西很时髦。您所说的重定向很有趣,但在这里并不重要-它们已被纳入标准(嗯,重定向不是,只是相关符号的存在,谁会两次实现这样的对-没人,因为这很愚蠢- 因此重定向)。
  • 不,真正的问题是:谁负责流程中的关键部分?让我分解一下:a)C++ 编译器,b)调用用户,如果(b)那么 b1)从手册页中获取 lib 名称?或b2)从其他地方找到它?或 b3) cmake/autoconf 应该弄清楚吗?或b4)cmake / autoconf的用户检查代码应该弄清楚吗?关于意义:Sun/Oracle 似乎在 C 运行时和 C++ 运行时两次实现了代码。这部分没有意义。除非用户能够在没有 libc 的情况下链接 cpp 应用程序,否则只能链接 cpp 运行时。
  • @UnslanderMonica 发布的编译器命令将生成 32 位二进制文​​件。但-L 选项表示正在搜索64 位 库。必须解决这个问题,因为我们不知道 /opt/csw/lib/64 中的内容,所以我们不知道哪些库无法加载。

标签: c++ solaris


【解决方案1】:

规则是#include &lt;xxx.h&gt; 将名称放入全局命名空间,并且也允许将它们放入std。相反,#include &lt;cxxx&gt; 将名称放入 std 并允许将它们放入全局命名空间中。实际上,这意味着有两种方法可以在 C++ 中实现标准 C 库中的函数:在 &lt;xxx.h&gt; 标头中声明标准 C 库名称并将这些声明提升到 cxxx 标头中的 std 中,或者在标头中声明 std 中的名称,并将这些声明提升到 &lt;xxx.h&gt; 标头中的全局命名空间中。使用前一种方法,函数的名称将是qsort;对于后者,它将是std::qsort。无论哪种方式,该错误消息通常表明编译器存在设置问题。链接器没有找到标准库。

【讨论】:

  • 链接器由 CC 调用,即 C++ 编译器(C++!不是 C)。然后它应该正确检测链接器以包含正确的 C++ 运行时库。但显然这不会发生。用户应该如何解决或解决这个问题?我找不到任何文档来解决这个问题。
【解决方案2】:

这个编译命令

/opt/developerstudio12.6/bin/CC -std=c++11 -xO3 -DNDEBUG ...

将生成一个 32 位的可执行文件。每the Oracle CC man page

在 Oracle Solaris 上,-m32 是默认值。在支持 64 位程序的 Linux 系统上,-m64 -xarch=sse2 是默认设置。

但是这个库选项

-L/opt/csw/lib/64

正在搜索一个包含 64 位 库的目录。

-m64添加到编译命令或使用32位库路径。

更新

如果问题包含完整的错误消息,几乎可以肯定是可以回答的,几乎可以肯定是这样的:

CC -g qsort.cc -o qsort
"qsort.cc", line 15: Error: Could not find a match for std::qsort(int[4], unsigned, unsigned, int(void*,void*)) needed in main(int, char**).
"/usr/include/iso/stdlib_iso.h", line 184: Note: Candidate 'std::qsort(void*, unsigned, unsigned, extern "C" int(*)(const void*,const void*))' is not viable: argument '4' can't be converted from 'int(void*,void*)' to 'extern "C" int(*)(const void*,const void*)'.
"/usr/include/iso/stdlib_iso.h", line 187: Note: Candidate 'std::qsort(void*, unsigned, unsigned, int(*)(const void*,const void*))' is not viable: argument '4' can't be converted from 'int(void*,void*)' to 'int(*)(const void*,const void*)'.

此代码在 Solaris 11.4 上使用 Oracle Developer Studio 12.6 编译时运行良好:

#include <stdlib.h>

int compare( const void *p1, const void *p2 )
{
    int i1 = *( ( int * ) p1 );
    int i2 = *( ( int * ) p2 );
    return( i1 - i2 );
}

int main( int argc, char **argv )
{
    int array[ 4 ] = { 5, 8, 12, 4 };

    qsort( array, sizeof( array ) / sizeof( array[ 0 ] ),
        sizeof( array[ 0 ] ), &compare );
}

【讨论】:

  • 你的提示是第一个进入一些有用的方向。但是,当我尝试修复它时,情况会变得更糟。即使是像这样的简单复制也会失败:#include &lt;errno.h&gt; #include &lt;limits.h&gt; #include &lt;stdarg.h&gt; 并像 /opt/developerstudio12.6/bin/CC -c repro.cc -std=c++11 -m64 -I/usr/include 一样构建它,结果是:"/usr/include/sys/va_impl.h", line 98: Error: Only one of a set of overloaded functions can be extern "C".。我现在对 Oracle 工具链非常反感,接下来要试试 clang。
  • @PasterOfMuppets 你不应该需要-I/usr/include。 Oracle 的 C++ 编译器在遵守 C++ 标准方面比 GCC 更加迂腐。例如,您可能需要改用#include &lt;cstdarg&gt;。或者,如果系统不是最新的,您可能需要修补它。
  • @PasterOfMuppets 请注意,即使是从 Solaris in the OpenSolaris source code 派生的 va_impl.h 的原始 2004 版本在第 98 行也有 cmets。如果您的系统尚未更新或修补,您可能会尝试这样做相当于使用 GCC 9 进行 C++11 编译,但在 15 到 20 岁的 RHEL 2 上
  • 不是最新的? 2004年的东西?严重地?抱歉,这是来自 Oracle 服务器(版本 11.4)的几周前的 VirtualBox 映像,我按照最新的下载说明安装了最新的 Oracle Studio。如果 Oracle 提供蹩脚的旧标头,这不是我的错。如果编译器无法理解包含非常基本的 C 头文件,这也不是我的错。从什么时候开始我必须包含 C++ 包装头文件而不是 C 版本?你在这里责备受害者。
  • @PasterOfMuppets 你不是受害者。编译器向您显示了一条完整的错误消息,其中包含您未能发布的大量信息。我敢打赌你传递给qsort() 的函数是int compare( void *, void * ) 而不是必需的int compare( const void *, const void * )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-04
  • 1970-01-01
相关资源
最近更新 更多