g++ 不包含它说它包含用于 C++11 的文件?

Posted

技术标签:

【中文标题】g++ 不包含它说它包含用于 C++11 的文件?【英文标题】:g++ does not include files it says it includes for C++11? 【发布时间】:2014-11-18 07:48:15 【问题描述】:

短版

当我使用 C++11 标准的特性(std::stod 函数)编译一个简单的代码时,GCC 4.9.1 失败并出现以下错误:

example.cpp: In function 'int main()':
example.cpp:10:18: error: 'stod' is not a member of 'std'
   double earth = std::stod (orbits,&sz);
                  ^
example.cpp:11:17: error: 'stod' is not a member of 'std'
   double moon = std::stod (orbits.substr(sz));
                 ^

什么?

我使用的命令是g++ -std=c++11 example.cpp

这是测试代码(在其他系统上编译良好):

// stod example from http://www.cplusplus.com/reference/string/stod/
#include <iostream>   // std::cout
#include <string>     // std::string, std::stod

int main ()

  std::string orbits ("365.24 29.53");
  std::string::size_type sz;     // alias of size_t

  double earth = std::stod (orbits,&sz);
  double moon = std::stod (orbits.substr(sz));
  std::cout << "The moon completes " << (earth/moon) << " orbits per Earth year.\n";
  return 0;

详情

我使用的是 GCC 4.9.1 版本,我在两个运行 CentOS 6.5 的不同集群上编译自己(我在我的主目录中使用模块系统,因为我不是管理员)。

我将它们称为集群 1 和集群 2:集群 1 是发生故障的地方。

GCC 以相同的方式同时编译,并使用相同的模块文件加载(除了基本路径中的微小差异)。据我可以轻松检查,安装是相同的(两个集群上存在相同的包含文件,并且具有相同的内容)。

g++ -v 的输出在两个集群上是相同的(同样,安装路径除外):

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/home/andyras/bin/gcc-4.9.1/libexec/gcc/x86_64-unknown-linux-gnu/4.9.1/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-4.9.1/configure --prefix=/home/andyras/bin/gcc-4.9.1 --enable-languages=c,c++,fortran
Thread model: posix
gcc version 4.9.1 (GCC)

g++ -v 使用系统 GCC 在两个集群上给出相同的输出,除了在集群 1 上它说它是 gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) 而在集群 2 上说它是 gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)

我正在尝试使用g++ -std=c++11 -save-temps -MD example.cpp 进行调试以获取更多信息...这提供了一些线索,但我不知道从这里去哪里。

集群 1 上的中间 (.ii) 文件缺少一些行,例如(摘自 diffing .ii 文件):

< # 277 "/opt/gcc-4.9.1/include/c++/4.9.1/cwchar" 3
---
> # 277 "/home/andyras/bin/gcc-4.9.1/include/c++/4.9.1/cwchar" 3
961,963c934,936
<   using std::wcstold;
<   using std::wcstoll;
<   using std::wcstoull;
---
> 
> 
>

正如我所解释的,两个集群上的 GCC 都试图包含像 cwchar 这样的文件,但在集群 1 上,有空行而不是定义的东西。在集群 2 上,stod 函数在中间文件中,但不在集群 1 上。

可能是预处理器错误?

