8

Short version

When I compile even a simple code using a feature of the C++11 standard (the std::stod function), GCC 4.9.1 fails with the following error:

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));
                 ^

What?

The command I use is g++ -std=c++11 example.cpp.

This is the test code (which compiles fine on other systems):

// 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;
}

details

I am using a version of GCC 4.9.1 I compiled myself on two different clusters running CentOS 6.5 (I use the modules system on stuff in my home dir since I'm not an admin).

I will call them cluster 1 and cluster 2: cluster 1 is where the failure happens.

The GCCs were compiled in the same way and at the same time, and loaded using identical module files (save for a minor difference in the base path). The installations are, as far as I can easily check, identical (the same include files exist on both clusters, and have the same contents).

The output from g++ -v is the same on both clusters (again, except for the install path):

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 using the system GCC gives the same output on both clusters, except on cluster 1 it says it is gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) and on cluster 2 says gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)

I am trying to debug using g++ -std=c++11 -save-temps -MD example.cpp for more info... this gives some clues, but I don't know where to go from here.

The intermediate (.ii) files on cluster 1 are missing some lines, for example (excerpt from diffing the .ii files):

< # 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;
---
> 
> 
>

As I interpret it, GCC on both clusters tries to include files like cwchar, but on cluster 1 there are blank lines instead of things being defined. On cluster 2 the stod function is in the intermediate file, but not on cluster 1.

Could it be a preprocessor error?

