Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined symbol “toupper” in MacPorts GCC 4.7 OS-X Mavericks 10.9 C11

EDIT2:

so here is an example of the program:

#include <stdio.h>
#include <ctype.h>
int main ()
{
  int i=0;
  char str[]="Test String.\n";
  char c;
  while (str[i])
  {
    c=str[i];
    putchar (toupper(c));
    i++;
  }
  return 0;
 }

1) clang:

clang++ -std=c++0x -stdlib=libc++ -lc++ main.cc -o main

compiles fine.

2) g++-mp-4.8 -std=c++11 main.cc -o main gives:

Undefined symbols for architecture x86_64:
  "toupper(int)", referenced from:
      _main in ccWjHauc.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

3) g++-mp-4.8 main.cc -o main compiles!

any ideas what is wrong with the setup?

==========

Can someone help to understand what changed in Gcc/macports/os 10.9 ?

I used to have a compiling script of some third party library working in os 10.8. Recently I updated to the new osx (10.9) and gcc 4.7 from macports stopped linking. In particular I have:

Undefined symbols for architecture x86_64:
 "isspace(int)", referenced from:

This problem is very similar to the one mentioned here for istype. However it seems isspace does not sit in libgcc++.dylib.

Any ideas what to try?

EDIT1:

indeed, 4.8 fixed the problem with isspace, but another surfaced - toupper:

Undefined symbols for architecture x86_64:
  "toupper(int)", referenced from: ...

What is going on here?!. Is it related to the new Xcode (5.0) ?

like image 673
Denis Avatar asked Oct 27 '13 18:10

Denis


2 Answers

There's a patch in http://trac.macports.org/ticket/41033 It solved my problem. You just have to patch the file in /usr/include/sys/cdefs.h and replace

#elif defined(__GNUC__) && defined(__GNUC_STDC_INLINE__)

by

#elif defined(__GNUC__) && defined(__GNUC_STDC_INLINE__) && !defined(__cplusplus)

Good luck.

like image 183
aaragon Avatar answered Oct 11 '22 05:10

aaragon


Most of the ctype.h items are declared as inline definitions, so they get expanded at compile time. When you compile without -std=c++11, it expands to:

extern inline int 
toupper(int _c) 
{ 
        return (__toupper(_c)); 
} 

When you compile with -std=c++11, it expands to:

extern inline __attribute__((__gnu_inline__)) int 
toupper(int _c) 
{ 
        return (__toupper(_c)); 
}

For some reason, g++ is then choosing to ignore the perfectly good definition that is presented there.

Based on the commentary on this invalid bug, it's gcc choosing to not optimize the code and looking for the definition in one of the linked libraries.

A workaround seems to be to compile with at least -O1 optimization, which avoids the issue, but it's a real pain in the ass.

Now when we look at the differences in the #defines between non-C++11 and C++11, we see that we have an extra #define:

$ touch x.cc
$ g++-4.9 -dM -E x.cc | grep STD
#define __STDC_HOSTED__ 1
#define __STDC__ 1
$ g++-4.9 -std=c++11 -dM -E x.cc | grep STD
#define __STDC_HOSTED__ 1
#define __GNUC_STDC_INLINE__ 1
#define __STDC__ 1

and because of a piece of code in the 10.9 SDK (usr/include/sys/cdefs.h), all those __DARWIN_CTYPE_TOP_inline in cytpe.h get turned into __header_inline which get turned into extern __inline __attribute__((__gnu_inline__)) thanks to this little bit of additional code:

#elif defined(__GNUC__) && defined(__GNUC_STDC_INLINE__)
# define __header_inline           extern __inline __attribute__((__gnu_inline__))

It looks like apple's header is trying to do the right thing, but they've not covered all their bases. There is another issue, which mentions a similar bug.

like image 4
Petesh Avatar answered Oct 11 '22 04:10

Petesh