Setting locales on OS X crashes - c++

The following code works fine on Linux but throws an exception on OS X 10.7:
#include <iostream>
#include <locale>
#include <stdexcept>
int main() try {
std::locale::global(std::locale(""));
std::cout << "Using locale: " << std::locale().name() << "\n";
}
catch (std::runtime_error const& e) {
std::cout << e.what() << "\n";
return 1;
}
The output on OS X is:
locale::facet::_S_create_c_locale name not valid
However, the standard explicitly says that
The set of valid string argument values is "C", "", and any implementation-defined values.
So whatever causes the behaviour above is violating the standard.
The compiler used is clang++ 3.1 (tags/Apple/clang-318.0.58); I’ve also tried it with GCC 4.7, installed via Homebrew, with the same result.
Can other people validate this problem? What causes it? Am I doing anything wrong? Is this a bug in OS X?
(Maybe this relates to another xlocale problem but the errors are actually completely different.)

I don't think you're using xlocale. I believe that your problem is with libstdc++, which uses a different locale support library that is not supported on OS X, as the question EitanT links to states.
If you switch to libc++ your program will work.

The poster above it correct...the problem is with libstdc++. I wanted to add my answer because it is not straightforward how to get OS X to link against libc++ and took me over an hour to figure out.
Invoking the compiler/linker by g++ -libstd=libc++ or by clang++ -libstd=libc++ or by the alias c++ -libstd=libc++ will all fail.
The solution for compiling simple programs from the command line instead of messing with the added overhead of Xcode is to allow Xcode to handle the linking by using the command xcrun clang++ -stdlib=libc++
xcrun allows Xcode to manage the tool chain and will build a successful executable where cout.imbue(locale(foo)) will successfully work.

Related

Boost filesystem failed silently because the "C++ language dialect" was set to an incompatible setting. How to make it not silent when this happens?

I had spent some time trying to get simple boost filesystem operations working, and managed successfully by changing the project settings in XCode. For reference, here is my code that uses boost::filesystem:
namespace bfs = boost::filesystem;
std::cerr << "Before bfs calls" << std::endl;
bfs::path levelDir("data/levels/");
std::cerr << "path object created" << std::endl;
try
{
if (bfs::exists(levelDir) && bfs::is_directory(levelDir))
{
std::cerr << "Directory exists according to bfs" << std::endl;
bfs::directory_iterator endIter;
std::vector<bfs::path> paths;
for (bfs::directory_iterator it = bfs::directory_iterator(levelDir); it != endIter; ++it)
{
if (bfs::is_regular_file(it->status()))
{
paths.push_back(it->path());
}
}
}
}
catch (...)
{
// Handle exception.
}
std::cerr << "After bfs calls" << std::endl;
A problem I had when debugging, was that attempting to step through the code line by line would behave very strangely. Before I got to any boost::filesystem functions/objects the program would continue running, completely skipping over any boost::filesystem code. Additionally the output for the above would be:
Before bfs calls
After bfs calls
During my investigation, I found that the solution was to change the C++ Language Dialect setting to C++11 and the C++ Standard Library to libc++, both in XCode project settings under the Apple LLVM 6.0 Language C++ section. I assume this has to do with matching the settings that boost filesystem was built under.
My program built normally with no errors, and ran fine except whenever I needed to read files in a directory on the filesystem.
So on to my actual question: Since this has to do with a mismatch in compiler settings, why wasn't there a compile/linker error and is there anything I can change in XCode settings to alert me when this is the case? Since the regression happened when I upgraded boost via Homebrew, is there a way to detect the settings used to build libraries? I am also concerned that an update to XCode and its compiler may cause a similar problem.
I am running boost 1.56.0 installed via Homebrew, and XCode 6.0.1.
To be honest, I don't think I've seen a red herring this big in a while. Of course the C++ Language Dialect does not make some library code "magically" disappear or not-work.
What is far more likely, though, is:
you were debugging with optimizations enabled and hence the "current statement" pointer jumped all over the place, seemingly skipping functions (that might have been inlined or simply optimized out).
there were other differences in the running environment (e.g. the working directory was different) hence you found different files (e.g. no matching files in that working directory) and you thought you were seeing the library fail ghosts.
in an off-chance you could be witnessing Undefined Behaviour. This could in theory happen if parts of your code base were compiled using different compiler version/settings than others. (Google ODR and ABI for background)