现在查看.d(依赖)文件,我也看到了一个具体的区别。集群 2 上列出的一些文件未在集群 1 上列出。这是列表(我处理了.d 文件的内容以说明不同的基本路径;// 代表安装路径):

85a86,108
> //gcc-4.9.1/include/c++/4.9.1/ext/string_conversions.h
> //gcc-4.9.1/include/c++/4.9.1/cstdlib
> /usr/include/stdlib.h
> /usr/include/bits/waitflags.h
> /usr/include/bits/waitstatus.h
> /usr/include/sys/types.h
> /usr/include/sys/select.h
> /usr/include/bits/select.h
> /usr/include/bits/sigset.h
> /usr/include/sys/sysmacros.h
> /usr/include/alloca.h
> //gcc-4.9.1/include/c++/4.9.1/cstdio
> /usr/include/libio.h
> /usr/include/_G_config.h
> /usr/include/bits/stdio_lim.h
> /usr/include/bits/sys_errlist.h
> //gcc-4.9.1/include/c++/4.9.1/cerrno
> /usr/include/errno.h
> /usr/include/bits/errno.h
> /usr/include/linux/errno.h
> /usr/include/asm/errno.h
> /usr/include/asm-generic/errno.h
> /usr/include/asm-generic/errno-base.h

我很好奇 cpp 是否在所有错误的地方寻找包含,但这似乎是合法的 (cpp -v):

#include <...> search starts here:
 /home/andyras/bin/gcc-4.9.1/include
 /home/andyras/bin/gcc-4.9.1/include/c++/4.9.1/
 /home/andyras/bin/gcc-4.9.1/include/c++/4.9.1/x86_64-unknown-linux-gnu/
 /home/andyras/bin/gcc-4.9.1/lib/gcc/x86_64-unknown-linux-gnu/4.9.1/include
 /usr/local/include
 /home/andyras/bin/gcc-4.9.1/lib/gcc/x86_64-unknown-linux-gnu/4.9.1/include-fixed
 /usr/include
End of search list.

这几个小时试图追查问题的根源非常令人沮丧。当然,我可以使用 atof(myString.c_str()) 之类的东西来代替 std::stod,但我想知道是否存在一个潜在问题会破坏使用 C++11 其他位的未来项目。

非常感谢任何更多的线索或见解。

【问题讨论】:

前段时间我也遇到过同样的问题,这是因为我遗漏了“-std=c++11”。我知道你说你有那个,但也许再检查一下? 也许可以试试“-std=c++0x”。以防万一。 我会检查你的路径。作为一个实验,我在我的 Debian 系统上加载了 g++-4.4,并尝试在没有 -stdc=c++11 标志的情况下编译 example.cpp,它就像你的一样在 stod 上窒息。我会验证您在编译时实际上使用的是正确的 g++ 编译器。如果我使用我的 g++-4.7 它工作正常。 我确实在使用我认为的 GCC 版本......有趣的是它在同一系统上与 GCC 4.8.3 一起工作正常。 狂拍:在你的 4.4.7 安装中“打破”字符串头或其他文件(例如重命名或添加废话),看看它是否会影响另一个? 【参考方案1】:

您已经完成了所有必要的步骤来确定根本原因。您已经知道答案:您已经发布了自定义 gcc 安装在“集群 1”和“集群 2”(非工作和工作构建)上的行为方式之间的明显差异。

所以,这两个 gcc 安装之间显然有些不同;如果一个编译、链接和运行一些代码,而另一个阻塞在完全相同的代码段上。不幸的是,很难确定事情在哪里出轨。以前我自己构建过 gcc,以前,我可以说 gcc 是一个非常困难且非常难以安装的包。例如,在链接一些 C++ 代码时追查了几天的神秘失败后,我最终追查到 gcc 在 gcc 的配置脚本中选择了错误版本的 binutils,并在内部关闭了一些晦涩的功能,最终表现为链接失败不是 gcc,而是用 gcc 构建的东西。 gcc 本身是构建和安装的,没有任何抱怨,但它被破坏了。

因此,我认为 gcc 本身在没有明显问题的情况下构建和安装,但它已损坏,并且会以这种方式阻塞有效代码,这完全不足为奇,而且完全合理。

我的猜测是你破坏的 gcc 构建使用了一个损坏的默认包含路径——它正在寻找 /usr/include 中的头文件,而不是你自己的自定义安装目录。这是最有可能的答案,但它真的可以是任何东西。

【讨论】:

你的建议——gcc 在构建时捡到了它不应该得到的东西——在我看来也很可能。 gcc 使用的工具(例如预处理器)中有一些不正确的地方,而不仅仅是编译器。问题是我不确定在哪里可以找到这些信息,因为我已经删除了编译 gcc 的目录。答案可能是尝试重新编译... 这个概念被粗略地称为“可重复构建”或“确定性构建”。如果您打算养成构建 gcc 的习惯,则需要组合某种框架,以便每次都能以完全相同的方式可靠地构建 gcc。在最简单的情况下,这采用预制脚本的形式,该脚本获取下载的 gcc 源的原始 tarball,运行 tar 解压缩源,更改提取源的目录,运行配置脚本、make 和 make安装。因此,每次执行此操作时,都会得到相同的结果(续)... ...(续)这样在构建完成后,您就有了一个可安装的包,并且可以毫不犹豫地吹走包含提取源代码的目录。它不再需要了。如果您需要创建另一个构建,只需再次运行脚本即可。 这是一个很好的建议,下次我构建时,我会为自己制作一个脚本。我在安装这些版本时记录了我运行的命令,但从未将它们作为脚本运行,因此我无法确定所有信息都在那里。 我重建并安装了 GCC(使用我编写的脚本),现在它运行良好......我从来没有深入了解具体发生了什么,但它看起来真的很脏,所以我会接受这个答案。【参考方案2】:

嗯,你显然有(就像你自己写的那样)两个不同的 gcc 版本(一个是 4.4.7-3,另一个是 4.4.7-4),而且似乎它们在编译代码。

正如我在某处读到的,C++11 标准还没有完全包含在所有编译器中,所以这似乎是一个集群上的原因。另一个有(你可能知道为什么)一个包含更多新标准的版本,既然你希望你完全使用这个功能,我建议你在另一个集群上也安装这个版本。

【讨论】:

我同意你的说法,但问题是我没有使用 GCC 的系统版本(4.4.7-3 或 4.4.7-4);我正在使用自己安装的完全相同的版本(4.9.1),这是在两个系统上具有不同行为的编译器版本。 4.4.7 没有实现我感兴趣的 C++11 标准的一部分,并且失败并出现不同的错误。系统 GCC 上的 -3-4 指的是 Redhat 软件包版本。 既然编译器可能包含它至少会尝试一下,即使不是它也少了一个不确定性

以上是关于g++ 不包含它说它包含用于 C++11 的文件?的主要内容,如果未能解决你的问题,请参考以下文章

PHP 可以包含“文件名”但 c#? [关闭]

c++11 新特性之 autokeyword

pcl::io 没有成员 savePolygonFile

如何修复“FOR 循环不包含关键字”。用于 OS 的 Robot IDE 中的错误

使用makefile以简单的方式编译c ++ 11程序

将库放在Linux中的exe文件夹中