On Sat, 9 Jan 2010, Ralf Wildenhues wrote:
[ moving from libtool@ ]
* Bob Friesenhahn wrote on Tue, Jan 05, 2010 at 05:11:56PM CET:
Using 'llvm-gcc' (GCC frontend to llvm compiler) I find that C++
exceptions do not work (are not caught) in the built programs.
[ and suspect libtool as culprit ]
We can only find out better if we have small examples to look at.
Here is a proposed patch to try exception handling in libraries and
modules. Tested with g++ on GNU/Linux; it will certainly need fixes
for other systems, and Libtool may as well.
I'd appreciate a look over it for any obvious glitches, before I commit
it.
My main comment is that it would be useful if the thrown class is
derived from std:exception (or one of its standard derived classes) in
order to flush out any issues which may stem from possible partial
template instantiation in libstdc++ (or pre-compiled headers) as well
as in the test translation unit.
Bob
Thanks,
Ralf
Testsuite exposure for C++ exception handling.
* tests/exceptions.at (C++ exception handling): New file, new
test.
* Makefile.am (TESTSUITE_AT): Update.
Report by Bob Friesenhahn.
diff --git a/Makefile.am b/Makefile.am
index 31b4275..e9f8566 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -496,6 +496,7 @@ TESTSUITE_AT = tests/testsuite.at \
tests/recursive.at \
tests/template.at \
tests/ctor.at \
+ tests/exceptions.at \
tests/early-libtool.at \
tests/no-executables.at \
tests/deplibs-ident.at \
diff --git a/tests/exceptions.at b/tests/exceptions.at
new file mode 100644
index 0000000..d551cb8
--- /dev/null
+++ b/tests/exceptions.at
@@ -0,0 +1,231 @@
+# exception.at -- test C++ exception handling with libtool -*- Autotest -*-
+#
+# Copyright (C) 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+####
+
+AT_SETUP([C++ exception handling])
+AT_KEYWORDS([libtool])
+AT_KEYWORDS([libltdl])
+: ${LTDLINCL="-I$abs_top_srcdir/libltdl"}
+: ${LIBLTDL="$abs_builddir/../libltdl/libltdlc.la"}
+CPPFLAGS="$LTDLINCL $CPPFLAGS"
+
+AT_DATA([module.h],
+[[class modexc { };
+extern "C" int modfoo () throw (modexc);
+]])
+
+AT_DATA([module.cpp],
+[[#include <iostream>
+#include "module.h"
+
+int modbar (void) throw (modexc)
+{
+ throw modexc ();
+}
+
+extern "C"
+int modfoo (void) throw (modexc)
+{
+ try {
+ modbar ();
+ }
+ catch (modexc) {
+ std::cerr << "caught inside module\n";
+ throw modexc ();
+ }
+ return 0;
+}
+]])
+
+AT_DATA([lib.h],
+[[class libexc { };
+int libfoo () throw (libexc);
+]])
+
+AT_DATA([lib.cpp],
+[[#include <iostream>
+#include "lib.h"
+
+int libbar (void) throw (libexc)
+{
+ throw libexc ();
+}
+
+int libfoo (void) throw (libexc)
+{
+ try {
+ libbar ();
+ }
+ catch (libexc) {
+ std::cerr << "caught inside lib\n";
+ throw libexc ();
+ }
+ return 0;
+}
+]])
+
+AT_DATA([main.cpp],
+[[#include <ltdl.h>
+#include <cstdlib>
+#include <iostream>
+#include "lib.h"
+#include "module.h"
+
+class exc { };
+
+int foo (void) throw (exc)
+{
+ throw exc ();
+ return 0;
+}
+
+int exceptions_in_prog (void)
+{
+ std::cerr << "exceptions_in_prog\n";
+ try {
+ foo ();
+ }
+ catch (exc) {
+ std::cerr << "caught\n";
+ return 0;
+ }
+ return 1;
+}
+
+int exceptions_in_lib (void)
+{
+ std::cerr << "exceptions_in_lib\n";
+ try {
+ libfoo ();
+ }
+ catch (libexc) {
+ std::cerr << "caught\n";
+ return 0;
+ }
+ return 1;
+}
+
+int exceptions_in_module (void)
+{
+ std::cerr << "exceptions_in_module\n";
+
+ if (lt_dlinit ())
+ {
+ std::cerr << "init error: " << lt_dlerror () << '\n';
+ return 1;
+ }
+
+ // Some systems need RTLD_GLOBAL for exceptions to work in modules.
+ lt_dladvise advise;
+ if (lt_dladvise_init (&advise) || lt_dladvise_global (&advise))
+ {
+ std::cerr << "error setting advise global\n";
+ return 1;
+ }
+
+ lt_dlhandle handle = lt_dlopenadvise ("module.la", advise);
+ if (handle == NULL)
+ {
+ std::cerr << "dlopen failed: " << lt_dlerror () << '\n';
+ return 1;
+ }
+ lt_dladvise_destroy (&advise);
+
+ typedef int (*pfun) (void);
+ pfun pf = (pfun) lt_dlsym (handle, "modfoo");
+ if (pf == NULL)
+ {
+ std::cerr << "dlsym failed: " << lt_dlerror () << '\n';
+ return 1;
+ }
+
+ try {
+ (*pf) ();
+ }
+ catch (modexc) {
+ if (lt_dlclose (handle))
+ {
+ std::cerr << "dlclose failed: " << lt_dlerror () << '\n';
+ return 1;
+ }
+ if (lt_dlexit ())
+ {
+ std::cerr << "lt_dlexit failed: " << lt_dlerror () << '\n';
+ return 1;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+int main (void)
+{
+ if (exceptions_in_prog ())
+ return 1;
+ if (exceptions_in_lib ())
+ return 1;
+ if (exceptions_in_module ())
+ return 1;
+ return 0;
+}
+]])
+
+inst=`pwd`/inst
+libdir=$inst/lib
+bindir=$inst/bin
+moddir=$inst/mod
+mkdir l m $inst $libdir $bindir $moddir
+
+# If the C++ compiler isn't capable, don't bother.
+AT_CHECK([$CXX $CPPFLAGS $CXXFLAGS -c main.cpp || exit 77], [], [ignore],
[ignore])
+
+for file in lib.cpp module.cpp; do
+ AT_CHECK([$LIBTOOL --mode=compile --tag=CXX $CXX $CPPFLAGS $CXXFLAGS -c
$file],
+ [], [ignore], [ignore])
+done
+AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o l/liba.la
]dnl
+ [lib.lo -no-undefined -version-info 1:0:0 -rpath $libdir],
+ [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o
m/module.la ]dnl
+ [module.lo -module -avoid-version -no-undefined -rpath $moddir],
+ [], [ignore], [ignore])
+
+# We need -export-dynamic for the exception handling in modules to work.
+AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o
main$EXEEXT ]dnl
+ [main.$OBJEXT l/liba.la -dlopen m/module.la $LIBLTDL -export-dynamic],
+ [], [ignore], [ignore])
+
+LT_AT_NOINST_EXEC_CHECK([./main], [-dlopen m/module.la], [], [ignore],
[ignore])
+
+AT_CHECK([$LIBTOOL --mode=install cp l/liba.la $libdir],
+ [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=install cp m/module.la $moddir],
+ [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=install cp main$EXEEXT $bindir],
+ [], [ignore], [ignore])
+rm -rf l m main$EXEEXT
+
+LTDL_LIBRARY_PATH=$moddir
+export LTDL_LIBRARY_PATH
+LT_AT_EXEC_CHECK([$bindir/main], [], [ignore], [ignore])
+
+AT_CLEANUP
--
Bob Friesenhahn
bfrie...@simple.dallas.tx.us, http://www.simplesystems.org/users/bfriesen/
GraphicsMagick Maintainer, http://www.GraphicsMagick.org/