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
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());
}
}
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:
LC_SYMTAB
command__ZTISt9bad_alloc
)N_UNDF|N_EXT
.(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.
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.