Problems throwing and catching exceptions on OS X with -fno-rtti

The issue is somewhat similar to this question but the accepted answer does not really propose a solution or workaround.
In our project, we have a dylib and the main executalble. The dylib is compiled with -fno-rtti, while the executable does use RTTI. The problem happens when an exception (e.g. std::bad_alloc) is thrown from the dylib and is caught in the exe.
(Before you yell "exceptions need RTTI so you must have it on!", please note that the RTTI necessary for exceptions is always generated regardless of the -frtti or -fno-rtti setting. This is actually documented in the -fno-rtti flag description. The issue on OS X is that it's not generated in the same way)
After some investigation, the following was discovered:
In the dylib (-fno-rtti), there is a local copy of the exception's RTTI structures; in particular, the __ZTISt9bad_alloc symbol (typeinfo for std::bad_alloc).
The exe (-frtti) imports the typeinfo symbol from libstdc++.6.dylib and does not have a local copy
Since the exception handling code relies on comparing typeinfo pointers to determine exception match, the matching fails, and only the catch(...) succeeds.
So far I see the following options:
1) compile everything, or at least the files that throw and catch exceptions, with -frtti. This is doable but I don't like the idea of generating RTTI for everything even if we don't use it; and the list of files which work with exceptions is prone to get stale.
2) when linking the dylib, somehow make the linker throw away the weak exception definition from the object file and use the one from libstdc++.6.dylib. So far I was not successful.
3) ???
I made a small test illustrating the problem.
--- throw.cpp ---
#include <iostream>
#if defined(__GNUC__)
#define EXPORT __attribute__((visibility("default")))
#else
#define EXPORT __declspec(dllexport)
#endif
EXPORT void dothrow ()
{
std::cout << "before throw" << std::endl;
throw std::bad_alloc();
}
--- main.cpp ---
#include <stdio.h>
#include <iostream>
#if defined(__GNUC__)
#define IMPORT extern
#else
#define IMPORT __declspec(dllimport)
#endif
IMPORT void dothrow ();
int main (void) {
try {
std::cout << "trying lib->main exception" << std::endl;
dothrow ();
}
catch ( const std::bad_alloc& )
{
std::cout << "caught bad_alloc in main - good." << std::endl;
}
catch (...)
{
std::cout << "caught ... in main - bad!" << std::endl;
}
}
--- makefile ---
# for main exe
CFLAGS_RTTI=-m32 -frtti -fvisibility=hidden -fvisibility-inlines-hidden -shared-libgcc -funwind-tables
# for dylib
CFLAGS_NORTTI=-m32 -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden -shared-libgcc
# for linking; some switches which don't help
CLFLAGS=-Wl,-why_live,-warn_commons,-weak_reference_mismatches,error,-commons,error
all: test
test: libThrow.dylib main.o
g++ $(CFLAGS_RTTI) -o test main.o -lthrow -L./ $(CLFLAGS)
main.o: main.cpp
g++ $(CFLAGS_RTTI) -c -o main.o main.cpp
throw.o: throw.cpp
g++ $(CFLAGS_NORTTI) -c -o throw.o throw.cpp
libThrow.dylib: throw.o
g++ $(CFLAGS_NORTTI) -dynamiclib -o libThrow.dylib throw.o
clean:
rm test main.o throw.o
Running:
$ ./test
trying lib->main exception
before throw
caught ... in main - bad!
Symbols of the files involved:
$ nm -m throw.o | grep bad_alloc
000001be (__TEXT,__textcoal_nt) weak private external __ZNSt9bad_allocC1Ev
000001be (__TEXT,__textcoal_nt) weak private external __ZNSt9bad_allocC1Ev
00000300 (__TEXT,__eh_frame) weak private external __ZNSt9bad_allocC1Ev.eh
(undefined) external __ZNSt9bad_allocD1Ev
00000290 (__DATA,__const_coal) weak external __ZTISt9bad_alloc
000002a4 (__TEXT,__const_coal) weak external __ZTSSt9bad_alloc
(undefined) external __ZTVSt9bad_alloc
$ nm -m libThrow.dylib | grep bad_alloc
00000ce6 (__TEXT,__text) non-external __ZNSt9bad_allocC1Ev
(undefined) external __ZNSt9bad_allocD1Ev (from libstdc++)
00001050 (__DATA,__const) weak external __ZTISt9bad_alloc
00000e05 (__TEXT,__const) weak external __ZTSSt9bad_alloc
(undefined) external __ZTVSt9bad_alloc (from libstdc++)
$ nm -m main.o | grep bad_alloc
(undefined) external __ZTISt9bad_alloc
$ nm -m test | grep bad_alloc
(undefined) external __ZTISt9bad_alloc (from libstdc++)
Note: similar compilation options on Linux and Windows works fine. I can throw exceptions from a shared object/dll and catch them in the main exe, even if they're compiled with different -frtti/-fno-rtti options.
EDIT: here's how I ended up solving it for the specific case of bad_alloc:
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
#define throw_nomem std::__throw_bad_alloc
#else
#define throw_nomem throw std::bad_alloc
#endif
EXPORT void dothrow ()
{
std::cout << "before throw" << std::endl;
throw_nomem();
}
The function __throw_bad_alloc is imported from libstdc++.6.dylib and so always throws a correct type.
You can simply move all your "throw exceptions" infrastructure to the helper library with -frtti enabled - and link it to other stuff. Without actual code it's hard to tell, if this decomposition is possible or not.
Here is some sample code:
// Thrower.cc
void DoThrow() {
throw std::bad_alloc;
}
// LibraryNoRTTI.cc
void f() {
DoThrow();
}
// main.cc
int main() {
try {
f();
}
catch(std::bad_alloc&) {}
return 0;
}
The simplest way is to move all your throw invocations to the separate functions with appropriate types, like: throw std::logical_error("message"); goes to void ThrowLogicError(const std::string& message) { ... }
If there is a problem with encapsulation (private exception classes), then you may make friends with throwing functions.
If you still want to use (throw/catch) exceptions inside the non-rtti library, then you have to make separation between internal exceptions and exceptions used in your library API.
The good way is to use native C++ throw-catch for internal purposes - and then rethrow some exceptions, using rtti-based library functions, to the outside - according to your interface:
// Thrower.cc
void Rethrow(const std::exception& e) {
throw e;
}
// LibraryNoRTTI.cc
namespace {
void internal_stuff() {
throw std::logical_error("something goes wrong!");
}
} // namespace
// You even may explicitly specify the thrown exceptions in declaration:
void f() throw(std::logical_error) {
try {
internal_stuff();
}
catch(std::exception& e) {
Rethrow(std::logical_error(std::string("Internal error: ") + e.what());
}
}
Start Edit March 4, 2014
I think the Clang++ compiler has a better chance of obtaining the desired exception handling. I have found this Stack Overflow post: Clang and the default compiler in OS X Lion. The post has helpful script lines for modifying ~/.bashrc to change the system default compiler settings on Snow Leopard and how to use the LLVM GCC. For Clang, add inside the ~/.bashrc:
# Set Clang as the default compiler for the system
export CC=clang
export CFLAGS=-Qunused-arguments
export CPPFLAGS=-Qunused-arguments
If the c++ symbolic link is not present, either call clang++ directly or add the c++ link as desired (e.g.
ln -s /usr/bin/clang++ c++
). It is a good idea to check all symbolic links within the /usr/bin by running:
ls -l `which lynx` | more
On my Mavericks command line tools installation c++ points to clang++ and cc points to clang. The g++ compiler version says:
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx- include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
The clang++ complier version says:
$clang++ --version
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
Notice that the g++ include directory path is set to /usr/include/c++/4.2.1, probably not the include path needed to resolve the issue.
MacPorts: Hopefully the Answer for any OS X version
The best solution I can find to obtain any Clang++ compiler version for any OS X version is to use the open source tool called MacPorts. There is extensive documentation in the MacPorts Guide. The application is called port and can be installed from an OS X installation package or obtain the source code and compile locally. The following is from installing MacPorts onto Snow Leopard. The other OS X versions should be similar. After obtaining MacPorts for Snow Leopard, run the port search command to observe all the different clang related ports available. For example, it looks like this:
$port search clang
The partial list of search results from Snow Leopard 10.6.8 is:
clang-2.9 #2.9_13 (lang)
C, C++, Objective C and Objective C++ compiler
clang-3.0 #3.0_12 (lang)
C, C++, Objective C and Objective C++ compiler
clang-3.1 #3.1_7 (lang)
C, C++, Objective C and Objective C++ compiler
clang-3.2 #3.2_2 (lang)
C, C++, Objective C and Objective C++ compiler
clang-3.3 #3.3_2 (lang)
C, C++, Objective C and Objective C++ compiler
clang-3.4 #3.4 (lang)
C, C++, Objective C and Objective C++ compiler
clang-3.5 #3.5-r202097 (lang)
C, C++, Objective C and Objective C++ compiler
clang_select #0.1 (sysutils)
common files for selecting default clang version
Then I successfully installed clang-3.3 with: sudo port install clang-3.3. After this completes, see the available versions by typing port select --list clang. Then run the
sudo port select --set clang mp-clang-3.3
or similar. When I execute clang++ --version it says (as expected):
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-apple-darwin10.8.0
Thread model: posix
Same for when the clang --version command is executed (after closing and restarting the terminal):
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-apple-darwin10.8.0
Thread model: posix
There are MacPorts installation packages for many OS X versions (e.g. Leopard, Snow Leopard, Lion, Mountain Lion, Mavericks, etc.). I did not go any further back than Leopard with my search. If using an OS X older than Leopard, please review the MacPorts site thoroughly.
If curious about details on where to find Xcode 4.2 (or used to be able to obtain it), I have found this post regarding obtaining Xcode 4.2 for Snow Leopard Xcode 4.2 download for Snow Leopard. Then these two additional ones: Can i use the latest features of C++11 in XCode 4 or OSX Lion? [duplicate] and Can I use C++11 with Xcode?. After trying a couple links to see if the 4.2 Xcode remains available for Snow Leopard, no joy.
More than likely the MacPorts libc++ installation will be necessary to have full C++11 support. To install the more recent version, execute sudo port install libcxx. The contents of the /usr/lib will be overwritten with the current C++11 libraries (as necessary per MacPorts Ticket #42385: libcxx/libcxxabi: OS update can render system unusable
If libc++ still appears to be lacking, try this: "libc++" C++ Standard Library. Then use this:
$ export TRIPLE=-apple-
$ export MACOSX_DEPLOYMENT_TARGET=10.6
$ ./buildit
from How to build libc++ with LLVM/Clang 3.3 on Mac OS X 10.6 "Snow Leopard".
On OS X Lion, Mountain Lion, and Mavericks, they all have recent independent command line tools downloads on the Apple Developer site. The Clang version may be older than what one needs, so be sure to confirm which C++11 features are needed when using the Developer site command line tools' Clang.
End Edit March 4, 2014
The above macro detection may need to change from __GNUC__ to __clang__ or __clang_version__. It all depends on what the predefined compiler macros are for each OS X compiler, and the best way to detect as needed here. The Stack Overflow answer at: What predefined macro can I use to detect clang? should be helpful in configuring the command line to obtain them (e.g. clang++ -dM -E -x c /dev/null).
I have noticed when running the preceding example command that there is a predefined macro called __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__. On the Mavericks clang++, the macro value is 1090. It might be necessary to have a family of #ifdef logic to set the appropriate EXPORT macro for each OS X clang++ compiler.
Well, even though I have accepted an answer it did not solve all problems. So I'm writing down the solution which did work in the end.
I made a small tool for post-processing the object files and marking the local symbols as UNDEF. This forces the linker to use definitions from libstdc++ and not local ones from the file. The basic approach of the tool is:
load the Mach-O header
walk the load commands and find the LC_SYMTAB command
load the list of symbols (struct nlist) and the strings
walk the symbols and look for those that we need (e.g. __ZTISt9bad_alloc)
set the found symbols' type to N_UNDF|N_EXT.
after processing, write the modified symbol table back to the file.
(I also made a similar implementation for ELF)
I post-process any file that's using std exceptions, either for throwing or for catching. To make sure the file list does not go stale, I added a post-link check for unwanted local symbols using nm.
This seems to resolve all the problems I've had so far.

C++ hello world not working?

I am new to C++ and I am self-teaching. I am using code::blocks, and have a question. When I write hello world, nothing happens. This is what is says in the debugger window:
Building to ensure sources are up-to-date
Selecting target:
Debug
ERROR: You need to specify a debugger program in the debuggers's settings.
(For MinGW compilers, it's 'gdb.exe' (without the quotes))
(For MSVC compilers, it's 'cdb.exe' (without the quotes))
and here is the program:
#include <iostream>
using namespace std;
int main()
{
cout << "Helloworld!" << endl;
return 0;
}
also if you need it, here is the build log:
"hello world again - Debug": The compiler's setup (GNU GCC Compiler) is invalid, so Code::Blocks cannot find/run the compiler.
Probably the toolchain path within the compiler options is not setup correctly?!
Goto "Settings->Compiler and debugger...->Global compiler settings->GNU GCC Compiler->Toolchain executables" and fix the compiler's setup.
Skipping...
Nothing to be done (all items are up-to-date).
Try to download the debugger and the compiler again. It worked for me when I had this problem. Try downloading the 'gdb.exe' from the internet.

Compiler option not working for unordered set C++11 feature

I am on Ubuntu 12.04 x64, using Eclipse Indigo w/ CDT plugin, and my g++ version is 4.7.3. I have added the compiler option -std=c++11 and the same option to discovery options (even though the code did not autocomplete when I wrote it).
Eclipse underlines parts of the following in red and gives warnings. However, the program, when run (ignoring errors), prints the expected result (Compiled with gcc 4.7\n 1 0\n). How can I fix this behavior?
#include <unordered_set>
#include <iostream>
using namespace std;
int main()
{
unordered_set<int> s; // Symbol unordered_set cannot be resolved
cout << "Compiled with gcc " << __GNUC__ << '.' << __GNUC_MINOR__ << endl;
s.insert(0); // Method insert cannot be resolved
s.insert(1); // Method insert cannot be resolved
s.insert(0); // Method insert cannot be resolved
for(auto i = s.begin(); i != s.end(); ++i) cout << ' ' << (*i);
// Method begin and end cannot be resolved
cout << endl;
return 0;
}
This is what Eclipse calls in command line:
...$ gcc -E -P -v -dD -std=c++11 .../specs.c
Using built-in specs.
...
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04)
After turning off the -std=c++11 compiler option for my C compiler (as it shouldn't be needed there anyway) - but keeping it on for the C++ compiler, the output printed to the console is as follows.
...$ g++ -E -P -v -dD -std=c++11 .../specs.cpp
Using built-in specs.
...
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04)
And, regardless of the errors Eclipse shows me, the output is still the same, showing the unordered set works and was compiled properly. This is clearly just an issue before the build. If my indexer isn't parsing properly before the build, how is the set working at runtime?
The compiler you are using may not include support for C++11, check your man page or IDE documentation and it will tell you if there is support or not.
Your problem is that the file's extension is .c instead of .cpp (or .cc), which causes it to be compiled with gcc instead of g++.
This means it is treated as pure C code instead of C++11, which makes it unsurprising that it won't compile.
I gave up because there was simply nothing else I could do, purged my my system of eclipse and my ~/.eclipse folder, downloaded Kepler and its CDT version, and now everything works.

Eclipse C++ on OS X

I'm trying to develop programs using C++ and Eclipse on MacOS X but I can't make it work. Please help me configure Eclipse! I have job interviews and I need to refresh my C++ skills!
I installed Eclipse CDT and GCC compiler for MacOS X and I try to compile a simple HelloWorld program (see code below).
#include <iostream>
using namespace std;
int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
return 0;
}
I get errors and warnings and I can't seem to resolve them. Any help would be much appreciated.
Errors
Symbol 'cout' could not be resolved (Semantic Error),
Same for 'endl',
Same for 'std'.
Warnings
Error launching external scanner info generator (g++),
Error launching external scanner info generator (gcc),
Program 'g++' is not found in $PATH,
Program 'gcc' is not found in $PATH.
On OSX, the compiler comes as part of XCode. So, even if you don't want to use the XCode IDE, you have to install XCode to get the compiler (and linker (and other tools you need)).