4

I am trying to run my C++ program on other Mac OSX machines which may have an older copy of libstdc++, but have all the other tools. I tried to follow this approach, also mentioned in this SO question, even though it discusses a linux setup. I have small program try.cpp:

#include <iostream>

int main() {
        int a = 10;
        std::cout << a << '\n';
        return 1;
}

Obviously, if I just compile it, I get

$ /usr/bin/g++ try.cpp 
$ otool -L a.out 
a.out:
 /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

I understand the dependency on libSystem.B.dylib, and we can leave that aside. To try to get rid of libstdc++, I try this:

$ /usr/bin/g++ try.cpp /usr/lib/libstdc++-static.a 
$ otool -L a.out 
a.out:
 /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

So, I try

$ ln /usr/lib/libstdc++-static.a .
$ /usr/bin/g++ try.cpp -L.
$ otool -L a.out 
a.out:
    /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

or,

$ /usr/bin/g++ try.cpp -L. -lstdc++-static
$ otool -L a.out 
a.out:
 /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

Finally, this works:

$ /usr/bin/gcc try.cpp -L. -lstdc++-static
$ otool -L a.out 
a.out:
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

Is this alright? (To use gcc to link C++ programs with libstdc++). I've heard somewhere that g++ is actually a script that uses gcc and libstdc++ to compile C++ programs. If that is the case, and we use it correctly, it should be ok.

However, I am actually using the macport compiler and a more complicated program, for which gcc generates some warnings, while it is C++ compliant. Something to the effect of:

ld: warning: std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf() has different visibility (hidden) in /opt/local/lib/gcc44/libstdc++.a(sstream-inst.o) and (default) in /var/folders/2u/2uLPtE+3HMi-BQIEfFVbSE+++TU/-Tmp-//ccoE2rqh.o

This suggests that we shouldnt be using gcc for c++ compilations. So to sum up, the questions are:

  • How to link libstdc++ statically
  • If g++ doesn't do it, is it ok to use gcc and supply the libstdc++ manually? Then why the visibility warnings?
  • If neither of the two approaches work because of the visibility problems in the compiled libraries, why not use libstdc++ source files (sstream.h, list.h, vector.c) etc and just include them in the compilation. Even though this will make the compilation slow, it might be useful for certain applications. It might even lead to better optimization!
Community
  • 1
  • 1
highBandWidth
  • 16,751
  • 20
  • 84
  • 131
  • To half-answer my own question, could we do so by compiling it with g++ -c first, and the linking with ld the required libraries. I don't see any broken rules here, since we use the g++ compiler for c++, and then link the libraries to give all the functions. What I don't know is which libraries we need to supply to ld. Apparently we need more than just libstdc++, since ld gives a ton of errors for missing symbols. – highBandWidth Oct 15 '10 at 03:10

2 Answers2

3

It sounds like you just want to target earlier Mac OS X versions, which can be done without statically linking with libstdc++. I think the GCC that ships with Xcode targets the host environment by default. However, it can handle a special flag called -mmacosx-version-min to change the target environment. If you provide this with the target OS X version number then it will automatically create binaries compatible with that version of Mac OS X.

#include <iostream>

int main(void)
{
    std::cout << "Hello world!" << std::endl;
    return 0;
}

Compile like this:

g++ -mmacosx-version-min=10.4 test.cpp

I compiled this program twice, once with the flag and once without, and then I copied both binaries to a Mac running 10.4. The one compiled with the flag executed properly, however the one compiled without the flag said “Bad CPU type in executable” (despite the fact that it was compiled on an identical machine just running a later version of OS X).

Some of the headers have macro guards that prevent you from using functions/classes introduced in 10.5 or 10.6 if you have specified 10.4 as a minimum target (I'm not sure about C++ headers, but the Cocoa, Foundation, AppKit etc. framework headers definitely do).

dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • I agree, the mmacosx-version-min flag should compile into something compatible with an earlier version. Even though I gave a trivial example, I am actually using some tr1 features that are not included in the earlier libstdc++'s (certain hash functions needed for std::tr1::unordered_set and maps). So I actually need to link to the newer libstdc++. However, if I were to link it statically, the code does run! So, it is not a matter of the OS not providing certain features. The features are provided by c++, and it __can__ run on earlier versions. I can give such a toy example, if someone asks. – highBandWidth Oct 15 '10 at 02:01
0

This is a stretch for my knowledge but I see few responses here so!

GCC is a compiler driver that will also drive the linker. g++ to my understanding is more of just a compiler. So to get G++ to build properly I believe you need to build the object files and link them manually. Of the top of my head I can't say how to do this as I'm IDE brain damaged at the moment.

As to the error you have seen that might be due to the wrong files being linked in. I'm on my iPhone right now so I'm not about to dechiper the error message you printed. I'm not a fan at all of MacPorts so don't be surprised that, that installation is screwed up. First though make sure you are using the MacPorts libs with the MacPorts compiler.

In the end I have no doubt that you can do what you want to do. You will need to however start reading Make files and more of the documentation of the GCC tool set. Focus on building and linking files into programs. You might want to find a small open source program tha builds nicely on a mac and look at the Make files there.

Of course finding a good C++ based project to learn from is not easy. I would however reccomend installing LLVM & CLang especially considering the new rev is suppose to be C++ ready. Obviously a different set of tools but CLang may resolve your issues or at least give you better debugging info. Maybe somebody can chime in with an opensource C++ project with simple clean make files. The closest I've seen lately is a project called HeeksCAD.

In the end when building anything non trivial you end up needing more than just GCC. A lot of that is taken care of with IDEs these days, however I'm not certain if XCode can be properly configured to do what you want.

  • Frantz: I agree, and I mentioned something earlier in the comment to dreamlax's answer. I am trying to find such a makefile to look at. Does xcode generate these makefiles? – highBandWidth Oct 15 '10 at 15:50
  • I tried the instructions [here][1] to get a Makefile but it didnt work. [1]: http://richarddingwall.name/2007/04/08/generating-a-makefile-from-xcode/ – highBandWidth Oct 15 '10 at 16:10