Now looking at the .d (dependency) files, I also see a concrete difference. There are some files listed on cluster 2 that are not listed on cluster 1. Here is the list (I processed the contents of the .d files to account for the different base paths; // stands in for the install path):

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

I was curious if cpp was looking for includes in all the wrong places, but this seems legit (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.

This has been a very frustrating couple of hours trying to track down the source of the problem. I could, of course, use something like atof(myString.c_str()) instead of std::stod, but I am wondering if there is an underlying issue that will foul up future projects using other bits of C++11.

Any more clues or insight would be very much appreciated.

andyras
  • 15,542
  • 6
  • 55
  • 77
  • 3
    this exact same problem happened to me some time ago, and it was because i left out the "-std=c++11". I know you say that you have that in, but maybe check again? – thang Sep 23 '14 at 23:50
  • Maybe try "-std=c++0x". Just in case. – davepmiller Sep 23 '14 at 23:52
  • I would check your paths. As an experiment I loaded g++-4.4 on my Debian system and tried to compile example.cpp without the -stdc=c++11 flag and it choked on stod just like yours. I'd verify that you are in fact using the right g++ compiler when compiling. If I use my g++-4.7 it works fine. – Michael Petch Sep 24 '14 at 00:10
  • I am indeed using the version of GCC I think I am... the funny thing is that it works fine with GCC 4.8.3 on the same system. – andyras Sep 24 '14 at 00:47
  • Wild shot: "break" the string header or other files (e.g. rename or add in nonsense) in your 4.4.7 installation and see if it affects the other? – leewz Sep 24 '14 at 03:08
  • Hmm. What happens if you try to `#include ` (a C++11-only header)? – T.C. Sep 24 '14 at 03:42
  • @leewangzhong I like the idea, but I don't have write access to the 4.4.7 installation. @T.C., when I `#include ` I have the same problem I did before, i.e. it breaks on the `stod` things, not the array things. Creating an array, e.g. `std::array myStrArray` works just fine. – andyras Sep 25 '14 at 02:29
  • Try breaking the string library on your 4.9 installation instead? Or, search the header (or grep through the folders that it should be in) to see whether stod is defined? – leewz Sep 25 '14 at 03:58
  • @leewangzhong, the `stod` function is defined in the header, but the contents of the header are not included in the intermediate file. That's what I show when I'm talking about the `.ii` files. If I break, for example, the `cwchar` header, the compilation fails at that header. – andyras Sep 25 '14 at 13:15
  • I would have expected cluster 2 to fail since (https://gcc.gnu.org/onlinedocs/gcc-4.9.1/libstdc++/manual/manual/status.html) - string conversions are not implemented (and it's including stuff from there) – Marco A. Sep 26 '14 at 07:50
  • What does ' std::cout << "C++ " << __cplusplus << std::endl; ' display on the two systems? – Surt Sep 30 '14 at 11:25
  • @Surt: the output of that code compiled with `g++ -std=c++11` is `C++ 201103` on both systems. – andyras Sep 30 '14 at 20:19
  • `The moon completes 12.3684 orbits per Earth year.` :) looks like is picking up the wrong includes, should be easy to verify diff'ing the two compiles with the flag `-E` (I think is what you done with save-temps), I would verify if there's some diff in the config*.log of the two g++ builds, also of the installed packages/version in the two system. – Alex Oct 02 '14 at 16:44

2 Answers2

4

You have already done all the necessary footwork to determine the root cause. You already know the answer: you have posted clear differences between how custom gcc installs behave on your "cluster 1" and "cluster 2", a non-working and a working build.

So, something is obviously different between these two gcc installs; if one compiles, links, and runs some code, and the other one chokes on the exact same piece of code. Unfortunately, it's hard to pinpoint where things go off the rails. Having built gcc myself before, previously, I can say that gcc is a hellishly difficult, and very fickle package to install. For example, after several days chasing a mysterious failure when linking some C++ code, I ended up chasing it down to gcc picking up the wrong version of binutils, in gcc's configure script, and internally turning off some obscure feature, that eventually manifested itself as a link failure not of gcc, but of stuff that got built with gcc. gcc itself got built, and installed, with nary a complaint, but it was broken.

So, I find it completely unsurprising, and entirely plausible, the proposition that gcc itself got built and installed without an apparent issue, but it's broken, and will choke on valid code, in this fashion.

My guess would be that your busted gcc build is using a broken default include path -- it's looking for headers in /usr/include, instead of your own custom installation directory. That's the most likely answer, but it could really be anything.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • What you suggest--that gcc picked up something it shouldn't while building--seems likely to me also. Something incorrect in the tools gcc uses (e.g. the preprocessor), not just the compiler. The trouble is I'm not sure where to look for that information since I have since deleted the directories where I compiled gcc. The answer may be to try recompiling... – andyras Sep 30 '14 at 20:21
  • This concept is loosely called "reproducible builds" or "deterministic builds". If you intend to make a habit of building gcc, you need to put together some kind of a framework for being able to reliably build gcc in an exact, identical way, every time. In the most simplest case, this takes a form of a pre-made script that takes the pristine tarball of the downloaded gcc sources, runs tar to unpack the sources, changes to the extract source's directory, runs the configure script, make, and make install. So that every time you do this, you get identical results (continued)... – Sam Varshavchik Oct 01 '14 at 00:52
  • ...(continued) so that after the build is done, you have an installable package, and the directory with the extracted sources can be blown away without hesitation. It's not needed anymore. If you ever need to create another build, you just run the script again. – Sam Varshavchik Oct 01 '14 at 00:53
  • That is a great suggestion, and next time I build I will make myself a script. I took notes on the commands I ran when I installed these versions, but never ran them as a script so I can't be sure all the information is there. – andyras Oct 02 '14 at 04:04
  • I rebuilt and installed GCC (using a script I wrote) and it works perfectly now... I never got to the bottom of what happened specifically, but it really looks like dirty paths so I will accept this answer. – andyras Oct 03 '14 at 03:31
1

Well, you obviously have (like you wrote yourself) two different versoins of gcc (one time 4.4.7-3 and the other 4.4.7-4), and It seems that they have (even though slightly) differences in compiling the code.

As I've read somewhere, the C++11-standard is not yet included completely in all compilers, so this seems to be the cause on the one Cluster. The other has (you might know why) a version where more of the new standard is included and since you want you use exactly this feature I'd recommend installing this version on the other Cluster too.

fkarg
  • 198
  • 2
  • 17
  • I would agree with what you say, but the thing is that I am not using the system versions (4.4.7-3 or 4.4.7-4) of GCC; I am using my own installations of the exact same version (4.9.1), and that is the version of the compiler that has different behavior on the two systems. 4.4.7 does not implement the part of the C++11 standard I am interested in, and fails with a different error. The `-3` and `-4` on the system GCCs refer to the Redhat package version. – andyras Oct 02 '14 at 04:03
  • Since the compiler might include it would at least try it, and even if it's not it there's one uncertainty less – fkarg Oct 02 '14 at 04:28